Skip to content

Commit

Permalink
extract aziot-check JSON API into separate crate
Browse files Browse the repository at this point in the history
this new crate is consumed by `iotedge check`, and ensures the two tools
stay in-sync.
  • Loading branch information
daprilik committed Dec 23, 2020
1 parent bd8329a commit 731c130
Show file tree
Hide file tree
Showing 8 changed files with 130 additions and 84 deletions.
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[workspace]
members = [
"aziot",
"aziot/aziot-check-common",

"aziotd",

Expand Down
2 changes: 2 additions & 0 deletions aziot/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
Expand Down
11 changes: 11 additions & 0 deletions aziot/aziot-check-common/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"
59 changes: 59 additions & 0 deletions aziot/aziot-check-common/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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<String, CheckOutputSerializable>,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "result")]
#[serde(rename_all = "snake_case")]
pub enum CheckResultSerializable {
Ok,
Warning { details: Vec<String> },
Ignored,
Skipped,
Fatal { details: Vec<String> },
Error { details: Vec<String> },
}

#[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<String, Vec<CheckerMetaSerializable>>;
96 changes: 31 additions & 65 deletions aziot/src/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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<String, CheckOutputSerializable> = Default::default();
let mut check_data = crate::internal::check::all_checks();
let mut check_cache = CheckerCache::new();

Expand Down Expand Up @@ -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: &section_name,
},
)?;
Expand Down Expand Up @@ -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,
},
)?;
Expand Down Expand Up @@ -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<String> },
Ignored,
Skipped,
Fatal { details: Vec<String> },
Error { details: Vec<String> },
}

#[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(())
}
11 changes: 7 additions & 4 deletions aziot/src/check_list.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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<String, Vec<_>> = 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(),
);
}

Expand Down
24 changes: 9 additions & 15 deletions aziot/src/internal/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -21,19 +19,6 @@ pub struct CheckerCfg {
// /// contained in <http://aka.ms/latest-iotedge-stable>
// 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<PathBuf>,

/// 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,
Expand Down Expand Up @@ -85,6 +70,15 @@ pub struct CheckerMeta {
pub description: &'static str,
}

impl From<CheckerMeta> 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;
Expand Down

0 comments on commit 731c130

Please sign in to comment.