Add more iLO data
This commit is contained in:
parent
5077bad918
commit
1ed1926697
445
Cargo.lock
generated
445
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "kon"
|
name = "kon"
|
||||||
version = "0.3.6"
|
version = "0.3.7"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
@ -66,50 +66,137 @@ struct Status {
|
|||||||
state: String
|
state: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
struct Power {
|
||||||
|
#[serde(rename = "PowerCapacityWatts")]
|
||||||
|
power_capacity_watts: i32,
|
||||||
|
#[serde(rename = "PowerConsumedWatts")]
|
||||||
|
power_consumed_watts: i32,
|
||||||
|
#[serde(rename = "PowerMetrics")]
|
||||||
|
power_metrics: PowerMetrics
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
struct PowerMetrics {
|
||||||
|
#[serde(rename = "AverageConsumedWatts")]
|
||||||
|
average_consumed_watts: i32,
|
||||||
|
#[serde(rename = "MaxConsumedWatts")]
|
||||||
|
max_consumed_watts: i32,
|
||||||
|
#[serde(rename = "MinConsumedWatts")]
|
||||||
|
min_consumed_watts: i32
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct System {
|
||||||
|
#[serde(rename = "Memory")]
|
||||||
|
memory: Memory,
|
||||||
|
#[serde(rename = "Model")]
|
||||||
|
model: String,
|
||||||
|
#[serde(rename = "Oem")]
|
||||||
|
oem: Oem,
|
||||||
|
#[serde(rename = "PowerState")]
|
||||||
|
power_state: String,
|
||||||
|
#[serde(rename = "ProcessorSummary")]
|
||||||
|
processor_summary: ProcessorSummary
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct Memory {
|
||||||
|
#[serde(rename = "TotalSystemMemoryGB")]
|
||||||
|
total_system_memory: i32
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct ProcessorSummary {
|
||||||
|
#[serde(rename = "Count")]
|
||||||
|
count: i32,
|
||||||
|
#[serde(rename = "Model")]
|
||||||
|
cpu: String
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct Oem {
|
||||||
|
#[serde(rename = "Hp")]
|
||||||
|
hp: Hp
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct Hp {
|
||||||
|
#[serde(rename = "PostState")]
|
||||||
|
post_state: String
|
||||||
|
}
|
||||||
|
|
||||||
const ILO_HOSTNAME: &str = "POMNI";
|
const ILO_HOSTNAME: &str = "POMNI";
|
||||||
|
|
||||||
async fn ilo_data() -> Result<Chassis, ReqError> {
|
enum RedfishEndpoint {
|
||||||
|
Thermal,
|
||||||
|
Power,
|
||||||
|
System
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RedfishEndpoint {
|
||||||
|
fn url(&self) -> String {
|
||||||
|
match self {
|
||||||
|
RedfishEndpoint::Thermal => "Chassis/1/Thermal".to_string(),
|
||||||
|
RedfishEndpoint::Power => "Chassis/1/Power".to_string(),
|
||||||
|
RedfishEndpoint::System => "Systems/1".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn ilo_data(endpoint: RedfishEndpoint) -> Result<Box<dyn std::any::Any + Send>, ReqError> {
|
||||||
let client = ClientBuilder::new()
|
let client = ClientBuilder::new()
|
||||||
.danger_accept_invalid_certs(true)
|
.danger_accept_invalid_certs(true)
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let res = client
|
let res = client
|
||||||
.get(format!("https://{}/redfish/v1/chassis/1/thermal", token_path().await.ilo_ip))
|
.get(format!("https://{}/redfish/v1/{}", token_path().await.ilo_ip, endpoint.url()))
|
||||||
.basic_auth(token_path().await.ilo_user, Some(token_path().await.ilo_pw))
|
.basic_auth(token_path().await.ilo_user, Some(token_path().await.ilo_pw))
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let body = res.json().await.unwrap();
|
match endpoint {
|
||||||
Ok(body)
|
RedfishEndpoint::Thermal => {
|
||||||
|
let body: Chassis = res.json().await.unwrap();
|
||||||
|
Ok(Box::new(body))
|
||||||
|
}
|
||||||
|
RedfishEndpoint::Power => {
|
||||||
|
let body: Power = res.json().await.unwrap();
|
||||||
|
Ok(Box::new(body))
|
||||||
|
}
|
||||||
|
RedfishEndpoint::System => {
|
||||||
|
let body: System = res.json().await.unwrap();
|
||||||
|
Ok(Box::new(body))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve data from the HP iLO4 interface
|
/// Retrieve data from the HP iLO4 interface
|
||||||
#[poise::command(
|
#[poise::command(
|
||||||
slash_command,
|
slash_command,
|
||||||
subcommands("temperature")
|
subcommands("temperature", "power", "system")
|
||||||
)]
|
)]
|
||||||
pub async fn ilo(_: poise::Context<'_, (), Error>) -> Result<(), Error> {
|
pub async fn ilo(_: poise::Context<'_, (), Error>) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve data from the HP iLO4 interface
|
/// Retrieve the server's temperature data
|
||||||
#[poise::command(slash_command)]
|
#[poise::command(slash_command)]
|
||||||
pub async fn temperature(ctx: poise::Context<'_, (), Error>) -> Result<(), Error> {
|
pub async fn temperature(ctx: poise::Context<'_, (), Error>) -> Result<(), Error> {
|
||||||
ctx.defer().await?;
|
ctx.defer().await?;
|
||||||
let data = ilo_data().await.unwrap();
|
let ilo = ilo_data(RedfishEndpoint::Thermal).await.unwrap();
|
||||||
|
let data = ilo.downcast_ref::<Chassis>().unwrap();
|
||||||
let mut tempdata = String::new();
|
let mut tempdata = String::new();
|
||||||
let mut fandata = String::new();
|
let mut fandata = String::new();
|
||||||
|
|
||||||
let allowed_sensors = [
|
let allowed_sensors = [
|
||||||
"01-Inlet Ambient",
|
"01-Inlet Ambient",
|
||||||
"04-P1 DIMM 1-6",
|
"04-P1 DIMM 1-6",
|
||||||
"13-Chipset",
|
|
||||||
"14-Chipset Zone"
|
"14-Chipset Zone"
|
||||||
];
|
];
|
||||||
|
|
||||||
for temp in data.temperatures {
|
for temp in &data.temperatures {
|
||||||
if temp.reading_celsius == 0 || !allowed_sensors.contains(&temp.name.as_str()) {
|
if temp.reading_celsius == 0 || !allowed_sensors.contains(&temp.name.as_str()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -117,14 +204,13 @@ pub async fn temperature(ctx: poise::Context<'_, (), Error>) -> Result<(), Error
|
|||||||
let name = match temp.name.as_str() {
|
let name = match temp.name.as_str() {
|
||||||
"01-Inlet Ambient" => "Inlet Ambient",
|
"01-Inlet Ambient" => "Inlet Ambient",
|
||||||
"04-P1 DIMM 1-6" => "P1 DIMM 1-6",
|
"04-P1 DIMM 1-6" => "P1 DIMM 1-6",
|
||||||
"13-Chipset" => "Chipset",
|
|
||||||
"14-Chipset Zone" => "Chipset Zone",
|
"14-Chipset Zone" => "Chipset Zone",
|
||||||
_ => "Unknown Sensor"
|
_ => "Unknown Sensor"
|
||||||
};
|
};
|
||||||
|
|
||||||
tempdata.push_str(&format!("**{}:** `{}°C`\n", name, temp.reading_celsius));
|
tempdata.push_str(&format!("**{}:** `{}°C`\n", name, temp.reading_celsius));
|
||||||
}
|
}
|
||||||
for fan in data.fans {
|
for fan in &data.fans {
|
||||||
if fan.current_reading == 0 {
|
if fan.current_reading == 0 {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -136,7 +222,7 @@ pub async fn temperature(ctx: poise::Context<'_, (), Error>) -> Result<(), Error
|
|||||||
CreateEmbed::new()
|
CreateEmbed::new()
|
||||||
.color(BINARY_PROPERTIES.embed_color)
|
.color(BINARY_PROPERTIES.embed_color)
|
||||||
.timestamp(Timestamp::now())
|
.timestamp(Timestamp::now())
|
||||||
.title(format!("{} - HP iLO4 Temperatures", ILO_HOSTNAME))
|
.title(format!("{} - Temperatures", ILO_HOSTNAME))
|
||||||
.fields(vec![
|
.fields(vec![
|
||||||
("Temperatures", tempdata, false),
|
("Temperatures", tempdata, false),
|
||||||
("Fans", fandata, false)
|
("Fans", fandata, false)
|
||||||
@ -145,3 +231,65 @@ pub async fn temperature(ctx: poise::Context<'_, (), Error>) -> Result<(), Error
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retrieve the server's power data
|
||||||
|
#[poise::command(slash_command)]
|
||||||
|
pub async fn power(ctx: poise::Context<'_, (), Error>) -> Result<(), Error> {
|
||||||
|
ctx.defer().await?;
|
||||||
|
let ilo = ilo_data(RedfishEndpoint::Power).await.unwrap();
|
||||||
|
let data = ilo.downcast_ref::<Power>().unwrap();
|
||||||
|
|
||||||
|
let mut powerdata = String::new();
|
||||||
|
|
||||||
|
powerdata.push_str(&format!("**Power Capacity:** `{}w`\n", &data.power_capacity_watts));
|
||||||
|
powerdata.push_str(&format!("**Power Consumed:** `{}w`\n", &data.power_consumed_watts));
|
||||||
|
powerdata.push_str(&format!("**Average Power:** `{}w`\n", &data.power_metrics.average_consumed_watts));
|
||||||
|
powerdata.push_str(&format!("**Max Consumed:** `{}w`\n", &data.power_metrics.max_consumed_watts));
|
||||||
|
powerdata.push_str(&format!("**Min Consumed:** `{}w`", &data.power_metrics.min_consumed_watts));
|
||||||
|
|
||||||
|
ctx.send(CreateReply::default().embed(
|
||||||
|
CreateEmbed::new()
|
||||||
|
.color(BINARY_PROPERTIES.embed_color)
|
||||||
|
.timestamp(Timestamp::now())
|
||||||
|
.title(format!("{} - Power", ILO_HOSTNAME))
|
||||||
|
.description(powerdata)
|
||||||
|
)).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieve the server's system data
|
||||||
|
#[poise::command(slash_command)]
|
||||||
|
pub async fn system(ctx: poise::Context<'_, (), Error>) -> Result<(), Error> {
|
||||||
|
ctx.defer().await?;
|
||||||
|
let ilo = ilo_data(RedfishEndpoint::System).await.unwrap();
|
||||||
|
let data = ilo.downcast_ref::<System>().unwrap();
|
||||||
|
|
||||||
|
let mut bios_data = String::new();
|
||||||
|
|
||||||
|
let post_state = match data.oem.hp.post_state.as_str() {
|
||||||
|
"FinishedPost" => "Finished POST",
|
||||||
|
_ => "???"
|
||||||
|
};
|
||||||
|
if data.oem.hp.post_state != "FinishedPost" {
|
||||||
|
println!("iLO:PostState = {}", data.oem.hp.post_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
bios_data.push_str(&format!("**POST:** `{}`\n", post_state));
|
||||||
|
bios_data.push_str(&format!("**Power:** `{}`\n", &data.power_state));
|
||||||
|
bios_data.push_str(&format!("**Model:** `{}`", &data.model));
|
||||||
|
|
||||||
|
ctx.send(CreateReply::default().embed(
|
||||||
|
CreateEmbed::new()
|
||||||
|
.color(BINARY_PROPERTIES.embed_color)
|
||||||
|
.timestamp(Timestamp::now())
|
||||||
|
.title(format!("{} - System", ILO_HOSTNAME))
|
||||||
|
.description(bios_data)
|
||||||
|
.fields(vec![
|
||||||
|
(format!("CPU ({}x)", data.processor_summary.count), data.processor_summary.cpu.trim().to_string(), true),
|
||||||
|
("RAM".to_string(), format!("{} GB", data.memory.total_system_memory), true)
|
||||||
|
])
|
||||||
|
)).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
32
src/main.rs
32
src/main.rs
@ -82,12 +82,40 @@ async fn on_ready(
|
|||||||
async fn event_processor(
|
async fn event_processor(
|
||||||
ctx: &Context,
|
ctx: &Context,
|
||||||
event: &FullEvent,
|
event: &FullEvent,
|
||||||
_framework: poise::FrameworkContext<'_, (), Error>
|
framework: poise::FrameworkContext<'_, (), Error>
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
match event {
|
match event {
|
||||||
FullEvent::Ratelimit { data } => {
|
FullEvent::Ratelimit { data } => {
|
||||||
println!("Event[Ratelimit]: {:#?}", data);
|
println!("Event[Ratelimit]: {:#?}", data);
|
||||||
}
|
}
|
||||||
|
FullEvent::Message { new_message } => {
|
||||||
|
if new_message.author.bot || !new_message.guild_id.is_none() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
if new_message.content.to_lowercase().starts_with("deploy") && new_message.author.id == BINARY_PROPERTIES.developers[0] {
|
||||||
|
let builder = poise::builtins::create_application_commands(&framework.options().commands);
|
||||||
|
let commands = Command::set_global_commands(&ctx.http, builder).await;
|
||||||
|
let mut commands_deployed = std::collections::HashSet::new();
|
||||||
|
|
||||||
|
match commands {
|
||||||
|
Ok(cmdmap) => for command in cmdmap.iter() {
|
||||||
|
commands_deployed.insert(command.name.clone());
|
||||||
|
},
|
||||||
|
Err(y) => {
|
||||||
|
eprintln!("Error registering commands: {:?}", y);
|
||||||
|
new_message.reply(&ctx.http, "Deployment failed, check console for more details!").await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if commands_deployed.len() > 0 {
|
||||||
|
new_message.reply(&ctx.http, format!(
|
||||||
|
"Deployed the commands globally:\n- {}",
|
||||||
|
commands_deployed.into_iter().collect::<Vec<_>>().join("\n- ")
|
||||||
|
)).await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
FullEvent::Ready { .. } => {
|
FullEvent::Ready { .. } => {
|
||||||
let thread_id = format!("{:?}", current().id());
|
let thread_id = format!("{:?}", current().id());
|
||||||
let thread_num: String = thread_id.chars().filter(|c| c.is_digit(10)).collect();
|
let thread_num: String = thread_id.chars().filter(|c| c.is_digit(10)).collect();
|
||||||
@ -162,6 +190,8 @@ async fn main() {
|
|||||||
let mut client = ClientBuilder::new(
|
let mut client = ClientBuilder::new(
|
||||||
token_path().await.main,
|
token_path().await.main,
|
||||||
GatewayIntents::GUILDS
|
GatewayIntents::GUILDS
|
||||||
|
| GatewayIntents::MESSAGE_CONTENT
|
||||||
|
| GatewayIntents::DIRECT_MESSAGES
|
||||||
)
|
)
|
||||||
.framework(framework)
|
.framework(framework)
|
||||||
.await.expect("Error creating client");
|
.await.expect("Error creating client");
|
||||||
|
Loading…
Reference in New Issue
Block a user