-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathtest_hardware.rs
169 lines (153 loc) · 5.96 KB
/
test_hardware.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
use crate::ConfigSettings;
use helpers::{error::BynarError, error::BynarResult, error::HardwareError};
use libredfish::{
common::Status, manager::Manager, power::Power, storage::ArrayController, storage::DiskDrive,
storage::Hardware, storage::StorageEnclosure, thermal::Thermal, *,
};
use log::debug;
use reqwest::Client;
/// Summary of all the hardware status information
pub struct HardwareHealthSummary {
pub array_controllers: Vec<BynarResult<()>>,
/// Physical disk drive status
pub disk_drives: Vec<BynarResult<()>>,
/// iLo status
pub manager: Vec<BynarResult<()>>,
/// Power supply status
pub power: Vec<BynarResult<()>>,
pub storage_enclosures: Vec<BynarResult<()>>,
/// Fan status
pub thermals: Vec<BynarResult<()>>,
}
fn collect_redfish_info(config: &ConfigSettings) -> BynarResult<HardwareHealthSummary> {
let client = Client::builder()
.danger_accept_invalid_certs(true)
.danger_accept_invalid_hostnames(true)
.build()?;
if config.redfish_ip.is_none() {
debug!("Redfish ip address not specified. Skipping checks");
return Ok(HardwareHealthSummary {
array_controllers: vec![],
disk_drives: vec![],
manager: vec![],
power: vec![],
storage_enclosures: vec![],
thermals: vec![],
});
}
let redfish_config = Config {
user: config.redfish_username.clone(),
password: config.redfish_password.clone(),
endpoint: config.redfish_ip.clone().unwrap(),
port: config.redfish_port,
};
let redfish = Redfish::new(client, redfish_config);
let controllers = redfish.get_array_controllers()?; //get_array_controllers(&client, &redfish_config)?;
let mut array_controllers: Vec<ArrayController> = Vec::new();
let mut storage_enclosures: Vec<StorageEnclosure> = Vec::new();
let mut disk_drives: Vec<DiskDrive> = Vec::new();
for controller_id in 1..=controllers.mult_hardware.total {
array_controllers.push(redfish.get_array_controller(controller_id as u64)?);
// Grab all the enclosures attached to this array controller
let enclosures = redfish.get_storage_enclosures(controller_id as u64)?;
for enclosure_id in 1..=enclosures.mult_hardware.total {
storage_enclosures
.push(redfish.get_storage_enclosure(controller_id as u64, enclosure_id as u64)?);
}
//Grab all disks attached to this array controller
let disks = redfish.get_physical_drives(controller_id as u64)?;
for disk_id in 1..disks.mult_hardware.total {
disk_drives.push(redfish.get_physical_drive(disk_id as u64, controller_id as u64)?);
}
}
let controller_results = array_controllers
.into_iter()
.map(evaluate_storage)
.collect();
let enclosure_results = storage_enclosures
.into_iter()
.map(evaluate_storage)
.collect();
let disk_drive_results = disk_drives.into_iter().map(evaluate_storage).collect();
let manager = redfish.get_manager_status()?;
let manager_result = evaluate_manager(&manager);
let thermal = redfish.get_thermal_status()?;
let thermal_result = evaluate_thermals(&thermal);
let power = redfish.get_power_status()?;
let power_result = evaluate_power(&power);
Ok(HardwareHealthSummary {
array_controllers: controller_results,
disk_drives: disk_drive_results,
manager: manager_result,
power: power_result,
storage_enclosures: enclosure_results,
thermals: thermal_result,
})
}
pub fn check_hardware(config: &ConfigSettings) -> BynarResult<HardwareHealthSummary> {
collect_redfish_info(&config)
}
fn evaluate_storage<T>(hardware: T) -> BynarResult<()>
where
T: Hardware + Status,
{
if hardware.health() != "OK" {
return Err(BynarError::HardwareError(HardwareError {
name: hardware.model(),
location: Some(hardware.location()),
location_format: Some(hardware.location_format()),
error: format!("{:?} has failed", hardware.get_type()),
serial_number: Some(hardware.serial_number()),
}));
}
Ok(())
}
fn evaluate_manager(manager: &Manager) -> Vec<BynarResult<()>> {
// Look through all the self test results
// Check if this is an HP machine first?
let mut results: Vec<BynarResult<()>> = Vec::new();
for res in &manager.oem.hp.i_lo_self_test_results {
if res.status != "OK" && res.status != "Informational" {
// Found an error
let err = format!("Hp ilo error detected: {}", res.notes);
results.push(Err(BynarError::new(err)));
}
}
results
}
fn evaluate_power(power: &Power) -> Vec<BynarResult<()>> {
let mut results: Vec<BynarResult<()>> = Vec::new();
for psu in &power.power_supplies {
if psu.status.health != "OK" {
// Power supply failed
let err = format!("PSU serial # {} has failed", psu.serial_number);
results.push(Err(BynarError::new(err)));
}
}
results
}
fn evaluate_thermals(thermal: &Thermal) -> Vec<BynarResult<()>> {
let mut results: Vec<BynarResult<()>> = Vec::new();
for fan in &thermal.fans {
if let Some(fan_health) = &fan.status.health {
if fan_health != "OK" {
// Fan failed
let err = format!("Chassis fan {} has failed", fan.fan_name);
results.push(Err(BynarError::new(err)));
}
}
}
for temp_reading in &thermal.temperatures {
if let Some(temp_health) = &temp_reading.status.health {
if temp_health != "OK" {
// Too hot ?
let err = format!(
"Temperature reading for {} is failing. Location: {}",
temp_reading.name, temp_reading.physical_context
);
results.push(Err(BynarError::new(err)));
}
}
}
results
}