summaryrefslogtreecommitdiffstats
path: root/crates/common/tedge_config/src/tedge_config.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/common/tedge_config/src/tedge_config.rs')
-rw-r--r--crates/common/tedge_config/src/tedge_config.rs455
1 files changed, 455 insertions, 0 deletions
diff --git a/crates/common/tedge_config/src/tedge_config.rs b/crates/common/tedge_config/src/tedge_config.rs
new file mode 100644
index 00000000..b4e88ce9
--- /dev/null
+++ b/crates/common/tedge_config/src/tedge_config.rs
@@ -0,0 +1,455 @@
+use crate::*;
+use certificate::{CertificateError, PemCertificate};
+use std::convert::{TryFrom, TryInto};
+
+/// Represents the complete configuration of a thin edge device.
+/// This configuration is a wrapper over the device specific configurations
+/// as well as the IoT cloud provider specific configurations.
+///
+#[derive(Debug)]
+pub struct TEdgeConfig {
+ pub(crate) data: TEdgeConfigDto,
+ pub(crate) config_location: TEdgeConfigLocation,
+ pub(crate) config_defaults: TEdgeConfigDefaults,
+}
+
+impl ConfigSettingAccessor<DeviceIdSetting> for TEdgeConfig {
+ fn query(&self, _setting: DeviceIdSetting) -> ConfigSettingResult<String> {
+ let cert_path = self.query(DeviceCertPathSetting)?;
+ let pem = PemCertificate::from_pem_file(cert_path)
+ .map_err(|err| cert_error_into_config_error(DeviceIdSetting::KEY, err))?;
+ let device_id = pem
+ .subject_common_name()
+ .map_err(|err| cert_error_into_config_error(DeviceIdSetting::KEY, err))?;
+ Ok(device_id)
+ }
+
+ fn update(&mut self, _setting: DeviceIdSetting, _value: String) -> ConfigSettingResult<()> {
+ Err(device_id_read_only_error())
+ }
+
+ fn unset(&mut self, _setting: DeviceIdSetting) -> ConfigSettingResult<()> {
+ Err(device_id_read_only_error())
+ }
+}
+
+fn device_id_read_only_error() -> ConfigSettingError {
+ ConfigSettingError::ReadonlySetting {
+ message: concat!(
+ "The device id is read from the device certificate and cannot be set directly.\n",
+ "To set 'device.id' to some <id>, you can use `tedge cert create --device-id <id>`.",
+ ),
+ }
+}
+
+fn cert_error_into_config_error(key: &'static str, err: CertificateError) -> ConfigSettingError {
+ match &err {
+ CertificateError::IoError(io_err) => match io_err.kind() {
+ std::io::ErrorKind::NotFound => ConfigSettingError::SettingIsNotConfigurable { key,
+ message: concat!(
+ "The device id is read from the device certificate.\n",
+ "To set 'device.id' to some <id>, you can use `tedge cert create --device-id <id>`.",
+ ),
+ },
+ _ => ConfigSettingError::DerivationFailed {
+ key,
+ cause: format!("{}", err),
+ },
+ },
+ _ => ConfigSettingError::DerivationFailed {
+ key,
+ cause: format!("{}", err),
+ },
+ }
+}
+
+impl ConfigSettingAccessor<AzureUrlSetting> for TEdgeConfig {
+ fn query(&self, _setting: AzureUrlSetting) -> ConfigSettingResult<ConnectUrl> {
+ self.data
+ .az
+ .url
+ .clone()
+ .ok_or(ConfigSettingError::ConfigNotSet {
+ key: AzureUrlSetting::KEY,
+ })
+ }
+
+ fn update(&mut self, _setting: AzureUrlSetting, value: ConnectUrl) -> ConfigSettingResult<()> {
+ self.data.az.url = Some(value);
+ Ok(())
+ }
+
+ fn unset(&mut self, _setting: AzureUrlSetting) -> ConfigSettingResult<()> {
+ self.data.az.url = None;
+ Ok(())
+ }
+}
+
+impl ConfigSettingAccessor<C8yUrlSetting> for TEdgeConfig {
+ fn query(&self, _setting: C8yUrlSetting) -> ConfigSettingResult<ConnectUrl> {
+ self.data
+ .c8y
+ .url
+ .clone()
+ .ok_or(ConfigSettingError::ConfigNotSet {
+ key: C8yUrlSetting::KEY,
+ })
+ }
+
+ fn update(&mut self, _setting: C8yUrlSetting, value: ConnectUrl) -> ConfigSettingResult<()> {
+ self.data.c8y.url = Some(value);
+ Ok(())
+ }
+
+ fn unset(&mut self, _setting: C8yUrlSetting) -> ConfigSettingResult<()> {
+ self.data.c8y.url = None;
+ Ok(())
+ }
+}
+
+impl ConfigSettingAccessor<DeviceCertPathSetting> for TEdgeConfig {
+ fn query(&self, _setting: DeviceCertPathSetting) -> ConfigSettingResult<FilePath> {
+ Ok(self
+ .data
+ .device
+ .cert_path
+ .clone()
+ .unwrap_or_else(|| self.config_defaults.default_device_cert_path.clone()))
+ }
+
+ fn update(
+ &mut self,
+ _setting: DeviceCertPathSetting,
+ value: FilePath,
+ ) -> ConfigSettingResult<()> {
+ self.data.device.cert_path = Some(value);
+ Ok(())
+ }
+
+ fn unset(&mut self, _setting: DeviceCertPathSetting) -> ConfigSettingResult<()> {
+ self.data.device.cert_path = None;
+ Ok(())
+ }
+}
+
+impl ConfigSettingAccessor<DeviceKeyPathSetting> for TEdgeConfig {
+ fn query(&self, _setting: DeviceKeyPathSetting) -> ConfigSettingResult<FilePath> {
+ Ok(self
+ .data
+ .device
+ .key_path
+ .clone()
+ .unwrap_or_else(|| self.config_defaults.default_device_key_path.clone()))
+ }
+
+ fn update(
+ &mut self,
+ _setting: DeviceKeyPathSetting,
+ value: FilePath,
+ ) -> ConfigSettingResult<()> {
+ self.data.device.key_path = Some(value);
+ Ok(())
+ }
+
+ fn unset(&mut self, _setting: DeviceKeyPathSetting) -> ConfigSettingResult<()> {
+ self.data.device.key_path = None;
+ Ok(())
+ }
+}
+
+impl ConfigSettingAccessor<AzureRootCertPathSetting> for TEdgeConfig {
+ fn query(&self, _setting: AzureRootCertPathSetting) -> ConfigSettingResult<FilePath> {
+ Ok(self
+ .data
+ .az
+ .root_cert_path
+ .clone()
+ .unwrap_or_else(|| self.config_defaults.default_azure_root_cert_path.clone()))
+ }
+
+ fn update(
+ &mut self,
+ _setting: AzureRootCertPathSetting,
+ value: FilePath,
+ ) -> ConfigSettingResult<()> {
+ self.data.az.root_cert_path = Some(value);
+ Ok(())
+ }
+
+ fn unset(&mut self, _setting: AzureRootCertPathSetting) -> ConfigSettingResult<()> {
+ self.data.az.root_cert_path = None;
+ Ok(())
+ }
+}
+
+impl ConfigSettingAccessor<AzureMapperTimestamp> for TEdgeConfig {
+ fn query(&self, _setting: AzureMapperTimestamp) -> ConfigSettingResult<Flag> {
+ Ok(self
+ .data
+ .az
+ .mapper_timestamp
+ .map(Flag)
+ .unwrap_or_else(|| self.config_defaults.default_mapper_timestamp.clone()))
+ }
+
+ fn update(&mut self, _setting: AzureMapperTimestamp, value: Flag) -> ConfigSettingResult<()> {
+ self.data.az.mapper_timestamp = Some(value.into());
+ Ok(())
+ }
+
+ fn unset(&mut self, _setting: AzureMapperTimestamp) -> ConfigSettingResult<()> {
+ self.data.az.mapper_timestamp = None;
+ Ok(())
+ }
+}
+
+impl ConfigSettingAccessor<C8yRootCertPathSetting> for TEdgeConfig {
+ fn query(&self, _setting: C8yRootCertPathSetting) -> ConfigSettingResult<FilePath> {
+ Ok(self
+ .data
+ .c8y
+ .root_cert_path
+ .clone()
+ .unwrap_or_else(|| self.config_defaults.default_c8y_root_cert_path.clone()))
+ }
+
+ fn update(
+ &mut self,
+ _setting: C8yRootCertPathSetting,
+ value: FilePath,
+ ) -> ConfigSettingResult<()> {
+ self.data.c8y.root_cert_path = Some(value);
+ Ok(())
+ }
+
+ fn unset(&mut self, _setting: C8yRootCertPathSetting) -> ConfigSettingResult<()> {
+ self.data.c8y.root_cert_path = None;
+ Ok(())
+ }
+}
+
+impl ConfigSettingAccessor<MqttPortSetting> for TEdgeConfig {
+ fn query(&self, _setting: MqttPortSetting) -> ConfigSettingResult<Port> {
+ Ok(self
+ .data
+ .mqtt
+ .port
+ .map(Port)
+ .unwrap_or_else(|| self.config_defaults.default_mqtt_port))
+ }
+
+ fn update(&mut self, _setting: MqttPortSetting, value: Port) -> ConfigSettingResult<()> {
+ self.data.mqtt.port = Some(value.into());
+ Ok(())
+ }
+
+ fn unset(&mut self, _setting: MqttPortSetting) -> ConfigSettingResult<()> {
+ self.data.mqtt.port = None;
+ Ok(())
+ }
+}
+
+impl ConfigSettingAccessor<MqttExternalPortSetting> for TEdgeConfig {
+ fn query(&self, _setting: MqttExternalPortSetting) -> ConfigSettingResult<Port> {
+ self.data
+ .mqtt
+ .external_port
+ .map(Port)
+ .clone()
+ .ok_or(ConfigSettingError::ConfigNotSet {
+ key: MqttExternalPortSetting::KEY,
+ })
+ }
+
+ fn update(
+ &mut self,
+ _setting: MqttExternalPortSetting,
+ value: Port,
+ ) -> ConfigSettingResult<()> {
+ self.data.mqtt.external_port = Some(value.into());
+ Ok(())
+ }
+
+ fn unset(&mut self, _setting: MqttExternalPortSetting) -> ConfigSettingResult<()> {
+ self.data.mqtt.external_port = None;
+ Ok(())
+ }
+}
+
+impl ConfigSettingAccessor<MqttExternalBindAddressSetting> for TEdgeConfig {
+ fn query(&self, _setting: MqttExternalBindAddressSetting) -> ConfigSettingResult<String> {
+ self.data
+ .mqtt
+ .external_bind_address
+ .clone()
+ .ok_or(ConfigSettingError::ConfigNotSet {
+ key: MqttExternalBindAddressSetting::KEY,
+ })
+ }
+
+ fn update(
+ &mut self,
+ _setting: MqttExternalBindAddressSetting,
+ value: String,
+ ) -> ConfigSettingResult<()> {
+ self.data.mqtt.external_bind_address = Some(value);
+ Ok(())
+ }
+
+ fn unset(&mut self, _setting: MqttExternalBindAddressSetting) -> ConfigSettingResult<()> {
+ self.data.mqtt.external_bind_address = None;
+ Ok(())
+ }
+}
+
+impl ConfigSettingAccessor<MqttExternalBindInterfaceSetting> for TEdgeConfig {
+ fn query(&self, _setting: MqttExternalBindInterfaceSetting) -> ConfigSettingResult<String> {
+ self.data
+ .mqtt
+ .external_bind_interface
+ .clone()
+ .ok_or(ConfigSettingError::ConfigNotSet {
+ key: MqttExternalBindInterfaceSetting::KEY,
+ })
+ }
+
+ fn update(
+ &mut self,
+ _setting: MqttExternalBindInterfaceSetting,
+ value: String,
+ ) -> ConfigSettingResult<()> {
+ self.data.mqtt.external_bind_interface = Some(value);
+ Ok(())
+ }
+
+ fn unset(&mut self, _setting: MqttExternalBindInterfaceSetting) -> ConfigSettingResult<()> {
+ self.data.mqtt.external_bind_interface = None;
+ Ok(())
+ }
+}
+
+impl ConfigSettingAccessor<MqttExternalCAPathSetting> for TEdgeConfig {
+ fn query(&self, _setting: MqttExternalCAPathSetting) -> ConfigSettingResult<FilePath> {
+ self.data
+ .mqtt
+ .external_capath
+ .clone()
+ .ok_or(ConfigSettingError::ConfigNotSet {
+ key: MqttExternalCAPathSetting::KEY,
+ })
+ }
+
+ fn update(
+ &mut self,
+ _setting: MqttExternalCAPathSetting,
+ value: FilePath,
+ ) -> ConfigSettingResult<()> {
+ self.data.mqtt.external_capath = Some(value);
+ Ok(())
+ }
+
+ fn unset(&mut self, _setting: MqttExternalCAPathSetting) -> ConfigSettingResult<()> {
+ self.data.mqtt.external_capath = None;
+ Ok(())
+ }
+}
+
+impl ConfigSettingAccessor<MqttExternalCertfileSetting> for TEdgeConfig {
+ fn query(&self, _setting: MqttExternalCertfileSetting) -> ConfigSettingResult<FilePath> {
+ self.data
+ .mqtt
+ .external_certfile
+ .clone()
+ .ok_or(ConfigSettingError::ConfigNotSet {
+ key: MqttExternalCertfileSetting::KEY,
+ })
+ }
+
+ fn update(
+ &mut self,
+ _setting: MqttExternalCertfileSetting,
+ value: FilePath,
+ ) -> ConfigSettingResult<()> {
+ self.data.mqtt.external_certfile = Some(value);
+ Ok(())
+ }
+
+ fn unset(&mut self, _setting: MqttExternalCertfileSetting) -> ConfigSettingResult<()> {
+ self.data.mqtt.external_certfile = None;
+ Ok(())
+ }
+}
+
+impl ConfigSettingAccessor<MqttExternalKeyfileSetting> for TEdgeConfig {
+ fn query(&self, _setting: MqttExternalKeyfileSetting) -> ConfigSettingResult<FilePath> {
+ self.data
+ .mqtt
+ .external_keyfile
+ .clone()
+ .ok_or(ConfigSettingError::ConfigNotSet {
+ key: MqttExternalKeyfileSetting::KEY,
+ })
+ }
+
+ fn update(
+ &mut self,
+ _setting: MqttExternalKeyfileSetting,
+ value: FilePath,
+ ) -> ConfigSettingResult<()> {
+ self.data.mqtt.external_keyfile = Some(value);
+ Ok(())
+ }
+
+ fn unset(&mut self, _setting: MqttExternalKeyfileSetting) -> ConfigSettingResult<()> {
+ self.data.mqtt.external_keyfile = None;
+ Ok(())
+ }
+}
+
+impl ConfigSettingAccessor<SoftwarePluginDefaultSetting> for TEdgeConfig {
+ fn query(&self, _setting: SoftwarePluginDefaultSetting) -> ConfigSettingResult<String> {
+ self.data
+ .software
+ .default_plugin_type
+ .clone()
+ .ok_or(ConfigSettingError::ConfigNotSet {
+ key: SoftwarePluginDefaultSetting::KEY,
+ })
+ }
+
+ fn update(
+ &mut self,
+ _setting: SoftwarePluginDefaultSetting,
+ value: String,
+ ) -> ConfigSettingResult<()> {
+ self.data.software.default_plugin_type = Some(value);
+ Ok(())
+ }
+
+ fn unset(&mut self, _setting: SoftwarePluginDefaultSetting) -> ConfigSettingResult<()> {
+ self.data.software.default_plugin_type = None;
+ Ok(())
+ }
+}
+
+/// Generic extension trait implementation for all `ConfigSetting`s of `TEdgeConfig`
+/// that provide `TryFrom`/`TryInto` implementations for `String`.
+impl<T, E, F> ConfigSettingAccessorStringExt<T> for TEdgeConfig
+where
+ T: ConfigSetting,
+ TEdgeConfig: ConfigSettingAccessor<T>,
+ T::Value: TryFrom<String, Error = E>,
+ T::Value: TryInto<String, Error = F>,
+{
+ fn query_string(&self, setting: T) -> ConfigSettingResult<String> {
+ self.query(setting)?
+ .try_into()
+ .map_err(|_e| ConfigSettingError::ConversionIntoStringFailed)
+ }
+
+ fn update_string(&mut self, setting: T, string_value: String) -> ConfigSettingResult<()> {
+ T::Value::try_from(string_value)
+ .map_err(|_e| ConfigSettingError::ConversionFromStringFailed)
+ .and_then(|value| self.update(setting, value))
+ }
+}