diff options
Diffstat (limited to 'crates/core')
56 files changed, 1922 insertions, 2249 deletions
diff --git a/crates/core/c8y_api/Cargo.toml b/crates/core/c8y_api/Cargo.toml index fe5da026..cf4a45c7 100644 --- a/crates/core/c8y_api/Cargo.toml +++ b/crates/core/c8y_api/Cargo.toml @@ -11,7 +11,6 @@ rust-version = "1.58.1" agent_interface = { path = "../agent_interface"} async-trait = "0.1" c8y_smartrest = { path = "../c8y_smartrest" } -chrono = "0.4" clock = { path = "../../common/clock" } csv = "1.1" download = { path = "../../common/download" } diff --git a/crates/core/c8y_api/src/http_proxy.rs b/crates/core/c8y_api/src/http_proxy.rs index dfd3c811..9f853043 100644 --- a/crates/core/c8y_api/src/http_proxy.rs +++ b/crates/core/c8y_api/src/http_proxy.rs @@ -1,9 +1,9 @@ use crate::json_c8y::{ C8yCreateEvent, C8yManagedObject, C8yUpdateSoftwareListResponse, InternalIdResponse, }; + use async_trait::async_trait; use c8y_smartrest::{error::SMCumulocityMapperError, smartrest_deserializer::SmartRestJwtResponse}; -use chrono::{DateTime, Local}; use mqtt_channel::{Connection, PubChannel, StreamExt, Topic, TopicFilter}; use reqwest::Url; use std::time::Duration; @@ -20,7 +20,7 @@ const RETRY_TIMEOUT_SECS: u64 = 60; /// An HttpProxy handles http requests to C8y on behalf of the device. #[async_trait] -pub trait C8YHttpProxy { +pub trait C8YHttpProxy: Send + Sync { async fn init(&mut self) -> Result<(), SMCumulocityMapperError>; fn url_is_in_my_tenant_domain(&self, url: &str) -> bool; @@ -155,7 +155,6 @@ impl JwtAuthHttpProxy { pub async fn try_new( tedge_config: &TEdgeConfig, - session_name: &str, ) -> Result<JwtAuthHttpProxy, SMCumulocityMapperError> { let c8y_host = tedge_config.query_string(C8yUrlSetting)?; let device_id = tedge_config.query_string(DeviceIdSetting)?; @@ -166,7 +165,6 @@ impl JwtAuthHttpProxy { let mqtt_config = mqtt_channel::Config::default() .with_port(mqtt_port) .with_clean_session(true) - .with_session_name(session_name) .with_subscriptions(topic); let mut mqtt_con = Connection::new(&mqtt_config).await?; diff --git a/crates/core/c8y_smartrest/src/event.rs b/crates/core/c8y_smartrest/src/event.rs index ad0ee5e3..bf114dba 100644 --- a/crates/core/c8y_smartrest/src/event.rs +++ b/crates/core/c8y_smartrest/src/event.rs @@ -7,15 +7,19 @@ const CREATE_EVENT_SMARTREST_CODE: u16 = 400; /// Converts from thin-edge event to C8Y event SmartREST message pub fn serialize_event(event: ThinEdgeEvent) -> Result<String, SmartRestSerializerError> { + let current_timestamp = OffsetDateTime::now_utc(); match event.data { - None => Ok(format!("{CREATE_EVENT_SMARTREST_CODE},{}", event.name)), + None => Ok(format!( + "{CREATE_EVENT_SMARTREST_CODE},{},{},{}", + event.name, + event.name, + current_timestamp.format(&Rfc3339)? + )), Some(event_data) => { - let current_timestamp = OffsetDateTime::now_utc(); - let smartrest_message = format!( "{CREATE_EVENT_SMARTREST_CODE},{},\"{}\",{}", - event.name, - event_data.message.unwrap_or_default(), + event.name.clone(), + event_data.message.unwrap_or(event.name), event_data.time.map_or_else( || current_timestamp.format(&Rfc3339), |timestamp| timestamp.format(&Rfc3339) @@ -56,7 +60,7 @@ mod tests { time: Some(datetime!(2021-04-23 19:00:00 +05:00)), }), }, - "400,click_event,\"\",2021-04-23T19:00:00+05:00" + "400,click_event,\"click_event\",2021-04-23T19:00:00+05:00" ;"event translation without message" )] #[test_case( @@ -105,7 +109,31 @@ mod tests { let smartrest_event: SmartRestEvent = result.expect("One entry expected")?; assert_eq!(smartrest_event.code, 400); assert_eq!(smartrest_event.name, "empty_event".to_string()); - assert_eq!(smartrest_event.message, None); + assert_eq!(smartrest_event.message, Some("empty_event".to_string())); + assert_matches!(smartrest_event.time, Some(_)); + + Ok(()) + } + + #[test] + fn event_translation_empty_payload() -> Result<()> { + let event = ThinEdgeEvent { + name: "empty_event".into(), + data: None, + }; + + let smartrest_message = serialize_event(event)?; + let mut reader = csv::ReaderBuilder::new() + .has_headers(false) + .from_reader(smartrest_message.as_bytes()); + let mut iter = reader.deserialize(); + let result = iter.next(); + + assert!(result.is_some()); + let smartrest_event: SmartRestEvent = result.expect("One entry expected")?; + assert_eq!(smartrest_event.code, 400); + assert_eq!(smartrest_event.name, "empty_event".to_string()); + assert_eq!(smartrest_event.message, Some("empty_event".to_string())); assert_matches!(smartrest_event.time, Some(_)); Ok(()) diff --git a/crates/core/c8y_smartrest/src/operations.rs b/crates/core/c8y_smartrest/src/operations.rs index b3909aac..7fec5cd7 100644 --- a/crates/core/c8y_smartrest/src/operations.rs +++ b/crates/core/c8y_smartrest/src/operations.rs @@ -49,14 +49,16 @@ pub struct Operations { operations_by_trigger: HashMap<String, usize>, } -impl Operations { - pub fn new() -> Self { +impl Default for Operations { + fn default() -> Self { Self { operations: vec![], operations_by_trigger: HashMap::new(), } } +} +impl Operations { pub fn add(&mut self, operation: Operation) { if let Some(detail) = operation.exec() { if let Some(on_message) = &detail.on_message { @@ -93,7 +95,7 @@ impl Operations { } fn get_operations(dir: impl AsRef<Path>, cloud_name: &str) -> Result<Operations, OperationsError> { - let mut operations = Operations::new(); + let mut operations = Operations::default(); let path = dir.as_ref().join(&cloud_name); let dir_entries = fs::read_dir(&path)? diff --git a/crates/core/c8y_smartrest/src/smartrest_deserializer.rs b/crates/core/c8y_smartrest/src/smartrest_deserializer.rs index 37e57cb4..714a5bba 100644 --- a/crates/core/c8y_smartrest/src/smartrest_deserializer.rs +++ b/crates/core/c8y_smartrest/src/smartrest_deserializer.rs @@ -5,7 +5,7 @@ use download::DownloadInfo; use serde::de::Error; use serde::{Deserialize, Deserializer, Serialize}; use std::convert::{TryFrom, TryInto}; -use std::path::PathBuf; +use std::path::Path; use time::{format_description, OffsetDateTime}; #[derive(Debug)] @@ -304,7 +304,7 @@ impl SmartRestJwtResponse { /// let path_bufdate_time = get_datetime_from_file_path(&path).unwrap(); /// ``` pub fn get_datetime_from_file_path( - log_path: &PathBuf, + log_path: &Path, ) -> Result<OffsetDateTime, SMCumulocityMapperError> { if let Some(stem_string) = log_path.file_stem().and_then(|s| s.to_str()) { // a typical file stem looks like this: software-list-2021-10-27T10:29:58Z. @@ -321,8 +321,8 @@ pub fn get_datetime_from_file_path( match log_path.to_str() { Some(path) => Err(SMCumulocityMapperError::InvalidDateInFileName( path.to_string(), - ))?, - None => Err(SMCumulocityMapperError::InvalidUtf8Path)?, + )), + None => Err(SMCumulocityMapperError::InvalidUtf8Path), } } @@ -332,8 +332,7 @@ mod tests { use agent_interface::*; use assert_json_diff::*; use serde_json::json; - use std::fs::File; - use std::io::Write; + use std::path::PathBuf; use std::str::FromStr; use test_case::test_case; @@ -634,18 +633,4 @@ mod tests { let path_buf_datetime = get_datetime_from_file_path(&path_buf); assert!(path_buf_datetime.is_err()); } - - fn parse_file_names_from_log_content(log_content: &str) -> [&str; 5] { - let mut files: Vec<&str> = vec![]; - for line in log_content.lines() { - if line.contains("filename: ") { - let filename: &str = line.split("filename: ").last().unwrap(); - files.push(filename); - } - } - match files.try_into() { - Ok(arr) => arr, - Err(_) => panic!("Could not convert to Array &str, size 5"), - } - } } diff --git a/crates/core/c8y_smartrest/src/topic.rs b/crates/core/c8y_smartrest/src/topic.rs index 2c6c96b0..7df4f5af 100644 --- a/crates/core/c8y_smartrest/src/topic.rs +++ b/crates/core/c8y_smartrest/src/topic.rs @@ -20,7 +20,7 @@ impl C8yTopic { } pub fn to_topic(&self) -> Result<Topic, MqttError> { - Ok(Topic::new(self.as_str())?) + Topic::new(self.as_str()) } } diff --git a/crates/core/plugin_sm/Cargo.toml b/crates/core/plugin_sm/Cargo.toml index 20a2fc1d..4924b113 100644 --- a/crates/core/plugin_sm/Cargo.toml +++ b/crates/core/plugin_sm/Cargo.toml @@ -21,7 +21,6 @@ url = "2.2" [dev-dependencies] anyhow = "1.0" assert_matches = "1.5" -structopt = "0.3" serial_test = "0.5.1" tempfile = "3.2" test-case = "1.2.1" diff --git a/crates/core/plugin_sm/src/plugin_manager.rs b/crates/core/plugin_sm/src/plugin_manager.rs index 2cb8a3f6..0c541280 100644 --- a/crates/core/plugin_sm/src/plugin_manager.rs +++ b/crates/core/plugin_sm/src/plugin_manager.rs @@ -12,7 +12,6 @@ use std::{ path::PathBuf, process::{Command, Stdio}, }; -use tedge_utils::paths::pathbuf_to_string; use tracing::{error, info, warn}; /// The main responsibility of a `Plugins` implementation is to retrieve the appropriate plugin for a given software module. @@ -141,17 +140,14 @@ impl ExternalPlugins { .status() { Ok(code) if code.success() => { - info!( - "Plugin activated: {}", - pathbuf_to_string(path.clone()).unwrap() - ); + info!("Plugin activated: {}", path.display()); } // If the file is not executable or returned non 0 status code we assume it is not a valid and skip further processing. Ok(_) => { error!( "File {} in plugin directory does not support list operation and may not be a valid plugin, skipping.", - pathbuf_to_string(path.clone()).unwrap() + path.display() ); continue; } @@ -160,7 +156,7 @@ impl ExternalPlugins { error!( "File {} Permission Denied, is the file an executable?\n The file will not be registered as a plugin.", - pathbuf_to_string(path.clone()).unwrap() + path.display() ); continue; } @@ -169,7 +165,7 @@ impl ExternalPlugins { error!( "An error occurred while trying to run: {}: {}\n The file will not be registered as a plugin.", - pathbuf_to_string(path.clone()).unwrap(), + path.display(), err ); continue; diff --git a/crates/core/plugin_sm/tests/plugin.rs b/crates/core/plugin_sm/tests/plugin.rs index 5e1573b8..e9c985f2 100644 --- a/crates/core/plugin_sm/tests/plugin.rs +++ b/crates/core/plugin_sm/tests/plugin.rs @@ -335,7 +335,7 @@ mod tests { .await; // Expect Ok as plugin should exit with code 0. If Ok, there is no response to assert. - assert_matches!(res, Err(SoftwareError::UpdateListNotSupported(_))); + assert!(res.is_ok()); } // Test validating if the plugin will fall back to `install` and `remove` options if the `update-list` option is not supported diff --git a/crates/core/tedge/Cargo.toml b/crates/core/tedge/Cargo.toml index 2180b35c..f19a91e7 100644 --- a/crates/core/tedge/Cargo.toml +++ b/crates/core/tedge/Cargo.toml @@ -16,6 +16,7 @@ maintainer-scripts = "../../../configuration/debian/tedge" anyhow = "1.0" base64 = "0.13" certificate = { path = "../../common/certificate" } +clap = { version = "3", features = ["cargo", "derive"] } futures = "0.3" hyper = { version = "0.14", default-features = false } reqwest = { version = "0.11", default-features = false, features = ["blocking", "json", "rustls-tls", "stream"] } @@ -25,7 +26,6 @@ rustls = "0.20.2" rustls_0_19 = {package = "rustls", version = "0.19.0" } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -structopt = "0.3" tedge_config = { path = "../../common/tedge_config" } tedge_users = { path = "../../common/tedge_users" } tedge_utils = { path = "../../common/tedge_utils" } diff --git a/crates/core/tedge/src/cli/certificate/cli.rs b/crates/core/tedge/src/cli/certificate/cli.rs index 7ef78fb5..a3e9db64 100644 --- a/crates/core/tedge/src/cli/certificate/cli.rs +++ b/crates/core/tedge/src/cli/certificate/cli.rs @@ -3,15 +3,14 @@ use super::{create::CreateCertCmd, remove::RemoveCertCmd, show::ShowCertCmd, upl use crate::command::{BuildCommand, BuildContext, Command}; use crate::ConfigError; -use structopt::StructOpt; use tedge_config::*; -#[derive(StructOpt, Debug)] +#[derive(clap::Subcommand, Debug)] pub enum TEdgeCertCli { /// Create a self-signed device certificate Create { /// The device identifier to be used as the common name for the certificate - #[structopt(long = "device-id")] + #[clap(long = "device-id")] id: String, }, @@ -22,6 +21,7 @@ pub enum TEdgeCertCli { Remove, /// Upload root certificate + #[clap(subcommand)] Upload(UploadCertCli), } @@ -73,13 +73,13 @@ impl BuildCommand for TEdgeCertCli { } } -#[derive(StructOpt, Debug)] +#[derive(clap::Subcommand, Debug)] pub enum UploadCertCli { /// Upload root certificate to Cumulocity /// /// The command will upload root certificate to Cumulocity. C8y { - #[structopt(long = "user")] + #[clap(long = "user")] /// Provided username should be a Cumulocity user with tenant management permissions. /// The password is req |