diff options
author | Lukasz Woznicki <75632179+makr11st@users.noreply.github.com> | 2022-05-17 13:30:05 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-05-17 13:30:05 +0100 |
commit | 2a8d917cbb377395cfeb4abcf34580541df80ace (patch) | |
tree | bc4ac1d65d227e30abe914cdb349af715edaf38d | |
parent | ba49c8bdd3ca4e7ad5249a89ac90d2aad9479dfb (diff) | |
parent | f71bb3194f045110d1b5c41491caae5536a73e50 (diff) |
Merge pull request #1142 from makr11st/feature/1051_smartrest_templates
[1051] Add support for smartrest templates to config
-rw-r--r-- | crates/common/tedge_config/src/models/mod.rs | 4 | ||||
-rw-r--r-- | crates/common/tedge_config/src/models/templates_set.rs | 57 | ||||
-rw-r--r-- | crates/common/tedge_config/src/settings.rs | 19 | ||||
-rw-r--r-- | crates/common/tedge_config/src/tedge_config.rs | 26 | ||||
-rw-r--r-- | crates/common/tedge_config/src/tedge_config_dto.rs | 3 | ||||
-rw-r--r-- | crates/core/tedge/src/cli/config/config_key.rs | 1 | ||||
-rw-r--r-- | crates/core/tedge/src/cli/connect/bridge_config_c8y.rs | 90 | ||||
-rw-r--r-- | crates/core/tedge/src/cli/connect/command.rs | 1 |
8 files changed, 169 insertions, 32 deletions
diff --git a/crates/common/tedge_config/src/models/mod.rs b/crates/common/tedge_config/src/models/mod.rs index 4044168d..37871da7 100644 --- a/crates/common/tedge_config/src/models/mod.rs +++ b/crates/common/tedge_config/src/models/mod.rs @@ -3,4 +3,6 @@ pub mod file_path; pub mod flag; pub mod ipaddress; pub mod port; -pub use self::{connect_url::*, file_path::*, flag::*, ipaddress::*, port::*}; +pub mod templates_set; + +pub use self::{connect_url::*, file_path::*, flag::*, ipaddress::*, port::*, templates_set::*}; diff --git a/crates/common/tedge_config/src/models/templates_set.rs b/crates/common/tedge_config/src/models/templates_set.rs new file mode 100644 index 00000000..da9d32f6 --- /dev/null +++ b/crates/common/tedge_config/src/models/templates_set.rs @@ -0,0 +1,57 @@ +use std::convert::TryInto; + +/// Represents a set of smartrest templates. +/// +/// New type to add conversion methods and deduplicate provided templates. +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq)] +#[serde(transparent)] +pub struct TemplatesSet(pub Vec<String>); + +#[derive(thiserror::Error, Debug)] +#[error("TemplateSet to String conversion failed: {0:?}")] +pub struct TemplatesSetToStringConversionFailure(String); + +impl TryFrom<Vec<String>> for TemplatesSet { + type Error = TemplatesSetToStringConversionFailure; + + fn try_from(value: Vec<String>) -> Result<Self, Self::Error> { + Ok(TemplatesSet(value)) + } +} + +impl TryFrom<Vec<&str>> for TemplatesSet { + type Error = TemplatesSetToStringConversionFailure; + + fn try_from(value: Vec<&str>) -> Result<Self, Self::Error> { + Ok(TemplatesSet( + value.into_iter().map(|s| s.into()).collect::<Vec<String>>(), + )) + } +} + +impl TryInto<Vec<String>> for TemplatesSet { + type Error = TemplatesSetToStringConversionFailure; + + fn try_into(self) -> Result<Vec<String>, TemplatesSetToStringConversionFailure> { + Ok(self.0) + } +} + +impl From<TemplatesSet> for String { + fn from(val: TemplatesSet) -> Self { + val.to_string() + } +} + +impl From<String> for TemplatesSet { + fn from(val: String) -> Self { + let strings = val.split(',').map(|ss| ss.into()).collect(); + TemplatesSet(strings) + } +} + +impl std::fmt::Display for TemplatesSet { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.0) + } +} diff --git a/crates/common/tedge_config/src/settings.rs b/crates/common/tedge_config/src/settings.rs index fb018408..bca85b1a 100644 --- a/crates/common/tedge_config/src/settings.rs +++ b/crates/common/tedge_config/src/settings.rs @@ -102,6 +102,25 @@ impl ConfigSetting for C8yRootCertPathSetting { } /// +/// Smartrest templates to subsribe to. +/// +/// Example: template1,template2 +/// +#[derive(Debug)] +pub struct C8ySmartRestTemplates; + +impl ConfigSetting for C8ySmartRestTemplates { + const KEY: &'static str = "c8y.smartrest.templates"; + + const DESCRIPTION: &'static str = concat!( + "Set of SmartRest templates for the device ", + "Example: template1,template2" + ); + + type Value = TemplatesSet; +} + +/// /// Tenant endpoint URL of Azure IoT tenant. /// /// Example: MyAzure.azure-devices.net diff --git a/crates/common/tedge_config/src/tedge_config.rs b/crates/common/tedge_config/src/tedge_config.rs index f37ea0e3..9952b2d1 100644 --- a/crates/common/tedge_config/src/tedge_config.rs +++ b/crates/common/tedge_config/src/tedge_config.rs @@ -138,6 +138,32 @@ impl ConfigSettingAccessor<C8yUrlSetting> for TEdgeConfig { } } +impl ConfigSettingAccessor<C8ySmartRestTemplates> for TEdgeConfig { + fn query(&self, _setting: C8ySmartRestTemplates) -> ConfigSettingResult<TemplatesSet> { + self.data + .c8y + .smartrest_templates + .clone() + .ok_or(ConfigSettingError::ConfigNotSet { + key: C8ySmartRestTemplates::KEY, + }) + } + + fn update( + &mut self, + _setting: C8ySmartRestTemplates, + value: TemplatesSet, + ) -> ConfigSettingResult<()> { + self.data.c8y.smartrest_templates = Some(value); + Ok(()) + } + + fn unset(&mut self, _setting: C8ySmartRestTemplates) -> ConfigSettingResult<()> { + self.data.c8y.smartrest_templates = None; + Ok(()) + } +} + impl ConfigSettingAccessor<DeviceCertPathSetting> for TEdgeConfig { fn query(&self, _setting: DeviceCertPathSetting) -> ConfigSettingResult<FilePath> { Ok(self diff --git a/crates/common/tedge_config/src/tedge_config_dto.rs b/crates/common/tedge_config/src/tedge_config_dto.rs index 28cbfcbd..75b576b6 100644 --- a/crates/common/tedge_config/src/tedge_config_dto.rs +++ b/crates/common/tedge_config/src/tedge_config_dto.rs @@ -72,6 +72,9 @@ pub(crate) struct CumulocityConfigDto { /// Boolean whether Azure mapper adds timestamp or not. pub(crate) mapper_timestamp: Option<bool>, + + /// Set of c8y templates used for subscriptions. + pub(crate) smartrest_templates: Option<TemplatesSet>, } #[derive(Debug, Default, Deserialize, Serialize)] diff --git a/crates/core/tedge/src/cli/config/config_key.rs b/crates/core/tedge/src/cli/config/config_key.rs index 96227269..161f0e4c 100644 --- a/crates/core/tedge/src/cli/config/config_key.rs +++ b/crates/core/tedge/src/cli/config/config_key.rs @@ -45,6 +45,7 @@ impl ConfigKey { config_key!(DeviceCertPathSetting), config_key!(C8yUrlSetting), config_key!(C8yRootCertPathSetting), + config_key!(C8ySmartRestTemplates), config_key!(AzureUrlSetting), config_key!(AzureRootCertPathSetting), config_key!(AzureMapperTimestamp), diff --git a/crates/core/tedge/src/cli/connect/bridge_config_c8y.rs b/crates/core/tedge/src/cli/connect/bridge_config_c8y.rs index 90fdab7e..31330598 100644 --- a/crates/core/tedge/src/cli/connect/bridge_config_c8y.rs +++ b/crates/core/tedge/src/cli/connect/bridge_config_c8y.rs @@ -1,5 +1,5 @@ use crate::cli::connect::BridgeConfig; -use tedge_config::{ConnectUrl, FilePath}; +use tedge_config::{ConnectUrl, FilePath, TemplatesSet}; #[derive(Debug, PartialEq)] pub struct BridgeConfigC8yParams { @@ -10,6 +10,7 @@ pub struct BridgeConfigC8yParams { pub bridge_root_cert_path: FilePath, pub bridge_certfile: FilePath, pub bridge_keyfile: FilePath, + pub smartrest_templates: TemplatesSet, } impl From<BridgeConfigC8yParams> for BridgeConfig { @@ -22,9 +23,57 @@ impl From<BridgeConfigC8yParams> for BridgeConfig { remote_clientid, bridge_certfile, bridge_keyfile, + smartrest_templates, } = params; let address = format!("{}:{}", connect_url.as_str(), mqtt_tls_port); + let mut topics: Vec<String> = vec![ + // Registration + r#"s/dcr in 2 c8y/ """#.into(), + r#"s/ucr out 2 c8y/ """#.into(), + // Templates + r#"s/dt in 2 c8y/ """#.into(), + r#"s/ut/# out 2 c8y/ """#.into(), + // Static templates + r#"s/us/# out 2 c8y/ """#.into(), + r#"t/us/# out 2 c8y/ """#.into(), + r#"q/us/# out 2 c8y/ """#.into(), + r#"c/us/# out 2 c8y/ """#.into(), + r#"s/ds in 2 c8y/ """#.into(), + // Debug + r#"s/e in 0 c8y/ """#.into(), + // SmartRest2 + r#"s/uc/# out 2 c8y/ """#.into(), + r#"t/uc/# out 2 c8y/ """#.into(), + r#"q/uc/# out 2 c8y/ """#.into(), + r#"c/uc/# out 2 c8y/ """#.into(), + r#"s/dc/# in 2 c8y/ """#.into(), + // c8y JSON + r#"inventory/managedObjects/update/# out 2 c8y/ """#.into(), + r#"measurement/measurements/create out 2 c8y/ """#.into(), + r#"event/events/create out 2 c8y/ """#.into(), + r#"error in 2 c8y/ """#.into(), + // c8y JWT token retrieval + r#"s/uat/# out 2 c8y/ """#.into(), + r#"s/dat/# in 2 c8y/ """#.into(), + ]; + + let templates_set = smartrest_templates + .0 + .iter() + .flat_map(|s| { + // Smartrest templates should be deserialized as: + // c8y/s/uc/template-1 (in from localhost), s/uc/template-1 + // c8y/s/dc/template-1 (out to localhost), s/dc/template-1 + [ + format!(r#"s/uc/{s} out 2 c8y/ """#), + format!(r#"s/dc/{s} in 2 c8y/ """#), + ] + .into_iter() + }) + .collect::<Vec<String>>(); + topics.extend(templates_set); + Self { cloud_name: "c8y".into(), config_file, @@ -45,36 +94,7 @@ impl From<BridgeConfigC8yParams> for BridgeConfig { notifications_local_only: true, notification_topic: "tedge/health/mosquitto-c8y-bridge".into(), bridge_attempt_unsubscribe: false, - topics: vec![ - // Registration - r#"s/dcr in 2 c8y/ """#.into(), - r#"s/ucr out 2 c8y/ """#.into(), - // Templates - r#"s/dt in 2 c8y/ """#.into(), - r#"s/ut/# out 2 c8y/ """#.into(), - // Static templates - r#"s/us/# out 2 c8y/ """#.into(), - r#"t/us/# out 2 c8y/ """#.into(), - r#"q/us/# out 2 c8y/ """#.into(), - r#"c/us/# out 2 c8y/ """#.into(), - r#"s/ds in 2 c8y/ """#.into(), - // Debug - r#"s/e in 0 c8y/ """#.into(), - // SmartRest2 - r#"s/uc/# out 2 c8y/ """#.into(), - r#"t/uc/# out 2 c8y/ """#.into(), - r#"q/uc/# out 2 c8y/ """#.into(), - r#"c/uc/# out 2 c8y/ """#.into(), - r#"s/dc/# in 2 c8y/ """#.into(), - // c8y JSON - r#"inventory/managedObjects/update/# out 2 c8y/ """#.into(), - r#"measurement/measurements/create out 2 c8y/ """#.into(), - r#"event/events/create out 2 c8y/ """#.into(), - r#"error in 2 c8y/ """#.into(), - // c8y JWT token retrieval - r#"s/uat/# out 2 c8y/ """#.into(), - r#"s/dat/# in 2 c8y/ """#.into(), - ], + topics, } } } @@ -90,6 +110,7 @@ fn test_bridge_config_from_c8y_params() -> anyhow::Result<()> { bridge_root_cert_path: "./test_root.pem".into(), bridge_certfile: "./test-certificate.pem".into(), bridge_keyfile: "./test-private-key.pem".into(), + smartrest_templates: TemplatesSet::try_from(vec!["abc", "def"])?, }; let bridge = BridgeConfig::from(params); @@ -136,6 +157,13 @@ fn test_bridge_config_from_c8y_params() -> anyhow::Result<()> { // c8y JWT token retrieval r#"s/uat/# out 2 c8y/ """#.into(), r#"s/dat/# in 2 c8y/ """#.into(), + // Smartrest templates should be deserialized as: + // s/uc/template-1 (in from localhost), s/uc/template-1 + // s/dc/template-1 (out to localhost), s/dc/template-1 + r#"s/uc/abc out 2 c8y/ """#.into(), + r#"s/dc/abc in 2 c8y/ """#.into(), + r#"s/uc/def out 2 c8y/ """#.into(), + r#"s/dc/def in 2 c8y/ """#.into(), ], try_private: false, start_type: "automatic".into(), diff --git a/crates/core/tedge/src/cli/connect/command.rs b/crates/core/tedge/src/cli/connect/command.rs index 30682ddd..7da926d0 100644 --- a/crates/core/tedge/src/cli/connect/command.rs +++ b/crates/core/tedge/src/cli/connect/command.rs @@ -203,6 +203,7 @@ impl ConnectCommand { remote_clientid: config.query(DeviceIdSetting)?, bridge_certfile: config.query(DeviceCertPathSetting)?, bridge_keyfile: config.query(DeviceKeyPathSetting)?, + smartrest_templates: config.query(C8ySmartRestTemplates)?, }; Ok(BridgeConfig::from(params)) |