diff options
author | Rina Fujino <18257209+rina23q@users.noreply.github.com> | 2021-05-20 18:14:16 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-05-20 18:14:16 +0200 |
commit | 8418ccc07c00f2b38275021f2de87952910250f2 (patch) | |
tree | 72d079e345c66edb9e4145a230862efcce312868 /tedge_config | |
parent | b77db397c9f877acb0da34d51203f8213bb79444 (diff) |
[CIT-162] Implement Azure IoT Mapper (#242)
Implement Azure Mapper
Features:
- Azure Mapper takes Thin Edge JSON formatted input and coverts to Thin Edge JSON.
- It adds a timestamp when `azure.mapper.timestamp` is true in the tedge config.
Code changes:
- Add many files in tedge_mapper crate.
- Now `tedge_mapper` requires one argument, c8y or az. Lauch by `tedge_mapper az`
- Add a key `azure.mapper.timestamp` in tedge config
- Give a temporary solution to add `az` to tedge-mapper systemd service.
Diffstat (limited to 'tedge_config')
-rw-r--r-- | tedge_config/src/models/flag.rs | 89 | ||||
-rw-r--r-- | tedge_config/src/models/mod.rs | 3 | ||||
-rw-r--r-- | tedge_config/src/settings.rs | 19 | ||||
-rw-r--r-- | tedge_config/src/tedge_config.rs | 21 | ||||
-rw-r--r-- | tedge_config/src/tedge_config_dto.rs | 4 |
5 files changed, 135 insertions, 1 deletions
diff --git a/tedge_config/src/models/flag.rs b/tedge_config/src/models/flag.rs new file mode 100644 index 00000000..debdbe36 --- /dev/null +++ b/tedge_config/src/models/flag.rs @@ -0,0 +1,89 @@ +use std::convert::TryFrom; + +/// Represents a boolean type. +/// +/// We need this newtype in order to implement `TryFrom<String>` and `TryInto<String>`. +/// The `config_key!` macro uses query_string() and update_string(). +/// Therefore, boolean needs to be converted from/to String. +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq)] +#[serde(transparent)] +pub struct Flag(pub bool); + +#[derive(thiserror::Error, Debug)] +#[error("Failed to parse flag: {input}. Supported values are: true, false")] +pub struct InvalidFlag { + input: String, +} + +impl TryFrom<String> for Flag { + type Error = InvalidFlag; + + fn try_from(input: String) -> Result<Self, Self::Error> { + match input.as_str() { + "true" => Ok(Flag(true)), + "false" => Ok(Flag(false)), + _ => Err(InvalidFlag { input }), + } + } +} + +impl From<Flag> for bool { + fn from(value: Flag) -> Self { + value.0 + } +} + +impl From<Flag> for String { + fn from(value: Flag) -> Self { + match value { + Flag(true) => "true".to_string(), + Flag(false) => "false".to_string(), + } + } +} + +impl Flag { + pub fn is_set(&self) -> bool { + self.0 + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::convert::TryInto; + + #[test] + fn convert_string_true_to_bool_true() { + let input = "true".to_string(); + let output: bool = Flag::try_from(input).unwrap().into(); + assert_eq!(output, true); + } + + #[test] + fn convert_string_false_to_bool_false() { + let input = "false".to_string(); + let output: bool = Flag::try_from(input).unwrap().into(); + assert_eq!(output, false); + } + + #[test] + fn return_error_for_unexpected_string_input() { + let input = "unknown".to_string(); + assert!(Flag::try_from(input).is_err()); + } + + #[test] + fn convert_bool_true_to_string_true() { + let input = true; + let output: String = Flag::try_into(Flag(input)).unwrap(); + assert_eq!(output, "true"); + } + + #[test] + fn convert_bool_false_to_string_false() { + let input = false; + let output: String = Flag::try_into(Flag(input)).unwrap(); + assert_eq!(output, "false"); + } +} diff --git a/tedge_config/src/models/mod.rs b/tedge_config/src/models/mod.rs index ce81e3af..9ea27a70 100644 --- a/tedge_config/src/models/mod.rs +++ b/tedge_config/src/models/mod.rs @@ -1,4 +1,5 @@ pub mod connect_url; pub mod file_path; +pub mod flag; -pub use self::{connect_url::*, file_path::*}; +pub use self::{connect_url::*, file_path::*, flag::*}; diff --git a/tedge_config/src/settings.rs b/tedge_config/src/settings.rs index f247cfe7..35092393 100644 --- a/tedge_config/src/settings.rs +++ b/tedge_config/src/settings.rs @@ -125,3 +125,22 @@ impl ConfigSetting for AzureRootCertPathSetting { type Value = FilePath; } + +/// +/// Boolean whether Azure mapper should add timestamp if timestamp is not added in the incoming payload. +/// +/// Example: true +/// +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct AzureMapperTimestamp; + +impl ConfigSetting for AzureMapperTimestamp { + const KEY: &'static str = "azure.mapper.timestamp"; + + const DESCRIPTION: &'static str = concat!( + "Boolean whether Azure mapper should add timestamp or not. ", + "Example: true" + ); + + type Value = Flag; +} diff --git a/tedge_config/src/tedge_config.rs b/tedge_config/src/tedge_config.rs index 29f611f5..d4d2fbbd 100644 --- a/tedge_config/src/tedge_config.rs +++ b/tedge_config/src/tedge_config.rs @@ -177,6 +177,27 @@ impl ConfigSettingAccessor<AzureRootCertPathSetting> for TEdgeConfig { } } +impl ConfigSettingAccessor<AzureMapperTimestamp> for TEdgeConfig { + fn query(&self, _setting: AzureMapperTimestamp) -> ConfigSettingResult<Flag> { + Ok(self + .data + .azure + .mapper_timestamp + .map(Flag) + .unwrap_or_else(|| Flag(true))) + } + + fn update(&mut self, _setting: AzureMapperTimestamp, value: Flag) -> ConfigSettingResult<()> { + self.data.azure.mapper_timestamp = Some(value.into()); + Ok(()) + } + + fn unset(&mut self, _setting: AzureMapperTimestamp) -> ConfigSettingResult<()> { + self.data.azure.mapper_timestamp = None; + Ok(()) + } +} + impl ConfigSettingAccessor<C8yRootCertPathSetting> for TEdgeConfig { fn query(&self, _setting: C8yRootCertPathSetting) -> ConfigSettingResult<FilePath> { Ok(self diff --git a/tedge_config/src/tedge_config_dto.rs b/tedge_config/src/tedge_config_dto.rs index 6da6c74c..0d00ffbe 100644 --- a/tedge_config/src/tedge_config_dto.rs +++ b/tedge_config/src/tedge_config_dto.rs @@ -50,6 +50,9 @@ pub(crate) struct CumulocityConfigDto { /// The path where Cumulocity root certificate(s) are stored. /// The value can be a directory path as well as the path of the direct certificate file. pub(crate) root_cert_path: Option<FilePath>, + + /// Boolean whether Azure mapper adds timestamp or not. + pub(crate) mapper_timestamp: Option<bool>, } #[derive(Debug, Default, Deserialize, Serialize)] @@ -58,4 +61,5 @@ pub(crate) struct AzureConfigDto { pub(crate) connect: Option<String>, pub(crate) url: Option<ConnectUrl>, pub(crate) root_cert_path: Option<FilePath>, + pub(crate) mapper_timestamp: Option<bool>, } |