it works
This commit is contained in:
commit
868f3eb13a
4 changed files with 464 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/target
|
282
Cargo.lock
generated
Normal file
282
Cargo.lock
generated
Normal 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
8
Cargo.toml
Normal 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
173
src/main.rs
Normal 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(),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue