This commit is contained in:
Tristan Smith 2024-09-12 22:36:14 -04:00
commit 868f3eb13a
4 changed files with 464 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/target

282
Cargo.lock generated Normal file
View file

@ -0,0 +1,282 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]]
name = "anstream"
version = "0.6.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
[[package]]
name = "anstyle-parse"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a"
dependencies = [
"windows-sys",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8"
dependencies = [
"anstyle",
"windows-sys",
]
[[package]]
name = "clap"
version = "4.5.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e5a21b8495e732f1b3c364c9949b201ca7bae518c502c80256c96ad79eaf6ac"
dependencies = [
"clap_builder",
"clap_derive",
]
[[package]]
name = "clap_builder"
version = "4.5.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cf2dd12af7a047ad9d6da2b6b249759a22a7abc0f474c1dae1777afa4b21a73"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_derive"
version = "4.5.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "clap_lex"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
[[package]]
name = "colorchoice"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0"
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "idrac"
version = "0.1.0"
dependencies = [
"clap",
"regex",
]
[[package]]
name = "is_terminal_polyfill"
version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "proc-macro2"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
version = "2.0.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"

8
Cargo.toml Normal file
View file

@ -0,0 +1,8 @@
[package]
name = "idrac"
version = "0.1.0"
edition = "2021"
[dependencies]
clap = { version = "4.5.17", features = ["derive"] }
regex = "1.10.6"

173
src/main.rs Normal file
View file

@ -0,0 +1,173 @@
use clap::{ArgAction, Arg, Command};
use regex::Regex;
use std::process::Command as Cmd;
use std::str;
const IPMIHOST: &str = "192.168.1.223";
const IPMIUSER: &str = "root";
const IPMIPASS: &str = "<password>";
fn execute_ipmi_command(command: &str) -> String {
let full_command = format!(
"ipmitool -I lanplus -H {} -U {} -P '{}' {}",
IPMIHOST, IPMIUSER, IPMIPASS, command
);
let output = Cmd::new("sh")
.arg("-c")
.arg(full_command)
.output()
.expect("Failed to execute command");
let stdout = str::from_utf8(&output.stdout).unwrap_or("");
let stderr = str::from_utf8(&output.stderr).unwrap_or("");
if !stderr.is_empty() {
eprintln!("{}", stderr);
}
stdout.trim().to_string()
}
fn power_on() {
println!("Powering on the server...");
execute_ipmi_command("chassis power on");
}
fn power_off() {
println!("Powering off the server...");
execute_ipmi_command("chassis power off");
println!("Enabling dynamic fan control...");
execute_ipmi_command("raw 0x30 0x30 0x01 0x01");
}
fn set_fan_speed(speed: u8) {
println!("Setting fan speed to {}%...", speed);
execute_ipmi_command(&format!("raw 0x30 0x30 0x02 0xff {:x}", speed));
}
fn enable_dynamic_fan_control() {
println!("Enabling dynamic fan control...");
execute_ipmi_command("raw 0x30 0x30 0x01 0x01");
}
fn disable_dynamic_fan_control() {
println!("Disabling dynamic fan control...");
execute_ipmi_command("raw 0x30 0x30 0x01 0x00");
}
fn get_server_temperature() -> f32 {
println!("Getting server temperature...");
let command = format!(
"ipmitool -I lanplus -H {} -U {} -P '{}' sdr type temperature",
IPMIHOST, IPMIUSER, IPMIPASS
);
let result = Cmd::new("sh")
.arg("-c")
.arg(command)
.output()
.expect("Failed to get temperature");
let stdout = str::from_utf8(&result.stdout).unwrap_or("");
let re = Regex::new(r"\| (\d+) degrees C").unwrap();
let mut temps = Vec::new();
for cap in re.captures_iter(stdout) {
if let Ok(temp) = cap[1].parse::<f32>() {
temps.push(temp);
}
}
let avg_temp = if !temps.is_empty() {
temps.iter().sum::<f32>() / temps.len() as f32
} else {
0.0
};
avg_temp
}
fn adjust_fan_speed_based_on_temp() {
let temp = get_server_temperature();
println!("Current temperature: {:.1} degrees C", temp);
let warning_threshold = 75.0;
let critical_threshold = 90.0;
if temp >= critical_threshold {
println!("Temperature is critical, setting fan speed to 100%.");
set_fan_speed(100);
} else if temp >= warning_threshold {
println!("Temperature is high, setting fan speed to 80%.");
set_fan_speed(80);
} else if temp >= 40.0 {
println!("Temperature is moderate, setting fan speed to 60%.");
set_fan_speed(60);
} else if temp >= 30.0 {
println!("Temperature is low, setting fan speed to 50%.");
set_fan_speed(50);
} else {
println!("Temperature is very low, setting fan speed to 40%.");
set_fan_speed(40);
}
}
fn main() {
let matches = Command::new("IDRAC helper script.")
.version("1.0")
.about("Controls server power, fan speed, and temperature monitoring for Dell servers")
.arg(
Arg::new("power")
.short('p')
.long("power")
.value_parser(["on", "off"])
.help("Power on or off the server"),
)
.arg(
Arg::new("fan")
.short('f')
.long("fan")
.value_parser(clap::value_parser!(u8).range(0..=100))
.help("Set fan speed percentage"),
)
.arg(
Arg::new("temp")
.short('t')
.long("temp")
.action(ArgAction::SetTrue)
.help("Adjust fan speed based on temperature"),
)
.arg(
Arg::new("dynamic")
.short('d')
.long("dynamic")
.value_parser(["on", "off"])
.help("Toggle dynamic fan control"),
)
.get_matches();
if let Some(power) = matches.get_one::<String>("power") {
match power.as_str() {
"on" => power_on(),
"off" => power_off(),
_ => {}
}
}
if let Some(fan_speed) = matches.get_one::<u8>("fan") {
set_fan_speed(*fan_speed);
}
if matches.get_flag("temp") {
adjust_fan_speed_based_on_temp();
}
if let Some(dynamic) = matches.get_one::<String>("dynamic") {
match dynamic.as_str() {
"on" => enable_dynamic_fan_control(),
"off" => disable_dynamic_fan_control(),
_ => {}
}
}
}