mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-04-28 19:54:35 +00:00
utils: Add utility functions to get cpu and distro details.
These functions is meant to be used for the kata-env command. Fixes: #5688 Signed-off-by: Archana Shinde <archana.m.shinde@intel.com>
This commit is contained in:
parent
d33e343613
commit
594b57d082
151
src/tools/kata-ctl/Cargo.lock
generated
151
src/tools/kata-ctl/Cargo.lock
generated
@ -533,57 +533,6 @@ dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hypervisor"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"dbs-utils",
|
||||
"dragonball",
|
||||
"go-flag",
|
||||
"kata-sys-util",
|
||||
"kata-types",
|
||||
"libc",
|
||||
"logging",
|
||||
"nix 0.24.2",
|
||||
"persist",
|
||||
"rand 0.8.5",
|
||||
"seccompiler",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"shim-interface",
|
||||
"slog",
|
||||
"slog-scope",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"vmm-sys-util 0.11.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.53"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone-haiku"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca"
|
||||
dependencies = [
|
||||
"cxx",
|
||||
"cxx-build",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.3.0"
|
||||
@ -910,21 +859,6 @@ version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
|
||||
|
||||
[[package]]
|
||||
name = "persist"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"kata-sys-util",
|
||||
"kata-types",
|
||||
"libc",
|
||||
"safe-path",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"shim-interface",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "petgraph"
|
||||
version = "0.5.1"
|
||||
@ -1218,71 +1152,6 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rlimit"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "347703a5ae47adf1e693144157be231dde38c72bd485925cae7407ad3e52480b"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rtnetlink"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46f1cfa18f8cebe685373a2697915d7e0db3b4554918bba118385e0f71f258a7"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"log",
|
||||
"netlink-packet-route",
|
||||
"netlink-proto",
|
||||
"nix 0.24.2",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "runtimes"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"common",
|
||||
"hyper",
|
||||
"hyperlocal",
|
||||
"hypervisor",
|
||||
"kata-types",
|
||||
"lazy_static",
|
||||
"logging",
|
||||
"oci",
|
||||
"persist",
|
||||
"shim-interface",
|
||||
"slog",
|
||||
"slog-scope",
|
||||
"tokio",
|
||||
"virt_container",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.34.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2079c267b8394eb529872c3cf92e181c378b41fea36e68130357b52493701d2e"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"io-lifetimes",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.20.6"
|
||||
@ -1415,17 +1284,6 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shim-interface"
|
||||
version = "0.1.0"
|
||||
@ -1436,15 +1294,6 @@ dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.7"
|
||||
|
@ -12,6 +12,8 @@ mod arch_specific {
|
||||
use std::path::Path;
|
||||
|
||||
const KVM_DEV: &str = "/dev/kvm";
|
||||
pub const ARCH_CPU_VENDOR_FIELD: &str = "CPU implementer";
|
||||
pub const ARCH_CPU_MODEL_FIELD: &str = "CPU architecture";
|
||||
|
||||
// List of check functions
|
||||
static CHECK_LIST: &[CheckItem] = &[CheckItem {
|
||||
|
@ -10,6 +10,9 @@ pub use arch_specific::*;
|
||||
mod arch_specific {
|
||||
use anyhow::Result;
|
||||
|
||||
pub const ARCH_CPU_VENDOR_FIELD: &str = "";
|
||||
pub const ARCH_CPU_MODEL_FIELD: &str = "model";
|
||||
|
||||
pub fn check() -> Result<()> {
|
||||
unimplemented!("Check not implemented in powerpc64le");
|
||||
}
|
||||
|
@ -16,6 +16,9 @@ mod arch_specific {
|
||||
const CPUINFO_FEATURES_TAG: &str = "features";
|
||||
const CPU_FEATURES_REQ: &[&str] = &["sie"];
|
||||
|
||||
pub const ARCH_CPU_VENDOR_FIELD: &str = check::GENERIC_CPU_VENDOR_FIELD;
|
||||
pub const ARCH_CPU_MODEL_FIELD: &str = "machine";
|
||||
|
||||
// check cpu
|
||||
fn check_cpu() -> Result<()> {
|
||||
println!("INFO: check CPU: s390x");
|
||||
|
@ -15,6 +15,8 @@ mod arch_specific {
|
||||
const CPUINFO_FLAGS_TAG: &str = "flags";
|
||||
const CPU_FLAGS_INTEL: &[&str] = &["lm", "sse4_1", "vmx"];
|
||||
const CPU_ATTRIBS_INTEL: &[&str] = &["GenuineIntel"];
|
||||
pub const ARCH_CPU_VENDOR_FIELD: &str = check::GENERIC_CPU_VENDOR_FIELD;
|
||||
pub const ARCH_CPU_MODEL_FIELD: &str = check::GENERIC_CPU_MODEL_FIELD;
|
||||
|
||||
// List of check functions
|
||||
static CHECK_LIST: &[CheckItem] = &[CheckItem {
|
||||
@ -28,6 +30,7 @@ mod arch_specific {
|
||||
Some(CHECK_LIST)
|
||||
}
|
||||
|
||||
// check cpu
|
||||
fn check_cpu(_args: &str) -> Result<()> {
|
||||
println!("INFO: check CPU: x86_64");
|
||||
|
||||
|
@ -23,6 +23,9 @@ const JSON_TYPE: &str = "application/json";
|
||||
|
||||
const USER_AGT: &str = "kata";
|
||||
|
||||
pub const GENERIC_CPU_VENDOR_FIELD: &str = "vendor_id";
|
||||
pub const GENERIC_CPU_MODEL_FIELD: &str = "model name";
|
||||
|
||||
pub const PROC_CPUINFO: &str = "/proc/cpuinfo";
|
||||
|
||||
#[cfg(any(target_arch = "s390x", target_arch = "x86_64"))]
|
||||
|
@ -5,6 +5,8 @@
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use crate::arch::arch_specific;
|
||||
use crate::check::get_single_cpu_info;
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use std::fs;
|
||||
|
||||
@ -38,9 +40,110 @@ pub fn get_kernel_version(proc_version_file: &str) -> Result<String> {
|
||||
Ok(kernel_version)
|
||||
}
|
||||
|
||||
const OS_RELEASE: &str = "/etc/os-release";
|
||||
|
||||
// Clear Linux has a different path (for stateless support)
|
||||
const OS_RELEASE_CLR: &str = "/usr/lib/os-release";
|
||||
|
||||
const UNKNOWN: &str = "unknown";
|
||||
|
||||
fn get_field_fn(line: &str, delimiter: &str, file_name: &str) -> Result<String> {
|
||||
let fields: Vec<&str> = line.split(delimiter).collect();
|
||||
if fields.len() < 2 {
|
||||
return Err(anyhow!("Unexpected file contents for {}", file_name));
|
||||
} else {
|
||||
let val = fields[1].trim();
|
||||
Ok(String::from(val))
|
||||
}
|
||||
}
|
||||
// Ref: https://www.freedesktop.org/software/systemd/man/os-release.html
|
||||
pub fn get_distro_details(os_release: &str, os_release_clr: &str) -> Result<(String, String)> {
|
||||
let files = vec![os_release, os_release_clr];
|
||||
let mut name = String::new();
|
||||
let mut version = String::new();
|
||||
|
||||
for release_file in files.iter() {
|
||||
match fs::read_to_string(release_file) {
|
||||
Err(e) => {
|
||||
if e.kind() == std::io::ErrorKind::NotFound {
|
||||
continue;
|
||||
} else {
|
||||
return Err(anyhow!(
|
||||
"Error reading file {}: {}",
|
||||
release_file,
|
||||
e.to_string()
|
||||
));
|
||||
}
|
||||
}
|
||||
Ok(contents) => {
|
||||
let lines = contents.lines();
|
||||
|
||||
for line in lines {
|
||||
if line.starts_with("NAME=") && name.is_empty() {
|
||||
name = get_field_fn(line, "=", release_file)?;
|
||||
} else if line.starts_with("VERSION_ID=") && version.is_empty() {
|
||||
version = get_field_fn(line, "=", release_file)?;
|
||||
}
|
||||
}
|
||||
if !name.is_empty() && !version.is_empty() {
|
||||
return Ok((name, version));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if name.is_empty() {
|
||||
name = String::from(UNKNOWN);
|
||||
}
|
||||
|
||||
if version.is_empty() {
|
||||
version = String::from(UNKNOWN);
|
||||
}
|
||||
|
||||
Ok((name, version))
|
||||
}
|
||||
|
||||
pub fn get_generic_cpu_details(cpu_info_file: &str) -> Result<(String, String)> {
|
||||
let cpu_info = get_single_cpu_info(cpu_info_file, "\n\n")?;
|
||||
let lines = cpu_info.lines();
|
||||
println!("Single cpu info: {}", cpu_info);
|
||||
let mut vendor = String::new();
|
||||
let mut model = String::new();
|
||||
|
||||
for line in lines {
|
||||
if !arch_specific::ARCH_CPU_VENDOR_FIELD.is_empty()
|
||||
&& line.starts_with(arch_specific::ARCH_CPU_VENDOR_FIELD)
|
||||
{
|
||||
vendor = get_field_fn(line, ":", cpu_info_file)?;
|
||||
}
|
||||
if !arch_specific::ARCH_CPU_MODEL_FIELD.is_empty()
|
||||
&& line.starts_with(arch_specific::ARCH_CPU_MODEL_FIELD)
|
||||
{
|
||||
model = get_field_fn(line, ":", cpu_info_file)?;
|
||||
}
|
||||
}
|
||||
|
||||
if vendor.is_empty() && !arch_specific::ARCH_CPU_VENDOR_FIELD.is_empty() {
|
||||
return Err(anyhow!(
|
||||
"Cannot find cpu vendor field in file : {}",
|
||||
cpu_info_file
|
||||
));
|
||||
}
|
||||
|
||||
if model.is_empty() && !arch_specific::ARCH_CPU_MODEL_FIELD.is_empty() {
|
||||
return Err(anyhow!(
|
||||
"Cannot find cpu model field in file : {}",
|
||||
cpu_info_file
|
||||
));
|
||||
}
|
||||
|
||||
Ok((vendor, model))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::check::PROC_CPUINFO;
|
||||
use std::io::Write;
|
||||
use tempfile::tempdir;
|
||||
|
||||
@ -91,4 +194,86 @@ mod tests {
|
||||
let expected = format!("unexpected contents in file {}", path.to_str().unwrap());
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_distro_details_empty_files() {
|
||||
let res = get_distro_details("xvz.xt", "bar.txt");
|
||||
assert!(res.is_ok());
|
||||
let (name, version) = res.unwrap();
|
||||
assert_eq!(name, UNKNOWN);
|
||||
assert_eq!(version, UNKNOWN);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_distro_details_valid_file() {
|
||||
let dir = tempdir().unwrap();
|
||||
let file_path = dir.path().join("os-version");
|
||||
let path = file_path.clone();
|
||||
let mut file = fs::File::create(file_path).unwrap();
|
||||
writeln!(file, "NAME=Ubuntu\nID_LIKE=debian\nVERSION_ID=20.04.4\n").unwrap();
|
||||
let res = get_distro_details("/etc/foo.txt", path.to_str().unwrap());
|
||||
let (name, version) = res.unwrap();
|
||||
assert_eq!(name, "Ubuntu");
|
||||
assert_eq!(version, "20.04.4");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_distro_details_system() {
|
||||
let res = get_distro_details(OS_RELEASE, OS_RELEASE_CLR);
|
||||
assert!(res.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_generic_cpu_details_system() {
|
||||
let res = get_generic_cpu_details(PROC_CPUINFO);
|
||||
assert!(res.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_generic_cpu_details_valid_contents() {
|
||||
let dir = tempdir().unwrap();
|
||||
let file_path = dir.path().join("cpuinfo");
|
||||
let path = file_path.clone();
|
||||
let mut file = fs::File::create(file_path).unwrap();
|
||||
let expected_vendor_id = "GenuineIntel";
|
||||
let expected_model_name = "i7-1065G7 CPU";
|
||||
let contents = format!(
|
||||
"{} : {} \n{} : {}\n stepping: 5\n\n",
|
||||
arch_specific::ARCH_CPU_VENDOR_FIELD,
|
||||
expected_vendor_id,
|
||||
arch_specific::ARCH_CPU_MODEL_FIELD,
|
||||
expected_model_name
|
||||
);
|
||||
writeln!(file, "{}", contents).unwrap();
|
||||
let res = get_generic_cpu_details(path.to_str().unwrap());
|
||||
assert_eq!(res.as_ref().unwrap().0, expected_vendor_id);
|
||||
assert_eq!(res.as_ref().unwrap().1, expected_model_name);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_generic_cpu_details_invalid_file() {
|
||||
let res = get_generic_cpu_details("/tmp/missing.txt");
|
||||
assert!(res.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_generic_cpu_details_invalid_contents() {
|
||||
let dir = tempdir().unwrap();
|
||||
let file_path = dir.path().join("cpuinfo");
|
||||
let path = file_path.clone();
|
||||
let mut file = fs::File::create(file_path).unwrap();
|
||||
writeln!(
|
||||
file,
|
||||
"vendor :GenuineIntel\nmodel_name=i7-1065G7 CPU\nstepping:5\n\n"
|
||||
)
|
||||
.unwrap();
|
||||
let actual = get_generic_cpu_details(path.to_str().unwrap())
|
||||
.unwrap_err()
|
||||
.to_string();
|
||||
let expected = format!(
|
||||
r#"Cannot find cpu vendor field in file : {}"#,
|
||||
path.to_str().unwrap()
|
||||
);
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user