diff --git a/Cargo.lock b/Cargo.lock index 726f62472..a6ca0756f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -91,6 +91,7 @@ dependencies = [ "anyhow", "async-trait", "aziot-certd-config", + "aziot-check-common", "aziot-identityd-config", "aziot-keyd-config", "aziot-keys-common", @@ -190,6 +191,15 @@ dependencies = [ "url", ] +[[package]] +name = "aziot-check-common" +version = "0.1.0" +dependencies = [ + "anyhow", + "serde", + "serde_json", +] + [[package]] name = "aziot-cloud-client-async-common" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index fe54f45bd..38153d47f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [workspace] members = [ "aziot", + "aziot/aziot-check-common", "aziotd", diff --git a/aziot/Cargo.toml b/aziot/Cargo.toml index 7000c8f23..4fbd9e3c9 100644 --- a/aziot/Cargo.toml +++ b/aziot/Cargo.toml @@ -29,6 +29,8 @@ tokio = { version = "0.2", features = ["macros", "fs", "io-util"] } toml = "0.5" url = "2" +aziot-check-common = { path = "./aziot-check-common" } + aziot-certd-config = { path = "../cert/aziot-certd-config" } aziot-identityd-config = { path = "../identity/aziot-identityd-config" } aziot-keyd-config = { path = "../key/aziot-keyd-config" } diff --git a/aziot/aziot-check-common/Cargo.toml b/aziot/aziot-check-common/Cargo.toml new file mode 100644 index 000000000..8d5484ef4 --- /dev/null +++ b/aziot/aziot-check-common/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "aziot-check-common" +version = "0.1.0" +authors = ["Azure IoT Edge Devs"] +edition = "2018" + + +[dependencies] +anyhow = "1.0.34" +serde = { version = "1", features = ["derive"] } +serde_json = "1.0.59" diff --git a/aziot/aziot-check-common/src/lib.rs b/aziot/aziot-check-common/src/lib.rs new file mode 100644 index 000000000..99e0cc151 --- /dev/null +++ b/aziot/aziot-check-common/src/lib.rs @@ -0,0 +1,59 @@ +// Copyright (c) Microsoft. All rights reserved. + +#![deny(rust_2018_idioms)] +#![warn(clippy::all, clippy::pedantic)] + +use std::collections::BTreeMap; + +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct CheckResultsSerializable { + pub additional_info: serde_json::Value, + pub checks: BTreeMap, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(tag = "result")] +#[serde(rename_all = "snake_case")] +pub enum CheckResultSerializable { + Ok, + Warning { details: Vec }, + Ignored, + Skipped, + Fatal { details: Vec }, + Error { details: Vec }, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct CheckOutputSerializable { + pub result: CheckResultSerializable, + pub additional_info: serde_json::Value, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(tag = "kind")] +#[serde(rename_all = "snake_case")] +pub enum CheckOuputSerializableStreaming { + AdditionalInfo(serde_json::Value), + Section { + name: String, + }, + Check { + #[serde(flatten)] + meta: CheckerMetaSerializable, + #[serde(flatten)] + output: CheckOutputSerializable, + }, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct CheckerMetaSerializable { + /// Unique human-readable identifier for the check. + pub id: String, + /// A brief description of what this check does. + pub description: String, +} + +/// Keys are section names +pub type CheckListOutput = BTreeMap>; diff --git a/aziot/src/check.rs b/aziot/src/check.rs index 857555157..4f8b84865 100644 --- a/aziot/src/check.rs +++ b/aziot/src/check.rs @@ -6,11 +6,15 @@ use std::str::FromStr; use anyhow::Result; use colored::Colorize; -use serde::Serialize; use structopt::StructOpt; +use aziot_check_common::{ + CheckOuputSerializableStreaming, CheckOutputSerializable, CheckResultSerializable, + CheckResultsSerializable, +}; + use crate::internal::check::{ - AdditionalInfo, CheckResult, CheckerCache, CheckerCfg, CheckerMeta, CheckerShared, + AdditionalInfo, CheckResult, CheckerCache, CheckerCfg, CheckerShared, }; #[derive(StructOpt)] @@ -71,7 +75,7 @@ pub async fn check(mut cfg: CheckCfg) -> Result<()> { let checker_shared = CheckerShared::new(cfg.checker_cfg); - let mut checks: BTreeMap<&str, CheckOutputSerializable> = Default::default(); + let mut checks: BTreeMap = Default::default(); let mut check_data = crate::internal::check::all_checks(); let mut check_cache = CheckerCache::new(); @@ -126,7 +130,7 @@ pub async fn check(mut cfg: CheckCfg) -> Result<()> { if matches!(cfg.output, OutputFormat::JsonStream) { serde_json::to_writer( std::io::stdout(), - &CheckResultsSerializableStreaming::Section { + &CheckOuputSerializableStreaming::Section { name: §ion_name, }, )?; @@ -226,13 +230,13 @@ pub async fn check(mut cfg: CheckCfg) -> Result<()> { match cfg.output { OutputFormat::Text => {} OutputFormat::Json => { - checks.insert(check.meta().id, output_serializable); + checks.insert(check.meta().id.into(), output_serializable); } OutputFormat::JsonStream => { serde_json::to_writer( std::io::stdout(), - &CheckResultsSerializableStreaming::Check { - meta: check.meta(), + &CheckOuputSerializableStreaming::Check { + meta: check.meta().into(), output: output_serializable, }, )?; @@ -292,69 +296,31 @@ pub async fn check(mut cfg: CheckCfg) -> Result<()> { } }); - AdditionalInfo::new(iothub_hostname) + serde_json::to_value(&AdditionalInfo::new(iothub_hostname))? }; - if matches!(cfg.output, OutputFormat::JsonStream) { - serde_json::to_writer( - std::io::stdout(), - &CheckResultsSerializableStreaming::AdditionalInfo(&top_level_additional_info), - )?; - std::io::stdout().flush()?; - } - - if matches!(cfg.output, OutputFormat::Json) { - let check_results = CheckResultsSerializable { - additional_info: &top_level_additional_info, - checks, - }; - - if let Err(err) = serde_json::to_writer(std::io::stdout(), &check_results) { - eprintln!("Could not write JSON output: {}", err,); + match cfg.output { + OutputFormat::JsonStream => { + serde_json::to_writer( + std::io::stdout(), + &CheckOuputSerializableStreaming::AdditionalInfo(top_level_additional_info), + )?; + std::io::stdout().flush()?; } + OutputFormat::Json => { + let check_results = CheckResultsSerializable { + additional_info: top_level_additional_info, + checks, + }; - println!(); + if let Err(err) = serde_json::to_writer(std::io::stdout(), &check_results) { + eprintln!("Could not write JSON output: {}", err,); + } + } + OutputFormat::Text => {} } - Ok(()) -} - -#[derive(Debug, Serialize)] -struct CheckResultsSerializable<'a> { - additional_info: &'a AdditionalInfo, - checks: BTreeMap<&'static str, CheckOutputSerializable>, -} + println!(); -#[derive(Debug, Serialize)] -#[serde(tag = "result")] -#[serde(rename_all = "snake_case")] -enum CheckResultSerializable { - Ok, - Warning { details: Vec }, - Ignored, - Skipped, - Fatal { details: Vec }, - Error { details: Vec }, -} - -#[derive(Debug, Serialize)] -struct CheckOutputSerializable { - result: CheckResultSerializable, - additional_info: serde_json::Value, -} - -#[derive(Debug, Serialize)] -#[serde(tag = "kind")] -#[serde(rename_all = "snake_case")] -enum CheckResultsSerializableStreaming<'a> { - AdditionalInfo(&'a AdditionalInfo), - Section { - name: &'a str, - }, - Check { - #[serde(flatten)] - meta: CheckerMeta, - #[serde(flatten)] - output: CheckOutputSerializable, - }, + Ok(()) } diff --git a/aziot/src/check_list.rs b/aziot/src/check_list.rs index 60b00a131..515e658a5 100644 --- a/aziot/src/check_list.rs +++ b/aziot/src/check_list.rs @@ -1,10 +1,10 @@ // Copyright (c) Microsoft. All rights reserved. -use std::collections::BTreeMap; - use anyhow::{Context, Result}; use structopt::StructOpt; +use aziot_check_common::CheckListOutput; + #[derive(StructOpt, Copy, Clone)] #[structopt(about = "List the checks that are run for 'aziot check'")] pub struct CheckListCfg { @@ -17,11 +17,14 @@ pub fn check_list(cfg: CheckListCfg) -> Result<()> { let checks = crate::internal::check::all_checks(); if cfg.json { - let mut output: BTreeMap> = BTreeMap::new(); + let mut output = CheckListOutput::new(); for (section_name, section_checks) in checks { output.insert( section_name.to_string(), - section_checks.into_iter().map(|c| c.meta()).collect(), + section_checks + .into_iter() + .map(|c| c.meta().into()) + .collect(), ); } diff --git a/aziot/src/internal/check/mod.rs b/aziot/src/internal/check/mod.rs index 2004ea60c..05c313c7a 100644 --- a/aziot/src/internal/check/mod.rs +++ b/aziot/src/internal/check/mod.rs @@ -11,8 +11,6 @@ mod checks; pub use additional_info::AdditionalInfo; pub use checks::all_checks; -const DEFAULT_BIN_DIR: &str = "/usr/bin/"; - // NOTE: this struct gets `structopt(flatten)`ed as part of the `aziot check` subcommand. #[derive(StructOpt)] pub struct CheckerCfg { @@ -21,19 +19,6 @@ pub struct CheckerCfg { // /// contained in // expected_iotedged_version: String, // - /// Sets the path to the aziotd daemon binaries directory. - #[structopt( - long, - value_name = "PATH_TO_AZIOTD_BINS", - default_value = DEFAULT_BIN_DIR - )] - pub bin_path: PathBuf, - - /// Sets the hostname of the Azure IoT Hub that this device would connect to. - /// If using manual provisioning, this does not need to be specified. - #[structopt(long, value_name = "IOTHUB_HOSTNAME")] - pub iothub_hostname: Option, - /// Sets the NTP server to use when checking host local time. #[structopt(long, value_name = "NTP_SERVER", default_value = "pool.ntp.org:123")] pub ntp_server: String, @@ -85,6 +70,15 @@ pub struct CheckerMeta { pub description: &'static str, } +impl From for aziot_check_common::CheckerMetaSerializable { + fn from(meta: CheckerMeta) -> aziot_check_common::CheckerMetaSerializable { + aziot_check_common::CheckerMetaSerializable { + id: meta.id.into(), + description: meta.description.into(), + } + } +} + #[async_trait::async_trait] pub trait Checker: erased_serde::Serialize { fn meta(&self) -> CheckerMeta;