From a86b1b7509af7e6fe459e7a4a7a17f4530129a29 Mon Sep 17 00:00:00 2001 From: onalante-msft <89409054+onalante-msft@users.noreply.github.com> Date: Tue, 7 Dec 2021 09:46:57 -0800 Subject: [PATCH 01/11] Factor out product info --- Cargo.lock | 15 +- aziotctl/Cargo.toml | 2 +- aziotctl/aziotctl-common/Cargo.toml | 3 +- aziotctl/aziotctl-common/src/host_info.rs | 256 ++++++++++++++++++ aziotctl/aziotctl-common/src/lib.rs | 1 + .../src/internal/check/additional_info.rs | 89 +----- http-common/Cargo.toml | 2 +- 7 files changed, 272 insertions(+), 96 deletions(-) create mode 100644 aziotctl/aziotctl-common/src/host_info.rs diff --git a/Cargo.lock b/Cargo.lock index f43c0a5d7..7bc0c5c72 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1529,9 +1529,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.86" +version = "0.2.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c" +checksum = "f98a04dce437184842841303488f70d0188c5f51437d2a834dc097eafa909a01" [[package]] name = "linked-hash-map" @@ -1588,9 +1588,9 @@ checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" [[package]] name = "memoffset" -version = "0.6.1" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "157b4208e3059a8f9e78d559edc658e13df41410cb3ae03979c83130067fdd87" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" dependencies = [ "autocfg", ] @@ -1718,14 +1718,15 @@ dependencies = [ [[package]] name = "nix" -version = "0.18.0" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83450fe6a6142ddd95fb064b746083fc4ef1705fe81f64a64e1d4b39f54a1055" +checksum = "d3bb9a13fa32bc5aeb64150cd3f32d6cf4c748f8f8a417cce5d2eb976a8370ba" dependencies = [ "bitflags", "cc", - "cfg-if 0.1.10", + "cfg-if 1.0.0", "libc", + "memoffset", ] [[package]] diff --git a/aziotctl/Cargo.toml b/aziotctl/Cargo.toml index 89a0abee5..c041a861b 100644 --- a/aziotctl/Cargo.toml +++ b/aziotctl/Cargo.toml @@ -18,7 +18,7 @@ foreign-types-shared = "0.1" hyper = "0.14" hyper-openssl = "0.9" libc = "0.2" -nix = "0.18" +nix = "0.22" log = "0.4" openssl = "0.10" serde = { version = "1", features = ["derive"] } diff --git a/aziotctl/aziotctl-common/Cargo.toml b/aziotctl/aziotctl-common/Cargo.toml index eec1794c7..404a10e53 100644 --- a/aziotctl/aziotctl-common/Cargo.toml +++ b/aziotctl/aziotctl-common/Cargo.toml @@ -9,9 +9,10 @@ edition = "2021" anyhow = "1.0.34" base64 = "0.13" log = "0.4" -nix = "0.18" +nix = "0.22" serde = { version = "1", features = ["derive"] } serde_json = "1.0.59" +toml = "0.5" url = { version = "2", features = ["serde"] } aziot-certd-config = { path = "../../cert/aziot-certd-config" } diff --git a/aziotctl/aziotctl-common/src/host_info.rs b/aziotctl/aziotctl-common/src/host_info.rs new file mode 100644 index 000000000..4473aa8b9 --- /dev/null +++ b/aziotctl/aziotctl-common/src/host_info.rs @@ -0,0 +1,256 @@ +use std::convert::TryFrom; +use std::env::consts::ARCH; +use std::fmt; +use std::fs; +use std::io::{self, BufRead}; +use std::path::PathBuf; + +use nix::sys::utsname::UtsName; +use serde::{Deserialize, Serialize}; + +/// A subset of the fields from /etc/os-release. +/// +/// Examples: +/// +/// ```ignore +/// OS | id | version_id +/// ---------------------+---------------------+------------ +/// CentOS 7 | centos | 7 +/// Debian 9 | debian | 9 +/// openSUSE Tumbleweed | opensuse-tumbleweed | 20190325 +/// Ubuntu 18.04 | ubuntu | 18.04 +/// ``` +/// +/// Ref: +#[derive(Clone, Debug, Serialize)] +pub struct OsInfo { + id: Option, + version_id: Option, + pretty_name: Option, + arch: &'static str, + bitness: usize, +} + +impl Default for OsInfo { + fn default() -> Self { + let mut result = Self { + id: None, + version_id: None, + pretty_name: None, + arch: ARCH, + // Technically wrong if someone runs an arm32 build on arm64, + // but we have dedicated arm64 builds so hopefully they don't. + bitness: std::mem::size_of::() * 8, + }; + + let os_release = fs::File::open("/etc/os-release") + .or_else(|_| fs::File::open("/usr/lib/os-release")); + + if let Ok(os_release) = os_release { + let os_release = io::BufReader::new(os_release); + + for line in os_release.lines() { + if let Ok(line) = &line { + match parse_os_release_line(line) { + Some(("ID", value)) => { + result.id = Some(value.to_owned()); + }, + Some(("VERSION_ID", value)) => { + result.version_id = Some(value.to_owned()); + }, + Some(("PRETTY_NAME", value)) => { + result.pretty_name = Some(value.to_owned()); + }, + _ => (), + }; + } + else { + break; + } + } + } + + result + } +} + +fn parse_os_release_line(line: &str) -> Option<(&str, &str)> { + let line = line.trim(); + + let (key, value) = line.split_once('=')?; + + // The value is essentially a shell string, so it can be quoted in single or + // double quotes, and can have escaped sequences using backslash. + // For simplicitly, just trim the quotes instead of implementing a full shell + // string grammar. + let value = if (value.starts_with('\'') && value.ends_with('\'')) + || (value.starts_with('"') && value.ends_with('"')) + { + &value[1..(value.len() - 1)] + } else { + value + }; + + Some((key, value)) +} + +pub struct HardwareInfo { + name: Option, + version: Option, + vendor: Option, +} + +impl Default for HardwareInfo { + fn default() -> Self { + Self { + name: try_read_dmi("product_name"), + version: try_read_dmi("product_version"), + vendor: try_read_dmi("sys_vendor"), + } + } +} + +fn try_read_dmi(entry: &'static str) -> Option { + let path = format!("/sys/devices/virtual/dmi/id/{}", entry); + + let bytes = fs::read(path).ok()?; + + Some(String::from_utf8(bytes) + .ok()? + .trim() + .to_owned()) +} + +#[derive(Debug, Deserialize, PartialEq)] +struct Product { + name: String, + version: String, + comment: Option, +} + +impl fmt::Display for Product { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}/{}", self.name, self.version)?; + + if let Some(comment) = &self.comment { + write!(f, " ({})", comment)?; + }; + + Ok(()) + } +} + +impl From for Product { + fn from(value: UtsName) -> Self { + Self { + name: value.sysname().to_owned(), + version: value.release().to_owned(), + comment: Some(value.version().to_owned()), + } + } +} + +impl From for Product { + fn from(value: OsInfo) -> Self { + Self { + name: value.id.unwrap_or_else(|| "UNKNOWN_OS".to_owned()), + version: value.version_id.unwrap_or_else(|| "UNKNOWN_OS_VERSION".to_owned()), + comment: value.pretty_name, + } + } +} + +impl From for Product { + fn from(value: HardwareInfo) -> Self { + Self { + name: value.name.unwrap_or_else(|| "UNKNOWN_HARDWARE".to_owned()), + version: value.version.unwrap_or_else(|| "UNKNOWN_HARDWARE_VERSION".to_owned()), + comment: value.vendor + } + } +} + +#[derive(Debug, Deserialize, PartialEq)] +#[serde(try_from = "PathBuf")] +pub struct ProductInfo { + product: Vec, +} + +impl TryFrom for ProductInfo { + type Error = io::Error; + + fn try_from(p: PathBuf) -> Result { + let bytes = fs::read(p)?; + + toml::de::from_slice(&bytes) + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) + } +} + +impl fmt::Display for ProductInfo { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut products = self.product.iter(); + + if let Some(first) = products.next() { + write!(f, "{}", first)?; + + for product in products { + write!(f, " {}", product)?; + } + } + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + impl From<(&str, &str)> for Product { + fn from(value: (&str, &str)) -> Self { + Product { + name: value.0.to_owned(), + version: value.1.to_owned(), + comment: None, + } + } + } + + impl From<(&str, &str, &str)> for Product { + fn from(value: (&str, &str, &str)) -> Self { + Product { + name: value.0.to_owned(), + version: value.1.to_owned(), + comment: Some(value.2.to_owned()), + } + } + } + + #[test] + fn product_string_no_comment() { + let p: Product = ("FOO", "BAR").into(); + + assert_eq!("FOO/BAR", p.to_string()); + } + + #[test] + fn product_string_with_comment() { + let p: Product = ("FOO", "BAR", "BAZ").into(); + + assert_eq!("FOO/BAR (BAZ)", p.to_string()); + } + + #[test] + fn multiple_products() { + let pinfo = ProductInfo { + product: vec![ + ("FOO", "BAR").into(), + ("A", "B", "C").into(), + ("name", "version", "comment").into(), + ], + }; + + assert_eq!("FOO/BAR A/B (C) name/version (comment)", pinfo.to_string()); + } +} diff --git a/aziotctl/aziotctl-common/src/lib.rs b/aziotctl/aziotctl-common/src/lib.rs index 520a7a157..ca02a9fe1 100644 --- a/aziotctl/aziotctl-common/src/lib.rs +++ b/aziotctl/aziotctl-common/src/lib.rs @@ -20,6 +20,7 @@ use serde::{Deserialize, Serialize}; pub mod check_last_modified; pub mod config; +pub mod host_info; pub mod system; #[derive(Debug, Serialize, Deserialize)] diff --git a/aziotctl/src/internal/check/additional_info.rs b/aziotctl/src/internal/check/additional_info.rs index 18d486e6f..254780c3b 100644 --- a/aziotctl/src/internal/check/additional_info.rs +++ b/aziotctl/src/internal/check/additional_info.rs @@ -1,12 +1,11 @@ // Copyright (c) Microsoft. All rights reserved. -use std::env::consts::ARCH; -use std::str; - use byte_unit::{Byte, ByteUnit}; use serde::Serialize; use sysinfo::{DiskExt, SystemExt}; +use aziotctl_common::host_info::OsInfo; + /// Additional info for the JSON output of `aziotctl check` #[derive(Clone, Debug, Serialize)] pub struct AdditionalInfo { @@ -26,7 +25,7 @@ impl AdditionalInfo { pub fn new(iothub_hostname: Option, local_gateway_hostname: Option) -> Self { AdditionalInfo { now: chrono::Utc::now(), - os: OsInfo::new(), + os: OsInfo::default(), system_info: SystemInfo::new(), iothub_hostname, @@ -35,88 +34,6 @@ impl AdditionalInfo { } } -/// A subset of the fields from /etc/os-release. -/// -/// Examples: -/// -/// ```ignore -/// OS | id | version_id -/// ---------------------+---------------------+------------ -/// CentOS 7 | centos | 7 -/// Debian 9 | debian | 9 -/// openSUSE Tumbleweed | opensuse-tumbleweed | 20190325 -/// Ubuntu 18.04 | ubuntu | 18.04 -/// ``` -/// -/// Ref: -#[derive(Clone, Debug, Serialize)] -pub struct OsInfo { - id: Option, - version_id: Option, - arch: &'static str, - bitness: usize, -} - -impl OsInfo { - pub fn new() -> Self { - use std::fs::File; - use std::io::{BufRead, BufReader}; - - let mut result = OsInfo { - id: None, - version_id: None, - arch: ARCH, - // Technically wrong if someone runs an arm32 build on arm64, - // but we have dedicated arm64 builds so hopefully they don't. - bitness: std::mem::size_of::() * 8, - }; - - if let Ok(os_release) = File::open("/etc/os-release") { - let mut os_release = BufReader::new(os_release); - - let mut line = String::new(); - loop { - match os_release.read_line(&mut line) { - Ok(0) | Err(_) => break, - Ok(_) => { - if let Some((key, value)) = parse_os_release_line(&line) { - if key == "ID" { - result.id = Some(value.to_owned()); - } else if key == "VERSION_ID" { - result.version_id = Some(value.to_owned()); - } - } - - line.clear(); - } - } - } - } - - result - } -} - -fn parse_os_release_line(line: &str) -> Option<(&str, &str)> { - let line = line.trim(); - - let (key, value) = line.split_once('=')?; - - // The value is essentially a shell string, so it can be quoted in single or - // double quotes, and can have escaped sequences using backslash. - // For simplicitly, just trim the quotes instead of implementing a full shell - // string grammar. - let value = if (value.starts_with('\'') && value.ends_with('\'')) - || (value.starts_with('"') && value.ends_with('"')) - { - &value[1..(value.len() - 1)] - } else { - value - }; - - Some((key, value)) -} - #[derive(Clone, Debug, Default, Serialize)] struct SystemInfo { used_ram: String, diff --git a/http-common/Cargo.toml b/http-common/Cargo.toml index 3a32c560c..56eea54a1 100644 --- a/http-common/Cargo.toml +++ b/http-common/Cargo.toml @@ -15,7 +15,7 @@ hyper-openssl = { version = "0.9" } hyper-proxy = { version = "0.9", features = ["openssl-tls"], default-features = false } libc = "0.2" log = "0.4" -nix = "0.18" +nix = "0.22" openssl = { version = "0.10" } openssl-sys = { version = "0.9" } percent-encoding = "2" From eb36041c1eaf0d1e28ca1bd61e8b7a77ac9b80fa Mon Sep 17 00:00:00 2001 From: onalante-msft <89409054+onalante-msft@users.noreply.github.com> Date: Tue, 14 Dec 2021 12:29:14 -0800 Subject: [PATCH 02/11] Remove TryFrom implementation for ProductInfo --- aziotctl/aziotctl-common/src/host_info.rs | 26 +++++++++++++------ .../test-files/product_info.toml | 4 +++ 2 files changed, 22 insertions(+), 8 deletions(-) create mode 100644 aziotctl/aziotctl-common/test-files/product_info.toml diff --git a/aziotctl/aziotctl-common/src/host_info.rs b/aziotctl/aziotctl-common/src/host_info.rs index 4473aa8b9..28d40178b 100644 --- a/aziotctl/aziotctl-common/src/host_info.rs +++ b/aziotctl/aziotctl-common/src/host_info.rs @@ -1,9 +1,9 @@ -use std::convert::TryFrom; +use std::convert::AsRef; use std::env::consts::ARCH; use std::fmt; use std::fs; use std::io::{self, BufRead}; -use std::path::PathBuf; +use std::path::Path; use nix::sys::utsname::UtsName; use serde::{Deserialize, Serialize}; @@ -171,16 +171,14 @@ impl From for Product { } #[derive(Debug, Deserialize, PartialEq)] -#[serde(try_from = "PathBuf")] pub struct ProductInfo { product: Vec, } -impl TryFrom for ProductInfo { - type Error = io::Error; - - fn try_from(p: PathBuf) -> Result { - let bytes = fs::read(p)?; +impl ProductInfo { + #[allow(dead_code)] + fn load_file>(path: P) -> Result { + let bytes = fs::read(path)?; toml::de::from_slice(&bytes) .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) @@ -253,4 +251,16 @@ mod tests { assert_eq!("FOO/BAR A/B (C) name/version (comment)", pinfo.to_string()); } + + #[test] + fn load_file() { + let test_load = ProductInfo::load_file("test-files/product_info.toml") + .unwrap(); + + assert_eq!(ProductInfo { + product: vec![ + ("A", "B", "C").into() + ] + }, test_load); + } } diff --git a/aziotctl/aziotctl-common/test-files/product_info.toml b/aziotctl/aziotctl-common/test-files/product_info.toml new file mode 100644 index 000000000..5139270f5 --- /dev/null +++ b/aziotctl/aziotctl-common/test-files/product_info.toml @@ -0,0 +1,4 @@ +[[product]] +name = "A" +version = "B" +comment = "C" From 12ef251e9ad6d8e9c6ea8d92857e2742fbc42560 Mon Sep 17 00:00:00 2001 From: onalante-msft <89409054+onalante-msft@users.noreply.github.com> Date: Mon, 3 Jan 2022 12:35:58 -0800 Subject: [PATCH 03/11] ProductInfo obsoleted --- aziotctl/aziotctl-common/src/host_info.rs | 195 +++--------------- .../src/internal/check/additional_info.rs | 5 +- 2 files changed, 35 insertions(+), 165 deletions(-) diff --git a/aziotctl/aziotctl-common/src/host_info.rs b/aziotctl/aziotctl-common/src/host_info.rs index 28d40178b..796fb1e46 100644 --- a/aziotctl/aziotctl-common/src/host_info.rs +++ b/aziotctl/aziotctl-common/src/host_info.rs @@ -1,4 +1,3 @@ -use std::convert::AsRef; use std::env::consts::ARCH; use std::fmt; use std::fs; @@ -6,7 +5,35 @@ use std::io::{self, BufRead}; use std::path::Path; use nix::sys::utsname::UtsName; -use serde::{Deserialize, Serialize}; +use serde::Serialize; + +/// A subset of the DMI variables exposed through /sys/devices/virtual/dmi/id. +/// +/// Examples: +/// +/// ```ignore +/// Host | name | version | vendor +/// ---------+-----------------+---------+----------------------- +/// Hyper-V | Virtual Machine | 7.0 | Microsoft Corporation +/// ``` +/// +/// Ref: +#[derive(Clone, Debug, Serialize)] +pub struct DmiInfo { + name: Option, + version: Option, + vendor: Option, +} + +impl Default for DmiInfo { + fn default() -> Self { + Self { + name: try_read_dmi("product_name"), + version: try_read_dmi("product_version"), + vendor: try_read_dmi("sys_vendor"), + } + } +} /// A subset of the fields from /etc/os-release. /// @@ -51,7 +78,7 @@ impl Default for OsInfo { for line in os_release.lines() { if let Ok(line) = &line { - match parse_os_release_line(line) { + match parse_shell_line(line) { Some(("ID", value)) => { result.id = Some(value.to_owned()); }, @@ -74,7 +101,7 @@ impl Default for OsInfo { } } -fn parse_os_release_line(line: &str) -> Option<(&str, &str)> { +fn parse_shell_line(line: &str) -> Option<(&str, &str)> { let line = line.trim(); let (key, value) = line.split_once('=')?; @@ -94,22 +121,6 @@ fn parse_os_release_line(line: &str) -> Option<(&str, &str)> { Some((key, value)) } -pub struct HardwareInfo { - name: Option, - version: Option, - vendor: Option, -} - -impl Default for HardwareInfo { - fn default() -> Self { - Self { - name: try_read_dmi("product_name"), - version: try_read_dmi("product_version"), - vendor: try_read_dmi("sys_vendor"), - } - } -} - fn try_read_dmi(entry: &'static str) -> Option { let path = format!("/sys/devices/virtual/dmi/id/{}", entry); @@ -120,147 +131,3 @@ fn try_read_dmi(entry: &'static str) -> Option { .trim() .to_owned()) } - -#[derive(Debug, Deserialize, PartialEq)] -struct Product { - name: String, - version: String, - comment: Option, -} - -impl fmt::Display for Product { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}/{}", self.name, self.version)?; - - if let Some(comment) = &self.comment { - write!(f, " ({})", comment)?; - }; - - Ok(()) - } -} - -impl From for Product { - fn from(value: UtsName) -> Self { - Self { - name: value.sysname().to_owned(), - version: value.release().to_owned(), - comment: Some(value.version().to_owned()), - } - } -} - -impl From for Product { - fn from(value: OsInfo) -> Self { - Self { - name: value.id.unwrap_or_else(|| "UNKNOWN_OS".to_owned()), - version: value.version_id.unwrap_or_else(|| "UNKNOWN_OS_VERSION".to_owned()), - comment: value.pretty_name, - } - } -} - -impl From for Product { - fn from(value: HardwareInfo) -> Self { - Self { - name: value.name.unwrap_or_else(|| "UNKNOWN_HARDWARE".to_owned()), - version: value.version.unwrap_or_else(|| "UNKNOWN_HARDWARE_VERSION".to_owned()), - comment: value.vendor - } - } -} - -#[derive(Debug, Deserialize, PartialEq)] -pub struct ProductInfo { - product: Vec, -} - -impl ProductInfo { - #[allow(dead_code)] - fn load_file>(path: P) -> Result { - let bytes = fs::read(path)?; - - toml::de::from_slice(&bytes) - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - } -} - -impl fmt::Display for ProductInfo { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut products = self.product.iter(); - - if let Some(first) = products.next() { - write!(f, "{}", first)?; - - for product in products { - write!(f, " {}", product)?; - } - } - - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - impl From<(&str, &str)> for Product { - fn from(value: (&str, &str)) -> Self { - Product { - name: value.0.to_owned(), - version: value.1.to_owned(), - comment: None, - } - } - } - - impl From<(&str, &str, &str)> for Product { - fn from(value: (&str, &str, &str)) -> Self { - Product { - name: value.0.to_owned(), - version: value.1.to_owned(), - comment: Some(value.2.to_owned()), - } - } - } - - #[test] - fn product_string_no_comment() { - let p: Product = ("FOO", "BAR").into(); - - assert_eq!("FOO/BAR", p.to_string()); - } - - #[test] - fn product_string_with_comment() { - let p: Product = ("FOO", "BAR", "BAZ").into(); - - assert_eq!("FOO/BAR (BAZ)", p.to_string()); - } - - #[test] - fn multiple_products() { - let pinfo = ProductInfo { - product: vec![ - ("FOO", "BAR").into(), - ("A", "B", "C").into(), - ("name", "version", "comment").into(), - ], - }; - - assert_eq!("FOO/BAR A/B (C) name/version (comment)", pinfo.to_string()); - } - - #[test] - fn load_file() { - let test_load = ProductInfo::load_file("test-files/product_info.toml") - .unwrap(); - - assert_eq!(ProductInfo { - product: vec![ - ("A", "B", "C").into() - ] - }, test_load); - } -} diff --git a/aziotctl/src/internal/check/additional_info.rs b/aziotctl/src/internal/check/additional_info.rs index 254780c3b..ed8f41085 100644 --- a/aziotctl/src/internal/check/additional_info.rs +++ b/aziotctl/src/internal/check/additional_info.rs @@ -4,7 +4,7 @@ use byte_unit::{Byte, ByteUnit}; use serde::Serialize; use sysinfo::{DiskExt, SystemExt}; -use aziotctl_common::host_info::OsInfo; +use aziotctl_common::host_info::{DmiInfo, OsInfo}; /// Additional info for the JSON output of `aziotctl check` #[derive(Clone, Debug, Serialize)] @@ -12,6 +12,8 @@ pub struct AdditionalInfo { // TODO: update https://github.com/Azure/azure-iotedge to include aziotd version now: chrono::DateTime, os: OsInfo, + kernel: KernelInfo, + dmi: DmiInfo, system_info: SystemInfo, #[serde(skip_serializing_if = "Option::is_none")] @@ -26,6 +28,7 @@ impl AdditionalInfo { AdditionalInfo { now: chrono::Utc::now(), os: OsInfo::default(), + dmi: DmiInfo::default(), system_info: SystemInfo::new(), iothub_hostname, From cfcf19174eeef31cd0064cf130dfb67d32ebc60c Mon Sep 17 00:00:00 2001 From: onalante-msft <89409054+onalante-msft@users.noreply.github.com> Date: Tue, 4 Jan 2022 10:24:50 -0800 Subject: [PATCH 04/11] Publish OSInfo fields --- Cargo.lock | 1 + aziotctl/aziotctl-common/Cargo.toml | 3 +- aziotctl/aziotctl-common/src/host_info.rs | 42 ++++++++++++++--------- 3 files changed, 29 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7bc0c5c72..1d2635323 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -618,6 +618,7 @@ dependencies = [ "nix", "serde", "serde_json", + "serde_with", "toml", "url", ] diff --git a/aziotctl/aziotctl-common/Cargo.toml b/aziotctl/aziotctl-common/Cargo.toml index 404a10e53..2f70a48df 100644 --- a/aziotctl/aziotctl-common/Cargo.toml +++ b/aziotctl/aziotctl-common/Cargo.toml @@ -11,7 +11,8 @@ base64 = "0.13" log = "0.4" nix = "0.22" serde = { version = "1", features = ["derive"] } -serde_json = "1.0.59" +serde_json = "1" +serde_with = "1" toml = "0.5" url = { version = "2", features = ["serde"] } diff --git a/aziotctl/aziotctl-common/src/host_info.rs b/aziotctl/aziotctl-common/src/host_info.rs index 796fb1e46..208e37d88 100644 --- a/aziotctl/aziotctl-common/src/host_info.rs +++ b/aziotctl/aziotctl-common/src/host_info.rs @@ -1,11 +1,16 @@ use std::env::consts::ARCH; -use std::fmt; use std::fs; use std::io::{self, BufRead}; -use std::path::Path; -use nix::sys::utsname::UtsName; use serde::Serialize; +use serde_with::skip_serializing_none; + +#[cfg(target_pointer_width = "32")] +const BITNESS: usize = 32; +#[cfg(target_pointer_width = "64")] +const BITNESS: usize = 64; +#[cfg(target_pointer_width = "128")] +const BITNESS: usize = 128; /// A subset of the DMI variables exposed through /sys/devices/virtual/dmi/id. /// @@ -20,15 +25,21 @@ use serde::Serialize; /// Ref: #[derive(Clone, Debug, Serialize)] pub struct DmiInfo { - name: Option, - version: Option, - vendor: Option, + pub board: Option, + pub family: Option, + pub product: Option, + pub sku: Option, + pub version: Option, + pub vendor: Option, } impl Default for DmiInfo { fn default() -> Self { Self { - name: try_read_dmi("product_name"), + board: try_read_dmi("board_name"), + family: try_read_dmi("product_family"), + product: try_read_dmi("product_name"), + sku: try_read_dmi("product_sku"), version: try_read_dmi("product_version"), vendor: try_read_dmi("sys_vendor"), } @@ -49,13 +60,14 @@ impl Default for DmiInfo { /// ``` /// /// Ref: +#[skip_serializing_none] #[derive(Clone, Debug, Serialize)] pub struct OsInfo { - id: Option, - version_id: Option, - pretty_name: Option, - arch: &'static str, - bitness: usize, + pub id: Option, + pub version_id: Option, + pub pretty_name: Option, + pub arch: &'static str, + pub bitness: usize, } impl Default for OsInfo { @@ -65,9 +77,7 @@ impl Default for OsInfo { version_id: None, pretty_name: None, arch: ARCH, - // Technically wrong if someone runs an arm32 build on arm64, - // but we have dedicated arm64 builds so hopefully they don't. - bitness: std::mem::size_of::() * 8, + bitness: BITNESS, }; let os_release = fs::File::open("/etc/os-release") @@ -101,7 +111,7 @@ impl Default for OsInfo { } } -fn parse_shell_line(line: &str) -> Option<(&str, &str)> { +pub fn parse_shell_line(line: &str) -> Option<(&str, &str)> { let line = line.trim(); let (key, value) = line.split_once('=')?; From afa691cfb5347a6a4698a5398ddb9f9ada4ffde6 Mon Sep 17 00:00:00 2001 From: onalante-msft <89409054+onalante-msft@users.noreply.github.com> Date: Tue, 4 Jan 2022 10:31:59 -0800 Subject: [PATCH 05/11] Remove unnecessary file --- aziotctl/aziotctl-common/test-files/product_info.toml | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 aziotctl/aziotctl-common/test-files/product_info.toml diff --git a/aziotctl/aziotctl-common/test-files/product_info.toml b/aziotctl/aziotctl-common/test-files/product_info.toml deleted file mode 100644 index 5139270f5..000000000 --- a/aziotctl/aziotctl-common/test-files/product_info.toml +++ /dev/null @@ -1,4 +0,0 @@ -[[product]] -name = "A" -version = "B" -comment = "C" From 3f5baf054c7788e04ecd9d874eeef8715389f9f7 Mon Sep 17 00:00:00 2001 From: onalante-msft <89409054+onalante-msft@users.noreply.github.com> Date: Tue, 4 Jan 2022 10:33:23 -0800 Subject: [PATCH 06/11] Remove unnecessary toml runtime dependency --- aziotctl/aziotctl-common/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/aziotctl/aziotctl-common/Cargo.toml b/aziotctl/aziotctl-common/Cargo.toml index 2f70a48df..ff68a6fd6 100644 --- a/aziotctl/aziotctl-common/Cargo.toml +++ b/aziotctl/aziotctl-common/Cargo.toml @@ -13,7 +13,6 @@ nix = "0.22" serde = { version = "1", features = ["derive"] } serde_json = "1" serde_with = "1" -toml = "0.5" url = { version = "2", features = ["serde"] } aziot-certd-config = { path = "../../cert/aziot-certd-config" } From 6703c25a46402538c786601530d8e62ac82037a1 Mon Sep 17 00:00:00 2001 From: onalante-msft <89409054+onalante-msft@users.noreply.github.com> Date: Tue, 4 Jan 2022 10:51:04 -0800 Subject: [PATCH 07/11] Remove missing datum --- aziotctl/src/internal/check/additional_info.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/aziotctl/src/internal/check/additional_info.rs b/aziotctl/src/internal/check/additional_info.rs index ed8f41085..489dca7de 100644 --- a/aziotctl/src/internal/check/additional_info.rs +++ b/aziotctl/src/internal/check/additional_info.rs @@ -12,7 +12,6 @@ pub struct AdditionalInfo { // TODO: update https://github.com/Azure/azure-iotedge to include aziotd version now: chrono::DateTime, os: OsInfo, - kernel: KernelInfo, dmi: DmiInfo, system_info: SystemInfo, From dbb0bd217eaffa384b68d2e03c443b81043e892c Mon Sep 17 00:00:00 2001 From: onalante-msft <89409054+onalante-msft@users.noreply.github.com> Date: Tue, 4 Jan 2022 11:09:00 -0800 Subject: [PATCH 08/11] Add copyright header --- aziotctl/aziotctl-common/src/host_info.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/aziotctl/aziotctl-common/src/host_info.rs b/aziotctl/aziotctl-common/src/host_info.rs index 208e37d88..f95292071 100644 --- a/aziotctl/aziotctl-common/src/host_info.rs +++ b/aziotctl/aziotctl-common/src/host_info.rs @@ -1,3 +1,5 @@ +// Copyright (c) Microsoft. All rights reserved. + use std::env::consts::ARCH; use std::fs; use std::io::{self, BufRead}; From b324ed5dc6921d6c4dd0c238932b6ef61639975e Mon Sep 17 00:00:00 2001 From: onalante-msft <89409054+onalante-msft@users.noreply.github.com> Date: Thu, 6 Jan 2022 10:29:46 -0800 Subject: [PATCH 09/11] Unify nix dependency and remove unnecessary clone --- Cargo.lock | 4 ++-- aziotctl/Cargo.toml | 2 +- aziotctl/aziotctl-common/Cargo.toml | 2 +- aziotctl/aziotctl-common/src/host_info.rs | 18 +++++++----------- http-common/Cargo.toml | 2 +- 5 files changed, 12 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1d2635323..f5603e4ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1719,9 +1719,9 @@ dependencies = [ [[package]] name = "nix" -version = "0.22.2" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3bb9a13fa32bc5aeb64150cd3f32d6cf4c748f8f8a417cce5d2eb976a8370ba" +checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" dependencies = [ "bitflags", "cc", diff --git a/aziotctl/Cargo.toml b/aziotctl/Cargo.toml index c041a861b..719b28440 100644 --- a/aziotctl/Cargo.toml +++ b/aziotctl/Cargo.toml @@ -18,7 +18,7 @@ foreign-types-shared = "0.1" hyper = "0.14" hyper-openssl = "0.9" libc = "0.2" -nix = "0.22" +nix = "0.23" log = "0.4" openssl = "0.10" serde = { version = "1", features = ["derive"] } diff --git a/aziotctl/aziotctl-common/Cargo.toml b/aziotctl/aziotctl-common/Cargo.toml index ff68a6fd6..d1fd326de 100644 --- a/aziotctl/aziotctl-common/Cargo.toml +++ b/aziotctl/aziotctl-common/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" anyhow = "1.0.34" base64 = "0.13" log = "0.4" -nix = "0.22" +nix = "0.23" serde = { version = "1", features = ["derive"] } serde_json = "1" serde_with = "1" diff --git a/aziotctl/aziotctl-common/src/host_info.rs b/aziotctl/aziotctl-common/src/host_info.rs index f95292071..13b7f977a 100644 --- a/aziotctl/aziotctl-common/src/host_info.rs +++ b/aziotctl/aziotctl-common/src/host_info.rs @@ -82,8 +82,8 @@ impl Default for OsInfo { bitness: BITNESS, }; - let os_release = fs::File::open("/etc/os-release") - .or_else(|_| fs::File::open("/usr/lib/os-release")); + let os_release = + fs::File::open("/etc/os-release").or_else(|_| fs::File::open("/usr/lib/os-release")); if let Ok(os_release) = os_release { let os_release = io::BufReader::new(os_release); @@ -93,17 +93,16 @@ impl Default for OsInfo { match parse_shell_line(line) { Some(("ID", value)) => { result.id = Some(value.to_owned()); - }, + } Some(("VERSION_ID", value)) => { result.version_id = Some(value.to_owned()); - }, + } Some(("PRETTY_NAME", value)) => { result.pretty_name = Some(value.to_owned()); - }, + } _ => (), }; - } - else { + } else { break; } } @@ -138,8 +137,5 @@ fn try_read_dmi(entry: &'static str) -> Option { let bytes = fs::read(path).ok()?; - Some(String::from_utf8(bytes) - .ok()? - .trim() - .to_owned()) + Some(std::str::from_utf8(&bytes).ok()?.trim().to_owned()) } diff --git a/http-common/Cargo.toml b/http-common/Cargo.toml index 56eea54a1..0c7fa52ff 100644 --- a/http-common/Cargo.toml +++ b/http-common/Cargo.toml @@ -15,7 +15,7 @@ hyper-openssl = { version = "0.9" } hyper-proxy = { version = "0.9", features = ["openssl-tls"], default-features = false } libc = "0.2" log = "0.4" -nix = "0.22" +nix = "0.23" openssl = { version = "0.10" } openssl-sys = { version = "0.9" } percent-encoding = "2" From 09d34eae1bcacc290eacae695a78e39898807e00 Mon Sep 17 00:00:00 2001 From: onalante-msft <89409054+onalante-msft@users.noreply.github.com> Date: Tue, 18 Jan 2022 12:16:40 -0800 Subject: [PATCH 10/11] Remove unnecessary DMI variables Unnecessary with respect to product info specification. --- aziotctl/aziotctl-common/src/host_info.rs | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/aziotctl/aziotctl-common/src/host_info.rs b/aziotctl/aziotctl-common/src/host_info.rs index 13b7f977a..539811f89 100644 --- a/aziotctl/aziotctl-common/src/host_info.rs +++ b/aziotctl/aziotctl-common/src/host_info.rs @@ -19,30 +19,22 @@ const BITNESS: usize = 128; /// Examples: /// /// ```ignore -/// Host | name | version | vendor -/// ---------+-----------------+---------+----------------------- -/// Hyper-V | Virtual Machine | 7.0 | Microsoft Corporation +/// Host | name | vendor +/// ---------+-----------------+----------------------- +/// Hyper-V | Virtual Machine | Microsoft Corporation /// ``` /// /// Ref: #[derive(Clone, Debug, Serialize)] pub struct DmiInfo { - pub board: Option, - pub family: Option, pub product: Option, - pub sku: Option, - pub version: Option, pub vendor: Option, } impl Default for DmiInfo { fn default() -> Self { Self { - board: try_read_dmi("board_name"), - family: try_read_dmi("product_family"), product: try_read_dmi("product_name"), - sku: try_read_dmi("product_sku"), - version: try_read_dmi("product_version"), vendor: try_read_dmi("sys_vendor"), } } @@ -67,7 +59,6 @@ impl Default for DmiInfo { pub struct OsInfo { pub id: Option, pub version_id: Option, - pub pretty_name: Option, pub arch: &'static str, pub bitness: usize, } @@ -77,7 +68,6 @@ impl Default for OsInfo { let mut result = Self { id: None, version_id: None, - pretty_name: None, arch: ARCH, bitness: BITNESS, }; @@ -97,9 +87,6 @@ impl Default for OsInfo { Some(("VERSION_ID", value)) => { result.version_id = Some(value.to_owned()); } - Some(("PRETTY_NAME", value)) => { - result.pretty_name = Some(value.to_owned()); - } _ => (), }; } else { From 1909315f2cd9950531b157208f846f403eb709bc Mon Sep 17 00:00:00 2001 From: onalante-msft <89409054+onalante-msft@users.noreply.github.com> Date: Tue, 18 Jan 2022 13:30:07 -0800 Subject: [PATCH 11/11] Restrict serde versions serde_json for consistency, serde_with for safety. --- aziotctl/aziotctl-common/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aziotctl/aziotctl-common/Cargo.toml b/aziotctl/aziotctl-common/Cargo.toml index d1fd326de..32931ef16 100644 --- a/aziotctl/aziotctl-common/Cargo.toml +++ b/aziotctl/aziotctl-common/Cargo.toml @@ -11,8 +11,8 @@ base64 = "0.13" log = "0.4" nix = "0.23" serde = { version = "1", features = ["derive"] } -serde_json = "1" -serde_with = "1" +serde_json = "1.0.59" +serde_with = "1.11" url = { version = "2", features = ["serde"] } aziot-certd-config = { path = "../../cert/aziot-certd-config" }