summaryrefslogtreecommitdiffstats
path: root/crates
diff options
context:
space:
mode:
authorinitard <alex.solomes@softwareag.com>2022-01-27 17:51:29 +0100
committerGitHub <noreply@github.com>2022-01-27 17:51:29 +0100
commitcd15f10bb6f893a18e63c54ad41a677a1e5ec1bb (patch)
treee8e2a571417837519ff4270214642a8c9c02aa0a /crates
parent6bbcdff8de2569bfff3e1a8085c21aaf98a5d96f (diff)
#733 Configurable Device Type (#782)
* configurable device type (#733) Signed-off-by: initard <solo@softwareag.com> * adding device data fragment to mapper init (#733) Signed-off-by: initard <solo@softwareag.com> * fixing test Signed-off-by: initard <solo@softwareag.com> * adding device type when making new device (#733) Signed-off-by: initard <solo@softwareag.com> * removing comment and unused package Signed-off-by: initard <solo@softwareag.com> * passing down device type and removing tedge util Signed-off-by: initard <solo@softwareag.com> * string formatting (#733) Signed-off-by: initard <solo@softwareag.com> * documenting device data settings Signed-off-by: initard <solo@softwareag.com> * addressing minor pr comments on syntax (#733) Signed-off-by: initard <solo@softwareag.com> Co-authored-by: initard <solo@softwareag.com>
Diffstat (limited to 'crates')
-rw-r--r--crates/common/tedge_config/Cargo.toml1
-rw-r--r--crates/common/tedge_config/src/error.rs3
-rw-r--r--crates/common/tedge_config/src/settings.rs11
-rw-r--r--crates/common/tedge_config/src/tedge_config.rs26
-rw-r--r--crates/common/tedge_config/src/tedge_config_defaults.rs8
-rw-r--r--crates/common/tedge_config/src/tedge_config_dto.rs3
-rw-r--r--crates/common/tedge_config/tests/test_tedge_config.rs1
-rw-r--r--crates/core/tedge/src/cli/config/config_key.rs1
-rw-r--r--crates/core/tedge/src/cli/connect/c8y_direct_connection.rs17
-rw-r--r--crates/core/tedge/src/cli/connect/command.rs5
-rw-r--r--crates/core/tedge_mapper/src/c8y_converter.rs40
-rw-r--r--crates/core/tedge_mapper/src/c8y_fragments.rs27
-rw-r--r--crates/core/tedge_mapper/src/c8y_mapper.rs9
13 files changed, 136 insertions, 16 deletions
diff --git a/crates/common/tedge_config/Cargo.toml b/crates/common/tedge_config/Cargo.toml
index dc82f240..bce75bd9 100644
--- a/crates/common/tedge_config/Cargo.toml
+++ b/crates/common/tedge_config/Cargo.toml
@@ -9,6 +9,7 @@ rust-version = "1.58"
certificate = { path = "../certificate" }
serde = { version = "1.0", features = ["derive"] }
tedge_utils = { path = "../tedge_utils" }
+tedge_users = { path = "../tedge_users" }
tempfile = "3.2"
thiserror = "1.0"
toml = "0.5"
diff --git a/crates/common/tedge_config/src/error.rs b/crates/common/tedge_config/src/error.rs
index f1e23642..09cc9383 100644
--- a/crates/common/tedge_config/src/error.rs
+++ b/crates/common/tedge_config/src/error.rs
@@ -17,4 +17,7 @@ pub enum TEdgeConfigError {
#[error("Config file not found: {0}")]
ConfigFileNotFound(std::path::PathBuf),
+
+ #[error("Home directory is not found.")]
+ HomeDirNotFound,
}
diff --git a/crates/common/tedge_config/src/settings.rs b/crates/common/tedge_config/src/settings.rs
index 6f043fb5..d7b8c0d7 100644
--- a/crates/common/tedge_config/src/settings.rs
+++ b/crates/common/tedge_config/src/settings.rs
@@ -23,6 +23,17 @@ impl ConfigSetting for DeviceIdSetting {
type Value = String;
}
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub struct DeviceTypeSetting;
+
+impl ConfigSetting for DeviceTypeSetting {
+ const KEY: &'static str = "device.type";
+
+ const DESCRIPTION: &'static str = "The default device type. Example: thin-edge.io";
+
+ type Value = String;
+}
+
///
/// Path to the private key file. Example: /home/user/.tedge/tedge-private-key.pem
///
diff --git a/crates/common/tedge_config/src/tedge_config.rs b/crates/common/tedge_config/src/tedge_config.rs
index 1385a010..52e0178e 100644
--- a/crates/common/tedge_config/src/tedge_config.rs
+++ b/crates/common/tedge_config/src/tedge_config.rs
@@ -33,6 +33,32 @@ impl ConfigSettingAccessor<DeviceIdSetting> for TEdgeConfig {
}
}
+impl ConfigSettingAccessor<DeviceTypeSetting> for TEdgeConfig {
+ fn query(&self, _setting: DeviceTypeSetting) -> ConfigSettingResult<String> {
+ let device_type = self
+ .data
+ .device
+ .device_type
+ .clone()
+ .unwrap_or_else(|| self.config_defaults.default_device_type.clone());
+ Ok(device_type)
+ }
+
+ fn update(
+ &mut self,
+ _setting: DeviceTypeSetting,
+ value: <DeviceTypeSetting as ConfigSetting>::Value,
+ ) -> ConfigSettingResult<()> {
+ self.data.device.device_type = Some(value);
+ Ok(())
+ }
+
+ fn unset(&mut self, _setting: DeviceTypeSetting) -> ConfigSettingResult<()> {
+ self.data.device.device_type = None;
+ Ok(())
+ }
+}
+
fn device_id_read_only_error() -> ConfigSettingError {
ConfigSettingError::ReadonlySetting {
message: concat!(
diff --git a/crates/common/tedge_config/src/tedge_config_defaults.rs b/crates/common/tedge_config/src/tedge_config_defaults.rs
index 99eac131..3c7cea92 100644
--- a/crates/common/tedge_config/src/tedge_config_defaults.rs
+++ b/crates/common/tedge_config/src/tedge_config_defaults.rs
@@ -6,6 +6,7 @@ use std::path::Path;
const DEFAULT_ETC_PATH: &str = "/etc";
const DEFAULT_PORT: u16 = 1883;
const DEFAULT_TMP_PATH: &str = "/tmp";
+const DEFAULT_DEVICE_TYPE: &str = "thin-edge.io";
/// Stores default values for use by `TEdgeConfig` in case no configuration setting
/// is available.
@@ -41,6 +42,9 @@ pub struct TEdgeConfigDefaults {
/// Default tmp path
pub default_tmp_path: FilePath,
+
+ /// Default device type
+ pub default_device_type: String,
}
impl From<&TEdgeConfigLocation> for TEdgeConfigDefaults {
@@ -63,6 +67,7 @@ impl From<&TEdgeConfigLocation> for TEdgeConfigDefaults {
default_mapper_timestamp: Flag(true),
default_mqtt_port: Port(DEFAULT_PORT),
default_tmp_path: tmp_path.into(),
+ default_device_type: DEFAULT_DEVICE_TYPE.into(),
}
}
}
@@ -85,7 +90,8 @@ fn test_from_tedge_config_location() {
default_c8y_root_cert_path: FilePath::from("/etc/ssl/certs"),
default_mapper_timestamp: Flag(true),
default_mqtt_port: Port(DEFAULT_PORT),
- default_tmp_path: FilePath::from("/tmp")
+ default_tmp_path: FilePath::from("/tmp"),
+ default_device_type: DEFAULT_DEVICE_TYPE.into(),
}
);
}
diff --git a/crates/common/tedge_config/src/tedge_config_dto.rs b/crates/common/tedge_config/src/tedge_config_dto.rs
index 8b9cc47c..ae9cd15f 100644
--- a/crates/common/tedge_config/src/tedge_config_dto.rs
+++ b/crates/common/tedge_config/src/tedge_config_dto.rs
@@ -44,6 +44,9 @@ pub(crate) struct DeviceConfigDto {
/// Path where the device's certificate is stored.
/// Defaults to $HOME/.tedge/tedge-certificate.crt
pub(crate) cert_path: Option<FilePath>,
+
+ #[serde(rename = "type")]
+ pub(crate) device_type: Option<String>,
}
/// Represents the Cumulocity specific configurations defined in the
diff --git a/crates/common/tedge_config/tests/test_tedge_config.rs b/crates/common/tedge_config/tests/test_tedge_config.rs
index c77aab7e..26118adf 100644
--- a/crates/common/tedge_config/tests/test_tedge_config.rs
+++ b/crates/common/tedge_config/tests/test_tedge_config.rs
@@ -857,6 +857,7 @@ fn dummy_tedge_config_defaults() -> TEdgeConfigDefaults {
default_mapper_timestamp: Flag(true),
default_mqtt_port: Port(1883),
default_tmp_path: FilePath::from("/tmp"),
+ default_device_type: String::from("test"),
}
}
diff --git a/crates/core/tedge/src/cli/config/config_key.rs b/crates/core/tedge/src/cli/config/config_key.rs
index f2c35c12..1b0fcef3 100644
--- a/crates/core/tedge/src/cli/config/config_key.rs
+++ b/crates/core/tedge/src/cli/config/config_key.rs
@@ -40,6 +40,7 @@ impl ConfigKey {
pub fn list_all() -> Vec<ConfigKey> {
vec![
config_key!(DeviceIdSetting),
+ config_key!(DeviceTypeSetting),
config_key!(DeviceKeyPathSetting),
config_key!(DeviceCertPathSetting),
config_key!(C8yUrlSetting),
diff --git a/crates/core/tedge/src/cli/connect/c8y_direct_connection.rs b/crates/core/tedge/src/cli/connect/c8y_direct_connection.rs
index a9c45b31..049429b2 100644
--- a/crates/core/tedge/src/cli/connect/c8y_direct_connection.rs
+++ b/crates/core/tedge/src/cli/connect/c8y_direct_connection.rs
@@ -18,6 +18,7 @@ use tedge_users::UserManager;
pub fn create_device_with_direct_connection(
user_manager: UserManager,
bridge_config: &BridgeConfig,
+ device_type: &str,
) -> Result<(), ConnectError> {
const DEVICE_ALREADY_EXISTS: &[u8] = b"41,100,Device already existing";
const DEVICE_CREATE_ERROR_TOPIC: &str = "s/e";
@@ -49,7 +50,11 @@ pub fn create_device_with_direct_connection(
for event in connection.iter() {
match event {
Ok(Event::Incoming(Packet::SubAck(_))) => {
- publish_device_create_message(&mut client, &bridge_config.remote_clientid.clone())?;
+ publish_device_create_message(
+ &mut client,
+ &bridge_config.remote_clientid.clone(),
+ &device_type,
+ )?;
}
Ok(Event::Incoming(Packet::Publish(response))) => {
// We got a response
@@ -64,6 +69,7 @@ pub fn create_device_with_direct_connection(
publish_device_create_message(
&mut client,
&bridge_config.remote_clientid.clone(),
+ &device_type,
)?;
device_create_try += 1;
} else {
@@ -88,14 +94,17 @@ pub fn create_device_with_direct_connection(
Err(ConnectError::TimeoutElapsedError)
}
-fn publish_device_create_message(client: &mut Client, device_id: &str) -> Result<(), ConnectError> {
+fn publish_device_create_message(
+ client: &mut Client,
+ device_id: &str,
+ device_type: &str,
+) -> Result<(), ConnectError> {
const DEVICE_CREATE_PUBLISH_TOPIC: &str = "s/us";
- const DEVICE_TYPE: &str = "thin-edge.io";
client.publish(
DEVICE_CREATE_PUBLISH_TOPIC,
QoS::ExactlyOnce,
false,
- format!("100,{},{}", device_id, DEVICE_TYPE).as_bytes(),
+ format!("100,{},{}", device_id, device_type).as_bytes(),
)?;
Ok(())
}
diff --git a/crates/core/tedge/src/cli/connect/command.rs b/crates/core/tedge/src/cli/connect/command.rs
index 004d1891..18052a03 100644
--- a/crates/core/tedge/src/cli/connect/command.rs
+++ b/crates/core/tedge/src/cli/connect/command.rs
@@ -118,12 +118,15 @@ impl Command for ConnectCommand {
);
self.config_repository.store(&config)?;
+ let device_type = config.query(DeviceTypeSetting)?;
+
new_bridge(
&bridge_config,
&updated_mosquitto_config,
self.service_manager.as_ref(),
self.user_manager.clone(),
&self.config_location,
+ &device_type,
)?;
match self.check_connection(&config) {
@@ -373,6 +376,7 @@ fn new_bridge(
service_manager: &dyn SystemServiceManager,
user_manager: UserManager,
config_location: &TEdgeConfigLocation,
+ device_type: &str,
) -> Result<(), ConnectError> {
println!("Checking if {} is available.\n", service_manager.name());
let service_manager_result = service_manager.check_operational();
@@ -397,6 +401,7 @@ fn new_bridge(
let () = c8y_direct_connection::create_device_with_direct_connection(
user_manager,
bridge_config,
+ &device_type,
)?;
}
diff --git a/crates/core/tedge_mapper/src/c8y_converter.rs b/crates/core/tedge_mapper/src/c8y_converter.rs
index 81c8e7c0..40c47f5f 100644
--- a/crates/core/tedge_mapper/src/c8y_converter.rs
+++ b/crates/core/tedge_mapper/src/c8y_converter.rs
@@ -1,4 +1,4 @@
-use crate::c8y_fragments::C8yAgentFragment;
+use crate::c8y_fragments::{C8yAgentFragment, C8yDeviceDataFragment};
use crate::error::*;
use crate::size_threshold::SizeThreshold;
use crate::{converter::*, operations::Operations};
@@ -24,10 +24,11 @@ pub struct CumulocityConverter {
children: HashSet<String>,
pub(crate) mapper_config: MapperConfig,
device_name: String,
+ device_type: String,
}
impl CumulocityConverter {
- pub fn new(size_threshold: SizeThreshold, device_name: String) -> Self {
+ pub fn new(size_threshold: SizeThreshold, device_name: String, device_type: String) -> Self {
let mut topic_fiter = make_valid_topic_filter_or_panic("tedge/measurements");
let () = topic_fiter
.add("tedge/measurements/+")
@@ -49,6 +50,7 @@ impl CumulocityConverter {
children,
mapper_config,
device_name,
+ device_type,
}
}
@@ -124,13 +126,28 @@ impl Converter for CumulocityConverter {
let supported_operations_message = create_supported_operations_fragments()?;
+ let device_data_message =
+ create_device_data_fragments(&self.device_name, &self.device_type)?;
+
Ok(vec![
supported_operations_message,
+ device_data_message,
inventory_fragments_message,
])
}
}
+fn create_device_data_fragments(
+ device_name: &str,
+ device_type: &str,
+) -> Result<Message, ConversionError> {
+ let device_data = C8yDeviceDataFragment::from_type(device_type)?;
+ let ops_msg = device_data.to_json()?;
+
+ let topic = Topic::new_unchecked(&format!("{INVENTORY_MANAGED_OBJECTS_TOPIC}/{device_name}",));
+ Ok(Message::new(&topic, ops_msg.to_string()))
+}
+
fn create_supported_operations_fragments() -> Result<Message, ConversionError> {
let ops = Operations::try_new(SUPPORTED_OPERATIONS_DIRECTORY, C8Y_CLOUD)?;
let ops = ops.get_operations_list();
@@ -144,10 +161,7 @@ fn create_supported_operations_fragments() -> Result<Message, ConversionError> {
fn create_inventory_fragments_message(device_name: &str) -> Result<Message, ConversionError> {
let ops_msg = get_inventory_fragments(INVENTORY_FRAGMENTS_FILE_LOCATION)?;
- let topic = Topic::new_unchecked(&format!(
- "{}/{}",
- INVENTORY_MANAGED_OBJECTS_TOPIC, device_name
- ));
+ let topic = Topic::new_unchecked(&format!("{INVENTORY_MANAGED_OBJECTS_TOPIC}/{device_name}",));
Ok(Message::new(&topic, ops_msg.to_string()))
}
@@ -227,10 +241,12 @@ mod test {
#[test]
fn convert_thin_edge_json_with_child_id() {
let device_name = String::from("test");
+ let device_type = String::from("test_type");
let mut converter = Box::new(CumulocityConverter::new(
SizeThreshold(16 * 1024),
device_name,
+ device_type,
));
let in_topic = "tedge/measurements/child1";
let in_payload = r#"{"temp": 1, "time": "2021-11-16T17:45:40.571760714+01:00"}"#;
@@ -263,10 +279,12 @@ mod test {
#[test]
fn convert_first_thin_edge_json_invalid_then_valid_with_child_id() {
let device_name = String::from("test");
+ let device_type = String::from("test_type");
let mut converter = Box::new(CumulocityConverter::new(
SizeThreshold(16 * 1024),
device_name,
+ device_type,
));
let in_topic = "tedge/measurements/child1";
let in_invalid_payload = r#"{"temp": invalid}"#;
@@ -304,10 +322,12 @@ mod test {
#[test]
fn convert_two_thin_edge_json_messages_given_different_child_id() {
let device_name = String::from("test");
+ let device_type = String::from("test_type");
let mut converter = Box::new(CumulocityConverter::new(
SizeThreshold(16 * 1024),
device_name,
+ device_type,
));
let in_payload = r#"{"temp": 1, "time": "2021-11-16T17:45:40.571760714+01:00"}"#;
@@ -358,10 +378,14 @@ mod test {
#[test]
fn check_c8y_threshold_packet_size() -> Result<(), anyhow::Error> {
- let size_threshold = SizeThreshold(16 * 1024);
let device_name = String::from("test");
+ let device_type = String::from("test_type");
- let converter = CumulocityConverter::new(size_threshold, device_name);
+ let converter = Box::new(CumulocityConverter::new(
+ SizeThreshold(16 * 1024),
+ device_name,
+ device_type,
+ ));
let buffer = create_packet(1024 * 20);
let err = converter.size_threshold.validate(&buffer).unwrap_err();
assert_eq!(
diff --git a/crates/core/tedge_mapper/src/c8y_fragments.rs b/crates/core/tedge_mapper/src/c8y_fragments.rs
index 3584ad8a..6536f648 100644
--- a/crates/core/tedge_mapper/src/c8y_fragments.rs
+++ b/crates/core/tedge_mapper/src/c8y_fragments.rs
@@ -4,10 +4,14 @@ use std::process::Command;
use crate::error::ConversionError;
use tracing::warn;
+const DEFAULT_AGENT_FRAGMENT_NAME: &str = "thin-edge.io";
+const DEFAULT_AGENT_FRAGMENT_URL: &str = "https://thin-edge.io";
+
#[derive(Debug, Serialize)]
pub struct C8yAgent {
name: String,
version: String,
+ url: String,
}
#[derive(Debug, Serialize)]
@@ -19,8 +23,9 @@ pub struct C8yAgentFragment {
impl C8yAgentFragment {
pub fn new() -> Result<Self, ConversionError> {
let c8y_agent = C8yAgent {
- name: "thin-edge.io".to_string(),
+ name: DEFAULT_AGENT_FRAGMENT_NAME.into(),
version: get_tedge_version()?,
+ url: DEFAULT_AGENT_FRAGMENT_URL.into(),
};
Ok(Self { c8y_agent })
}
@@ -50,3 +55,23 @@ pub fn get_tedge_version() -> Result<String, ConversionError> {
}
}
}
+
+#[derive(Debug, Serialize)]
+pub struct C8yDeviceDataFragment {
+ #[serde(rename = "type")]
+ device_type: String,
+}
+
+impl C8yDeviceDataFragment {
+ pub fn from_type(device_type: &str) -> Result<Self, ConversionError> {
+ Ok(Self {
+ device_type: device_type.into(),
+ })
+ }
+
+ pub fn to_json(&self) -> Result<serde_json::Value, ConversionError> {
+ let json_string = serde_json::to_string(&self)?;
+ let jsond: serde_json::Value = serde_json::from_str(&json_string)?;
+ Ok(jsond)
+ }
+}
diff --git a/crates/core/tedge_mapper/src/c8y_mapper.rs b/crates/core/tedge_mapper/src/c8y_mapper.rs
index aa5c553e..cf38dee9 100644
--- a/crates/core/tedge_mapper/src/c8y_mapper.rs
+++ b/crates/core/tedge_mapper/src/c8y_mapper.rs
@@ -3,7 +3,7 @@ use crate::component::TEdgeComponent;
use crate::mapper::*;
use crate::size_threshold::SizeThreshold;
use async_trait::async_trait;
-use tedge_config::{ConfigSettingAccessor, DeviceIdSetting, TEdgeConfig};
+use tedge_config::{ConfigSettingAccessor, DeviceIdSetting, DeviceTypeSetting, TEdgeConfig};
use tracing::{info_span, Instrument};
const CUMULOCITY_MAPPER_NAME: &str = "tedge-mapper-c8y";
@@ -22,8 +22,13 @@ impl TEdgeComponent for CumulocityMapper {
let size_threshold = SizeThreshold(16 * 1024);
let device_name = tedge_config.query(DeviceIdSetting)?;
+ let device_type = tedge_config.query(DeviceTypeSetting)?;
- let converter = Box::new(CumulocityConverter::new(size_threshold, device_name));
+ let converter = Box::new(CumulocityConverter::new(
+ size_threshold,
+ device_name,
+ device_type,
+ ));
let mut mapper = create_mapper(CUMULOCITY_MAPPER_NAME, &tedge_config, converter).await?;