diff options
Diffstat (limited to 'crates/common/tedge_config/src/tedge_config.rs')
-rw-r--r-- | crates/common/tedge_config/src/tedge_config.rs | 455 |
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)) + } +} |