From c235cd742290b9de24244e8bb9bffff37730e499 Mon Sep 17 00:00:00 2001 From: Reuben Miller Date: Tue, 13 Feb 2024 16:24:06 +0100 Subject: [PATCH 01/10] remove c8y-log-plugin Signed-off-by: Reuben Miller --- Cargo.lock | 45 -- Cargo.toml | 2 - .../init/systemd/c8y-log-plugin.service | 13 - .../nfpm.c8y-log-plugin.yaml | 74 --- configuration/package_scripts/README.md | 3 - .../_generated/c8y-log-plugin/apk/postinst | 3 - .../_generated/c8y-log-plugin/apk/postrm | 3 - .../_generated/c8y-log-plugin/apk/preinst | 2 - .../_generated/c8y-log-plugin/apk/prerm | 2 - .../_generated/c8y-log-plugin/deb/postinst | 32 -- .../_generated/c8y-log-plugin/deb/postrm | 21 - .../_generated/c8y-log-plugin/deb/preinst | 2 - .../_generated/c8y-log-plugin/deb/prerm | 7 - .../_generated/c8y-log-plugin/rpm/postinst | 19 - .../_generated/c8y-log-plugin/rpm/postrm | 14 - .../_generated/c8y-log-plugin/rpm/preinst | 2 - .../_generated/c8y-log-plugin/rpm/prerm | 8 - configuration/package_scripts/packages.json | 5 - .../src/system_services/managers/config.rs | 3 - crates/extensions/c8y_log_manager/Cargo.toml | 35 -- .../extensions/c8y_log_manager/src/actor.rs | 478 ------------------ .../extensions/c8y_log_manager/src/config.rs | 61 --- crates/extensions/c8y_log_manager/src/lib.rs | 129 ----- plugins/c8y_log_plugin/Cargo.toml | 30 -- plugins/c8y_log_plugin/build.rs | 10 - plugins/c8y_log_plugin/src/main.rs | 166 ------ 26 files changed, 1169 deletions(-) delete mode 100644 configuration/init/systemd/c8y-log-plugin.service delete mode 100644 configuration/package_manifests/nfpm.c8y-log-plugin.yaml delete mode 100644 configuration/package_scripts/_generated/c8y-log-plugin/apk/postinst delete mode 100644 configuration/package_scripts/_generated/c8y-log-plugin/apk/postrm delete mode 100644 configuration/package_scripts/_generated/c8y-log-plugin/apk/preinst delete mode 100644 configuration/package_scripts/_generated/c8y-log-plugin/apk/prerm delete mode 100755 configuration/package_scripts/_generated/c8y-log-plugin/deb/postinst delete mode 100755 configuration/package_scripts/_generated/c8y-log-plugin/deb/postrm delete mode 100644 configuration/package_scripts/_generated/c8y-log-plugin/deb/preinst delete mode 100755 configuration/package_scripts/_generated/c8y-log-plugin/deb/prerm delete mode 100644 configuration/package_scripts/_generated/c8y-log-plugin/rpm/postinst delete mode 100644 configuration/package_scripts/_generated/c8y-log-plugin/rpm/postrm delete mode 100644 configuration/package_scripts/_generated/c8y-log-plugin/rpm/preinst delete mode 100644 configuration/package_scripts/_generated/c8y-log-plugin/rpm/prerm delete mode 100644 crates/extensions/c8y_log_manager/Cargo.toml delete mode 100644 crates/extensions/c8y_log_manager/src/actor.rs delete mode 100644 crates/extensions/c8y_log_manager/src/config.rs delete mode 100644 crates/extensions/c8y_log_manager/src/lib.rs delete mode 100644 plugins/c8y_log_plugin/Cargo.toml delete mode 100644 plugins/c8y_log_plugin/build.rs delete mode 100644 plugins/c8y_log_plugin/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 8186d0489f5..f69dfd09388 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -601,27 +601,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "c8y-log-plugin" -version = "1.0.0" -dependencies = [ - "anyhow", - "c8y_http_proxy", - "c8y_log_manager", - "clap", - "tedge_actors", - "tedge_api", - "tedge_config", - "tedge_file_system_ext", - "tedge_health_ext", - "tedge_http_ext", - "tedge_mqtt_ext", - "tedge_signal_ext", - "tedge_utils", - "tokio", - "tracing", -] - [[package]] name = "c8y-remote-access-plugin" version = "1.0.0" @@ -780,30 +759,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "c8y_log_manager" -version = "1.0.0" -dependencies = [ - "anyhow", - "async-trait", - "c8y_api", - "c8y_http_proxy", - "filetime", - "log", - "log_manager", - "serde", - "tedge_actors", - "tedge_api", - "tedge_config", - "tedge_file_system_ext", - "tedge_mqtt_ext", - "tedge_test_utils", - "tedge_utils", - "thiserror", - "time", - "tokio", -] - [[package]] name = "c8y_mapper_ext" version = "1.0.0" diff --git a/Cargo.toml b/Cargo.toml index d30871eb85c..b6e9d69fb86 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,6 @@ members = [ "crates/tests/*", "plugins/c8y_configuration_plugin", "plugins/c8y_firmware_plugin", - "plugins/c8y_log_plugin", "plugins/c8y_remote_access_plugin", "plugins/tedge_apt_plugin", "plugins/tedge_configuration_plugin", @@ -53,7 +52,6 @@ c8y_auth_proxy = { path = "crates/extensions/c8y_auth_proxy" } c8y_config_manager = { path = "crates/extensions/c8y_config_manager" } c8y_firmware_manager = { path = "crates/extensions/c8y_firmware_manager" } c8y_http_proxy = { path = "crates/extensions/c8y_http_proxy" } -c8y_log_manager = { path = "crates/extensions/c8y_log_manager" } c8y_mapper_ext = { path = "crates/extensions/c8y_mapper_ext" } camino = "1.1" cap = "0.1" diff --git a/configuration/init/systemd/c8y-log-plugin.service b/configuration/init/systemd/c8y-log-plugin.service deleted file mode 100644 index 5c084520b28..00000000000 --- a/configuration/init/systemd/c8y-log-plugin.service +++ /dev/null @@ -1,13 +0,0 @@ -[Unit] -Description=Thin-edge logfile retriever for Cumulocity -After=syslog.target network.target mosquitto.service - -[Service] -User=root -ExecStart=/usr/bin/c8y-log-plugin -Restart=on-failure -RestartPreventExitStatus=255 -RestartSec=5 - -[Install] -WantedBy=multi-user.target diff --git a/configuration/package_manifests/nfpm.c8y-log-plugin.yaml b/configuration/package_manifests/nfpm.c8y-log-plugin.yaml deleted file mode 100644 index 107ca7d6651..00000000000 --- a/configuration/package_manifests/nfpm.c8y-log-plugin.yaml +++ /dev/null @@ -1,74 +0,0 @@ -# yaml-language-server: $schema=https://nfpm.goreleaser.com/static/schema.json ---- -name: c8y-log-plugin -description: | - thin-edge.io device log file retriever for Cumulocity -arch: "${PKG_ARCH}" -platform: "linux" -version: "${GIT_SEMVER}" -release: "${RELEASE}" -section: misc -priority: "optional" -maintainer: "thin-edge.io team " -vendor: "thin-edge.io" -homepage: "https://thin-edge.io" -license: "Apache-2.0" - -replaces: - - c8y_log_plugin -conflicts: - - c8y_log_plugin (<= 0.8.1) - -deb: - fields: - Vcs-Browser: ${CI_PROJECT_URL} - Vcs-Git: ${CI_PROJECT_URL} - compression: xz - breaks: - - c8y_log_plugin (<= 0.8.1) - -contents: - # binary - - src: .build/c8y-log-plugin - dst: /usr/bin/ - - # service definitions - - src: ./configuration/init/systemd/c8y-log-plugin.service - dst: /lib/systemd/system/ - file_info: - mode: 0644 - packager: deb - - - src: ./configuration/init/systemd/c8y-log-plugin.service - dst: /lib/systemd/system/ - file_info: - mode: 0644 - packager: rpm - - # Symlink for backwards compatibility - # Deprecate: Remove symlink in 1.x release - - src: /usr/bin/c8y-log-plugin - dst: /usr/bin/c8y_log_plugin - type: symlink - -overrides: - apk: - scripts: - preinstall: configuration/package_scripts/_generated/c8y-log-plugin/apk/preinst - postinstall: configuration/package_scripts/_generated/c8y-log-plugin/apk/postinst - preremove: configuration/package_scripts/_generated/c8y-log-plugin/apk/prerm - postremove: configuration/package_scripts/_generated/c8y-log-plugin/apk/postrm - - rpm: - scripts: - preinstall: configuration/package_scripts/_generated/c8y-log-plugin/rpm/preinst - postinstall: configuration/package_scripts/_generated/c8y-log-plugin/rpm/postinst - preremove: configuration/package_scripts/_generated/c8y-log-plugin/rpm/prerm - postremove: configuration/package_scripts/_generated/c8y-log-plugin/rpm/postrm - - deb: - scripts: - preinstall: configuration/package_scripts/_generated/c8y-log-plugin/deb/preinst - postinstall: configuration/package_scripts/_generated/c8y-log-plugin/deb/postinst - preremove: configuration/package_scripts/_generated/c8y-log-plugin/deb/prerm - postremove: configuration/package_scripts/_generated/c8y-log-plugin/deb/postrm diff --git a/configuration/package_scripts/README.md b/configuration/package_scripts/README.md index 092c6e4f4d5..fbdd4c9c646 100644 --- a/configuration/package_scripts/README.md +++ b/configuration/package_scripts/README.md @@ -109,9 +109,6 @@ Below shows the general workflow to editing an existing maintainer script for th -rw-r--r--@ 1 developer staff 2506444 Aug 8 11:47 c8y-firmware-plugin-0.11.1~340+g1441e71d.aarch64.rpm -rw-r--r--@ 1 developer staff 2490272 Aug 8 11:47 c8y-firmware-plugin_0.11.1~340+g1441e71d_aarch64.apk -rw-r--r--@ 1 developer staff 2018558 Aug 8 11:47 c8y-firmware-plugin_0.11.1~340+g1441e71d_arm64.deb - -rw-r--r--@ 1 developer staff 2794275 Aug 8 11:47 c8y-log-plugin-0.11.1~340+g1441e71d.aarch64.rpm - -rw-r--r--@ 1 developer staff 2789684 Aug 8 11:47 c8y-log-plugin_0.11.1~340+g1441e71d_aarch64.apk - -rw-r--r--@ 1 developer staff 2223752 Aug 8 11:47 c8y-log-plugin_0.11.1~340+g1441e71d_arm64.deb -rw-r--r--@ 1 developer staff 1735095 Aug 8 11:47 c8y-remote-access-plugin-0.11.1~340+g1441e71d.aarch64.rpm -rw-r--r--@ 1 developer staff 1737980 Aug 8 11:47 c8y-remote-access-plugin_0.11.1~340+g1441e71d_aarch64.apk -rw-r--r--@ 1 developer staff 1413456 Aug 8 11:47 c8y-remote-access-plugin_0.11.1~340+g1441e71d_arm64.deb diff --git a/configuration/package_scripts/_generated/c8y-log-plugin/apk/postinst b/configuration/package_scripts/_generated/c8y-log-plugin/apk/postinst deleted file mode 100644 index aa2813997b3..00000000000 --- a/configuration/package_scripts/_generated/c8y-log-plugin/apk/postinst +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -set -e - diff --git a/configuration/package_scripts/_generated/c8y-log-plugin/apk/postrm b/configuration/package_scripts/_generated/c8y-log-plugin/apk/postrm deleted file mode 100644 index aa2813997b3..00000000000 --- a/configuration/package_scripts/_generated/c8y-log-plugin/apk/postrm +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -set -e - diff --git a/configuration/package_scripts/_generated/c8y-log-plugin/apk/preinst b/configuration/package_scripts/_generated/c8y-log-plugin/apk/preinst deleted file mode 100644 index d37118bbe57..00000000000 --- a/configuration/package_scripts/_generated/c8y-log-plugin/apk/preinst +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -set -e diff --git a/configuration/package_scripts/_generated/c8y-log-plugin/apk/prerm b/configuration/package_scripts/_generated/c8y-log-plugin/apk/prerm deleted file mode 100644 index d37118bbe57..00000000000 --- a/configuration/package_scripts/_generated/c8y-log-plugin/apk/prerm +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -set -e diff --git a/configuration/package_scripts/_generated/c8y-log-plugin/deb/postinst b/configuration/package_scripts/_generated/c8y-log-plugin/deb/postinst deleted file mode 100755 index 672a8a88efa..00000000000 --- a/configuration/package_scripts/_generated/c8y-log-plugin/deb/postinst +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/sh -set -e -# Automatically added by thin-edge.io -if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ] || [ "$1" = "abort-deconfigure" ] || [ "$1" = "abort-remove" ] ; then - # This will only remove masks created by d-s-h on package removal. - deb-systemd-helper unmask c8y-log-plugin.service >/dev/null || true - - # was-enabled defaults to true, so new installations run enable. - if deb-systemd-helper --quiet was-enabled c8y-log-plugin.service; then - # Enables the unit on first installation, creates new - # symlinks on upgrades if the unit file has changed. - deb-systemd-helper enable c8y-log-plugin.service >/dev/null || true - else - # Update the statefile to add new symlinks (if any), which need to be - # cleaned up on purge. Also remove old symlinks. - deb-systemd-helper update-state c8y-log-plugin.service >/dev/null || true - fi -fi -# End automatically added section -# Automatically added by thin-edge.io -if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ] || [ "$1" = "abort-deconfigure" ] || [ "$1" = "abort-remove" ] ; then - if [ -d /run/systemd/system ]; then - systemctl --system daemon-reload >/dev/null || true - if [ -n "$2" ]; then - _dh_action=restart - else - _dh_action=start - fi - deb-systemd-invoke $_dh_action c8y-log-plugin.service >/dev/null || true - fi -fi -# End automatically added section \ No newline at end of file diff --git a/configuration/package_scripts/_generated/c8y-log-plugin/deb/postrm b/configuration/package_scripts/_generated/c8y-log-plugin/deb/postrm deleted file mode 100755 index 6076087b9da..00000000000 --- a/configuration/package_scripts/_generated/c8y-log-plugin/deb/postrm +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/sh -set -e -# Automatically added by thin-edge.io -if [ -d /run/systemd/system ]; then - systemctl --system daemon-reload >/dev/null || true -fi -# End automatically added section -# Automatically added by thin-edge.io -if [ "$1" = "remove" ]; then - if [ -x "/usr/bin/deb-systemd-helper" ]; then - deb-systemd-helper mask c8y-log-plugin.service >/dev/null || true - fi -fi - -if [ "$1" = "purge" ]; then - if [ -x "/usr/bin/deb-systemd-helper" ]; then - deb-systemd-helper purge c8y-log-plugin.service >/dev/null || true - deb-systemd-helper unmask c8y-log-plugin.service >/dev/null || true - fi -fi -# End automatically added section \ No newline at end of file diff --git a/configuration/package_scripts/_generated/c8y-log-plugin/deb/preinst b/configuration/package_scripts/_generated/c8y-log-plugin/deb/preinst deleted file mode 100644 index d37118bbe57..00000000000 --- a/configuration/package_scripts/_generated/c8y-log-plugin/deb/preinst +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -set -e diff --git a/configuration/package_scripts/_generated/c8y-log-plugin/deb/prerm b/configuration/package_scripts/_generated/c8y-log-plugin/deb/prerm deleted file mode 100755 index ea6a2cb8030..00000000000 --- a/configuration/package_scripts/_generated/c8y-log-plugin/deb/prerm +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh -set -e -# Automatically added by thin-edge.io -if [ -d /run/systemd/system ] && [ "$1" = remove ]; then - deb-systemd-invoke stop c8y-log-plugin.service >/dev/null || true -fi -# End automatically added section \ No newline at end of file diff --git a/configuration/package_scripts/_generated/c8y-log-plugin/rpm/postinst b/configuration/package_scripts/_generated/c8y-log-plugin/rpm/postinst deleted file mode 100644 index dcf586b471e..00000000000 --- a/configuration/package_scripts/_generated/c8y-log-plugin/rpm/postinst +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh -set -e -# Automatically added by thin-edge.io -if [ $1 -eq 1 ] && [ -x "/usr/lib/systemd/systemd-update-helper" ]; then - # Initial installation - /usr/lib/systemd/systemd-update-helper install-system-units c8y-log-plugin.service || : -fi -# End automatically added section -# Automatically added by thin-edge.io -if [ -d /run/systemd/system ]; then - systemctl --system daemon-reload >/dev/null || true - if [ $1 -eq 2 ]; then - _dh_action=restart - else - _dh_action=start - fi - systemctl $_dh_action c8y-log-plugin.service >/dev/null || true -fi -# End automatically added section \ No newline at end of file diff --git a/configuration/package_scripts/_generated/c8y-log-plugin/rpm/postrm b/configuration/package_scripts/_generated/c8y-log-plugin/rpm/postrm deleted file mode 100644 index 3d0d8620462..00000000000 --- a/configuration/package_scripts/_generated/c8y-log-plugin/rpm/postrm +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh -set -e -# Automatically added by thin-edge.io -if [ -d /run/systemd/system ]; then - systemctl --system daemon-reload >/dev/null || true -fi -# End automatically added section -# Automatically added by thin-edge.io -if [ $1 -ge 1 ] && [ -x "/usr/lib/systemd/systemd-update-helper" ]; then - # Package upgrade, not uninstall - /usr/lib/systemd/systemd-update-helper mark-restart-system-units c8y-log-plugin.service || : -fi - -# End automatically added section \ No newline at end of file diff --git a/configuration/package_scripts/_generated/c8y-log-plugin/rpm/preinst b/configuration/package_scripts/_generated/c8y-log-plugin/rpm/preinst deleted file mode 100644 index d37118bbe57..00000000000 --- a/configuration/package_scripts/_generated/c8y-log-plugin/rpm/preinst +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -set -e diff --git a/configuration/package_scripts/_generated/c8y-log-plugin/rpm/prerm b/configuration/package_scripts/_generated/c8y-log-plugin/rpm/prerm deleted file mode 100644 index 564b4a215e2..00000000000 --- a/configuration/package_scripts/_generated/c8y-log-plugin/rpm/prerm +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -set -e -# Automatically added by thin-edge.io -if [ $1 -eq 0 ] && [ -x "/usr/lib/systemd/systemd-update-helper" ]; then - # Package removal, not upgrade - /usr/lib/systemd/systemd-update-helper remove-system-units c8y-log-plugin.service || : -fi -# End automatically added section \ No newline at end of file diff --git a/configuration/package_scripts/packages.json b/configuration/package_scripts/packages.json index abe4e14fe17..2da4c42c2f4 100644 --- a/configuration/package_scripts/packages.json +++ b/configuration/package_scripts/packages.json @@ -20,11 +20,6 @@ {"name": "c8y-configuration-plugin", "enable": true, "start": true, "restart_after_upgrade": true, "stop_on_upgrade": true} ] }, - "c8y-log-plugin": { - "services": [ - {"name": "c8y-log-plugin", "enable": true, "start": true, "restart_after_upgrade": true, "stop_on_upgrade": true} - ] - }, "c8y-firmware-plugin": { "services": [ {"name": "c8y-firmware-plugin", "enable": true, "start": true, "restart_after_upgrade": true, "stop_on_upgrade": true} diff --git a/crates/common/tedge_config/src/system_services/managers/config.rs b/crates/common/tedge_config/src/system_services/managers/config.rs index a3b62ee40eb..9da9a7b61a7 100644 --- a/crates/common/tedge_config/src/system_services/managers/config.rs +++ b/crates/common/tedge_config/src/system_services/managers/config.rs @@ -159,7 +159,6 @@ mod tests { tedge_mapper = "Debug" tedge_agent = "Info" tedge_watchdog = "Warn" - c8y_log_plugin = "Error" c8y_config_plugin = "Debug" "#, ) @@ -186,7 +185,6 @@ mod tests { assert_eq!(config.log.get("tedge_mapper").unwrap(), "Debug"); assert_eq!(config.log.get("tedge_agent").unwrap(), "Info"); assert_eq!(config.log.get("tedge_watchdog").unwrap(), "Warn"); - assert_eq!(config.log.get("c8y_log_plugin").unwrap(), "Error"); assert_eq!(config.log.get("c8y_config_plugin").unwrap(), "Debug"); } @@ -216,7 +214,6 @@ mod tests { tedge_mapper = "Debug" tedge_agent = "Info" tedge_watchdog = "Warn" - c8y_log_plugin = "Error" c8y_config_plugin = "Debug" "#; let expected_config: SystemConfig = toml::from_str(toml_conf)?; diff --git a/crates/extensions/c8y_log_manager/Cargo.toml b/crates/extensions/c8y_log_manager/Cargo.toml deleted file mode 100644 index 5daaa9c56b4..00000000000 --- a/crates/extensions/c8y_log_manager/Cargo.toml +++ /dev/null @@ -1,35 +0,0 @@ -[package] -name = "c8y_log_manager" -description = "thin-edge Cumulocity extension adding support for log management" -version = { workspace = true } -authors = { workspace = true } -edition = { workspace = true } -rust-version = { workspace = true } -license = { workspace = true } -homepage = { workspace = true } -repository = { workspace = true } - -[dependencies] -anyhow = { workspace = true } -async-trait = { workspace = true } -c8y_api = { workspace = true } -c8y_http_proxy = { workspace = true } -log = { workspace = true } -log_manager = { workspace = true } -serde = { workspace = true } -tedge_actors = { workspace = true } -tedge_api = { workspace = true } -tedge_config = { workspace = true } -tedge_file_system_ext = { workspace = true } -tedge_mqtt_ext = { workspace = true } -tedge_utils = { workspace = true } -thiserror = { workspace = true } -tokio = { workspace = true, features = ["macros"] } - -[dev-dependencies] -filetime = { workspace = true } -tedge_test_utils = { workspace = true } -time = { workspace = true } - -[lints] -workspace = true diff --git a/crates/extensions/c8y_log_manager/src/actor.rs b/crates/extensions/c8y_log_manager/src/actor.rs deleted file mode 100644 index 7036545be02..00000000000 --- a/crates/extensions/c8y_log_manager/src/actor.rs +++ /dev/null @@ -1,478 +0,0 @@ -use super::LogManagerConfig; -use async_trait::async_trait; -use c8y_api::smartrest::message::get_smartrest_device_id; -use c8y_api::smartrest::smartrest_deserializer::SmartRestLogRequest; -use c8y_api::smartrest::smartrest_deserializer::SmartRestRequestGeneric; -use c8y_api::smartrest::smartrest_serializer::fail_operation; -use c8y_api::smartrest::smartrest_serializer::set_operation_executing; -use c8y_api::smartrest::smartrest_serializer::succeed_static_operation; -use c8y_api::smartrest::smartrest_serializer::CumulocitySupportedOperations; -use c8y_api::smartrest::smartrest_serializer::OperationStatusMessage; -use c8y_api::smartrest::topic::C8yTopic; -use c8y_api::utils::bridge::is_c8y_bridge_up; -use c8y_http_proxy::handle::C8YHttpProxy; -use log::error; -use log::info; -use log::trace; -use log_manager::LogPluginConfig; -use tedge_actors::fan_in_message_type; -use tedge_actors::Actor; -use tedge_actors::LoggingSender; -use tedge_actors::MessageReceiver; -use tedge_actors::NoMessage; -use tedge_actors::RuntimeError; -use tedge_actors::Sender; -use tedge_actors::SimpleMessageBox; -use tedge_file_system_ext::FsWatchEvent; -use tedge_mqtt_ext::MqttMessage; -use tedge_utils::paths::PathsError; - -fan_in_message_type!(LogInput[MqttMessage, FsWatchEvent] : Debug); -fan_in_message_type!(LogOutput[MqttMessage]: Debug); - -pub struct LogManagerActor { - config: LogManagerConfig, - plugin_config: LogPluginConfig, - mqtt_publisher: LoggingSender, - http_proxy: C8YHttpProxy, - messages: SimpleMessageBox, -} - -impl LogManagerActor { - pub fn new( - config: LogManagerConfig, - plugin_config: LogPluginConfig, - mqtt_publisher: LoggingSender, - http_proxy: C8YHttpProxy, - messages: SimpleMessageBox, - ) -> Self { - Self { - config, - plugin_config, - mqtt_publisher, - http_proxy, - messages, - } - } - - pub async fn process_mqtt_message( - &mut self, - message: MqttMessage, - ) -> Result<(), anyhow::Error> { - if is_c8y_bridge_up(&message) { - self.reload_supported_log_types().await?; - self.get_pending_operations_from_cloud().await?; - } else if let Ok(payload) = message.payload_str() { - for smartrest_message in payload.split('\n') { - let result = match smartrest_message.split(',').next().unwrap_or_default() { - "522" => { - let topic = &message.topic.name; - info!("Log request received on topic: {topic}"); - trace!("payload: {payload}"); - match get_smartrest_device_id(payload) { - Some(device_id) if device_id == self.config.device_id => { - // retrieve smartrest object from payload - let maybe_smartrest_obj = - SmartRestLogRequest::from_smartrest(smartrest_message); - if let Ok(smartrest_obj) = maybe_smartrest_obj { - self.handle_logfile_request_operation(&smartrest_obj).await - } else { - error!("Incorrect SmartREST payload: {}", smartrest_message); - Ok(()) - } - } - // Ignore operation messages created for child devices - _ => Ok(()), - } - } - _ => { - // Ignore operation messages not meant for this plugin - Ok(()) - } - }; - - if let Err(err) = result { - let error_message = format!( - "Handling of operation: '{}' failed with {}", - smartrest_message, err - ); - error!("{}", error_message); - } - } - } - Ok(()) - } - - /// executes the log file request - /// - /// - sends request executing (mqtt) - /// - uploads log content (http) - /// - sends request successful (mqtt) - async fn execute_logfile_request_operation( - &mut self, - smartrest_request: &SmartRestLogRequest, - ) -> Result<(), anyhow::Error> { - let executing = LogfileRequest::executing(); - self.mqtt_publisher.send(executing).await?; - - let log_path = log_manager::new_read_logs( - &self.plugin_config.files, - &smartrest_request.log_type, - smartrest_request.date_from, - smartrest_request.lines, - &smartrest_request.search_text, - &self.config.tmp_dir, - )?; - - let log_content = std::fs::read_to_string(&log_path)?; - - let upload_event_url = self - .http_proxy - .upload_log_binary( - &smartrest_request.log_type, - &log_content, - self.config.device_id.clone(), - ) - .await?; - - let successful = LogfileRequest::successful(Some(&upload_event_url)); - self.mqtt_publisher.send(successful).await?; - - std::fs::remove_file(log_path)?; - - info!("Log request processed."); - Ok(()) - } - pub async fn handle_logfile_request_operation( - &mut self, - smartrest_request: &SmartRestLogRequest, - ) -> Result<(), anyhow::Error> { - match self - .execute_logfile_request_operation(smartrest_request) - .await - { - Ok(()) => Ok(()), - Err(error) => { - let error_message = format!("Handling of operation failed with {}", error); - let failed_msg = LogfileRequest::failed(&error_message); - self.mqtt_publisher.send(failed_msg).await?; - error!( - "Handling of operation for log type {} failed with: {}", - smartrest_request.log_type, error - ); - Ok(()) - } - } - } - - pub async fn process_file_watch_events( - &mut self, - event: FsWatchEvent, - ) -> Result<(), anyhow::Error> { - let path = match event { - FsWatchEvent::Modified(path) => path, - FsWatchEvent::FileDeleted(path) => path, - FsWatchEvent::FileCreated(path) => path, - FsWatchEvent::DirectoryDeleted(_) => return Ok(()), - FsWatchEvent::DirectoryCreated(_) => return Ok(()), - }; - - if path - .file_name() - .ok_or_else(|| PathsError::ParentDirNotFound { - path: path.as_os_str().into(), - })? - .eq("c8y-log-plugin.toml") - { - self.reload_supported_log_types().await?; - } - - Ok(()) - } - - pub async fn reload_supported_log_types(&mut self) -> Result<(), anyhow::Error> { - self.plugin_config = LogPluginConfig::new(self.config.plugin_config_path.as_path()); - self.publish_supported_log_types().await - } - - /// updates the log types on Cumulocity - /// sends 118,typeA,typeB,... on mqtt - pub async fn publish_supported_log_types(&mut self) -> Result<(), anyhow::Error> { - let topic = C8yTopic::SmartRestResponse.to_topic()?; - let mut config_types = self.plugin_config.get_all_file_types(); - config_types.sort(); - let supported_config_types = config_types.join(","); - let payload = format!("118,{supported_config_types}"); - let msg = MqttMessage::new(&topic, payload); - Ok(self.mqtt_publisher.send(msg).await?) - } - - async fn get_pending_operations_from_cloud(&mut self) -> Result<(), anyhow::Error> { - // Get pending operations - let msg = MqttMessage::new(&C8yTopic::SmartRestResponse.to_topic()?, "500"); - self.mqtt_publisher.send(msg).await?; - Ok(()) - } -} - -#[async_trait] -impl Actor for LogManagerActor { - fn name(&self) -> &str { - "LogManager" - } - - async fn run(mut self) -> Result<(), RuntimeError> { - self.reload_supported_log_types().await.unwrap(); - self.get_pending_operations_from_cloud().await.unwrap(); - - while let Some(event) = self.messages.recv().await { - match event { - LogInput::MqttMessage(message) => { - self.process_mqtt_message(message).await.unwrap(); - } - LogInput::FsWatchEvent(event) => { - self.process_file_watch_events(event).await.unwrap(); - } - } - } - Ok(()) - } -} - -pub struct LogfileRequest {} - -impl LogfileRequest { - const OP: CumulocitySupportedOperations = CumulocitySupportedOperations::C8yLogFileRequest; -} - -impl OperationStatusMessage for LogfileRequest { - /// returns a c8y message specifying to set log status to executing. - /// - /// example message: '501,c8y_LogfileRequest' - fn status_executing() -> String { - set_operation_executing(Self::OP) - } - - fn status_successful(parameter: Option<&str>) -> String { - succeed_static_operation(Self::OP, parameter) - } - - fn status_failed(failure_reason: &str) -> String { - fail_operation(Self::OP, failure_reason) - } -} - -#[cfg(test)] -mod tests { - use crate::LogManagerBuilder; - use crate::LogManagerConfig; - use crate::Topic; - use c8y_http_proxy::messages::C8YRestRequest; - use c8y_http_proxy::messages::C8YRestResponse; - use c8y_http_proxy::messages::C8YRestResult; - use c8y_http_proxy::messages::UploadLogBinary; - use filetime::set_file_mtime; - use filetime::FileTime; - use std::path::Path; - use tedge_actors::Actor; - use tedge_actors::Builder; - use tedge_actors::MessageReceiver; - use tedge_actors::NoMessage; - use tedge_actors::Sender; - use tedge_actors::SimpleMessageBox; - use tedge_actors::SimpleMessageBoxBuilder; - use tedge_file_system_ext::FsWatchEvent; - use tedge_mqtt_ext::MqttMessage; - use tedge_test_utils::fs::TempTedgeDir; - - /// Preparing a temp directory containing four files, with - /// two types { type_one, type_two }: - /// - /// file_a, type_one - /// file_b, type_one - /// file_c, type_two - /// file_d, type_one - /// - /// each file has the following modified "file update" timestamp: - /// file_a has timestamp: 1970/01/01 00:00:02 - /// file_b has timestamp: 1970/01/01 00:00:03 - /// file_c has timestamp: 1970/01/01 00:00:11 - /// file_d has timestamp: (current, not modified) - fn prepare() -> Result { - let tempdir = TempTedgeDir::new(); - let tempdir_path = tempdir - .path() - .to_str() - .ok_or_else(|| anyhow::anyhow!("temp dir not created"))?; - - std::fs::File::create(format!("{tempdir_path}/file_a"))?; - std::fs::File::create(format!("{tempdir_path}/file_b"))?; - tempdir.file("file_c").with_raw_content("Some content"); - std::fs::File::create(format!("{tempdir_path}/file_d"))?; - - let new_mtime = FileTime::from_unix_time(2, 0); - set_file_mtime(format!("{tempdir_path}/file_a"), new_mtime).unwrap(); - - let new_mtime = FileTime::from_unix_time(3, 0); - set_file_mtime(format!("{tempdir_path}/file_b"), new_mtime).unwrap(); - - let new_mtime = FileTime::from_unix_time(11, 0); - set_file_mtime(format!("{tempdir_path}/file_c"), new_mtime).unwrap(); - - tempdir - .file("c8y-log-plugin.toml") - .with_raw_content(&format!( - r#"files = [ - {{ type = "type_one", path = "{tempdir_path}/file_a" }}, - {{ type = "type_one", path = "{tempdir_path}/file_b" }}, - {{ type = "type_two", path = "{tempdir_path}/file_c" }}, - {{ type = "type_one", path = "{tempdir_path}/file_d" }}, - ]"# - )); - - Ok(tempdir) - } - - /// Create a log manager actor builder - /// along two boxes to exchange MQTT and HTTP messages with the log actor - #[allow(clippy::type_complexity)] - fn new_log_manager_builder( - temp_dir: &Path, - ) -> ( - LogManagerBuilder, - SimpleMessageBox, - SimpleMessageBox, - SimpleMessageBox, - ) { - let config = LogManagerConfig { - config_dir: temp_dir.to_path_buf(), - log_dir: temp_dir.to_path_buf(), - tmp_dir: temp_dir.to_path_buf(), - device_id: "SUT".to_string(), - mqtt_host: "127.0.0.1".to_string(), - mqtt_port: 1883, - tedge_http_host: "127.0.0.1".into(), - tedge_http_port: 80, - ops_dir: temp_dir.to_path_buf(), - plugin_config_dir: temp_dir.to_path_buf(), - plugin_config_path: temp_dir.join("c8y-log-plugin.toml"), - }; - - let mut mqtt_builder: SimpleMessageBoxBuilder = - SimpleMessageBoxBuilder::new("MQTT", 5); - let mut c8y_proxy_builder: SimpleMessageBoxBuilder = - SimpleMessageBoxBuilder::new("C8Y", 1); - let mut fs_watcher_builder: SimpleMessageBoxBuilder = - SimpleMessageBoxBuilder::new("FS", 5); - - let log_builder = LogManagerBuilder::try_new( - config, - &mut mqtt_builder, - &mut c8y_proxy_builder, - &mut fs_watcher_builder, - ) - .unwrap(); - - ( - log_builder, - mqtt_builder.build(), - c8y_proxy_builder.build(), - fs_watcher_builder.build(), - ) - } - - /// Spawn a log manager actor and return 2 boxes to exchange MQTT and HTTP messages with it - fn spawn_log_manager_actor( - temp_dir: &Path, - ) -> ( - SimpleMessageBox, - SimpleMessageBox, - SimpleMessageBox, - ) { - let (actor_builder, mqtt, http, fs) = new_log_manager_builder(temp_dir); - let actor = actor_builder.build(); - tokio::spawn(async move { actor.run().await }); - (mqtt, http, fs) - } - - #[tokio::test] - async fn log_manager_send_log_types_on_start_and_bridge_up_and_config_update( - ) -> Result<(), anyhow::Error> { - let tempdir = prepare()?; - let (mut mqtt, _http, mut fs) = spawn_log_manager_actor(tempdir.path()); - - let c8y_s_us = Topic::new_unchecked("c8y/s/us"); - let bridge = - Topic::new_unchecked("te/device/main/service/mosquitto-c8y-bridge/status/health"); - - assert_eq!( - mqtt.recv().await, - Some(MqttMessage::new(&c8y_s_us, "118,type_one,type_two")) - ); - assert_eq!(mqtt.recv().await, Some(MqttMessage::new(&c8y_s_us, "500"))); - - mqtt.send(MqttMessage::new(&bridge, "1")).await?; - assert_eq!( - mqtt.recv().await, - Some(MqttMessage::new(&c8y_s_us, "118,type_one,type_two")) - ); - assert_eq!(mqtt.recv().await, Some(MqttMessage::new(&c8y_s_us, "500"))); - - fs.send(FsWatchEvent::Modified( - tempdir.path().join("c8y-log-plugin.toml"), - )) - .await?; - assert_eq!( - mqtt.recv().await, - Some(MqttMessage::new(&c8y_s_us, "118,type_one,type_two")) - ); - - Ok(()) - } - - #[tokio::test] - async fn log_manager_upload_log_files_on_request() -> Result<(), anyhow::Error> { - let tempdir = prepare()?; - let (mut mqtt, mut http, _fs) = spawn_log_manager_actor(tempdir.path()); - - let c8y_s_ds = Topic::new_unchecked("c8y/s/ds"); - let c8y_s_us = Topic::new_unchecked("c8y/s/us"); - - // Let's ignore the 2 init messages sent on start - assert!(mqtt.recv().await.is_some()); - assert!(mqtt.recv().await.is_some()); - - // When a log request is received - let log_request = - "522,SUT,type_two,1970-01-01T00:00:00+0000,1970-01-01T00:00:30+0000,,1000"; - mqtt.send(MqttMessage::new(&c8y_s_ds, log_request)).await?; - - // The log manager notifies C8Y that the request has been received and is processed - assert_eq!( - mqtt.recv().await, - Some(MqttMessage::new(&c8y_s_us, "501,c8y_LogfileRequest")) - ); - - // Then uploads the requested content over HTTP - assert_eq!( - http.recv().await, - Some(C8YRestRequest::UploadLogBinary(UploadLogBinary { - log_type: "type_two".to_string(), - log_content: "filename: file_c\nSome content\n".to_string(), - device_id: "SUT".into() - })) - ); - - // C8Y responds with an event id - http.send(Ok(C8YRestResponse::EventId("12345".to_string()))) - .await?; - - // Finally, the log manager uses the event id to notify C8Y that the request has been fully processed - assert_eq!( - mqtt.recv().await, - Some(MqttMessage::new(&c8y_s_us, "503,c8y_LogfileRequest,12345")) - ); - - Ok(()) - } -} diff --git a/crates/extensions/c8y_log_manager/src/config.rs b/crates/extensions/c8y_log_manager/src/config.rs deleted file mode 100644 index 483b967a460..00000000000 --- a/crates/extensions/c8y_log_manager/src/config.rs +++ /dev/null @@ -1,61 +0,0 @@ -use std::path::Path; -use std::path::PathBuf; -use std::sync::Arc; -use tedge_config::ReadError; -use tedge_config::TEdgeConfig; - -pub const DEFAULT_PLUGIN_CONFIG_FILE_NAME: &str = "c8y-log-plugin.toml"; -pub const DEFAULT_PLUGIN_CONFIG_DIR_NAME: &str = "c8y/"; - -/// Configuration of the Configuration Manager -#[derive(Clone, Debug)] -pub struct LogManagerConfig { - pub config_dir: PathBuf, - pub tmp_dir: PathBuf, - pub log_dir: PathBuf, - pub device_id: String, - pub mqtt_host: String, - pub mqtt_port: u16, - pub tedge_http_host: Arc, - pub tedge_http_port: u16, - pub ops_dir: PathBuf, - pub plugin_config_dir: PathBuf, - pub plugin_config_path: PathBuf, -} - -impl LogManagerConfig { - pub fn from_tedge_config( - config_dir: impl AsRef, - tedge_config: &TEdgeConfig, - ) -> Result { - let config_dir: PathBuf = config_dir.as_ref().into(); - let device_id = tedge_config.device.id.try_read(tedge_config)?.to_string(); - let tmp_dir = tedge_config.tmp.path.as_std_path().to_path_buf(); - let log_dir = tedge_config.logs.path.as_std_path().to_path_buf(); - let mqtt_host = tedge_config.mqtt.client.host.clone(); - let mqtt_port = u16::from(tedge_config.mqtt.client.port); - - let tedge_http_host = tedge_config.http.client.host.clone(); - let tedge_http_port = tedge_config.http.client.port; - - let ops_dir = config_dir.join("operations/c8y"); - - let plugin_config_dir = config_dir.join(DEFAULT_PLUGIN_CONFIG_DIR_NAME); - - let plugin_config_path = plugin_config_dir.join(DEFAULT_PLUGIN_CONFIG_FILE_NAME); - - Ok(Self { - config_dir, - tmp_dir, - log_dir, - device_id, - mqtt_host, - mqtt_port, - tedge_http_host, - tedge_http_port, - ops_dir, - plugin_config_dir, - plugin_config_path, - }) - } -} diff --git a/crates/extensions/c8y_log_manager/src/lib.rs b/crates/extensions/c8y_log_manager/src/lib.rs deleted file mode 100644 index 79e4b3b2d4a..00000000000 --- a/crates/extensions/c8y_log_manager/src/lib.rs +++ /dev/null @@ -1,129 +0,0 @@ -mod actor; -mod config; - -use actor::*; -use c8y_api::smartrest::topic::C8yTopic; -use c8y_api::utils::bridge::C8Y_BRIDGE_HEALTH_TOPIC; -use c8y_http_proxy::handle::C8YHttpProxy; -use c8y_http_proxy::messages::C8YRestRequest; -use c8y_http_proxy::messages::C8YRestResult; -pub use config::*; -use log_manager::LogPluginConfig; -use std::path::PathBuf; -use tedge_actors::adapt; -use tedge_actors::Builder; -use tedge_actors::DynSender; -use tedge_actors::LinkError; -use tedge_actors::LoggingSender; -use tedge_actors::MessageSink; -use tedge_actors::MessageSource; -use tedge_actors::NoConfig; -use tedge_actors::NoMessage; -use tedge_actors::RuntimeRequest; -use tedge_actors::RuntimeRequestSink; -use tedge_actors::ServiceProvider; -use tedge_actors::SimpleMessageBoxBuilder; -use tedge_file_system_ext::FsWatchEvent; -use tedge_mqtt_ext::*; -use tedge_utils::file::create_directory_with_defaults; -use tedge_utils::file::create_file_with_defaults; -use tedge_utils::file::FileError; -/// This is an actor builder. -pub struct LogManagerBuilder { - config: LogManagerConfig, - plugin_config: LogPluginConfig, - box_builder: SimpleMessageBoxBuilder, - mqtt_publisher: DynSender, - http_proxy: C8YHttpProxy, -} - -impl LogManagerBuilder { - pub fn try_new( - config: LogManagerConfig, - mqtt: &mut impl ServiceProvider, - http: &mut impl ServiceProvider, - fs_notify: &mut impl MessageSource, - ) -> Result { - Self::init(&config)?; - let plugin_config = LogPluginConfig::new(&config.plugin_config_path); - - let box_builder = SimpleMessageBoxBuilder::new("C8Y Log Manager", 16); - let http_proxy = C8YHttpProxy::new("LogManager => C8Y", http); - let mqtt_publisher = mqtt.connect_consumer( - LogManagerBuilder::subscriptions(), - adapt(&box_builder.get_sender()), - ); - fs_notify.register_peer( - LogManagerBuilder::watched_directory(&config), - adapt(&box_builder.get_sender()), - ); - - Ok(Self { - config, - plugin_config, - box_builder, - mqtt_publisher, - http_proxy, - }) - } - - pub fn init(config: &LogManagerConfig) -> Result<(), FileError> { - // creating c8y_LogfileRequest operation file - create_file_with_defaults(config.ops_dir.join("c8y_LogfileRequest"), None)?; - - // creating plugin config parent dir - create_directory_with_defaults(&config.plugin_config_dir)?; - - // creating c8y-log-plugin.toml - let logs_path = format!("{}/agent/software-*", config.log_dir.display()); - let data = format!( - r#"files = [ - {{ type = "software-management", path = "{logs_path}" }}, -]"# - ); - - create_file_with_defaults(&config.plugin_config_path, Some(&data))?; - - Ok(()) - } - - /// List of MQTT topic filters the log actor has to subscribe to - fn subscriptions() -> TopicFilter { - vec![ - // subscribing to c8y smartrest requests - C8yTopic::SmartRestRequest.to_string().as_ref(), - // subscribing also to c8y bridge health topic to know when the bridge is up - C8Y_BRIDGE_HEALTH_TOPIC, - ] - .try_into() - .expect("Well-formed topic filters") - } - - /// Directory watched by the log actors for configuration changes - fn watched_directory(config: &LogManagerConfig) -> PathBuf { - config.config_dir.clone() - } -} - -impl RuntimeRequestSink for LogManagerBuilder { - fn get_signal_sender(&self) -> DynSender { - self.box_builder.get_signal_sender() - } -} - -impl Builder for LogManagerBuilder { - type Error = LinkError; - - fn try_build(self) -> Result { - let mqtt_publisher = LoggingSender::new("C8Y-Log-Manager".into(), self.mqtt_publisher); - let message_box = self.box_builder.build(); - - Ok(LogManagerActor::new( - self.config, - self.plugin_config, - mqtt_publisher, - self.http_proxy, - message_box, - )) - } -} diff --git a/plugins/c8y_log_plugin/Cargo.toml b/plugins/c8y_log_plugin/Cargo.toml deleted file mode 100644 index 1ad5bbe0336..00000000000 --- a/plugins/c8y_log_plugin/Cargo.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package] -name = "c8y-log-plugin" -description = "Thin-edge device log file retriever for Cumulocity" -version = { workspace = true } -authors = { workspace = true } -edition = { workspace = true } -rust-version = { workspace = true } -license = { workspace = true } -homepage = { workspace = true } -repository = { workspace = true } - -[dependencies] -anyhow = { workspace = true } -c8y_http_proxy = { workspace = true } -c8y_log_manager = { workspace = true } -clap = { workspace = true } -tedge_actors = { workspace = true } -tedge_api = { workspace = true } -tedge_config = { workspace = true } -tedge_file_system_ext = { workspace = true } -tedge_health_ext = { workspace = true } -tedge_http_ext = { workspace = true } -tedge_mqtt_ext = { workspace = true } -tedge_signal_ext = { workspace = true } -tedge_utils = { workspace = true } -tokio = { workspace = true, features = ["rt", "rt-multi-thread"] } -tracing = { workspace = true } - -[lints] -workspace = true diff --git a/plugins/c8y_log_plugin/build.rs b/plugins/c8y_log_plugin/build.rs deleted file mode 100644 index 7d918c19f0b..00000000000 --- a/plugins/c8y_log_plugin/build.rs +++ /dev/null @@ -1,10 +0,0 @@ -fn main() { - // export GIT_SEMVER=$(git describe --always --tags --abbrev=8 --dirty) - // https://github.com/rust-lang/cargo/issues/6583#issuecomment-1259871885 - if let Ok(val) = std::env::var("GIT_SEMVER") { - println!("Using version defined by 'GIT_SEMVER={}'", val); - println!("cargo:rustc-env=CARGO_PKG_VERSION={}", val); - } - println!("cargo:rerun-if-env-changed=GIT_SEMVER"); - println!("cargo:rerun-if-changed=build.rs"); -} diff --git a/plugins/c8y_log_plugin/src/main.rs b/plugins/c8y_log_plugin/src/main.rs deleted file mode 100644 index d3313f1ab2a..00000000000 --- a/plugins/c8y_log_plugin/src/main.rs +++ /dev/null @@ -1,166 +0,0 @@ -use anyhow::Context; -use anyhow::Result; -use c8y_http_proxy::credentials::C8YJwtRetriever; -use c8y_http_proxy::C8YHttpProxyBuilder; -use c8y_log_manager::LogManagerBuilder; -use c8y_log_manager::LogManagerConfig; -use clap::Parser; -use std::path::Path; -use std::path::PathBuf; -use tedge_actors::Runtime; -use tedge_api::mqtt_topics::DeviceTopicId; -use tedge_api::mqtt_topics::EntityTopicId; -use tedge_api::mqtt_topics::MqttSchema; -use tedge_api::mqtt_topics::Service; -use tedge_config::system_services::get_log_level; -use tedge_config::system_services::set_log_level; -use tedge_config::CertificateError; -use tedge_config::TEdgeConfig; -use tedge_config::DEFAULT_TEDGE_CONFIG_PATH; -use tedge_file_system_ext::FsWatchActorBuilder; -use tedge_health_ext::HealthMonitorBuilder; -use tedge_http_ext::HttpActor; -use tedge_mqtt_ext::MqttActorBuilder; -use tedge_mqtt_ext::MqttConfig; -use tedge_signal_ext::SignalActor; -use tracing::info; -use tracing::log::warn; - -const AFTER_HELP_TEXT: &str = r#"On start, `c8y-log-plugin` notifies the cloud tenant of the log types listed in the `CONFIG_FILE`, sending this list with a `118` on `c8y/s/us`. -`c8y-log-plugin` subscribes then to `c8y/s/ds` listening for logfile operation requests (`522`) notifying the Cumulocity tenant of their progress (messages `501`, `502` and `503`). - -The thin-edge `CONFIG_DIR` is used to store: - * c8y-log-plugin.toml - the configuration file that specifies which logs to be retrieved"#; - -const PLUGIN_NAME: &str = "c8y-log-plugin"; - -#[derive(Debug, clap::Parser, Clone)] -#[clap( -name = clap::crate_name!(), -version = clap::crate_version!(), -about = clap::crate_description!(), -after_help = AFTER_HELP_TEXT -)] -pub struct LogfileRequestPluginOpt { - /// Turn-on the debug log level. - /// - /// If off only reports ERROR, WARN, and INFO - /// If on also reports DEBUG - #[clap(long)] - pub debug: bool, - - /// Create supported operation files - #[clap(short, long)] - pub init: bool, - - #[clap(long = "config-dir", default_value = DEFAULT_TEDGE_CONFIG_PATH)] - pub config_dir: PathBuf, -} - -// FIXME: -// - subscribing also to c8y bridge health topic to know when the bridge is up -// topics.add(C8Y_BRIDGE_HEALTH_TOPIC)?; -// - use the health check actor - -#[tokio::main] -async fn main() -> Result<(), anyhow::Error> { - let config_plugin_opt = LogfileRequestPluginOpt::parse(); - let config_dir = config_plugin_opt.config_dir; - - // Load tedge config from the provided location - let tedge_config_location = tedge_config::TEdgeConfigLocation::from_custom_root(&config_dir); - let log_level = if config_plugin_opt.debug { - tracing::Level::DEBUG - } else { - get_log_level( - "c8y-log-plugin", - &tedge_config_location.tedge_config_root_path, - )? - }; - - set_log_level(log_level); - - let config_repository = tedge_config::TEdgeConfigRepository::new(tedge_config_location.clone()); - let tedge_config = config_repository.load()?; - - if config_plugin_opt.init { - warn!("This --init option has been deprecated and will be removed in a future release"); - Ok(()) - } else { - run(config_dir, tedge_config).await - } -} - -async fn run(config_dir: impl AsRef, tedge_config: TEdgeConfig) -> Result<(), anyhow::Error> { - let runtime_events_logger = None; - let mut runtime = Runtime::try_new(runtime_events_logger).await?; - - let base_mqtt_config = mqtt_config(&tedge_config)?; - let mqtt_config = base_mqtt_config.clone().with_session_name(PLUGIN_NAME); - - let c8y_http_config = (&tedge_config).try_into()?; - - let mut mqtt_actor = MqttActorBuilder::new(mqtt_config); - - // TODO: take a user-configurable service topic id - let mqtt_device_topic_id = &tedge_config - .mqtt - .device_topic_id - .parse::() - .unwrap(); - - let service_topic_id = mqtt_device_topic_id - .to_default_service_topic_id(PLUGIN_NAME) - .with_context(|| { - format!( - "Device topic id {mqtt_device_topic_id} currently needs default scheme, e.g: 'device/DEVICE_NAME//'", - ) - })?; - let service = Service { - service_topic_id, - device_topic_id: DeviceTopicId::new(mqtt_device_topic_id.clone()), - }; - let mqtt_schema = MqttSchema::with_root(tedge_config.mqtt.topic_root.to_string()); - let health_actor = HealthMonitorBuilder::from_service_topic_id( - service, - &mut mqtt_actor, - &mqtt_schema, - &tedge_config.service, - ); - - let mut jwt_actor = C8YJwtRetriever::builder(base_mqtt_config); - let mut http_actor = HttpActor::new().builder(); - let mut c8y_http_proxy_actor = - C8YHttpProxyBuilder::new(c8y_http_config, &mut http_actor, &mut jwt_actor); - let mut fs_watch_actor = FsWatchActorBuilder::new(); - - // Instantiate log manager actor - let log_manager_config = LogManagerConfig::from_tedge_config(config_dir, &tedge_config)?; - let log_actor = LogManagerBuilder::try_new( - log_manager_config, - &mut mqtt_actor, - &mut c8y_http_proxy_actor, - &mut fs_watch_actor, - )?; - - // Shutdown on SIGINT - let signal_actor = SignalActor::builder(&runtime.get_handle()); - - // Run the actors - runtime.spawn(mqtt_actor).await?; - runtime.spawn(jwt_actor).await?; - runtime.spawn(http_actor).await?; - runtime.spawn(c8y_http_proxy_actor).await?; - runtime.spawn(fs_watch_actor).await?; - runtime.spawn(log_actor).await?; - runtime.spawn(signal_actor).await?; - runtime.spawn(health_actor).await?; - - info!("Ready to serve log requests"); - runtime.run_to_completion().await?; - Ok(()) -} - -fn mqtt_config(tedge_config: &TEdgeConfig) -> Result { - tedge_config.mqtt_config() -} From 5a2f19d98210f40c387f2fa559ec067603ad1b7e Mon Sep 17 00:00:00 2001 From: Reuben Miller Date: Tue, 13 Feb 2024 16:27:06 +0100 Subject: [PATCH 02/10] remove c8y-configuration-plugin Signed-off-by: Reuben Miller --- Cargo.lock | 45 - Cargo.toml | 3 - ci/package_list.sh | 4 +- .../systemd/c8y-configuration-plugin.service | 12 - .../nfpm.c8y-configuration-plugin.yaml | 74 -- .../c8y-configuration-plugin/apk/postinst | 3 - .../c8y-configuration-plugin/apk/postrm | 3 - .../c8y-configuration-plugin/apk/preinst | 2 - .../c8y-configuration-plugin/apk/prerm | 2 - .../c8y-configuration-plugin/deb/postinst | 32 - .../c8y-configuration-plugin/deb/postrm | 21 - .../c8y-configuration-plugin/deb/preinst | 2 - .../c8y-configuration-plugin/deb/prerm | 7 - .../c8y-configuration-plugin/rpm/postinst | 19 - .../c8y-configuration-plugin/rpm/postrm | 14 - .../c8y-configuration-plugin/rpm/preinst | 2 - .../c8y-configuration-plugin/rpm/prerm | 8 - configuration/package_scripts/packages.json | 5 - .../src/system_services/managers/config.rs | 3 - .../extensions/c8y_config_manager/Cargo.toml | 37 - .../c8y_config_manager/src/actor.rs | 449 -------- .../c8y_config_manager/src/child_device.rs | 305 ----- .../c8y_config_manager/src/config.rs | 102 -- .../c8y_config_manager/src/download.rs | 364 ------ .../c8y_config_manager/src/error.rs | 47 - .../extensions/c8y_config_manager/src/lib.rs | 151 --- .../c8y_config_manager/src/plugin_config.rs | 201 ---- .../c8y_config_manager/src/tests.rs | 1020 ----------------- .../c8y_config_manager/src/upload.rs | 418 ------- plugins/c8y_configuration_plugin/Cargo.toml | 31 - plugins/c8y_configuration_plugin/build.rs | 10 - plugins/c8y_configuration_plugin/src/lib.rs | 162 --- plugins/c8y_configuration_plugin/src/main.rs | 8 - .../child_conf_mgmt_plugin.robot | 236 ---- 34 files changed, 1 insertion(+), 3801 deletions(-) delete mode 100644 configuration/init/systemd/c8y-configuration-plugin.service delete mode 100644 configuration/package_manifests/nfpm.c8y-configuration-plugin.yaml delete mode 100644 configuration/package_scripts/_generated/c8y-configuration-plugin/apk/postinst delete mode 100644 configuration/package_scripts/_generated/c8y-configuration-plugin/apk/postrm delete mode 100644 configuration/package_scripts/_generated/c8y-configuration-plugin/apk/preinst delete mode 100644 configuration/package_scripts/_generated/c8y-configuration-plugin/apk/prerm delete mode 100755 configuration/package_scripts/_generated/c8y-configuration-plugin/deb/postinst delete mode 100755 configuration/package_scripts/_generated/c8y-configuration-plugin/deb/postrm delete mode 100644 configuration/package_scripts/_generated/c8y-configuration-plugin/deb/preinst delete mode 100755 configuration/package_scripts/_generated/c8y-configuration-plugin/deb/prerm delete mode 100644 configuration/package_scripts/_generated/c8y-configuration-plugin/rpm/postinst delete mode 100644 configuration/package_scripts/_generated/c8y-configuration-plugin/rpm/postrm delete mode 100644 configuration/package_scripts/_generated/c8y-configuration-plugin/rpm/preinst delete mode 100644 configuration/package_scripts/_generated/c8y-configuration-plugin/rpm/prerm delete mode 100644 crates/extensions/c8y_config_manager/Cargo.toml delete mode 100644 crates/extensions/c8y_config_manager/src/actor.rs delete mode 100644 crates/extensions/c8y_config_manager/src/child_device.rs delete mode 100644 crates/extensions/c8y_config_manager/src/config.rs delete mode 100644 crates/extensions/c8y_config_manager/src/download.rs delete mode 100644 crates/extensions/c8y_config_manager/src/error.rs delete mode 100644 crates/extensions/c8y_config_manager/src/lib.rs delete mode 100644 crates/extensions/c8y_config_manager/src/plugin_config.rs delete mode 100644 crates/extensions/c8y_config_manager/src/tests.rs delete mode 100644 crates/extensions/c8y_config_manager/src/upload.rs delete mode 100644 plugins/c8y_configuration_plugin/Cargo.toml delete mode 100644 plugins/c8y_configuration_plugin/build.rs delete mode 100644 plugins/c8y_configuration_plugin/src/lib.rs delete mode 100644 plugins/c8y_configuration_plugin/src/main.rs delete mode 100644 tests/RobotFramework/tests/config_management/child_conf_mgmt_plugin.robot diff --git a/Cargo.lock b/Cargo.lock index f69dfd09388..a59aee072f8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -559,28 +559,6 @@ dependencies = [ "serde", ] -[[package]] -name = "c8y-configuration-plugin" -version = "1.0.0" -dependencies = [ - "anyhow", - "c8y_config_manager", - "c8y_http_proxy", - "clap", - "tedge_actors", - "tedge_api", - "tedge_config", - "tedge_file_system_ext", - "tedge_health_ext", - "tedge_http_ext", - "tedge_mqtt_ext", - "tedge_signal_ext", - "tedge_timer_ext", - "tedge_utils", - "tokio", - "tracing", -] - [[package]] name = "c8y-firmware-plugin" version = "1.0.0" @@ -683,29 +661,6 @@ dependencies = [ "url", ] -[[package]] -name = "c8y_config_manager" -version = "1.0.0" -dependencies = [ - "async-trait", - "c8y_api", - "c8y_http_proxy", - "log", - "serde", - "serde_json", - "tedge_actors", - "tedge_api", - "tedge_config", - "tedge_file_system_ext", - "tedge_mqtt_ext", - "tedge_test_utils", - "tedge_timer_ext", - "tedge_utils", - "thiserror", - "tokio", - "toml 0.7.8", -] - [[package]] name = "c8y_firmware_manager" version = "1.0.0" diff --git a/Cargo.toml b/Cargo.toml index b6e9d69fb86..34ea013dc20 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,6 @@ members = [ "crates/core/*", "crates/extensions/*", "crates/tests/*", - "plugins/c8y_configuration_plugin", "plugins/c8y_firmware_plugin", "plugins/c8y_remote_access_plugin", "plugins/tedge_apt_plugin", @@ -44,12 +43,10 @@ backoff = { version = "0.4", features = ["tokio"] } base64 = "0.13" batcher = { path = "crates/common/batcher" } bytes = "1.4" -c8y-configuration-plugin = { path = "plugins/c8y_configuration_plugin" } c8y-firmware-plugin = { path = "plugins/c8y_firmware_plugin" } c8y-remote-access-plugin = { path = "plugins/c8y_remote_access_plugin" } c8y_api = { path = "crates/core/c8y_api" } c8y_auth_proxy = { path = "crates/extensions/c8y_auth_proxy" } -c8y_config_manager = { path = "crates/extensions/c8y_config_manager" } c8y_firmware_manager = { path = "crates/extensions/c8y_firmware_manager" } c8y_http_proxy = { path = "crates/extensions/c8y_http_proxy" } c8y_mapper_ext = { path = "crates/extensions/c8y_mapper_ext" } diff --git a/ci/package_list.sh b/ci/package_list.sh index b7e68c6a9a4..9508384bcf1 100755 --- a/ci/package_list.sh +++ b/ci/package_list.sh @@ -15,9 +15,7 @@ export RELEASE_PACKAGES # Deprecated packages are still built but not explicitly tested # This allows users to still access the packages if needed, however # it is only reserved for packages with a more public facing API -DEPRECATED_PACKAGES=( - c8y-configuration-plugin -) +DEPRECATED_PACKAGES=() export DEPRECATED_PACKAGES TEST_PACKAGES=( diff --git a/configuration/init/systemd/c8y-configuration-plugin.service b/configuration/init/systemd/c8y-configuration-plugin.service deleted file mode 100644 index ec4bcaaf19b..00000000000 --- a/configuration/init/systemd/c8y-configuration-plugin.service +++ /dev/null @@ -1,12 +0,0 @@ -[Unit] -Description=Thin-edge device configuration management for Cumulocity -After=syslog.target network.target mosquitto.service - -[Service] -ExecStart=/usr/bin/c8y-configuration-plugin -Restart=on-failure -RestartPreventExitStatus=255 -RestartSec=5 - -[Install] -WantedBy=multi-user.target diff --git a/configuration/package_manifests/nfpm.c8y-configuration-plugin.yaml b/configuration/package_manifests/nfpm.c8y-configuration-plugin.yaml deleted file mode 100644 index f0f549e7b7e..00000000000 --- a/configuration/package_manifests/nfpm.c8y-configuration-plugin.yaml +++ /dev/null @@ -1,74 +0,0 @@ -# yaml-language-server: $schema=https://nfpm.goreleaser.com/static/schema.json ---- -name: c8y-configuration-plugin -description: | - thin-edge.io device configuration management for Cumulocity -arch: "${PKG_ARCH}" -platform: "linux" -version: "${GIT_SEMVER}" -release: "${RELEASE}" -section: misc -priority: "optional" -maintainer: "thin-edge.io team " -vendor: "thin-edge.io" -homepage: "https://thin-edge.io" -license: "Apache-2.0" - -replaces: - - c8y_configuration_plugin -conflicts: - - c8y_configuration_plugin (<= 0.8.1) - -deb: - fields: - Vcs-Browser: ${CI_PROJECT_URL} - Vcs-Git: ${CI_PROJECT_URL} - compression: xz - breaks: - - c8y_configuration_plugin (<= 0.8.1) - -contents: - # binary - - src: .build/c8y-configuration-plugin - dst: /usr/bin/ - - # service definitions - - src: ./configuration/init/systemd/c8y-configuration-plugin.service - dst: /lib/systemd/system/ - file_info: - mode: 0644 - packager: deb - - - src: ./configuration/init/systemd/c8y-configuration-plugin.service - dst: /lib/systemd/system/ - file_info: - mode: 0644 - packager: rpm - - # Symlink for backwards compatibility - # Deprecate: Remove symlink in 1.x release - - src: /usr/bin/c8y-configuration-plugin - dst: /usr/bin/c8y_configuration_plugin - type: symlink - -overrides: - apk: - scripts: - preinstall: configuration/package_scripts/_generated/c8y-configuration-plugin/apk/preinst - postinstall: configuration/package_scripts/_generated/c8y-configuration-plugin/apk/postinst - preremove: configuration/package_scripts/_generated/c8y-configuration-plugin/apk/prerm - postremove: configuration/package_scripts/_generated/c8y-configuration-plugin/apk/postrm - - rpm: - scripts: - preinstall: configuration/package_scripts/_generated/c8y-configuration-plugin/rpm/preinst - postinstall: configuration/package_scripts/_generated/c8y-configuration-plugin/rpm/postinst - preremove: configuration/package_scripts/_generated/c8y-configuration-plugin/rpm/prerm - postremove: configuration/package_scripts/_generated/c8y-configuration-plugin/rpm/postrm - - deb: - scripts: - preinstall: configuration/package_scripts/_generated/c8y-configuration-plugin/deb/preinst - postinstall: configuration/package_scripts/_generated/c8y-configuration-plugin/deb/postinst - preremove: configuration/package_scripts/_generated/c8y-configuration-plugin/deb/prerm - postremove: configuration/package_scripts/_generated/c8y-configuration-plugin/deb/postrm diff --git a/configuration/package_scripts/_generated/c8y-configuration-plugin/apk/postinst b/configuration/package_scripts/_generated/c8y-configuration-plugin/apk/postinst deleted file mode 100644 index aa2813997b3..00000000000 --- a/configuration/package_scripts/_generated/c8y-configuration-plugin/apk/postinst +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -set -e - diff --git a/configuration/package_scripts/_generated/c8y-configuration-plugin/apk/postrm b/configuration/package_scripts/_generated/c8y-configuration-plugin/apk/postrm deleted file mode 100644 index aa2813997b3..00000000000 --- a/configuration/package_scripts/_generated/c8y-configuration-plugin/apk/postrm +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -set -e - diff --git a/configuration/package_scripts/_generated/c8y-configuration-plugin/apk/preinst b/configuration/package_scripts/_generated/c8y-configuration-plugin/apk/preinst deleted file mode 100644 index d37118bbe57..00000000000 --- a/configuration/package_scripts/_generated/c8y-configuration-plugin/apk/preinst +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -set -e diff --git a/configuration/package_scripts/_generated/c8y-configuration-plugin/apk/prerm b/configuration/package_scripts/_generated/c8y-configuration-plugin/apk/prerm deleted file mode 100644 index d37118bbe57..00000000000 --- a/configuration/package_scripts/_generated/c8y-configuration-plugin/apk/prerm +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -set -e diff --git a/configuration/package_scripts/_generated/c8y-configuration-plugin/deb/postinst b/configuration/package_scripts/_generated/c8y-configuration-plugin/deb/postinst deleted file mode 100755 index b249a02c887..00000000000 --- a/configuration/package_scripts/_generated/c8y-configuration-plugin/deb/postinst +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/sh -set -e -# Automatically added by thin-edge.io -if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ] || [ "$1" = "abort-deconfigure" ] || [ "$1" = "abort-remove" ] ; then - # This will only remove masks created by d-s-h on package removal. - deb-systemd-helper unmask c8y-configuration-plugin.service >/dev/null || true - - # was-enabled defaults to true, so new installations run enable. - if deb-systemd-helper --quiet was-enabled c8y-configuration-plugin.service; then - # Enables the unit on first installation, creates new - # symlinks on upgrades if the unit file has changed. - deb-systemd-helper enable c8y-configuration-plugin.service >/dev/null || true - else - # Update the statefile to add new symlinks (if any), which need to be - # cleaned up on purge. Also remove old symlinks. - deb-systemd-helper update-state c8y-configuration-plugin.service >/dev/null || true - fi -fi -# End automatically added section -# Automatically added by thin-edge.io -if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ] || [ "$1" = "abort-deconfigure" ] || [ "$1" = "abort-remove" ] ; then - if [ -d /run/systemd/system ]; then - systemctl --system daemon-reload >/dev/null || true - if [ -n "$2" ]; then - _dh_action=restart - else - _dh_action=start - fi - deb-systemd-invoke $_dh_action c8y-configuration-plugin.service >/dev/null || true - fi -fi -# End automatically added section \ No newline at end of file diff --git a/configuration/package_scripts/_generated/c8y-configuration-plugin/deb/postrm b/configuration/package_scripts/_generated/c8y-configuration-plugin/deb/postrm deleted file mode 100755 index 5f67134b611..00000000000 --- a/configuration/package_scripts/_generated/c8y-configuration-plugin/deb/postrm +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/sh -set -e -# Automatically added by thin-edge.io -if [ -d /run/systemd/system ]; then - systemctl --system daemon-reload >/dev/null || true -fi -# End automatically added section -# Automatically added by thin-edge.io -if [ "$1" = "remove" ]; then - if [ -x "/usr/bin/deb-systemd-helper" ]; then - deb-systemd-helper mask c8y-configuration-plugin.service >/dev/null || true - fi -fi - -if [ "$1" = "purge" ]; then - if [ -x "/usr/bin/deb-systemd-helper" ]; then - deb-systemd-helper purge c8y-configuration-plugin.service >/dev/null || true - deb-systemd-helper unmask c8y-configuration-plugin.service >/dev/null || true - fi -fi -# End automatically added section \ No newline at end of file diff --git a/configuration/package_scripts/_generated/c8y-configuration-plugin/deb/preinst b/configuration/package_scripts/_generated/c8y-configuration-plugin/deb/preinst deleted file mode 100644 index d37118bbe57..00000000000 --- a/configuration/package_scripts/_generated/c8y-configuration-plugin/deb/preinst +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -set -e diff --git a/configuration/package_scripts/_generated/c8y-configuration-plugin/deb/prerm b/configuration/package_scripts/_generated/c8y-configuration-plugin/deb/prerm deleted file mode 100755 index 534473ef56e..00000000000 --- a/configuration/package_scripts/_generated/c8y-configuration-plugin/deb/prerm +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh -set -e -# Automatically added by thin-edge.io -if [ -d /run/systemd/system ] && [ "$1" = remove ]; then - deb-systemd-invoke stop c8y-configuration-plugin.service >/dev/null || true -fi -# End automatically added section \ No newline at end of file diff --git a/configuration/package_scripts/_generated/c8y-configuration-plugin/rpm/postinst b/configuration/package_scripts/_generated/c8y-configuration-plugin/rpm/postinst deleted file mode 100644 index c50f82a7e6a..00000000000 --- a/configuration/package_scripts/_generated/c8y-configuration-plugin/rpm/postinst +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh -set -e -# Automatically added by thin-edge.io -if [ $1 -eq 1 ] && [ -x "/usr/lib/systemd/systemd-update-helper" ]; then - # Initial installation - /usr/lib/systemd/systemd-update-helper install-system-units c8y-configuration-plugin.service || : -fi -# End automatically added section -# Automatically added by thin-edge.io -if [ -d /run/systemd/system ]; then - systemctl --system daemon-reload >/dev/null || true - if [ $1 -eq 2 ]; then - _dh_action=restart - else - _dh_action=start - fi - systemctl $_dh_action c8y-configuration-plugin.service >/dev/null || true -fi -# End automatically added section \ No newline at end of file diff --git a/configuration/package_scripts/_generated/c8y-configuration-plugin/rpm/postrm b/configuration/package_scripts/_generated/c8y-configuration-plugin/rpm/postrm deleted file mode 100644 index 33857c6897e..00000000000 --- a/configuration/package_scripts/_generated/c8y-configuration-plugin/rpm/postrm +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh -set -e -# Automatically added by thin-edge.io -if [ -d /run/systemd/system ]; then - systemctl --system daemon-reload >/dev/null || true -fi -# End automatically added section -# Automatically added by thin-edge.io -if [ $1 -ge 1 ] && [ -x "/usr/lib/systemd/systemd-update-helper" ]; then - # Package upgrade, not uninstall - /usr/lib/systemd/systemd-update-helper mark-restart-system-units c8y-configuration-plugin.service || : -fi - -# End automatically added section \ No newline at end of file diff --git a/configuration/package_scripts/_generated/c8y-configuration-plugin/rpm/preinst b/configuration/package_scripts/_generated/c8y-configuration-plugin/rpm/preinst deleted file mode 100644 index d37118bbe57..00000000000 --- a/configuration/package_scripts/_generated/c8y-configuration-plugin/rpm/preinst +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -set -e diff --git a/configuration/package_scripts/_generated/c8y-configuration-plugin/rpm/prerm b/configuration/package_scripts/_generated/c8y-configuration-plugin/rpm/prerm deleted file mode 100644 index bcec8f6347f..00000000000 --- a/configuration/package_scripts/_generated/c8y-configuration-plugin/rpm/prerm +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -set -e -# Automatically added by thin-edge.io -if [ $1 -eq 0 ] && [ -x "/usr/lib/systemd/systemd-update-helper" ]; then - # Package removal, not upgrade - /usr/lib/systemd/systemd-update-helper remove-system-units c8y-configuration-plugin.service || : -fi -# End automatically added section \ No newline at end of file diff --git a/configuration/package_scripts/packages.json b/configuration/package_scripts/packages.json index 2da4c42c2f4..21b612764af 100644 --- a/configuration/package_scripts/packages.json +++ b/configuration/package_scripts/packages.json @@ -15,11 +15,6 @@ {"name": "tedge-agent", "enable": false, "start": false, "restart_after_upgrade": false, "stop_on_upgrade": false} ] }, - "c8y-configuration-plugin": { - "services": [ - {"name": "c8y-configuration-plugin", "enable": true, "start": true, "restart_after_upgrade": true, "stop_on_upgrade": true} - ] - }, "c8y-firmware-plugin": { "services": [ {"name": "c8y-firmware-plugin", "enable": true, "start": true, "restart_after_upgrade": true, "stop_on_upgrade": true} diff --git a/crates/common/tedge_config/src/system_services/managers/config.rs b/crates/common/tedge_config/src/system_services/managers/config.rs index 9da9a7b61a7..3f2436c24a2 100644 --- a/crates/common/tedge_config/src/system_services/managers/config.rs +++ b/crates/common/tedge_config/src/system_services/managers/config.rs @@ -159,7 +159,6 @@ mod tests { tedge_mapper = "Debug" tedge_agent = "Info" tedge_watchdog = "Warn" - c8y_config_plugin = "Debug" "#, ) .unwrap(); @@ -185,7 +184,6 @@ mod tests { assert_eq!(config.log.get("tedge_mapper").unwrap(), "Debug"); assert_eq!(config.log.get("tedge_agent").unwrap(), "Info"); assert_eq!(config.log.get("tedge_watchdog").unwrap(), "Warn"); - assert_eq!(config.log.get("c8y_config_plugin").unwrap(), "Debug"); } #[test] @@ -214,7 +212,6 @@ mod tests { tedge_mapper = "Debug" tedge_agent = "Info" tedge_watchdog = "Warn" - c8y_config_plugin = "Debug" "#; let expected_config: SystemConfig = toml::from_str(toml_conf)?; let (_dir, config_root_path) = create_temp_system_config(toml_conf)?; diff --git a/crates/extensions/c8y_config_manager/Cargo.toml b/crates/extensions/c8y_config_manager/Cargo.toml deleted file mode 100644 index bbb7826b442..00000000000 --- a/crates/extensions/c8y_config_manager/Cargo.toml +++ /dev/null @@ -1,37 +0,0 @@ -[package] -name = "c8y_config_manager" -description = "thin-edge Cumulocity extension adding support for configuration management" -version = { workspace = true } -authors = { workspace = true } -edition = { workspace = true } -rust-version = { workspace = true } -license = { workspace = true } -homepage = { workspace = true } -repository = { workspace = true } - -[dependencies] -async-trait = { workspace = true } -c8y_api = { workspace = true } -c8y_http_proxy = { workspace = true } -log = { workspace = true } -serde = { workspace = true } -serde_json = { workspace = true } -tedge_actors = { workspace = true } -tedge_api = { workspace = true } -tedge_config = { workspace = true } -tedge_file_system_ext = { workspace = true } -tedge_mqtt_ext = { workspace = true } -tedge_timer_ext = { workspace = true } -tedge_utils = { workspace = true } -thiserror = { workspace = true } -tokio = { workspace = true, features = ["macros"] } -toml = { workspace = true } - -[dev-dependencies] -tedge_actors = { workspace = true, features = ["test-helpers"] } -tedge_test_utils = { workspace = true } -tokio = { workspace = true, features = ["time", "test-util"] } -toml = { workspace = true } - -[lints] -workspace = true diff --git a/crates/extensions/c8y_config_manager/src/actor.rs b/crates/extensions/c8y_config_manager/src/actor.rs deleted file mode 100644 index 6cb48e2a343..00000000000 --- a/crates/extensions/c8y_config_manager/src/actor.rs +++ /dev/null @@ -1,449 +0,0 @@ -use super::child_device::get_child_id_from_child_topic; -use super::child_device::get_operation_name_from_child_topic; -use super::child_device::ChildConfigOperationKey; -use super::child_device::ConfigOperationResponse; -use super::download::ConfigDownloadManager; -use super::download::DownloadConfigFileStatusMessage; -use super::error::ConfigManagementError; -use super::plugin_config::PluginConfig; -use super::upload::ConfigUploadManager; -use super::upload::UploadConfigFileStatusMessage; -use super::ConfigManagerConfig; -use super::DEFAULT_PLUGIN_CONFIG_FILE_NAME; -use crate::child_device::InvalidChildDeviceTopicError; -use async_trait::async_trait; -use c8y_api::smartrest::smartrest_deserializer::SmartRestConfigDownloadRequest; -use c8y_api::smartrest::smartrest_deserializer::SmartRestConfigUploadRequest; -use c8y_api::smartrest::smartrest_deserializer::SmartRestRequestGeneric; -use c8y_api::smartrest::smartrest_serializer::OperationStatusMessage; -use c8y_api::smartrest::topic::C8yTopic; -use c8y_http_proxy::handle::C8YHttpProxy; -use log::error; -use tedge_actors::fan_in_message_type; -use tedge_actors::Actor; -use tedge_actors::ChannelError; -use tedge_actors::LoggingReceiver; -use tedge_actors::LoggingSender; -use tedge_actors::MessageReceiver; -use tedge_actors::RuntimeError; -use tedge_actors::RuntimeRequest; -use tedge_actors::Sender; -use tedge_actors::WrappedInput; -use tedge_file_system_ext::FsWatchEvent; -use tedge_mqtt_ext::MqttMessage; -use tedge_mqtt_ext::Topic; -use tedge_timer_ext::SetTimeout; -use tedge_timer_ext::Timeout; -use tedge_utils::paths::PathsError; - -pub type OperationTimer = SetTimeout; -pub type OperationTimeout = Timeout; - -fan_in_message_type!(ConfigInput[MqttMessage, FsWatchEvent, OperationTimeout] : Debug); -fan_in_message_type!(ConfigOutput[MqttMessage, OperationTimer] : Debug); - -pub struct ConfigManagerActor { - config: ConfigManagerConfig, - plugin_config: PluginConfig, - config_upload_manager: ConfigUploadManager, - config_download_manager: ConfigDownloadManager, - messages: ConfigManagerMessageBox, -} - -impl ConfigManagerActor { - pub fn new( - config: ConfigManagerConfig, - plugin_config: PluginConfig, - messages: ConfigManagerMessageBox, - ) -> Self { - let config_upload_manager = ConfigUploadManager::new(config.clone()); - - let config_download_manager = ConfigDownloadManager::new(config.clone()); - - ConfigManagerActor { - config, - plugin_config, - config_upload_manager, - config_download_manager, - messages, - } - } - - pub async fn process_mqtt_message( - &mut self, - message: MqttMessage, - ) -> Result<(), ConfigManagementError> { - if self.config.c8y_request_topics.accept(&message) { - self.process_smartrest_message(message).await?; - } else if self.config.config_snapshot_response_topics.accept(&message) - || self.config.config_update_response_topics.accept(&message) - { - self.handle_child_device_config_operation_response(&message) - .await?; - } else { - error!( - "Received unexpected message on topic: {}", - message.topic.name - ); - } - Ok(()) - } - - pub async fn process_smartrest_message( - &mut self, - message: MqttMessage, - ) -> Result<(), ConfigManagementError> { - let payload = message.payload_str()?; - for smartrest_message in payload.split('\n') { - let result: Result<(), ConfigManagementError> = match smartrest_message - .split(',') - .next() - .unwrap_or_default() - { - "524" => { - let maybe_config_download_request = - SmartRestConfigDownloadRequest::from_smartrest(smartrest_message); - if let Ok(config_download_request) = maybe_config_download_request { - if let Err(err) = self - .config_download_manager - .handle_config_download_request( - config_download_request, - &mut self.messages, - ) - .await - { - Self::fail_config_operation_in_c8y( - ConfigOperation::Update, - None, - ActiveOperationState::Pending, - &format!("Failed due to {err}"), - &mut self.messages, - ) - .await?; - } - } else { - error!("Incorrect Download SmartREST payload: {smartrest_message}"); - } - Ok(()) - } - "526" => { - // retrieve config file upload smartrest request from payload - let maybe_config_upload_request = - SmartRestConfigUploadRequest::from_smartrest(smartrest_message); - - if let Ok(config_upload_request) = maybe_config_upload_request { - // handle the config file upload request - if let Err(err) = self - .config_upload_manager - .handle_config_upload_request(config_upload_request, &mut self.messages) - .await - { - Self::fail_config_operation_in_c8y( - ConfigOperation::Snapshot, - None, - ActiveOperationState::Pending, - &format!("Failed due to {err}"), - &mut self.messages, - ) - .await?; - } - } else { - error!("Incorrect Upload SmartREST payload: {smartrest_message}"); - } - Ok(()) - } - _ => { - // Ignore operation messages not meant for this plugin - Ok(()) - } - }; - - if let Err(err) = result { - error!("Handling of operation: '{smartrest_message}' failed with {err}"); - } - } - - Ok(()) - } - - pub async fn handle_child_device_config_operation_response( - &mut self, - message: &MqttMessage, - ) -> Result<(), ConfigManagementError> { - match ConfigOperationResponse::try_from(message) { - Ok(config_response) => { - let smartrest_responses = match &config_response { - ConfigOperationResponse::Update { .. } => { - self.config_download_manager - .handle_child_device_config_update_response( - &config_response, - &mut self.messages, - ) - .await? - } - ConfigOperationResponse::Snapshot { .. } => { - self.config_upload_manager - .handle_child_device_config_snapshot_response( - &config_response, - &mut self.messages, - ) - .await? - } - }; - - for smartrest_response in smartrest_responses { - self.messages.send(smartrest_response.into()).await? - } - - Ok(()) - } - Err(err) => { - let config_operation = message.try_into()?; - let child_id = get_child_id_from_child_topic(&message.topic.name)?; - - Self::fail_config_operation_in_c8y( - config_operation, - Some(child_id), - ActiveOperationState::Pending, - &err.to_string(), - &mut self.messages, - ) - .await - } - } - } - - pub async fn process_file_watch_events( - &mut self, - event: FsWatchEvent, - ) -> Result<(), ConfigManagementError> { - let path = match event { - FsWatchEvent::Modified(path) => path, - FsWatchEvent::FileDeleted(path) => path, - FsWatchEvent::FileCreated(path) => path, - FsWatchEvent::DirectoryDeleted(_) => return Ok(()), - FsWatchEvent::DirectoryCreated(_) => return Ok(()), - }; - - if let Some(file_name) = path.file_name() { - // this if check is done to avoid matching on temporary files created by editors - if file_name.eq(DEFAULT_PLUGIN_CONFIG_FILE_NAME) { - let parent_dir_name = path.parent().and_then(|dir| dir.file_name()).ok_or( - PathsError::ParentDirNotFound { - path: path.as_os_str().into(), - }, - )?; - - if parent_dir_name.eq("c8y") { - self.publish_supported_config_types().await?; - } else { - // this is a child device - let plugin_config = PluginConfig::new(&path); - let message = plugin_config.to_supported_config_types_message_for_child( - &parent_dir_name.to_string_lossy(), - )?; - self.messages.send(message.into()).await?; - } - } - } - - Ok(()) - } - - pub async fn process_operation_timeout( - &mut self, - timeout: OperationTimeout, - ) -> Result<(), ConfigManagementError> { - match timeout.event.operation_type { - ConfigOperation::Snapshot => { - self.config_upload_manager - .process_operation_timeout(timeout, &mut self.messages) - .await - } - ConfigOperation::Update => { - self.config_download_manager - .process_operation_timeout(timeout, &mut self.messages) - .await - } - } - } - - async fn publish_supported_config_types(&mut self) -> Result<(), ConfigManagementError> { - self.plugin_config = PluginConfig::new(self.config.plugin_config_path.as_path()); - let message = self.plugin_config.to_supported_config_types_message()?; - self.messages.send(message.into()).await?; - Ok(()) - } - - async fn get_pending_operations_from_cloud(&mut self) -> Result<(), ConfigManagementError> { - // Get pending operations - let message = MqttMessage::new(&C8yTopic::SmartRestResponse.to_topic()?, "500"); - self.messages.send(message.into()).await?; - Ok(()) - } - - pub async fn fail_config_operation_in_c8y( - config_operation: ConfigOperation, - child_id: Option, - op_state: ActiveOperationState, - failure_reason: &str, - message_box: &mut ConfigManagerMessageBox, - ) -> Result<(), ConfigManagementError> { - // Fail the operation in the cloud by sending EXECUTING and FAILED responses back to back - let executing_msg; - let failed_msg; - - if let Some(child_id) = child_id { - let c8y_child_topic = - Topic::new_unchecked(&C8yTopic::ChildSmartRestResponse(child_id).to_string()); - - match config_operation { - ConfigOperation::Snapshot => { - executing_msg = MqttMessage::new( - &c8y_child_topic, - UploadConfigFileStatusMessage::status_executing(), - ); - failed_msg = MqttMessage::new( - &c8y_child_topic, - UploadConfigFileStatusMessage::status_failed(failure_reason), - ); - } - ConfigOperation::Update => { - executing_msg = MqttMessage::new( - &c8y_child_topic, - DownloadConfigFileStatusMessage::status_executing(), - ); - failed_msg = MqttMessage::new( - &c8y_child_topic, - DownloadConfigFileStatusMessage::status_failed(failure_reason), - ); - } - } - } else { - match config_operation { - ConfigOperation::Snapshot => { - executing_msg = UploadConfigFileStatusMessage::executing(); - failed_msg = UploadConfigFileStatusMessage::failed(failure_reason); - } - ConfigOperation::Update => { - executing_msg = DownloadConfigFileStatusMessage::executing(); - failed_msg = UploadConfigFileStatusMessage::failed(failure_reason); - } - }; - } - - if op_state == ActiveOperationState::Pending { - message_box.send(executing_msg.into()).await?; - } - message_box.send(failed_msg.into()).await?; - - Ok(()) - } -} - -#[async_trait] -impl Actor for ConfigManagerActor { - fn name(&self) -> &str { - "ConfigManager" - } - - async fn run(mut self) -> Result<(), RuntimeError> { - self.publish_supported_config_types().await?; - self.get_pending_operations_from_cloud().await?; - - while let Some(event) = self.messages.recv().await { - let result = match event { - ConfigInput::MqttMessage(message) => self.process_mqtt_message(message).await, - ConfigInput::FsWatchEvent(event) => self.process_file_watch_events(event).await, - ConfigInput::OperationTimeout(timeout) => { - self.process_operation_timeout(timeout).await - } - }; - - if let Err(err) = result { - error!("Error processing event: {err:?}"); - } - } - - Ok(()) - } -} - -pub struct ConfigManagerMessageBox { - input_receiver: LoggingReceiver, - pub mqtt_publisher: LoggingSender, - pub c8y_http_proxy: C8YHttpProxy, - timer_sender: LoggingSender>, -} - -impl ConfigManagerMessageBox { - pub fn new( - input_receiver: LoggingReceiver, - mqtt_publisher: LoggingSender, - c8y_http_proxy: C8YHttpProxy, - timer_sender: LoggingSender>, - ) -> ConfigManagerMessageBox { - ConfigManagerMessageBox { - input_receiver, - mqtt_publisher, - c8y_http_proxy, - timer_sender, - } - } - - pub async fn send(&mut self, message: ConfigOutput) -> Result<(), ChannelError> { - match message { - ConfigOutput::MqttMessage(message) => self.mqtt_publisher.send(message).await, - ConfigOutput::OperationTimer(message) => self.timer_sender.send(message).await, - } - } -} - -#[async_trait] -impl MessageReceiver for ConfigManagerMessageBox { - async fn try_recv(&mut self) -> Result, RuntimeRequest> { - self.input_receiver.try_recv().await - } - - async fn recv_message(&mut self) -> Option> { - self.input_receiver.recv_message().await - } - - async fn recv(&mut self) -> Option { - self.input_receiver.recv().await - } - - async fn recv_signal(&mut self) -> Option { - self.input_receiver.recv_signal().await - } -} - -#[derive(Debug, PartialEq, Eq, Hash, Clone)] -pub enum ConfigOperation { - Snapshot, - Update, -} - -impl TryFrom<&MqttMessage> for ConfigOperation { - type Error = InvalidChildDeviceTopicError; - - fn try_from(message: &MqttMessage) -> Result { - let operation_name = get_operation_name_from_child_topic(&message.topic.name)?; - - if operation_name == "config_snapshot" { - Ok(Self::Snapshot) - } else if operation_name == "config_update" { - Ok(Self::Update) - } else { - Err(InvalidChildDeviceTopicError { - topic: message.topic.name.clone(), - }) - } - } -} - -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -pub enum ActiveOperationState { - Pending, - Executing, -} diff --git a/crates/extensions/c8y_config_manager/src/child_device.rs b/crates/extensions/c8y_config_manager/src/child_device.rs deleted file mode 100644 index 8898672477e..00000000000 --- a/crates/extensions/c8y_config_manager/src/child_device.rs +++ /dev/null @@ -1,305 +0,0 @@ -use super::actor::ConfigOperation; -use super::plugin_config::FileEntry; -use c8y_api::smartrest::topic::C8yTopic; -use log::error; -use std::fs; -use std::path::PathBuf; -use std::time::Duration; -use tedge_api::OperationStatus; -use tedge_mqtt_ext::MqttMessage; -use tedge_mqtt_ext::Topic; -use tedge_mqtt_ext::TopicFilter; -use thiserror::Error; - -pub const DEFAULT_OPERATION_TIMEOUT: Duration = Duration::from_secs(60); //TODO: Make this configurable? - -#[derive(Debug, Clone, Eq, PartialEq)] -pub enum ConfigOperationResponseTopic { - SnapshotResponse, - UpdateResponse, -} - -#[allow(clippy::from_over_into)] -// can not implement From since the topic can be anything (`new_unchecked` can be any &str) -impl Into for ConfigOperationResponseTopic { - fn into(self) -> TopicFilter { - match self { - ConfigOperationResponseTopic::SnapshotResponse => { - TopicFilter::new_unchecked("tedge/+/commands/res/config_snapshot") - } - ConfigOperationResponseTopic::UpdateResponse => { - TopicFilter::new_unchecked("tedge/+/commands/res/config_update") - } - } - } -} - -pub trait ConfigOperationMessage { - fn http_file_repository_relative_path(&self) -> String; - - fn file_transfer_repository_full_path(&self, file_transfer_dir: PathBuf) -> PathBuf { - file_transfer_dir.join(self.http_file_repository_relative_path()) - } -} - -/// A child device can receive the following operation requests: -/// -/// - Update: -/// -/// An operation that requests the child device to update its configuration with an update from the cloud. -/// -/// - Snapshot: -/// -/// An operation that requests the child device to upload its current configuration snapshot to the cloud. -pub enum ConfigOperationRequest { - Update { - child_id: String, - file_entry: FileEntry, - }, - Snapshot { - child_id: String, - file_entry: FileEntry, - }, -} - -pub enum ConfigOperationResponse { - Update { - child_id: String, - payload: ChildDeviceResponsePayload, - }, - Snapshot { - child_id: String, - payload: ChildDeviceResponsePayload, - }, -} - -impl ConfigOperationResponse { - pub fn get_child_id(&self) -> String { - match self { - ConfigOperationResponse::Update { child_id, .. } => child_id.to_string(), - ConfigOperationResponse::Snapshot { child_id, .. } => child_id.to_string(), - } - } - - pub fn get_config_type(&self) -> String { - match self { - ConfigOperationResponse::Update { payload, .. } => payload.config_type.to_string(), - ConfigOperationResponse::Snapshot { payload, .. } => payload.config_type.to_string(), - } - } - - pub fn get_child_topic(&self) -> String { - match self { - ConfigOperationResponse::Update { child_id, .. } => { - C8yTopic::ChildSmartRestResponse(child_id.to_owned()).to_string() - } - ConfigOperationResponse::Snapshot { child_id, .. } => { - C8yTopic::ChildSmartRestResponse(child_id.to_owned()).to_string() - } - } - } - - pub fn get_payload(&self) -> &ChildDeviceResponsePayload { - match self { - ConfigOperationResponse::Update { payload, .. } => payload, - ConfigOperationResponse::Snapshot { payload, .. } => payload, - } - } -} - -impl ConfigOperationMessage for ConfigOperationResponse { - fn http_file_repository_relative_path(&self) -> String { - match self { - ConfigOperationResponse::Update { - child_id, payload, .. - } => { - format!("{}/config_update/{}", child_id, payload.config_type) - } - ConfigOperationResponse::Snapshot { - child_id, payload, .. - } => { - format!("{}/config_snapshot/{}", child_id, payload.config_type) - } - } - } -} - -pub fn try_cleanup_config_file_from_file_transfer_repositoy( - file_transfer_dir: PathBuf, - config_response: &ConfigOperationResponse, -) { - let config_file_path = config_response.file_transfer_repository_full_path(file_transfer_dir); - if let Err(err) = fs::remove_file(&config_file_path) { - error!( - "Failed to remove config file copy at {:?} with {}", - config_file_path, err - ); - } -} - -/// Return child id from topic. -pub fn get_child_id_from_child_topic(topic: &str) -> Result { - let mut topic_split = topic.split('/'); - // the second element is the child id - let child_id = topic_split.nth(1).ok_or(InvalidChildDeviceTopicError { - topic: topic.into(), - })?; - Ok(child_id.to_string()) -} - -/// Return operation name from topic. -pub fn get_operation_name_from_child_topic( - topic: &str, -) -> Result { - let topic_split = topic.split('/'); - let operation_name = topic_split.last().ok_or(InvalidChildDeviceTopicError { - topic: topic.into(), - })?; - Ok(operation_name.to_string()) -} - -#[derive(Error, Debug)] -#[error("Message received on invalid topic from child device: {topic}")] -pub struct InvalidChildDeviceTopicError { - pub topic: String, -} - -impl TryFrom<&MqttMessage> for ConfigOperationResponse { - type Error = ParseOperationResponseError; - - fn try_from(message: &MqttMessage) -> Result { - let topic = &message.topic.name; - let child_id = get_child_id_from_child_topic(topic)?; - let operation_name = get_operation_name_from_child_topic(topic)?; - - let request_payload: ChildDeviceResponsePayload = - serde_json::from_slice(message.payload.as_bytes())?; - - if operation_name == "config_snapshot" { - return Ok(Self::Snapshot { - child_id, - payload: request_payload, - }); - } - if operation_name == "config_update" { - return Ok(Self::Update { - child_id, - payload: request_payload, - }); - } - Err(InvalidChildDeviceTopicError { - topic: topic.to_string(), - } - .into()) - } -} - -#[derive(Error, Debug)] -pub enum ParseOperationResponseError { - #[error("Failed to parse response from child device with: {0}")] - DeserializationError(#[from] serde_json::Error), - - #[error(transparent)] - InvalidChildDeviceTopic(#[from] InvalidChildDeviceTopicError), -} - -impl ConfigOperationRequest { - /// The configuration management topic for a child device. - /// - /// # Example: - /// For a configuration update returns: - /// - "tedge/CHILD_ID/commands/req/config_update" - /// - /// For a configuration snapshot returns: - /// - "tedge/CHILD_ID/commands/req/config_snapshot" - pub fn operation_request_topic(&self) -> Topic { - match self { - ConfigOperationRequest::Update { child_id, .. } => { - Topic::new_unchecked(&format!("tedge/{}/commands/req/config_update", child_id)) - } - ConfigOperationRequest::Snapshot { child_id, .. } => { - Topic::new_unchecked(&format!("tedge/{}/commands/req/config_snapshot", child_id)) - } - } - } - - /// The configuration management payload for a child device. - pub fn operation_request_payload( - &self, - local_http_host: &str, - ) -> Result { - let url = format!( - "http://{local_http_host}/tedge/file-transfer/{}", - self.http_file_repository_relative_path() - ); - match self { - ConfigOperationRequest::Update { - child_id: _, - file_entry, - } => { - let request = ChildDeviceRequestPayload { - url, - path: file_entry.path.clone(), - config_type: Some(file_entry.config_type.clone()), - }; - Ok(serde_json::to_string(&request)?) - } - ConfigOperationRequest::Snapshot { - child_id: _, - file_entry, - } => { - let request = ChildDeviceRequestPayload { - url, - path: file_entry.path.clone(), - config_type: Some(file_entry.config_type.clone()), - }; - Ok(serde_json::to_string(&request)?) - } - } - } -} - -impl ConfigOperationMessage for ConfigOperationRequest { - fn http_file_repository_relative_path(&self) -> String { - match self { - ConfigOperationRequest::Update { - child_id, - file_entry, - .. - } => { - format!("{}/config_update/{}", child_id, file_entry.config_type) - } - ConfigOperationRequest::Snapshot { - child_id, - file_entry, - .. - } => { - format!("{}/config_snapshot/{}", child_id, file_entry.config_type) - } - } - } -} - -#[derive(serde::Serialize, serde::Deserialize)] -pub struct ChildDeviceResponsePayload { - pub status: Option, - pub path: String, - #[serde(rename = "type")] - pub config_type: String, - pub reason: Option, -} - -#[derive(serde::Serialize, serde::Deserialize)] -pub struct ChildDeviceRequestPayload { - pub url: String, - pub path: String, - #[serde(rename = "type")] - pub config_type: Option, -} - -#[derive(Debug, PartialEq, Eq, Hash, Clone)] -pub struct ChildConfigOperationKey { - pub child_id: String, - pub operation_type: ConfigOperation, - pub config_type: String, -} diff --git a/crates/extensions/c8y_config_manager/src/config.rs b/crates/extensions/c8y_config_manager/src/config.rs deleted file mode 100644 index c43939499c0..00000000000 --- a/crates/extensions/c8y_config_manager/src/config.rs +++ /dev/null @@ -1,102 +0,0 @@ -use super::child_device::ConfigOperationResponseTopic; - -use c8y_api::smartrest::topic::C8yTopic; -use std::path::Path; -use std::path::PathBuf; -use std::sync::Arc; -use tedge_api::path::DataDir; -use tedge_config::ReadError; -use tedge_config::TEdgeConfig; -use tedge_mqtt_ext::TopicFilter; - -pub const DEFAULT_PLUGIN_CONFIG_FILE_NAME: &str = "c8y-configuration-plugin.toml"; -pub const DEFAULT_OPERATION_DIR_NAME: &str = "c8y/"; -pub const DEFAULT_PLUGIN_CONFIG_TYPE: &str = "c8y-configuration-plugin"; - -/// Configuration of the Configuration Manager -#[derive(Clone, Debug)] -pub struct ConfigManagerConfig { - pub config_dir: PathBuf, - pub tmp_dir: PathBuf, - pub file_transfer_dir: PathBuf, - pub device_id: String, - pub mqtt_host: String, - pub mqtt_port: u16, - pub tedge_http_host: Arc, - pub ops_dir: PathBuf, - pub plugin_config_dir: PathBuf, - pub plugin_config_path: PathBuf, - pub c8y_request_topics: TopicFilter, - pub config_snapshot_response_topics: TopicFilter, - pub config_update_response_topics: TopicFilter, -} - -impl ConfigManagerConfig { - #[allow(clippy::too_many_arguments)] - pub fn new( - config_dir: PathBuf, - tmp_dir: PathBuf, - data_dir: DataDir, - device_id: String, - mqtt_host: String, - mqtt_port: u16, - tedge_http_host: Arc, - tedge_http_port: u16, - ) -> Self { - let tedge_http_host = format!("{}:{}", tedge_http_host, tedge_http_port).into(); - - let ops_dir = config_dir.join("operations/c8y"); - let plugin_config_dir = config_dir.join(DEFAULT_OPERATION_DIR_NAME); - let plugin_config_path = plugin_config_dir.join(DEFAULT_PLUGIN_CONFIG_FILE_NAME); - - let file_transfer_dir = data_dir.file_transfer_dir().into(); - - let c8y_request_topics: TopicFilter = C8yTopic::SmartRestRequest.into(); - let config_snapshot_response_topics: TopicFilter = - ConfigOperationResponseTopic::SnapshotResponse.into(); - let config_update_response_topics: TopicFilter = - ConfigOperationResponseTopic::UpdateResponse.into(); - - ConfigManagerConfig { - config_dir, - tmp_dir, - file_transfer_dir, - device_id, - mqtt_host, - mqtt_port, - tedge_http_host, - ops_dir, - plugin_config_dir, - plugin_config_path, - c8y_request_topics, - config_snapshot_response_topics, - config_update_response_topics, - } - } - - pub fn from_tedge_config( - config_dir: impl AsRef, - tedge_config: &TEdgeConfig, - ) -> Result { - let config_dir = config_dir.as_ref().into(); - let device_id = tedge_config.device.id.try_read(tedge_config)?.to_string(); - let tmp_dir = tedge_config.tmp.path.as_std_path().to_path_buf(); - let data_dir = tedge_config.data.path.clone().into(); - let mqtt_host = tedge_config.mqtt.client.host.clone(); - let mqtt_port = tedge_config.mqtt.client.port.get(); - let tedge_http_host = tedge_config.http.client.host.clone(); - let tedge_http_port = tedge_config.http.client.port; - - let config = ConfigManagerConfig::new( - config_dir, - tmp_dir, - data_dir, - device_id, - mqtt_host, - mqtt_port, - tedge_http_host, - tedge_http_port, - ); - Ok(config) - } -} diff --git a/crates/extensions/c8y_config_manager/src/download.rs b/crates/extensions/c8y_config_manager/src/download.rs deleted file mode 100644 index 96806807c41..00000000000 --- a/crates/extensions/c8y_config_manager/src/download.rs +++ /dev/null @@ -1,364 +0,0 @@ -use crate::child_device::ChildConfigOperationKey; -use crate::child_device::DEFAULT_OPERATION_TIMEOUT; -use crate::plugin_config::InvalidConfigTypeError; - -use super::actor::ActiveOperationState; -use super::actor::ConfigManagerActor; -use super::actor::ConfigManagerMessageBox; -use super::actor::ConfigOperation; -use super::actor::OperationTimeout; -use super::child_device::try_cleanup_config_file_from_file_transfer_repositoy; -use super::child_device::ConfigOperationMessage; -use super::child_device::ConfigOperationRequest; -use super::child_device::ConfigOperationResponse; -use super::error::ConfigManagementError; -use super::plugin_config::FileEntry; -use super::plugin_config::PluginConfig; -use super::ConfigManagerConfig; -use super::DEFAULT_PLUGIN_CONFIG_FILE_NAME; -use c8y_api::smartrest::smartrest_deserializer::SmartRestConfigDownloadRequest; -use c8y_api::smartrest::smartrest_serializer::fail_operation; -use c8y_api::smartrest::smartrest_serializer::set_operation_executing; -use c8y_api::smartrest::smartrest_serializer::succeed_static_operation; -use c8y_api::smartrest::smartrest_serializer::CumulocitySupportedOperations; -use c8y_api::smartrest::smartrest_serializer::OperationStatusMessage; -use c8y_api::smartrest::smartrest_serializer::SmartRest; -use log::error; -use log::info; -use log::warn; -use serde_json::json; -use std::collections::HashMap; -use std::path::Path; -use std::path::PathBuf; -use tedge_actors::Sender; -use tedge_api::OperationStatus; -use tedge_mqtt_ext::MqttMessage; -use tedge_mqtt_ext::Topic; -use tedge_timer_ext::SetTimeout; -use tedge_utils::file::PermissionEntry; - -pub const CONFIG_CHANGE_TOPIC: &str = "tedge/configuration_change"; - -pub struct ConfigDownloadManager { - config: ConfigManagerConfig, - active_child_ops: HashMap, -} - -impl ConfigDownloadManager { - pub fn new(config: ConfigManagerConfig) -> Self { - let active_child_ops = HashMap::new(); - ConfigDownloadManager { - config, - active_child_ops, - } - } - - pub async fn handle_config_download_request( - &mut self, - smartrest_request: SmartRestConfigDownloadRequest, - message_box: &mut ConfigManagerMessageBox, - ) -> Result<(), ConfigManagementError> { - info!( - "Received c8y_DownloadConfigFile request for config type: {} from device: {}", - smartrest_request.config_type, smartrest_request.device - ); - - if smartrest_request.device == self.config.device_id { - self.handle_config_download_request_tedge_device(smartrest_request, message_box) - .await - } else { - self.handle_config_download_request_child_device(smartrest_request, message_box) - .await - } - } - - pub async fn handle_config_download_request_tedge_device( - &mut self, - smartrest_request: SmartRestConfigDownloadRequest, - message_box: &mut ConfigManagerMessageBox, - ) -> Result<(), ConfigManagementError> { - let executing_message = DownloadConfigFileStatusMessage::executing(); - message_box.mqtt_publisher.send(executing_message).await?; - - let target_config_type = smartrest_request.config_type.clone(); - let mut target_file_entry = FileEntry::default(); - - let plugin_config = PluginConfig::new(&self.config.plugin_config_path); - let download_result = match plugin_config.get_file_entry_from_type(&target_config_type) { - Ok(file_entry) => { - target_file_entry = file_entry; - self.download_config_file( - smartrest_request.url.as_str(), - PathBuf::from(&target_file_entry.path), - target_file_entry.file_permissions, - message_box, - ) - .await - } - Err(err) => Err(err.into()), - }; - - match download_result { - Ok(_) => { - info!("The configuration download for '{target_config_type}' is successful."); - - let successful_message = DownloadConfigFileStatusMessage::successful(None); - message_box.mqtt_publisher.send(successful_message).await?; - - let notification_message = get_file_change_notification_message( - &target_file_entry.path, - &target_config_type, - ); - message_box - .mqtt_publisher - .send(notification_message) - .await?; - Ok(()) - } - Err(err) => { - error!("The configuration download for '{target_config_type}' failed.",); - - let failed_message = DownloadConfigFileStatusMessage::failed(&err.to_string()); - message_box.mqtt_publisher.send(failed_message).await?; - Err(err) - } - } - } - - async fn download_config_file( - &mut self, - download_url: &str, - file_path: PathBuf, - file_permissions: PermissionEntry, - message_box: &mut ConfigManagerMessageBox, - ) -> Result<(), ConfigManagementError> { - message_box - .c8y_http_proxy - .download_file(download_url, file_path, file_permissions) - .await?; - - Ok(()) - } - - /// Map the c8y_DownloadConfigFile request into a tedge/commands/req/config_update command for the child device. - /// The config file update is shared with the child device via the file transfer service. - /// The configuration update is downloaded from Cumulocity and is uploaded to the file transfer service, - /// so that it can be shared with a child device. - /// A unique URL path for this config file, from the file transfer service, is shared with the child device in the command. - /// The child device can use this URL to download the config file update from the file transfer service. - pub async fn handle_config_download_request_child_device( - &mut self, - smartrest_request: SmartRestConfigDownloadRequest, - message_box: &mut ConfigManagerMessageBox, - ) -> Result<(), ConfigManagementError> { - let child_id = smartrest_request.device; - let config_type = smartrest_request.config_type; - - let operation_key = ChildConfigOperationKey { - child_id: child_id.clone(), - operation_type: ConfigOperation::Update, - config_type: config_type.clone(), - }; - - let plugin_config = PluginConfig::new(Path::new(&format!( - "{}/c8y/{child_id}/{DEFAULT_PLUGIN_CONFIG_FILE_NAME}", - self.config.config_dir.display(), - ))); - - match plugin_config.get_file_entry_from_type(&config_type) { - Ok(file_entry) => { - let config_management = ConfigOperationRequest::Update { - child_id: child_id.clone(), - file_entry, - }; - - if let Err(err) = self - .download_config_file( - smartrest_request.url.as_str(), - config_management.file_transfer_repository_full_path( - self.config.file_transfer_dir.clone(), - ), - PermissionEntry::new(None, None, None), //no need to change ownership of downloaded file - message_box, - ) - .await - { - // Fail the operation in the cloud if the file download itself fails - // by sending EXECUTING and FAILED responses back to back - - let failure_reason = format!( - "Downloading the config file update from {} failed with {}", - smartrest_request.url, err - ); - ConfigManagerActor::fail_config_operation_in_c8y( - ConfigOperation::Update, - Some(child_id), - ActiveOperationState::Pending, - &failure_reason, - message_box, - ) - .await?; - } else { - let config_update_req_msg = MqttMessage::new( - &config_management.operation_request_topic(), - config_management - .operation_request_payload(&self.config.tedge_http_host)?, - ); - message_box.send(config_update_req_msg.into()).await?; - info!("Config update request for config type: {config_type} sent to child device: {child_id}"); - - self.active_child_ops - .insert(operation_key.clone(), ActiveOperationState::Pending); - - // Start the timer for operation timeout - message_box - .send(SetTimeout::new(DEFAULT_OPERATION_TIMEOUT, operation_key).into()) - .await?; - } - } - Err(InvalidConfigTypeError { config_type }) => { - warn!( - "Ignoring the config operation request for unknown config type: {config_type}" - ); - } - } - - Ok(()) - } - - pub async fn handle_child_device_config_update_response( - &mut self, - config_response: &ConfigOperationResponse, - message_box: &mut ConfigManagerMessageBox, - ) -> Result, ConfigManagementError> { - let c8y_child_topic = Topic::new_unchecked(&config_response.get_child_topic()); - let child_device_payload = config_response.get_payload(); - let child_id = config_response.get_child_id(); - let config_type = config_response.get_config_type(); - let operation_key = ChildConfigOperationKey { - child_id: child_id.clone(), - operation_type: ConfigOperation::Update, - config_type: config_type.clone(), - }; - - info!("Config update response received for type: {config_type} from child: {child_id}"); - - let mut mapped_responses = vec![]; - if let Some(operation_status) = child_device_payload.status { - let current_operation_state = self.active_child_ops.get(&operation_key); - if current_operation_state != Some(&ActiveOperationState::Executing) { - let executing_status_payload = DownloadConfigFileStatusMessage::status_executing(); - mapped_responses.push(MqttMessage::new(&c8y_child_topic, executing_status_payload)); - } - - match operation_status { - OperationStatus::Successful => { - self.active_child_ops.remove(&operation_key); - - // Cleanup the downloaded file after the operation completes - try_cleanup_config_file_from_file_transfer_repositoy( - self.config.file_transfer_dir.clone(), - config_response, - ); - let successful_status_payload = - DownloadConfigFileStatusMessage::status_successful(None); - mapped_responses.push(MqttMessage::new( - &c8y_child_topic, - successful_status_payload, - )); - } - OperationStatus::Failed => { - self.active_child_ops.remove(&operation_key); - - // Cleanup the downloaded file after the operation completes - try_cleanup_config_file_from_file_transfer_repositoy( - self.config.file_transfer_dir.clone(), - config_response, - ); - if let Some(error_message) = &child_device_payload.reason { - let failed_status_payload = - DownloadConfigFileStatusMessage::status_failed(error_message); - mapped_responses - .push(MqttMessage::new(&c8y_child_topic, failed_status_payload)); - } else { - let default_error_message = "No fail reason provided by child device."; - let failed_status_payload = - DownloadConfigFileStatusMessage::status_failed(default_error_message); - mapped_responses - .push(MqttMessage::new(&c8y_child_topic, failed_status_payload)); - } - } - OperationStatus::Executing => { - self.active_child_ops - .insert(operation_key.clone(), ActiveOperationState::Executing); - - // Reset the timer - message_box - .send(SetTimeout::new(DEFAULT_OPERATION_TIMEOUT, operation_key).into()) - .await?; - } - } - - Ok(mapped_responses) - } else { - Err(ConfigManagementError::EmptyOperationStatus(c8y_child_topic)) - } - } - - pub async fn process_operation_timeout( - &mut self, - timeout: OperationTimeout, - message_box: &mut ConfigManagerMessageBox, - ) -> Result<(), ConfigManagementError> { - let child_id = timeout.event.child_id; - let config_type = timeout.event.config_type; - let operation_key = ChildConfigOperationKey { - child_id: child_id.clone(), - operation_type: ConfigOperation::Update, - config_type: config_type.clone(), - }; - - if let Some(operation_state) = self.active_child_ops.remove(&operation_key) { - ConfigManagerActor::fail_config_operation_in_c8y( - ConfigOperation::Update, - Some(child_id.clone()), - operation_state, - &format!("Timeout due to lack of response from child device: {child_id} for config type: {config_type}"), - message_box, - ).await - } else { - // Ignore the timeout as the operation has already completed. - Ok(()) - } - } -} - -pub fn get_file_change_notification_message(file_path: &str, config_type: &str) -> MqttMessage { - let notification = json!({ "path": file_path }).to_string(); - let topic = Topic::new(format!("{CONFIG_CHANGE_TOPIC}/{config_type}").as_str()) - .unwrap_or_else(|_err| { - warn!("The type cannot be used as a part of the topic name. Using {CONFIG_CHANGE_TOPIC} instead."); - Topic::new_unchecked(CONFIG_CHANGE_TOPIC) - }); - MqttMessage::new(&topic, notification) -} - -pub struct DownloadConfigFileStatusMessage {} - -impl DownloadConfigFileStatusMessage { - const OP: CumulocitySupportedOperations = CumulocitySupportedOperations::C8yDownloadConfigFile; -} - -impl OperationStatusMessage for DownloadConfigFileStatusMessage { - fn status_executing() -> SmartRest { - set_operation_executing(Self::OP) - } - - fn status_successful(parameter: Option<&str>) -> SmartRest { - succeed_static_operation(Self::OP, parameter) - } - - fn status_failed(failure_reason: &str) -> SmartRest { - fail_operation(Self::OP, failure_reason) - } -} diff --git a/crates/extensions/c8y_config_manager/src/error.rs b/crates/extensions/c8y_config_manager/src/error.rs deleted file mode 100644 index f1e89b68366..00000000000 --- a/crates/extensions/c8y_config_manager/src/error.rs +++ /dev/null @@ -1,47 +0,0 @@ -use std::io; -use tedge_actors::RuntimeError; -use tedge_mqtt_ext::Topic; -use tedge_utils::file::FileError; -use tedge_utils::paths::PathsError; - -#[derive(thiserror::Error, Debug)] -pub enum ConfigManagementError { - #[error(transparent)] - InvalidRequestedConfigType(#[from] super::plugin_config::InvalidConfigTypeError), - - #[error(transparent)] - InvalidChildDeviceTopic(#[from] super::child_device::InvalidChildDeviceTopicError), - - #[error("Invalid operation response with empty status received on topic: {0:?}")] - EmptyOperationStatus(Topic), - - #[error(transparent)] - FromFile(#[from] FileError), - - #[error(transparent)] - FromIoError(#[from] io::Error), - - #[error(transparent)] - FromMqttError(#[from] tedge_mqtt_ext::MqttError), - - #[error(transparent)] - FromSmartRestSerializerError(#[from] c8y_api::smartrest::error::SmartRestSerializerError), - - #[error("Failed to parse response from child device with: {0}")] - FromSerdeJsonError(#[from] serde_json::Error), - - #[error(transparent)] - FromChannelError(#[from] tedge_actors::ChannelError), - - #[error(transparent)] - FromC8YRestError(#[from] c8y_http_proxy::messages::C8YRestError), - - #[error(transparent)] - FromPathsError(#[from] PathsError), -} - -impl From for RuntimeError { - fn from(error: ConfigManagementError) -> Self { - RuntimeError::ActorError(Box::new(error)) - } -} diff --git a/crates/extensions/c8y_config_manager/src/lib.rs b/crates/extensions/c8y_config_manager/src/lib.rs deleted file mode 100644 index 37c1993d747..00000000000 --- a/crates/extensions/c8y_config_manager/src/lib.rs +++ /dev/null @@ -1,151 +0,0 @@ -mod actor; -mod child_device; -mod config; -mod download; -mod error; -mod plugin_config; -mod upload; - -#[cfg(test)] -mod tests; - -use self::child_device::ChildConfigOperationKey; -use actor::*; -use c8y_http_proxy::handle::C8YHttpProxy; -use c8y_http_proxy::messages::C8YRestRequest; -use c8y_http_proxy::messages::C8YRestResult; -pub use config::*; -use error::ConfigManagementError; -use plugin_config::PluginConfig; -use std::path::PathBuf; -use tedge_actors::futures::channel::mpsc; -use tedge_actors::Builder; -use tedge_actors::DynSender; -use tedge_actors::LinkError; -use tedge_actors::LoggingReceiver; -use tedge_actors::LoggingSender; -use tedge_actors::MessageSource; -use tedge_actors::NoConfig; -use tedge_actors::RuntimeRequest; -use tedge_actors::RuntimeRequestSink; -use tedge_actors::ServiceProvider; -use tedge_file_system_ext::FsWatchEvent; -use tedge_mqtt_ext::*; -use tedge_timer_ext::SetTimeout; -use tedge_utils::file::create_directory_with_defaults; -use tedge_utils::file::create_file_with_defaults; - -/// An instance of the config manager -/// -/// This is an actor builder. -pub struct ConfigManagerBuilder { - config: ConfigManagerConfig, - plugin_config: PluginConfig, - receiver: LoggingReceiver, - mqtt_publisher: DynSender, - c8y_http_proxy: C8YHttpProxy, - timer_sender: DynSender>, - signal_sender: mpsc::Sender, -} - -impl ConfigManagerConfig { - pub fn subscriptions(&self) -> TopicFilter { - vec![ - "c8y/s/ds", - "tedge/+/commands/res/config_snapshot", - "tedge/+/commands/res/config_update", - ] - .try_into() - .unwrap() - } - - pub fn config_directory(&self) -> PathBuf { - self.config_dir.clone().join(DEFAULT_OPERATION_DIR_NAME) - } -} - -impl ConfigManagerBuilder { - pub fn try_new( - config: ConfigManagerConfig, - mqtt: &mut impl ServiceProvider, - http: &mut impl ServiceProvider, - timer: &mut impl ServiceProvider, - fs_notify: &mut impl MessageSource, - ) -> Result { - Self::init(&config)?; - - let plugin_config = PluginConfig::new(&config.plugin_config_path); - - let (events_sender, events_receiver) = mpsc::channel(10); - let (signal_sender, signal_receiver) = mpsc::channel(10); - let receiver = LoggingReceiver::new( - "C8Y-Config-Manager".into(), - events_receiver, - signal_receiver, - ); - - let mqtt_publisher = - mqtt.connect_consumer(config.subscriptions(), events_sender.clone().into()); - let c8y_http_proxy = C8YHttpProxy::new("ConfigManager => C8Y", http); - let timer_sender = timer.connect_consumer(NoConfig, events_sender.clone().into()); - fs_notify.register_peer(config.config_directory(), events_sender.into()); - - Ok(ConfigManagerBuilder { - config, - plugin_config, - receiver, - mqtt_publisher, - c8y_http_proxy, - timer_sender, - signal_sender, - }) - } - - pub fn init(config: &ConfigManagerConfig) -> Result<(), ConfigManagementError> { - create_directory_with_defaults(&config.plugin_config_dir)?; - let example_config = r#"# Add the configurations to be managed by c8y-configuration-plugin -files = [ -# { path = '/etc/tedge/tedge.toml' }, -# { path = '/etc/tedge/mosquitto-conf/c8y-bridge.conf', type = 'c8y-bridge.conf' }, -# { path = '/etc/tedge/mosquitto-conf/tedge-mosquitto.conf', type = 'tedge-mosquitto.conf' }, -# { path = '/etc/mosquitto/mosquitto.conf', type = 'mosquitto.conf' }, -# { path = '/etc/tedge/c8y/example.txt', type = 'example', user = 'tedge', group = 'tedge', mode = 0o444 } -]"#; - create_file_with_defaults(&config.plugin_config_path, Some(example_config))?; - - create_directory_with_defaults(&config.ops_dir)?; - create_file_with_defaults(config.ops_dir.join("c8y_UploadConfigFile"), None)?; - create_file_with_defaults(config.ops_dir.join("c8y_DownloadConfigFile"), None)?; - - Ok(()) - } -} - -impl RuntimeRequestSink for ConfigManagerBuilder { - fn get_signal_sender(&self) -> DynSender { - Box::new(self.signal_sender.clone()) - } -} - -impl Builder for ConfigManagerBuilder { - type Error = LinkError; - - fn try_build(self) -> Result { - let mqtt_publisher = - LoggingSender::new("ConfigManager MQTT publisher".into(), self.mqtt_publisher); - let timer_sender = LoggingSender::new("ConfigManager timer".into(), self.timer_sender); - - let peers = ConfigManagerMessageBox::new( - self.receiver, - mqtt_publisher, - self.c8y_http_proxy, - timer_sender, - ); - - Ok(ConfigManagerActor::new( - self.config, - self.plugin_config, - peers, - )) - } -} diff --git a/crates/extensions/c8y_config_manager/src/plugin_config.rs b/crates/extensions/c8y_config_manager/src/plugin_config.rs deleted file mode 100644 index 13adaa24eb5..00000000000 --- a/crates/extensions/c8y_config_manager/src/plugin_config.rs +++ /dev/null @@ -1,201 +0,0 @@ -use super::DEFAULT_PLUGIN_CONFIG_TYPE; -use c8y_api::smartrest::topic::C8yTopic; -use log::error; -use log::info; -use serde::Deserialize; -use std::borrow::Borrow; -use std::collections::HashSet; -use std::fs; -use std::hash::Hash; -use std::hash::Hasher; -use std::path::Path; -use tedge_mqtt_ext::MqttError; -use tedge_mqtt_ext::MqttMessage; -use tedge_mqtt_ext::Topic; -use tedge_utils::file::PermissionEntry; - -#[derive(Deserialize, Debug, Default)] -#[serde(deny_unknown_fields)] -struct RawPluginConfig { - pub files: Vec, -} - -#[derive(Deserialize, Debug, Default, Eq, PartialEq)] -#[serde(deny_unknown_fields)] -pub struct RawFileEntry { - pub path: String, - #[serde(rename = "type")] - config_type: Option, - user: Option, - group: Option, - mode: Option, -} - -#[derive(Debug, Eq, PartialEq, Default, Clone)] -pub struct PluginConfig { - pub files: HashSet, -} - -#[derive(Debug, Eq, Default, Clone)] -pub struct FileEntry { - pub path: String, - pub config_type: String, - pub file_permissions: PermissionEntry, -} - -impl Hash for FileEntry { - fn hash(&self, state: &mut H) { - self.config_type.hash(state); - } -} - -impl PartialEq for FileEntry { - fn eq(&self, other: &Self) -> bool { - self.config_type == other.config_type - } -} - -impl Borrow for FileEntry { - fn borrow(&self) -> &String { - &self.config_type - } -} - -impl FileEntry { - pub fn new( - path: String, - config_type: String, - user: Option, - group: Option, - mode: Option, - ) -> Self { - Self { - path, - config_type, - file_permissions: PermissionEntry { user, group, mode }, - } - } -} - -impl RawPluginConfig { - fn new(config_file_path: &Path) -> Self { - let path_str = config_file_path.display().to_string(); - info!("Reading the config file from {}", path_str); - match fs::read_to_string(config_file_path) { - Ok(contents) => match toml::from_str(contents.as_str()) { - Ok(config) => config, - Err(err) => { - error!("The config file {path_str} is malformed. {err}"); - Self::default() - } - }, - Err(err) => { - error!("The config file {path_str} does not exist or is not readable. {err}"); - Self::default() - } - } - } -} - -impl PluginConfig { - pub fn new(config_file_path: &Path) -> Self { - let plugin_config = Self::new_with_config_file_entry(config_file_path); - let raw_config = RawPluginConfig::new(config_file_path); - plugin_config.add_entries_from_raw_config(raw_config) - } - - fn new_with_config_file_entry(config_file_path: &Path) -> Self { - let c8y_configuration_plugin = FileEntry::new( - config_file_path.display().to_string(), - DEFAULT_PLUGIN_CONFIG_TYPE.into(), - None, - None, - None, - ); - Self { - files: HashSet::from([c8y_configuration_plugin]), - } - } - - fn add_entries_from_raw_config(mut self, raw_config: RawPluginConfig) -> Self { - let original_plugin_config = self.clone(); - for raw_entry in raw_config.files { - let config_type = raw_entry - .config_type - .unwrap_or_else(|| raw_entry.path.clone()); - - if config_type.contains(['+', '#']) { - error!( - "The config type '{}' contains the forbidden characters, '+' or '#'.", - config_type - ); - return original_plugin_config; - } - - let entry = FileEntry::new( - raw_entry.path, - config_type.clone(), - raw_entry.user, - raw_entry.group, - raw_entry.mode, - ); - if !self.files.insert(entry) { - error!("The config file has the duplicated type '{}'.", config_type); - return original_plugin_config; - } - } - self - } - - pub fn to_supported_config_types_message(&self) -> Result { - let topic = C8yTopic::SmartRestResponse.to_topic()?; - Ok(MqttMessage::new(&topic, self.to_smartrest_payload())) - } - - pub fn to_supported_config_types_message_for_child( - &self, - child_id: &str, - ) -> Result { - let topic_str = &format!("c8y/s/us/{child_id}"); - let topic = Topic::new(topic_str)?; - Ok(MqttMessage::new(&topic, self.to_smartrest_payload())) - } - - pub fn get_all_file_types(&self) -> Vec { - self.files - .iter() - .map(|x| x.config_type.to_string()) - .collect::>() - } - - pub fn get_file_entry_from_type( - &self, - config_type: &str, - ) -> Result { - let file_entry = self - .files - .get(&config_type.to_string()) - .ok_or(InvalidConfigTypeError { - config_type: config_type.to_owned(), - })? - .to_owned(); - Ok(file_entry) - } - - // 119,typeA,typeB,... - fn to_smartrest_payload(&self) -> String { - let mut config_types = self.get_all_file_types(); - // Sort because hashset doesn't guarantee the order - config_types.sort(); - let supported_config_types = config_types.join(","); - format!("119,{supported_config_types}") - } -} - -#[derive(thiserror::Error, Debug)] -#[error( - "The requested config_type {config_type:?} is not defined in the plugin configuration file." -)] -pub struct InvalidConfigTypeError { - pub config_type: String, -} diff --git a/crates/extensions/c8y_config_manager/src/tests.rs b/crates/extensions/c8y_config_manager/src/tests.rs deleted file mode 100644 index 97154145c66..00000000000 --- a/crates/extensions/c8y_config_manager/src/tests.rs +++ /dev/null @@ -1,1020 +0,0 @@ -use crate::actor::OperationTimeout; -use crate::actor::OperationTimer; -use crate::child_device::ChildDeviceRequestPayload; -use crate::child_device::ChildDeviceResponsePayload; -use crate::ConfigManagerBuilder; -use crate::ConfigManagerConfig; -use c8y_api::smartrest::topic::C8yTopic; -use c8y_http_proxy::messages::C8YRestError; -use c8y_http_proxy::messages::C8YRestRequest; -use c8y_http_proxy::messages::C8YRestResponse; -use c8y_http_proxy::messages::C8YRestResult; -use c8y_http_proxy::messages::DownloadFile; -use c8y_http_proxy::messages::UploadFile; -use c8y_http_proxy::messages::Url; -use serde_json::json; -use std::time::Duration; -use tedge_actors::test_helpers::MessageReceiverExt; -use tedge_actors::test_helpers::WithTimeout; -use tedge_actors::Actor; -use tedge_actors::Builder; -use tedge_actors::DynError; -use tedge_actors::MessageReceiver; -use tedge_actors::NoMessage; -use tedge_actors::Sender; -use tedge_actors::SimpleMessageBox; -use tedge_actors::SimpleMessageBoxBuilder; -use tedge_api::OperationStatus; -use tedge_file_system_ext::FsWatchEvent; -use tedge_mqtt_ext::MqttMessage; -use tedge_mqtt_ext::Topic; -use tedge_test_utils::fs::TempTedgeDir; -use tedge_timer_ext::Timeout; -use tedge_utils::file::PermissionEntry; - -const TEST_TIMEOUT: Duration = Duration::from_secs(5); - -#[tokio::test] -async fn test_config_plugin_init() -> Result<(), DynError> { - let device_id = "tedge-device".to_string(); - let test_config_type = "test-config"; - let test_config_path = "/some/test/config"; - let ttd = TempTedgeDir::new(); - ttd.dir("c8y") - .file("c8y-configuration-plugin.toml") - .with_toml_content(toml::toml! { - files = [ - { path = test_config_path, type = test_config_type } - ] - }); - - let (mut mqtt_message_box, mut _c8y_proxy_message_box, mut _timer_message_box) = - spawn_config_manager(&device_id, &ttd).await?; - - mqtt_message_box - .assert_received([ - MqttMessage::new( - &C8yTopic::SmartRestResponse.to_topic()?, - format!("119,c8y-configuration-plugin,{test_config_type}"), // Supported config types - ), - MqttMessage::new(&C8yTopic::SmartRestResponse.to_topic().unwrap(), "500"), // Get pending operations - ]) - .await; - Ok(()) -} - -#[tokio::test] -async fn test_config_upload_tedge_device() -> Result<(), DynError> { - let device_id = "tedge-device".to_string(); - let test_config_type = "test-config"; - let test_config_path = "/some/test/config"; - let ttd = TempTedgeDir::new(); - ttd.dir("c8y") - .file("c8y-configuration-plugin.toml") - .with_toml_content(toml::toml! { - files = [ - { path = test_config_path, type = test_config_type } - ] - }); - - let (mqtt_message_box, c8y_proxy_message_box, mut _timer_message_box) = - spawn_config_manager(&device_id, &ttd).await?; - - let mut mqtt_message_box = mqtt_message_box.with_timeout(TEST_TIMEOUT); - let mut c8y_proxy_message_box = c8y_proxy_message_box.with_timeout(TEST_TIMEOUT); - - // Skip the initial bootstrap messages - mqtt_message_box.skip(2).await; - - let c8y_config_upload_msg = MqttMessage::new( - &Topic::new_unchecked("c8y/s/ds"), - format!("526,{device_id},{test_config_type}").as_str(), - ); - mqtt_message_box.send(c8y_config_upload_msg).await?; - - // Assert EXECUTING SmartREST MQTT message - mqtt_message_box - .assert_received([MqttMessage::new( - &C8yTopic::SmartRestResponse.to_topic()?, - "501,c8y_UploadConfigFile", - )]) - .await; - - // Assert config file upload HTTP request - c8y_proxy_message_box - .assert_received([UploadFile { - file_path: test_config_path.into(), - file_type: test_config_type.to_string(), - device_id, - }]) - .await; - - // Provide mock config file upload HTTP response to continue - c8y_proxy_message_box - .send(Ok(Url("test-url".to_string()).into())) - .await?; - - // Assert SUCCESSFUL SmartREST MQTT message - mqtt_message_box - .assert_received([MqttMessage::new( - &C8yTopic::SmartRestResponse.to_topic()?, - "503,c8y_UploadConfigFile,test-url", - )]) - .await; - - Ok(()) -} - -#[tokio::test] -async fn test_config_download_tedge_device() -> Result<(), DynError> { - let device_id = "tedge-device".to_string(); - let test_config_type = "test-config"; - let test_config_path = "/some/test/config"; - let ttd = TempTedgeDir::new(); - ttd.dir("c8y") - .file("c8y-configuration-plugin.toml") - .with_toml_content(toml::toml! { - files = [ - { path = test_config_path, type = test_config_type } - ] - }); - - let (mqtt_message_box, c8y_proxy_message_box, mut _timer_message_box) = - spawn_config_manager(&device_id, &ttd).await?; - - let mut mqtt_message_box = mqtt_message_box.with_timeout(TEST_TIMEOUT); - let mut c8y_proxy_message_box = c8y_proxy_message_box.with_timeout(TEST_TIMEOUT); - - // Skip the initial bootstrap messages - mqtt_message_box.skip(2).await; - - let download_url = "http://test.domain.com"; - mqtt_message_box - .send(MqttMessage::new( - &C8yTopic::SmartRestRequest.to_topic().unwrap(), - format!("524,{device_id},{download_url},{test_config_type}"), - )) - .await?; - - // Assert EXECUTING SmartREST MQTT message - mqtt_message_box - .assert_received([MqttMessage::new( - &C8yTopic::SmartRestResponse.to_topic()?, - "501,c8y_DownloadConfigFile", - )]) - .await; - - // Assert config file upload HTTP request - c8y_proxy_message_box - .assert_received([DownloadFile { - download_url: download_url.into(), - file_path: test_config_path.into(), - file_permissions: PermissionEntry::default(), - }]) - .await; - - // Provide mock config file download HTTP response to continue - c8y_proxy_message_box - .send(Ok(C8YRestResponse::Unit(()))) - .await?; - - // Assert SUCCESSFUL SmartREST MQTT message - mqtt_message_box - .assert_received([MqttMessage::new( - &C8yTopic::SmartRestResponse.to_topic()?, - "503,c8y_DownloadConfigFile", - )]) - .await; - - Ok(()) -} - -#[tokio::test] -async fn test_child_device_config_upload_request_mapping() -> Result<(), DynError> { - let device_id = "tedge-device".to_string(); - let child_device_id = "child-aa"; - let test_config_type = "file_a"; - let test_config_path = "/some/test/config"; - - let ttd = TempTedgeDir::new(); - ttd.dir("c8y") - .dir(child_device_id) - .file("c8y-configuration-plugin.toml") - .with_toml_content(toml::toml! { - files = [ - { path = test_config_path, type = test_config_type } - ] - }); - - let (mqtt_message_box, _c8y_proxy_message_box, _timer_message_box) = - spawn_config_manager(&device_id, &ttd).await?; - - let mut mqtt_message_box = mqtt_message_box.with_timeout(TEST_TIMEOUT); - - // Skip the initial bootstrap messages - mqtt_message_box.skip(2).await; - - mqtt_message_box - .send(MqttMessage::new( - &Topic::new_unchecked("c8y/s/ds"), - format!("526,{child_device_id},{test_config_type}").as_str(), - )) - .await?; - - let expected_payload = ChildDeviceRequestPayload { - url: format!( - "http://127.0.0.1:9876/tedge/file-transfer/{child_device_id}/config_snapshot/{test_config_type}" - ), - path: test_config_path.into(), - config_type: Some(test_config_type.into()), - }; - - mqtt_message_box - .assert_received([MqttMessage::new( - &Topic::new_unchecked(&format!( - "tedge/{child_device_id}/commands/req/config_snapshot" - )), - serde_json::to_string(&expected_payload)?, - )]) - .await; - - Ok(()) -} - -#[tokio::test] -async fn test_child_device_config_upload_executing_response_mapping() -> Result<(), DynError> { - let device_id = "tedge-device".to_string(); - let child_device_id = "child-aa"; - let test_config_type = "file_a"; - let test_config_path = "/some/test/config"; - - let ttd = TempTedgeDir::new(); - ttd.dir("c8y") - .dir(child_device_id) - .file("c8y-configuration-plugin.toml") - .with_toml_content(toml::toml! { - files = [ - { path = test_config_path, type = test_config_type } - ] - }); - - let (mqtt_message_box, _c8y_proxy_message_box, _timer_message_box) = - spawn_config_manager(&device_id, &ttd).await?; - - let mut mqtt_message_box = mqtt_message_box.with_timeout(TEST_TIMEOUT); - - // Skip the initial bootstrap messages - mqtt_message_box.skip(2).await; - - let c8y_config_upload_msg = MqttMessage::new( - &Topic::new_unchecked(&format!( - "tedge/{child_device_id}/commands/res/config_snapshot" - )), - serde_json::to_string(&ChildDeviceResponsePayload { - status: Some(OperationStatus::Executing), - path: test_config_path.into(), - config_type: test_config_type.into(), - reason: None, - })?, - ); - mqtt_message_box.send(c8y_config_upload_msg).await?; - - mqtt_message_box - .with_timeout(TEST_TIMEOUT) - .assert_received([MqttMessage::new( - &C8yTopic::ChildSmartRestResponse(child_device_id.into()).to_topic()?, - "501,c8y_UploadConfigFile", - )]) - .await; - - Ok(()) -} - -#[tokio::test] -async fn test_child_device_config_upload_failed_response_mapping() -> Result<(), DynError> { - let device_id = "tedge-device".to_string(); - let child_device_id = "child-aa"; - let test_config_type = "file_a"; - let test_config_path = "/some/test/config"; - - let ttd = TempTedgeDir::new(); - ttd.dir("c8y") - .dir(child_device_id) - .file("c8y-configuration-plugin.toml") - .with_toml_content(toml::toml! { - files = [ - { path = test_config_path, type = test_config_type } - ] - }); - - let (mqtt_message_box, _c8y_proxy_message_box, _timer_message_box) = - spawn_config_manager(&device_id, &ttd).await?; - - let mut mqtt_message_box = mqtt_message_box.with_timeout(TEST_TIMEOUT); - - // Skip the initial bootstrap messages - mqtt_message_box.skip(2).await; - - let c8y_config_upload_msg = MqttMessage::new( - &Topic::new_unchecked(&format!( - "tedge/{child_device_id}/commands/res/config_snapshot" - )), - json!({ - "status": "failed", - "path": test_config_path, - "type": test_config_type, - "reason": "upload failed" - }) - .to_string(), - ); - mqtt_message_box.send(c8y_config_upload_msg).await?; - - mqtt_message_box - .with_timeout(TEST_TIMEOUT) - .assert_received([ - MqttMessage::new( - &C8yTopic::ChildSmartRestResponse(child_device_id.into()).to_topic()?, - "501,c8y_UploadConfigFile", - ), - MqttMessage::new( - &C8yTopic::ChildSmartRestResponse(child_device_id.into()).to_topic()?, - "502,c8y_UploadConfigFile,upload failed", - ), - ]) - .await; - - Ok(()) -} - -// Test invalid config_snapshot response from child is mapped to -// back-to-back EXECUTING and FAILED messages for c8y_UploadConfigFile operation -#[tokio::test] -async fn test_invalid_config_snapshot_response_child_device() -> Result<(), DynError> { - let device_id = "tedge-device".to_string(); - let child_device_id = "child-aa"; - let test_config_type = "file_a"; - let test_config_path = "/some/test/config"; - - let ttd = TempTedgeDir::new(); - ttd.dir("c8y") - .dir(child_device_id) - .file("c8y-configuration-plugin.toml") - .with_toml_content(toml::toml! { - files = [ - { path = test_config_path, type = test_config_type } - ] - }); - - let (mqtt_message_box, _c8y_proxy_message_box, _timer_message_box) = - spawn_config_manager(&device_id, &ttd).await?; - - let mut mqtt_message_box = mqtt_message_box.with_timeout(TEST_TIMEOUT); - - // Skip the initial bootstrap messages - mqtt_message_box.skip(2).await; - - let c8y_config_upload_msg = MqttMessage::new( - &Topic::new_unchecked(&format!( - "tedge/{child_device_id}/commands/res/config_snapshot" - )), - "invalid json", - ); - mqtt_message_box.send(c8y_config_upload_msg).await?; - - mqtt_message_box - .assert_received( - [ - MqttMessage::new( - &C8yTopic::ChildSmartRestResponse(child_device_id.into()).to_topic()?, - "501,c8y_UploadConfigFile", - ), - MqttMessage::new( - &C8yTopic::ChildSmartRestResponse(child_device_id.into()).to_topic()?, - "502,c8y_UploadConfigFile,Failed to parse response from child device with: expected value at line 1 column 1", - ), - ], - ) - .await; - - Ok(()) -} - -// No response from the child for a config_snapshot request results in a timeout -// with back-to-back EXECUTING and FAILED messages for c8y_UploadConfigFile operation -#[tokio::test] -async fn test_timeout_on_no_config_snapshot_response_child_device() -> Result<(), DynError> { - let device_id = "tedge-device".to_string(); - let child_device_id = "child-aa"; - let test_config_type = "file_a"; - let test_config_path = "/some/test/config"; - - let ttd = TempTedgeDir::new(); - ttd.dir("c8y") - .dir(child_device_id) - .file("c8y-configuration-plugin.toml") - .with_toml_content(toml::toml! { - files = [ - { path = test_config_path, type = test_config_type } - ] - }); - - let (mqtt_message_box, _c8y_proxy_message_box, mut timer_message_box) = - spawn_config_manager(&device_id, &ttd).await?; - - let mut mqtt_message_box = mqtt_message_box.with_timeout(TEST_TIMEOUT); - - // Skip the initial bootstrap messages - mqtt_message_box.skip(2).await; - - let c8y_config_upload_msg = MqttMessage::new( - &Topic::new_unchecked("c8y/s/ds"), - format!("526,{child_device_id},{test_config_type}").as_str(), - ); - mqtt_message_box.send(c8y_config_upload_msg).await?; - - // Skip mapped tedge/config_snapshot request - mqtt_message_box.skip(1).await; - - // Assert the that a SetTimeout request is sent to the TimerActor - let set_timeout_msg = timer_message_box - .recv() - .with_timeout(TEST_TIMEOUT) - .await? - .expect("Start timeout message"); - - // Send mocked Timeout response simulating a timeout from TimerActor - timer_message_box - .send(Timeout::new(set_timeout_msg.event)) - .await?; - - mqtt_message_box - .assert_received([ - MqttMessage::new( - &C8yTopic::ChildSmartRestResponse(child_device_id.into()).to_topic()?, - "501,c8y_UploadConfigFile", - ), - MqttMessage::new( - &C8yTopic::ChildSmartRestResponse(child_device_id.into()).to_topic()?, - "502,c8y_UploadConfigFile,Timeout due to lack of response from child device: child-aa for config type: file_a", - ), - ], - ) - .await; - - Ok(()) -} - -#[tokio::test] -async fn test_child_device_successful_config_snapshot_response_mapping() -> Result<(), DynError> { - let device_id = "tedge-device".to_string(); - let child_device_id = "child-aa"; - let test_config_type = "file_a"; - let test_config_path = "/some/test/config"; - - let ttd = TempTedgeDir::new(); - ttd.dir("c8y") - .dir(child_device_id) - .file("c8y-configuration-plugin.toml") - .with_toml_content(toml::toml! { - files = [ - { path = test_config_path, type = test_config_type } - ] - }); - - let (mut mqtt_message_box, mut c8y_proxy_message_box, _timer_message_box) = - spawn_config_manager(&device_id, &ttd).await?; - - // Skip the initial bootstrap messages - for _ in 0..2 { - let _ = tokio::time::timeout(TEST_TIMEOUT, mqtt_message_box.recv()).await?; - } - - let c8y_config_upload_msg = MqttMessage::new( - &Topic::new_unchecked(&format!( - "tedge/{child_device_id}/commands/res/config_snapshot" - )), - json!({ - "status": "successful", - "path": test_config_path, - "type": test_config_type, - }) - .to_string(), - ); - mqtt_message_box.send(c8y_config_upload_msg).await?; - - c8y_proxy_message_box - .assert_received([UploadFile { - file_path: ttd - .to_path_buf() - .join("file-transfer") - .join(child_device_id) - .join("config_snapshot") - .join(test_config_type), - file_type: test_config_type.into(), - device_id: child_device_id.into(), - }]) - .await; - - // Provide mock config file upload HTTP response to continue - c8y_proxy_message_box - .send(Ok(Url("test-url".to_string()).into())) - .await?; - - mqtt_message_box - .with_timeout(TEST_TIMEOUT) - .assert_received([ - MqttMessage::new( - &C8yTopic::ChildSmartRestResponse(child_device_id.into()).to_topic()?, - "501,c8y_UploadConfigFile", - ), - MqttMessage::new( - &C8yTopic::ChildSmartRestResponse(child_device_id.into()).to_topic()?, - "503,c8y_UploadConfigFile,test-url", - ), - ]) - .await; - - Ok(()) -} - -#[tokio::test] -async fn test_child_config_snapshot_successful_response_without_uploaded_file_mapped_failed( -) -> Result<(), DynError> { - let device_id = "tedge-device".to_string(); - let child_device_id = "child-aa"; - let test_config_type = "file_a"; - let test_config_path = "/some/test/config"; - - let ttd = TempTedgeDir::new(); - ttd.dir("c8y") - .dir(child_device_id) - .file("c8y-configuration-plugin.toml") - .with_toml_content(toml::toml! { - files = [ - { path = test_config_path, type = test_config_type } - ] - }); - - let (mut mqtt_message_box, mut c8y_proxy_message_box, _timer_message_box) = - spawn_config_manager(&device_id, &ttd).await?; - - // Skip the initial bootstrap messages - for _ in 0..2 { - let _ = tokio::time::timeout(TEST_TIMEOUT, mqtt_message_box.recv()).await?; - } - - let c8y_config_upload_msg = MqttMessage::new( - &Topic::new_unchecked(&format!( - "tedge/{child_device_id}/commands/res/config_snapshot" - )), - json!({ - "status": "successful", - "path": test_config_path, - "type": test_config_type, - }) - .to_string(), - ); - mqtt_message_box.send(c8y_config_upload_msg).await?; - - c8y_proxy_message_box - .assert_received([UploadFile { - file_path: ttd - .to_path_buf() - .join("file-transfer") - .join(child_device_id) - .join("config_snapshot") - .join(test_config_type), - file_type: test_config_type.into(), - device_id: child_device_id.into(), - }]) - .await; - - // Provide mock config file upload HTTP response to continue - c8y_proxy_message_box - .send(Err(C8YRestError::CustomError("file not found".into()))) - .await?; - - mqtt_message_box - .with_timeout(TEST_TIMEOUT) - .assert_received([ - MqttMessage::new( - &C8yTopic::ChildSmartRestResponse(child_device_id.into()).to_topic()?, - "501,c8y_UploadConfigFile", - ), - MqttMessage::new( - &C8yTopic::ChildSmartRestResponse(child_device_id.into()).to_topic()?, - "502,c8y_UploadConfigFile,Failed with file not found", - ), - ]) - .await; - - Ok(()) -} - -#[tokio::test] -async fn test_child_device_config_download_request_mapping() -> Result<(), DynError> { - let device_id = "tedge-device".to_string(); - let child_device_id = "child-aa"; - let test_config_type = "file_a"; - let test_config_path = "/some/test/config"; - - let ttd = TempTedgeDir::new(); - ttd.dir("c8y") - .dir(child_device_id) - .file("c8y-configuration-plugin.toml") - .with_toml_content(toml::toml! { - files = [ - { path = test_config_path, type = test_config_type } - ] - }); - - let (mut mqtt_message_box, mut c8y_proxy_message_box, _timer_message_box) = - spawn_config_manager(&device_id, &ttd).await?; - - // Skip the initial bootstrap messages - for _ in 0..2 { - let _ = tokio::time::timeout(TEST_TIMEOUT, mqtt_message_box.recv()).await?; - } - - let download_url = "http://test.domain.com"; - let c8y_config_download_msg = MqttMessage::new( - &C8yTopic::SmartRestRequest.to_topic().unwrap(), - format!("524,{child_device_id},{download_url},{test_config_type}"), - ); - mqtt_message_box.send(c8y_config_download_msg).await?; - - // Assert download request sent to c8y-proxy - c8y_proxy_message_box - .assert_received([DownloadFile { - download_url: download_url.into(), - file_path: ttd - .to_path_buf() - .join("file-transfer") - .join(child_device_id) - .join("config_update") - .join(test_config_type), - file_permissions: PermissionEntry::default(), - }]) - .await; - - // Provide mock download response to continue - c8y_proxy_message_box.send(Ok(().into())).await?; - - let expected_payload = ChildDeviceRequestPayload { - url: format!( - "http://127.0.0.1:9876/tedge/file-transfer/{child_device_id}/config_update/{test_config_type}" - ), - path: test_config_path.into(), - config_type: Some(test_config_type.into()), - }; - mqtt_message_box - .with_timeout(TEST_TIMEOUT) - .assert_received([MqttMessage::new( - &Topic::new_unchecked(&format!( - "tedge/{child_device_id}/commands/req/config_update" - )), - serde_json::to_string(&expected_payload)?, - )]) - .await; - - Ok(()) -} - -#[tokio::test] -async fn test_child_device_config_update_executing_response_mapping() -> Result<(), DynError> { - let device_id = "tedge-device".to_string(); - let child_device_id = "child-aa"; - let test_config_type = "file_a"; - let test_config_path = "/some/test/config"; - - let ttd = TempTedgeDir::new(); - ttd.dir("c8y") - .dir(child_device_id) - .file("c8y-configuration-plugin.toml") - .with_toml_content(toml::toml! { - files = [ - { path = test_config_path, type = test_config_type } - ] - }); - - let (mut mqtt_message_box, _c8y_proxy_message_box, _timer_message_box) = - spawn_config_manager(&device_id, &ttd).await?; - - // Skip the initial bootstrap messages - for _ in 0..2 { - let _ = tokio::time::timeout(TEST_TIMEOUT, mqtt_message_box.recv()).await?; - } - - let c8y_config_update_msg = MqttMessage::new( - &Topic::new_unchecked(&format!( - "tedge/{child_device_id}/commands/res/config_update" - )), - json!({ - "status": "executing", - "path": test_config_path, - "type": test_config_type, - }) - .to_string(), - ); - mqtt_message_box.send(c8y_config_update_msg).await?; - - mqtt_message_box - .with_timeout(TEST_TIMEOUT) - .assert_received([MqttMessage::new( - &C8yTopic::ChildSmartRestResponse(child_device_id.into()).to_topic()?, - "501,c8y_DownloadConfigFile", - )]) - .await; - - Ok(()) -} - -#[tokio::test] -async fn test_child_device_config_update_successful_response_mapping() -> Result<(), DynError> { - let device_id = "tedge-device".to_string(); - let child_device_id = "child-aa"; - let test_config_type = "file_a"; - let test_config_path = "/some/test/config"; - - let ttd = TempTedgeDir::new(); - ttd.dir("c8y") - .dir(child_device_id) - .file("c8y-configuration-plugin.toml") - .with_toml_content(toml::toml! { - files = [ - { path = test_config_path, type = test_config_type } - ] - }); - - let (mut mqtt_message_box, _c8y_proxy_message_box, _timer_message_box) = - spawn_config_manager(&device_id, &ttd).await?; - - // Skip the initial bootstrap messages - for _ in 0..2 { - let _ = tokio::time::timeout(TEST_TIMEOUT, mqtt_message_box.recv()).await?; - } - - let c8y_config_update_msg = MqttMessage::new( - &Topic::new_unchecked(&format!( - "tedge/{child_device_id}/commands/res/config_update" - )), - json!({ - "status": "successful", - "path": test_config_path, - "type": test_config_type, - }) - .to_string(), - ); - mqtt_message_box.send(c8y_config_update_msg).await?; - - mqtt_message_box - .with_timeout(TEST_TIMEOUT) - .assert_received([ - MqttMessage::new( - &C8yTopic::ChildSmartRestResponse(child_device_id.into()).to_topic()?, - "501,c8y_DownloadConfigFile", - ), - MqttMessage::new( - &C8yTopic::ChildSmartRestResponse(child_device_id.into()).to_topic()?, - "503,c8y_DownloadConfigFile", - ), - ]) - .await; - - Ok(()) -} - -#[tokio::test] -async fn test_child_device_config_update_failed_response_mapping() -> Result<(), DynError> { - let device_id = "tedge-device".to_string(); - let child_device_id = "child-aa"; - let test_config_type = "file_a"; - let test_config_path = "/some/test/config"; - - let ttd = TempTedgeDir::new(); - ttd.dir("c8y") - .dir(child_device_id) - .file("c8y-configuration-plugin.toml") - .with_toml_content(toml::toml! { - files = [ - { path = test_config_path, type = test_config_type } - ] - }); - - let (mut mqtt_message_box, _c8y_proxy_message_box, _timer_message_box) = - spawn_config_manager(&device_id, &ttd).await?; - - // Skip the initial bootstrap messages - for _ in 0..2 { - let _ = tokio::time::timeout(TEST_TIMEOUT, mqtt_message_box.recv()).await?; - } - - let c8y_config_update_msg = MqttMessage::new( - &Topic::new_unchecked(&format!( - "tedge/{child_device_id}/commands/res/config_update" - )), - json!({ - "status": "failed", - "path": test_config_path, - "type": test_config_type, - "reason": "download failed" - }) - .to_string(), - ); - mqtt_message_box.send(c8y_config_update_msg).await?; - - mqtt_message_box - .with_timeout(TEST_TIMEOUT) - .assert_received([ - MqttMessage::new( - &C8yTopic::ChildSmartRestResponse(child_device_id.into()).to_topic()?, - "501,c8y_DownloadConfigFile", - ), - MqttMessage::new( - &C8yTopic::ChildSmartRestResponse(child_device_id.into()).to_topic()?, - "502,c8y_DownloadConfigFile,download failed", - ), - ]) - .await; - - Ok(()) -} - -#[tokio::test] -async fn test_child_device_config_download_fail_with_broken_url() -> Result<(), DynError> { - let device_id = "tedge-device".to_string(); - let child_device_id = "child-aa"; - let test_config_type = "file_a"; - let test_config_path = "/some/test/config"; - - let ttd = TempTedgeDir::new(); - ttd.dir("c8y") - .dir(child_device_id) - .file("c8y-configuration-plugin.toml") - .with_toml_content(toml::toml! { - files = [ - { path = test_config_path, type = test_config_type } - ] - }); - - let (mut mqtt_message_box, mut c8y_proxy_message_box, _timer_message_box) = - spawn_config_manager(&device_id, &ttd).await?; - - // Skip the initial bootstrap messages - for _ in 0..2 { - let _ = tokio::time::timeout(TEST_TIMEOUT, mqtt_message_box.recv()).await?; - } - - let download_url = "bad-url"; - let c8y_config_download_msg = MqttMessage::new( - &C8yTopic::SmartRestRequest.to_topic().unwrap(), - format!("524,{child_device_id},{download_url},{test_config_type}"), - ); - mqtt_message_box.send(c8y_config_download_msg).await?; - - // Assert download request sent to c8y-proxy - c8y_proxy_message_box - .assert_received([DownloadFile { - download_url: download_url.into(), - file_path: ttd - .to_path_buf() - .join("file-transfer") - .join(child_device_id) - .join("config_update") - .join(test_config_type), - file_permissions: PermissionEntry::default(), - }]) - .await; - - // Provide mock download response to continue - c8y_proxy_message_box - .send(Err(C8YRestError::CustomError("file not found".into()))) - .await?; - - mqtt_message_box - .with_timeout(TEST_TIMEOUT) - .assert_received([MqttMessage::new( - &C8yTopic::ChildSmartRestResponse(child_device_id.into()).to_topic()?, - "501,c8y_DownloadConfigFile", - ), - MqttMessage::new( - &C8yTopic::ChildSmartRestResponse(child_device_id.into()).to_topic()?, - "502,c8y_DownloadConfigFile,Downloading the config file update from bad-url failed with Failed with file not found", - ), - ], - ) - .await; - - Ok(()) -} - -#[tokio::test] -async fn test_multiline_smartrest_requests() -> Result<(), DynError> { - let device_id = "tedge-device".to_string(); - let test_config_type = "test-config"; - let test_config_path = "/some/test/config"; - let ttd = TempTedgeDir::new(); - ttd.dir("c8y") - .file("c8y-configuration-plugin.toml") - .with_toml_content(toml::toml! { - files = [ - { path = test_config_path, type = test_config_type } - ] - }); - - let (mqtt_message_box, mut c8y_proxy_message_box, mut _timer_message_box) = - spawn_config_manager(&device_id, &ttd).await?; - - let mut mqtt_message_box = mqtt_message_box.with_timeout(TEST_TIMEOUT); - - // Task to send dummy C8yHttpResponse - tokio::spawn(async move { - loop { - if let Some(_req) = c8y_proxy_message_box.recv().await { - c8y_proxy_message_box - .send(Ok(Url("test-url".to_string()).into())) - .await - .unwrap(); - } - } - }); - - // Skip the initial bootstrap messages - mqtt_message_box.skip(2).await; - - mqtt_message_box - .send(MqttMessage::new( - &Topic::new_unchecked("c8y/s/ds"), - format!("526,{device_id},{test_config_type}").as_str(), - )) - .await?; - - // Assert EXECUTING and SUCCESSFUL SmartREST MQTT message - mqtt_message_box - .assert_received([ - MqttMessage::new( - &C8yTopic::SmartRestResponse.to_topic()?, - "501,c8y_UploadConfigFile", - ), - MqttMessage::new( - &C8yTopic::SmartRestResponse.to_topic()?, - "503,c8y_UploadConfigFile,test-url", - ), - ]) - .await; - - Ok(()) -} - -async fn spawn_config_manager( - device_id: &str, - tedge_temp_dir: &TempTedgeDir, -) -> Result< - ( - SimpleMessageBox, - SimpleMessageBox, - SimpleMessageBox, - ), - DynError, -> { - let tedge_host = "127.0.0.1"; - let mqtt_port = 1234; - let tedge_http_port = 9876; - - let config = ConfigManagerConfig::new( - tedge_temp_dir.to_path_buf(), - tedge_temp_dir.to_path_buf(), - tedge_temp_dir.utf8_path_buf().into(), - device_id.to_string(), - tedge_host.to_string(), - mqtt_port, - tedge_host.into(), - tedge_http_port, - ); - - let mut mqtt_builder: SimpleMessageBoxBuilder = - SimpleMessageBoxBuilder::new("MQTT", 5); - let mut c8y_proxy_builder: SimpleMessageBoxBuilder = - SimpleMessageBoxBuilder::new("C8Y", 1); - let mut timer_builder: SimpleMessageBoxBuilder = - SimpleMessageBoxBuilder::new("Timer", 5); - let mut fs_builder: SimpleMessageBoxBuilder = - SimpleMessageBoxBuilder::new("FsNotify", 5); - - let config_manager_builder = ConfigManagerBuilder::try_new( - config, - &mut mqtt_builder, - &mut c8y_proxy_builder, - &mut timer_builder, - &mut fs_builder, - )?; - - let mqtt_message_box = mqtt_builder.build(); - let c8y_proxy_message_box = c8y_proxy_builder.build(); - let timer_message_box = timer_builder.build(); - - let actor = config_manager_builder.build(); - let _join_handle = tokio::spawn(async move { actor.run().await }); - - Ok((mqtt_message_box, c8y_proxy_message_box, timer_message_box)) -} diff --git a/crates/extensions/c8y_config_manager/src/upload.rs b/crates/extensions/c8y_config_manager/src/upload.rs deleted file mode 100644 index 4460c9e834d..00000000000 --- a/crates/extensions/c8y_config_manager/src/upload.rs +++ /dev/null @@ -1,418 +0,0 @@ -use crate::child_device::try_cleanup_config_file_from_file_transfer_repositoy; -use crate::child_device::ChildConfigOperationKey; -use crate::child_device::ConfigOperationMessage; -use crate::child_device::DEFAULT_OPERATION_TIMEOUT; -use crate::plugin_config::InvalidConfigTypeError; - -use super::actor::ActiveOperationState; -use super::actor::ConfigManagerActor; -use super::actor::ConfigManagerMessageBox; -use super::actor::ConfigOperation; -use super::actor::OperationTimeout; -use super::child_device::ConfigOperationRequest; -use super::child_device::ConfigOperationResponse; -use super::error::ConfigManagementError; -use super::plugin_config::PluginConfig; -use super::ConfigManagerConfig; -use c8y_api::smartrest::smartrest_deserializer::SmartRestConfigUploadRequest; -use c8y_api::smartrest::smartrest_serializer::fail_operation; -use c8y_api::smartrest::smartrest_serializer::set_operation_executing; -use c8y_api::smartrest::smartrest_serializer::succeed_static_operation; -use c8y_api::smartrest::smartrest_serializer::CumulocitySupportedOperations; -use c8y_api::smartrest::smartrest_serializer::OperationStatusMessage; -use c8y_api::smartrest::smartrest_serializer::SmartRest; -use log::error; -use log::info; -use log::warn; -use std::collections::HashMap; -use std::path::Path; -use tedge_actors::Sender; -use tedge_api::OperationStatus; -use tedge_mqtt_ext::MqttMessage; -use tedge_mqtt_ext::Topic; -use tedge_timer_ext::SetTimeout; -use tedge_utils::file::create_directory_with_user_group; -use tedge_utils::file::create_file_with_user_group; -use tedge_utils::file::move_file; -use tedge_utils::file::FileError; -use tedge_utils::file::PermissionEntry; - -pub struct ConfigUploadManager { - config: ConfigManagerConfig, - active_child_ops: HashMap, -} - -impl ConfigUploadManager { - pub fn new(config: ConfigManagerConfig) -> Self { - let active_child_ops = HashMap::new(); - ConfigUploadManager { - config, - active_child_ops, - } - } - - pub async fn handle_config_upload_request( - &mut self, - config_upload_request: SmartRestConfigUploadRequest, - message_box: &mut ConfigManagerMessageBox, - ) -> Result<(), ConfigManagementError> { - info!( - "Received c8y_UploadConfigFile request for config type: {} from device: {}", - config_upload_request.config_type, config_upload_request.device - ); - - if config_upload_request.device == self.config.device_id { - self.handle_config_upload_request_tedge_device(config_upload_request, message_box) - .await - } else { - self.handle_config_upload_request_child_device(config_upload_request, message_box) - .await - } - } - - pub async fn handle_config_upload_request_tedge_device( - &mut self, - config_upload_request: SmartRestConfigUploadRequest, - message_box: &mut ConfigManagerMessageBox, - ) -> Result<(), ConfigManagementError> { - // set config upload request to executing - let msg = UploadConfigFileStatusMessage::executing(); - message_box.mqtt_publisher.send(msg).await?; - - let plugin_config = PluginConfig::new(&self.config.plugin_config_path); - - let upload_result = - match plugin_config.get_file_entry_from_type(&config_upload_request.config_type) { - Ok(file_entry) => { - let config_file_path = file_entry.path; - self.upload_config_file( - Path::new(config_file_path.as_str()), - &config_upload_request.config_type, - config_upload_request.device, - message_box, - ) - .await - } - Err(err) => Err(err.into()), - }; - - let target_config_type = &config_upload_request.config_type; - - match upload_result { - Ok(upload_event_url) => { - info!("The configuration upload for '{target_config_type}' is successful."); - - let successful_message = - UploadConfigFileStatusMessage::successful(Some(&upload_event_url)); - message_box.mqtt_publisher.send(successful_message).await?; - } - Err(err) => { - error!("The configuration upload for '{target_config_type}' failed.",); - - let failed_message = UploadConfigFileStatusMessage::failed(&err.to_string()); - message_box.mqtt_publisher.send(failed_message).await?; - } - } - - Ok(()) - } - - /// Map the c8y_UploadConfigFile request into a tedge/commands/req/config_snapshot command for the child device. - /// The child device is expected to upload the config fie snapshot to the file transfer service. - /// A unique URL path for this config file, from the file transfer service, is shared with the child device in the command. - /// The child device can use this URL to upload the config file snapshot to the file transfer service. - pub async fn handle_config_upload_request_child_device( - &mut self, - config_upload_request: SmartRestConfigUploadRequest, - message_box: &mut ConfigManagerMessageBox, - ) -> Result<(), ConfigManagementError> { - let child_id = config_upload_request.device; - let config_type = config_upload_request.config_type; - let operation_key = ChildConfigOperationKey { - child_id: child_id.clone(), - operation_type: ConfigOperation::Snapshot, - config_type: config_type.clone(), - }; - - let plugin_config = PluginConfig::new(Path::new(&format!( - "{}/c8y/{child_id}/c8y-configuration-plugin.toml", - self.config.config_dir.display() - ))); - - match plugin_config.get_file_entry_from_type(&config_type) { - Ok(file_entry) => { - let config_management = ConfigOperationRequest::Snapshot { - child_id: child_id.clone(), - file_entry: file_entry.clone(), - }; - - let msg = MqttMessage::new( - &config_management.operation_request_topic(), - config_management.operation_request_payload(&self.config.tedge_http_host)?, - ); - message_box.send(msg.into()).await?; - info!("Config snapshot request for config type: {config_type} sent to child device: {child_id}"); - - self.active_child_ops - .insert(operation_key.clone(), ActiveOperationState::Pending); - - // Start the timer for operation timeout - message_box - .send(SetTimeout::new(DEFAULT_OPERATION_TIMEOUT, operation_key).into()) - .await?; - } - Err(InvalidConfigTypeError { config_type }) => { - warn!( - "Ignoring the config management request for unknown config type: {config_type}" - ); - } - } - - Ok(()) - } - - pub async fn handle_child_device_config_snapshot_response( - &mut self, - config_response: &ConfigOperationResponse, - message_box: &mut ConfigManagerMessageBox, - ) -> Result, ConfigManagementError> { - let payload = config_response.get_payload(); - let c8y_child_topic = Topic::new_unchecked(&config_response.get_child_topic()); - let config_dir = self.config.config_dir.display(); - let child_id = config_response.get_child_id(); - let config_type = config_response.get_config_type(); - let operation_key = ChildConfigOperationKey { - child_id: child_id.clone(), - operation_type: ConfigOperation::Snapshot, - config_type: config_type.clone(), - }; - - info!("Config snapshot response received for type: {config_type} from child: {child_id}"); - - let mut mapped_responses = vec![]; - if let Some(operation_status) = payload.status { - let current_operation_state = self.active_child_ops.get(&operation_key); - if current_operation_state != Some(&ActiveOperationState::Executing) { - let executing_status_payload = UploadConfigFileStatusMessage::status_executing(); - mapped_responses.push(MqttMessage::new(&c8y_child_topic, executing_status_payload)); - } - - match operation_status { - OperationStatus::Successful => { - self.active_child_ops.remove(&operation_key); - - match self - .handle_child_device_successful_config_snapshot_response( - config_response, - message_box, - ) - .await - { - Ok(message) => mapped_responses.push(message), - Err(err) => { - let failed_status_payload = - UploadConfigFileStatusMessage::status_failed(&err.to_string()); - mapped_responses - .push(MqttMessage::new(&c8y_child_topic, failed_status_payload)); - } - } - } - OperationStatus::Failed => { - self.active_child_ops.remove(&operation_key); - - if let Some(error_message) = &payload.reason { - let failed_status_payload = - UploadConfigFileStatusMessage::status_failed(error_message); - mapped_responses - .push(MqttMessage::new(&c8y_child_topic, failed_status_payload)); - } else { - let default_error_message = "No failure reason provided by child device."; - let failed_status_payload = - UploadConfigFileStatusMessage::status_failed(default_error_message); - mapped_responses - .push(MqttMessage::new(&c8y_child_topic, failed_status_payload)); - } - } - OperationStatus::Executing => { - self.active_child_ops - .insert(operation_key.clone(), ActiveOperationState::Executing); - - // Reset the timer - message_box - .send(SetTimeout::new(DEFAULT_OPERATION_TIMEOUT, operation_key).into()) - .await?; - } - } - Ok(mapped_responses) - } else { - if &config_response.get_config_type() == "c8y-configuration-plugin" { - // create directories - create_directory_with_user_group( - format!("{}/c8y/{}", config_dir, config_response.get_child_id()), - "tedge", - "tedge", - 0o755, - )?; - create_directory_with_user_group( - format!( - "{}/operations/c8y/{}", - config_dir, - config_response.get_child_id() - ), - "tedge", - "tedge", - 0o755, - )?; - create_file_with_user_group( - format!( - "{}/operations/c8y/{}/c8y_DownloadConfigFile", - config_dir, - config_response.get_child_id() - ), - "tedge", - "tedge", - 0o755, - None, - )?; - create_file_with_user_group( - format!( - "{}/operations/c8y/{}/c8y_UploadConfigFile", - config_dir, - config_response.get_child_id() - ), - "tedge", - "tedge", - 0o755, - None, - )?; - // copy to /etc/c8y - let path_from = &format!( - "{}/{}/c8y-configuration-plugin", - self.config.file_transfer_dir.display(), - config_response.get_child_id() - ); - let path_from = Path::new(path_from); - let path_to = &format!( - "{}/c8y/{}/c8y-configuration-plugin.toml", - config_dir, - config_response.get_child_id() - ); - let path_to = Path::new(path_to); - move_file(path_from, path_to, PermissionEntry::default()) - .await - .map_err(FileError::from)?; - } - // send 119 - let child_plugin_config = PluginConfig::new(Path::new(&format!( - "{}/c8y/{}/c8y-configuration-plugin.toml", - config_dir, - config_response.get_child_id() - ))); - - // Publish supported configuration types for child devices - let message = child_plugin_config - .to_supported_config_types_message_for_child(&config_response.get_child_id())?; - Ok(vec![message]) - } - } - - pub async fn handle_child_device_successful_config_snapshot_response( - &mut self, - config_response: &ConfigOperationResponse, - message_box: &mut ConfigManagerMessageBox, - ) -> Result { - let c8y_child_topic = Topic::new_unchecked(&config_response.get_child_topic()); - - let uploaded_config_file_path = config_response - .file_transfer_repository_full_path(self.config.file_transfer_dir.clone()); - - let c8y_upload_event_url = self - .upload_config_file( - Path::new(&uploaded_config_file_path), - &config_response.get_config_type(), - config_response.get_child_id(), - message_box, - ) - .await?; - - // Cleanup the child uploaded file after uploading it to cloud - try_cleanup_config_file_from_file_transfer_repositoy( - self.config.file_transfer_dir.clone(), - config_response, - ); - - info!("Marking the c8y_UploadConfigFile operation as successful with the Cumulocity URL for the uploaded file: {c8y_upload_event_url}"); - let successful_status_payload = - UploadConfigFileStatusMessage::status_successful(Some(&c8y_upload_event_url)); - let message = MqttMessage::new(&c8y_child_topic, successful_status_payload); - - Ok(message) - } - - pub async fn upload_config_file( - &mut self, - config_file_path: &Path, - config_type: &str, - device_id: String, - message_box: &mut ConfigManagerMessageBox, - ) -> Result { - let url = message_box - .c8y_http_proxy - .upload_file(config_file_path, config_type, device_id) - .await?; - Ok(url) - } - - pub async fn process_operation_timeout( - &mut self, - timeout: OperationTimeout, - message_box: &mut ConfigManagerMessageBox, - ) -> Result<(), ConfigManagementError> { - let child_id = timeout.event.child_id; - let config_type = timeout.event.config_type; - let operation_key = ChildConfigOperationKey { - child_id: child_id.clone(), - operation_type: ConfigOperation::Snapshot, - config_type: config_type.clone(), - }; - - if let Some(operation_state) = self.active_child_ops.remove(&operation_key) { - ConfigManagerActor::fail_config_operation_in_c8y( - ConfigOperation::Snapshot, - Some(child_id.clone()), - operation_state, - &format!("Timeout due to lack of response from child device: {child_id} for config type: {config_type}"), - message_box, - ).await - } else { - // Ignore the timeout as the operation has already completed. - Ok(()) - } - } -} - -pub struct UploadConfigFileStatusMessage {} - -impl UploadConfigFileStatusMessage { - const OP: CumulocitySupportedOperations = CumulocitySupportedOperations::C8yUploadConfigFile; -} - -impl OperationStatusMessage for UploadConfigFileStatusMessage { - // returns a c8y message specifying to set the upload config file operation status to executing. - // example message: '501,c8y_UploadConfigFile' - fn status_executing() -> SmartRest { - set_operation_executing(Self::OP) - } - - // returns a c8y SmartREST message indicating the success of the upload config file operation. - // example message: '503,c8y_UploadConfigFile,https://{c8y.url}/etc...' - fn status_successful(parameter: Option<&str>) -> SmartRest { - succeed_static_operation(Self::OP, parameter) - } - - // returns a c8y SmartREST message indicating the failure of the upload config file operation. - // example message: '502,c8y_UploadConfigFile,"failure reason"' - fn status_failed(failure_reason: &str) -> SmartRest { - fail_operation(Self::OP, failure_reason) - } -} diff --git a/plugins/c8y_configuration_plugin/Cargo.toml b/plugins/c8y_configuration_plugin/Cargo.toml deleted file mode 100644 index c6688f154b5..00000000000 --- a/plugins/c8y_configuration_plugin/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -name = "c8y-configuration-plugin" -description = "Thin-edge device configuration management for Cumulocity" -version = { workspace = true } -authors = { workspace = true } -edition = { workspace = true } -rust-version = { workspace = true } -license = { workspace = true } -homepage = { workspace = true } -repository = { workspace = true } - -[dependencies] -anyhow = { workspace = true } -c8y_config_manager = { workspace = true } -c8y_http_proxy = { workspace = true } -clap = { workspace = true } -tedge_actors = { workspace = true } -tedge_api = { workspace = true } -tedge_config = { workspace = true } -tedge_file_system_ext = { workspace = true } -tedge_health_ext = { workspace = true } -tedge_http_ext = { workspace = true } -tedge_mqtt_ext = { workspace = true } -tedge_signal_ext = { workspace = true } -tedge_timer_ext = { workspace = true } -tedge_utils = { workspace = true } -tokio = { workspace = true, features = ["rt", "rt-multi-thread"] } -tracing = { workspace = true } - -[lints] -workspace = true diff --git a/plugins/c8y_configuration_plugin/build.rs b/plugins/c8y_configuration_plugin/build.rs deleted file mode 100644 index 7d918c19f0b..00000000000 --- a/plugins/c8y_configuration_plugin/build.rs +++ /dev/null @@ -1,10 +0,0 @@ -fn main() { - // export GIT_SEMVER=$(git describe --always --tags --abbrev=8 --dirty) - // https://github.com/rust-lang/cargo/issues/6583#issuecomment-1259871885 - if let Ok(val) = std::env::var("GIT_SEMVER") { - println!("Using version defined by 'GIT_SEMVER={}'", val); - println!("cargo:rustc-env=CARGO_PKG_VERSION={}", val); - } - println!("cargo:rerun-if-env-changed=GIT_SEMVER"); - println!("cargo:rerun-if-changed=build.rs"); -} diff --git a/plugins/c8y_configuration_plugin/src/lib.rs b/plugins/c8y_configuration_plugin/src/lib.rs deleted file mode 100644 index 78513b10a9b..00000000000 --- a/plugins/c8y_configuration_plugin/src/lib.rs +++ /dev/null @@ -1,162 +0,0 @@ -use anyhow::Context; -use c8y_config_manager::ConfigManagerBuilder; -use c8y_config_manager::ConfigManagerConfig; -use c8y_http_proxy::credentials::C8YJwtRetriever; -use c8y_http_proxy::C8YHttpProxyBuilder; -use std::path::Path; -use std::path::PathBuf; -use tedge_actors::Runtime; -use tedge_api::mqtt_topics::DeviceTopicId; -use tedge_api::mqtt_topics::EntityTopicId; -use tedge_api::mqtt_topics::MqttSchema; -use tedge_api::mqtt_topics::Service; -use tedge_config::system_services::get_log_level; -use tedge_config::system_services::set_log_level; -use tedge_config::CertificateError; -use tedge_config::TEdgeConfig; -use tedge_config::DEFAULT_TEDGE_CONFIG_PATH; -use tedge_file_system_ext::FsWatchActorBuilder; -use tedge_health_ext::HealthMonitorBuilder; -use tedge_http_ext::HttpActor; -use tedge_mqtt_ext::MqttActorBuilder; -use tedge_mqtt_ext::MqttConfig; -use tedge_signal_ext::SignalActor; -use tedge_timer_ext::TimerActor; -use tracing::log::warn; - -const PLUGIN_NAME: &str = "c8y-configuration-plugin"; - -const AFTER_HELP_TEXT: &str = r#"On start, `c8y-configuration-plugin` notifies the cloud tenant of the managed configuration files, listed in the `CONFIG_FILE`, sending this list with a `119` on `c8y/s/us`. -`c8y-configuration-plugin` subscribes then to `c8y/s/ds` listening for configuration operation requests (messages `524` and `526`). -notifying the Cumulocity tenant of their progress (messages `501`, `502` and `503`). - -The thin-edge `CONFIG_DIR` is used to find where: - * to store temporary files on download: `tedge config get tmp.path`, - * to log operation errors and progress: `tedge config get log.path`, - * to connect the MQTT bus: `tedge config get mqtt.client.port`."#; - -#[derive(Debug, clap::Parser)] -#[clap( -name = clap::crate_name!(), -version = clap::crate_version!(), -about = clap::crate_description!(), -after_help = AFTER_HELP_TEXT -)] -pub struct ConfigPluginOpt { - /// Turn-on the debug log level. - /// - /// If off only reports ERROR, WARN, and INFO - /// If on also reports DEBUG - #[clap(long)] - pub debug: bool, - - /// Create supported operation files - #[clap(short, long)] - pub init: bool, - - #[clap(long = "config-dir", default_value = DEFAULT_TEDGE_CONFIG_PATH)] - pub config_dir: PathBuf, -} - -pub async fn run(config_plugin_opt: ConfigPluginOpt) -> Result<(), anyhow::Error> { - let config_dir = config_plugin_opt.config_dir; - - // Load tedge config from the provided location - let tedge_config_location = tedge_config::TEdgeConfigLocation::from_custom_root(&config_dir); - let log_level = if config_plugin_opt.debug { - tracing::Level::DEBUG - } else { - get_log_level(PLUGIN_NAME, &tedge_config_location.tedge_config_root_path)? - }; - - set_log_level(log_level); - - let config_repository = tedge_config::TEdgeConfigRepository::new(tedge_config_location.clone()); - let tedge_config = config_repository.load()?; - - if config_plugin_opt.init { - warn!("This --init option has been deprecated and will be removed in a future release"); - Ok(()) - } else { - run_with(config_dir, tedge_config).await - } -} - -async fn run_with( - config_dir: impl AsRef, - tedge_config: TEdgeConfig, -) -> Result<(), anyhow::Error> { - let runtime_events_logger = None; - let mut runtime = Runtime::try_new(runtime_events_logger).await?; - - // Create actor instances - let mqtt_config = mqtt_config(&tedge_config)?; - let mut jwt_actor = C8YJwtRetriever::builder(mqtt_config.clone()); - let mut http_actor = HttpActor::new().builder(); - let c8y_http_config = (&tedge_config).try_into()?; - let mut c8y_http_proxy_actor = - C8YHttpProxyBuilder::new(c8y_http_config, &mut http_actor, &mut jwt_actor); - - let mut fs_watch_actor = FsWatchActorBuilder::new(); - let mut timer_actor = TimerActor::builder(); - let mut mqtt_actor = MqttActorBuilder::new(mqtt_config.clone().with_session_name(PLUGIN_NAME)); - - // Instantiate health monitor actor - // TODO: take a user-configurable service topic id - let mqtt_device_topic_id = &tedge_config - .mqtt - .device_topic_id - .parse::() - .unwrap(); - - let service_topic_id = mqtt_device_topic_id - .to_default_service_topic_id(PLUGIN_NAME) - .with_context(|| { - format!( - "Device topic id {mqtt_device_topic_id} currently needs default scheme, e.g: 'device/DEVICE_NAME//'", - ) - })?; - let service = Service { - service_topic_id, - device_topic_id: DeviceTopicId::new(mqtt_device_topic_id.clone()), - }; - let mqtt_schema = MqttSchema::with_root(tedge_config.mqtt.topic_root.to_string()); - let health_actor = HealthMonitorBuilder::from_service_topic_id( - service, - &mut mqtt_actor, - &mqtt_schema, - &tedge_config.service, - ); - - // Instantiate config manager actor - let config_manager_config = ConfigManagerConfig::from_tedge_config(config_dir, &tedge_config)?; - let config_actor = ConfigManagerBuilder::try_new( - config_manager_config, - &mut mqtt_actor, - &mut c8y_http_proxy_actor, - &mut timer_actor, - &mut fs_watch_actor, - )?; - - // Shutdown on SIGINT - let signal_actor = SignalActor::builder(&runtime.get_handle()); - - // Run the actors - runtime.spawn(signal_actor).await?; - runtime.spawn(mqtt_actor).await?; - runtime.spawn(jwt_actor).await?; - runtime.spawn(http_actor).await?; - runtime.spawn(c8y_http_proxy_actor).await?; - runtime.spawn(fs_watch_actor).await?; - runtime.spawn(config_actor).await?; - runtime.spawn(timer_actor).await?; - runtime.spawn(health_actor).await?; - - runtime.run_to_completion().await?; - - Ok(()) -} - -fn mqtt_config(tedge_config: &TEdgeConfig) -> Result { - tedge_config.mqtt_config() -} diff --git a/plugins/c8y_configuration_plugin/src/main.rs b/plugins/c8y_configuration_plugin/src/main.rs deleted file mode 100644 index 26ad03a74b8..00000000000 --- a/plugins/c8y_configuration_plugin/src/main.rs +++ /dev/null @@ -1,8 +0,0 @@ -use c8y_configuration_plugin::ConfigPluginOpt; -use clap::Parser; - -#[tokio::main] -async fn main() { - let opt = ConfigPluginOpt::parse(); - c8y_configuration_plugin::run(opt).await.unwrap(); -} diff --git a/tests/RobotFramework/tests/config_management/child_conf_mgmt_plugin.robot b/tests/RobotFramework/tests/config_management/child_conf_mgmt_plugin.robot deleted file mode 100644 index 0555e84a1e2..00000000000 --- a/tests/RobotFramework/tests/config_management/child_conf_mgmt_plugin.robot +++ /dev/null @@ -1,236 +0,0 @@ -*** Comments *** -#PRECONDITION: -#Device CH_DEV_CONF_MGMT is existing on tenant, if not -#use -v DeviceID:xxxxxxxxxxx in the command line to use your existing device - - -*** Settings *** -Resource ../../resources/common.resource -Library ThinEdgeIO -Library Cumulocity -Library JSONLibrary -Library Collections - -Suite Setup Custom Setup -Suite Teardown Get Logs name=${PARENT_SN} - -Force Tags theme:configuration theme:childdevices - - -*** Variables *** -${PARENT_IP} -${HTTP_PORT} 8000 - -${config} files = [\n\t { path = '/home/pi/config1', type = 'config1' },\n ]\n -${PARENT_SN} -${CHILD_SN} - -${topic_snap} /commands/res/config_snapshot -${topic_upd} /commands/res/config_update -${payl_notify} {"status": null, "path": "", "type":"c8y-configuration-plugin", "reason": null} -${payl_exec} {"status": "executing", "path": "/home/pi/config1", "type": "config1", "reason": null} -${payl_succ} {"status": "successful", "path": "/home/pi/config1", "type": "config1", "reason": null} - -${CHILD_CONFIG}= SEPARATOR=\n -... files = [ -... { path = '/home/pi/config1', type = 'config1' }, -... ] - - -*** Test Cases *** -Prerequisite Parent - Set Device Context ${PARENT_SN} #Creates ssh connection to the parent device - Execute Command sudo tedge disconnect c8y - - Delete child related content #Delete any previous created child related configuration files/folders on the parent device - Check for child related content #Checks if folders that will trigger child device creation are existing - Set external MQTT bind address #Setting external MQTT bind address which child will use for communication - Set external MQTT port #Setting external MQTT port which child will use for communication Default:1883 - Restart agent - - Sleep 3s - Execute Command sudo tedge connect c8y - Restart Configuration plugin #Stop and Start c8y-configuration-plugin - Cumulocity.Log Device Info - -Prerequisite Child - Child device delete configuration files #Delete any previous created child related configuration files/folders on the child device - -Child device bootstrapping - Startup child device #Setting up/Bootstrapping of a child device - Validate child Name #This is to check the existence of the bug: https://github.com/thin-edge/thin-edge.io/issues/1569 - -Snapshot from device - Request snapshot from child device #Using the cloud command: "Get snapshot from device" - Child device response on snapshot request #Child device is sending 'executing' and 'successful' MQTT responses - No response from child device on snapshot request #Tests the failing of request after timeout of 10s - -Child device config update - Send configuration to device #Using the cloud command: "Send configuration to device" - Child device response on update request #Child device is sending 'executing' and 'successful' MQTT responses - No response from child device on config update #Tests the failing of request after timeout of 10s - - -*** Keywords *** -Set external MQTT bind address - Set Device Context ${PARENT_SN} - Execute Command sudo tedge config set mqtt.external.bind.address ${PARENT_IP} - Execute Command sudo tedge config set http.client.host ${PARENT_IP} - -Set external MQTT port - Set Device Context ${PARENT_SN} - Execute Command sudo tedge config set mqtt.external.bind.port 1883 - -Restart agent - Set Device Context ${PARENT_SN} - Restart Service tedge-agent - -Check for child related content - Set Device Context ${CHILD_SN} - Directory Should Not Have Sub Directories /etc/tedge/operations/c8y - Directory Should Not Have Sub Directories /etc/tedge/c8y - Directory Should Not Have Sub Directories /var/tedge - -Delete child related content - Execute Command sudo rm -rf /etc/tedge/operations/c8y/TST* #if folder exists, child device will be created - Execute Command sudo rm -f c8y-configuration-plugin.toml - Execute Command sudo rm -rf /etc/tedge/c8y/TST* #if folder exists, child device will be created - Execute Command sudo rm -rf /var/tedge/* - -Check parent child relationship - Cumulocity.Set Device ${PARENT_SN} - Cumulocity.Device Should Have A Child Devices ${CHILD_SN} - -Restart Configuration plugin - Restart Service c8y-configuration-plugin.service - -Child device delete configuration files - Set Device Context ${CHILD_SN} - Execute Command sudo rm -f config1 - Execute Command sudo rm -f c8y-configuration-plugin - -Validate child Name - Device Should Exist ${CHILD_SN} - ${child_mo}= Cumulocity.Device Should Have Fragments name - Should Be Equal device_${PARENT_SN} ${child_mo["owner"]} # The parent is the owner of the child - -Startup child device - Sleep 5s reason=The registration of child devices is flakey - Set Device Context ${CHILD_SN} - Execute Command printf "${config}" > c8y-configuration-plugin - - Execute Command - ... curl -X PUT http://${PARENT_IP}:${HTTP_PORT}/tedge/file-transfer/${CHILD_SN}/c8y-configuration-plugin --data-binary "${CHILD_CONFIG}" - - Sleep 5s reason=The registration of child devices is flakey - - Execute Command sudo apt-get install mosquitto-clients -y - Execute Command mosquitto_pub -h ${PARENT_IP} -t "tedge/${CHILD_SN}${topic_snap}" -m '${payl_notify}' -q 1 - -Request snapshot from child device - Cumulocity.Set Device ${CHILD_SN} - ${operation}= Get Configuration config1 - Set Suite Variable $operation - - Set Device Context ${PARENT_SN} - @{listen}= Should Have MQTT Messages topic=tedge/${CHILD_SN}/commands/req/config_snapshot date_from=-5s - Should Be Equal - ... @{listen} - ... {"url":"http://${PARENT_IP}:${HTTP_PORT}/tedge/file-transfer/${CHILD_SN}/config_snapshot/config1","path":"/home/pi/config1","type":"config1"} - - #CHECK OPERATION - Cumulocity.Operation Should Be PENDING ${operation} - -Child device response on snapshot request - Set Device Context ${CHILD_SN} - Execute Command mosquitto_pub -h ${PARENT_IP} -t "tedge/${CHILD_SN}${topic_snap}" -m '${payl_exec}' - - Transfer To Device ${CURDIR}/config.txt.tar.gz /home/pi/config1 - Execute Command - ... curl -f -X PUT --data-binary @/home/pi/config1 http://${PARENT_IP}:${HTTP_PORT}/tedge/file-transfer/${CHILD_SN}/config_snapshot/config1 - - Sleep 5s - Execute Command mosquitto_pub -h ${PARENT_IP} -t "tedge/${CHILD_SN}${topic_snap}" -m '${payl_succ}' - - Sleep 2s - - #CHECK OPERATION - Cumulocity.Operation Should Be SUCCESSFUL ${operation} - -Send configuration to device - ${file_url}= Create Inventory Binary test-config.toml config1 file=${CURDIR}/config.txt.tar.gz - ${operation}= Set Configuration - ... config1 - ... ${file_url} - ... description=Send configuration snapshot config1 of configuration type config1 to device ${CHILD_SN} - Set Suite Variable $operation - - Set Device Context ${PARENT_SN} - @{listen}= Should Have MQTT Messages topic=tedge/${CHILD_SN}/commands/req/config_update date_from=-5s - Should Be Equal - ... @{listen} - ... {"url":"http://${PARENT_IP}:${HTTP_PORT}/tedge/file-transfer/${CHILD_SN}/config_update/config1","path":"/home/pi/config1","type":"config1"} - - #CHECK OPERATION - Operation Should Be DELIVERED ${operation} - -Child device response on update request - Set Device Context ${CHILD_SN} - Execute Command mosquitto_pub -h ${PARENT_IP} -t "tedge/${CHILD_SN}${topic_upd}" -m '${payl_exec}' - - Execute Command - ... curl -f http://${PARENT_IP}:${HTTP_PORT}/tedge/file-transfer/${CHILD_SN}/config_update/config1 --output config1 - - # Sleep 5s #Enable if tests starts to fail - Execute Command mosquitto_pub -h ${PARENT_IP} -t "tedge/${CHILD_SN}${topic_upd}" -m '${payl_succ}' - - Cumulocity.Operation Should Be SUCCESSFUL ${operation} - -No response from child device on snapshot request - ${operation}= Get Configuration config1 - - Set Device Context ${PARENT_SN} - @{listen}= Should Have MQTT Messages topic=tedge/${CHILD_SN}/commands/req/config_snapshot - Should Be Equal - ... @{listen} - ... {"url":"http://${PARENT_IP}:${HTTP_PORT}/tedge/file-transfer/${CHILD_SN}/config_snapshot/config1","path":"/home/pi/config1","type":"config1"} - - #CHECK TIMEOUT MESSAGE - Cumulocity.Operation Should Be FAILED - ... ${operation} - ... failure_reason=Timeout due to lack of response from child device: ${CHILD_SN} for config type: config1 - ... timeout=60 - -No response from child device on config update - ${file_url}= Create Inventory Binary test-config.toml config1 contents=Dummy config - ${operation}= Set Configuration config1 ${file_url} - - Set Device Context ${PARENT_SN} - @{listen}= Should Have MQTT Messages topic=tedge/${CHILD_SN}/commands/req/config_update - Should Be Equal - ... @{listen} - ... {"url":"http://${PARENT_IP}:${HTTP_PORT}/tedge/file-transfer/${CHILD_SN}/config_update/config1","path":"/home/pi/config1","type":"config1"} - - #CHECK OPERATION - Cumulocity.Operation Should Be FAILED - ... ${operation} - ... failure_reason=Timeout due to lack of response from child device: ${CHILD_SN} for config type: config1 - ... timeout=60 - -Custom Setup - # Parent - ${parent_sn}= Setup skip_bootstrap=False - Set Suite Variable $PARENT_SN ${parent_sn} - # Disable new generic handling - Execute Command sudo tedge config set c8y.enable.config_snapshot false - Execute Command sudo tedge config set c8y.enable.config_update false - - # Use deprecated c8y-configuration-plugin over tedge-agent (configuration) - Execute Command find . -type f -name "c8y-configuration-plugin_*.deb" -exec dpkg -i {} \\; - - ${parent_ip}= Get IP Address - Set Suite Variable $PARENT_IP ${parent_ip} - - # Child - ${child_sn}= Setup skip_bootstrap=True - Set Suite Variable $CHILD_SN ${child_sn} From d16f09b5d54261a256687a18e068e04a585c07a0 Mon Sep 17 00:00:00 2001 From: Reuben Miller Date: Tue, 13 Feb 2024 16:47:35 +0100 Subject: [PATCH 03/10] remove individual entrypoints tedge is the only binary/entrypoint needed. All other packages are libraries Signed-off-by: Reuben Miller --- Cargo.lock | 2 -- crates/core/tedge_agent/Cargo.toml | 1 - crates/core/tedge_agent/src/main.rs | 23 ------------------ crates/core/tedge_mapper/Cargo.toml | 1 - crates/core/tedge_mapper/src/main.rs | 24 ------------------- crates/core/tedge_watchdog/src/main.rs | 7 ------ plugins/c8y_firmware_plugin/src/main.rs | 7 ------ plugins/c8y_remote_access_plugin/src/main.rs | 9 ------- plugins/tedge_apt_plugin/src/main.rs | 6 ----- .../tedge_configuration_plugin/src/main.rs | 7 ------ plugins/tedge_log_plugin/src/main.rs | 7 ------ 11 files changed, 94 deletions(-) delete mode 100644 crates/core/tedge_agent/src/main.rs delete mode 100644 crates/core/tedge_mapper/src/main.rs delete mode 100644 crates/core/tedge_watchdog/src/main.rs delete mode 100644 plugins/c8y_firmware_plugin/src/main.rs delete mode 100644 plugins/c8y_remote_access_plugin/src/main.rs delete mode 100644 plugins/tedge_apt_plugin/src/main.rs delete mode 100644 plugins/tedge_configuration_plugin/src/main.rs delete mode 100644 plugins/tedge_log_plugin/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index a59aee072f8..d314fa488c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3585,7 +3585,6 @@ dependencies = [ "axum_tls", "bytes", "camino", - "cap", "clap", "flockfile", "futures", @@ -3697,7 +3696,6 @@ dependencies = [ "c8y_auth_proxy", "c8y_http_proxy", "c8y_mapper_ext", - "cap", "clap", "clock", "collectd_ext", diff --git a/crates/core/tedge_agent/Cargo.toml b/crates/core/tedge_agent/Cargo.toml index fb5771b1fe5..23122f72d56 100644 --- a/crates/core/tedge_agent/Cargo.toml +++ b/crates/core/tedge_agent/Cargo.toml @@ -16,7 +16,6 @@ axum = { workspace = true } axum-server = { workspace = true } axum_tls = { workspace = true } camino = { workspace = true } -cap = { workspace = true } clap = { workspace = true } flockfile = { workspace = true } futures = { workspace = true } diff --git a/crates/core/tedge_agent/src/main.rs b/crates/core/tedge_agent/src/main.rs deleted file mode 100644 index b0a549132db..00000000000 --- a/crates/core/tedge_agent/src/main.rs +++ /dev/null @@ -1,23 +0,0 @@ -use cap::Cap; -use clap::Parser; -use std::alloc; - -#[global_allocator] -static ALLOCATOR: Cap = Cap::new(alloc::System, usize::MAX); - -#[tokio::main] -async fn main() -> anyhow::Result<()> { - let agent_opt = tedge_agent::AgentOpt::parse(); - let tedge_config = tedge_config::load_tedge_config(&agent_opt.config_dir)?; - let log_memory_interval = tedge_config.run.log_memory_interval.duration(); - if !log_memory_interval.is_zero() { - tokio::spawn(async move { - loop { - log::info!("Allocated memory: {} Bytes", ALLOCATOR.allocated()); - tokio::time::sleep(log_memory_interval).await; - } - }); - } - - tedge_agent::run(agent_opt).await -} diff --git a/crates/core/tedge_mapper/Cargo.toml b/crates/core/tedge_mapper/Cargo.toml index d56cef835bd..c039f563364 100644 --- a/crates/core/tedge_mapper/Cargo.toml +++ b/crates/core/tedge_mapper/Cargo.toml @@ -19,7 +19,6 @@ c8y_api = { workspace = true } c8y_auth_proxy = { workspace = true } c8y_http_proxy = { workspace = true } c8y_mapper_ext = { workspace = true } -cap = { workspace = true } clap = { workspace = true } clock = { workspace = true } collectd_ext = { workspace = true } diff --git a/crates/core/tedge_mapper/src/main.rs b/crates/core/tedge_mapper/src/main.rs deleted file mode 100644 index 6d1dabeadaf..00000000000 --- a/crates/core/tedge_mapper/src/main.rs +++ /dev/null @@ -1,24 +0,0 @@ -use cap::Cap; -use clap::Parser; -use std::alloc; -use tracing::log; - -#[global_allocator] -static ALLOCATOR: Cap = Cap::new(alloc::System, usize::MAX); - -#[tokio::main] -async fn main() -> anyhow::Result<()> { - let mapper_opt = tedge_mapper::MapperOpt::parse(); - let tedge_config = tedge_config::load_tedge_config(&mapper_opt.config_dir)?; - let log_memory_interval = tedge_config.run.log_memory_interval.duration(); - if !log_memory_interval.is_zero() { - tokio::spawn(async move { - loop { - log::info!("Allocated memory: {} Bytes", ALLOCATOR.allocated()); - tokio::time::sleep(log_memory_interval).await; - } - }); - } - - tedge_mapper::run(mapper_opt).await -} diff --git a/crates/core/tedge_watchdog/src/main.rs b/crates/core/tedge_watchdog/src/main.rs deleted file mode 100644 index 2134b02d586..00000000000 --- a/crates/core/tedge_watchdog/src/main.rs +++ /dev/null @@ -1,7 +0,0 @@ -use clap::Parser; - -#[tokio::main] -async fn main() { - let opt = tedge_watchdog::WatchdogOpt::parse(); - tedge_watchdog::run(opt).await.unwrap(); -} diff --git a/plugins/c8y_firmware_plugin/src/main.rs b/plugins/c8y_firmware_plugin/src/main.rs deleted file mode 100644 index 891c379e5d8..00000000000 --- a/plugins/c8y_firmware_plugin/src/main.rs +++ /dev/null @@ -1,7 +0,0 @@ -use clap::Parser; - -#[tokio::main] -async fn main() { - let opt = c8y_firmware_plugin::FirmwarePluginOpt::parse(); - c8y_firmware_plugin::run(opt).await.unwrap(); -} diff --git a/plugins/c8y_remote_access_plugin/src/main.rs b/plugins/c8y_remote_access_plugin/src/main.rs deleted file mode 100644 index 412c45e3a0f..00000000000 --- a/plugins/c8y_remote_access_plugin/src/main.rs +++ /dev/null @@ -1,9 +0,0 @@ -use c8y_remote_access_plugin::C8yRemoteAccessPluginOpt; -use clap::Parser; - -#[tokio::main] -async fn main() { - miette::set_panic_hook(); - let opt = C8yRemoteAccessPluginOpt::parse(); - c8y_remote_access_plugin::run(opt).await.unwrap(); -} diff --git a/plugins/tedge_apt_plugin/src/main.rs b/plugins/tedge_apt_plugin/src/main.rs deleted file mode 100644 index cb2be35b461..00000000000 --- a/plugins/tedge_apt_plugin/src/main.rs +++ /dev/null @@ -1,6 +0,0 @@ -use clap::Parser; - -fn main() { - let cli = tedge_apt_plugin::AptCli::try_parse(); - tedge_apt_plugin::run_and_exit(cli); -} diff --git a/plugins/tedge_configuration_plugin/src/main.rs b/plugins/tedge_configuration_plugin/src/main.rs deleted file mode 100644 index 035456afde7..00000000000 --- a/plugins/tedge_configuration_plugin/src/main.rs +++ /dev/null @@ -1,7 +0,0 @@ -use clap::Parser; - -#[tokio::main] -async fn main() { - let opt = tedge_configuration_plugin::ConfigPluginOpt::parse(); - tedge_configuration_plugin::run(opt).await.unwrap(); -} diff --git a/plugins/tedge_log_plugin/src/main.rs b/plugins/tedge_log_plugin/src/main.rs deleted file mode 100644 index 30880c25ffe..00000000000 --- a/plugins/tedge_log_plugin/src/main.rs +++ /dev/null @@ -1,7 +0,0 @@ -use clap::Parser; - -#[tokio::main] -async fn main() { - let opt = tedge_log_plugin::LogfilePluginOpt::parse(); - tedge_log_plugin::run(opt).await.unwrap(); -} From 73f17bb07a163028dc1be7f660c4964cce5ad6b2 Mon Sep 17 00:00:00 2001 From: Reuben Miller Date: Tue, 13 Feb 2024 17:12:16 +0100 Subject: [PATCH 04/10] skip building deprecated and test packages by default Signed-off-by: Reuben Miller --- ci/build_scripts/build.sh | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ci/build_scripts/build.sh b/ci/build_scripts/build.sh index 64d34065426..ca6b855870d 100755 --- a/ci/build_scripts/build.sh +++ b/ci/build_scripts/build.sh @@ -80,8 +80,8 @@ ARCH= TARGET=() BUILD_OPTIONS=() BUILD=1 -INCLUDE_TEST_PACKAGES=1 -INCLUDE_DEPRECATED_PACKAGES=1 +INCLUDE_TEST_PACKAGES=0 +INCLUDE_DEPRECATED_PACKAGES=0 REST_ARGS=() while [ $# -gt 0 ] @@ -91,10 +91,16 @@ do BUILD=0 ;; + --include-test-packages) + INCLUDE_TEST_PACKAGES=1 + ;; --skip-test-packages) INCLUDE_TEST_PACKAGES=0 ;; + --include-deprecated-packages) + INCLUDE_DEPRECATED_PACKAGES=1 + ;; --skip-deprecated-packages) INCLUDE_DEPRECATED_PACKAGES=0 ;; From 4598cdfafd043863163b5ead87c62fb02628b71f Mon Sep 17 00:00:00 2001 From: Reuben Miller Date: Tue, 13 Feb 2024 17:17:35 +0100 Subject: [PATCH 05/10] remove sawtooth_publisher Signed-off-by: Reuben Miller --- Cargo.lock | 234 ++++++------------ ci/package_list.sh | 4 +- .../nfpm.sawtooth-publisher.yaml | 26 -- crates/tests/sawtooth_publisher/Cargo.toml | 19 -- crates/tests/sawtooth_publisher/src/main.rs | 233 ----------------- 5 files changed, 78 insertions(+), 438 deletions(-) delete mode 100644 configuration/package_manifests/nfpm.sawtooth-publisher.yaml delete mode 100644 crates/tests/sawtooth_publisher/Cargo.toml delete mode 100644 crates/tests/sawtooth_publisher/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index d314fa488c9..ae3c9d57613 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -134,8 +134,8 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 1.0.109", "synstructure", ] @@ -146,8 +146,8 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -195,36 +195,14 @@ dependencies = [ "tokio", ] -[[package]] -name = "async-log" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac39aabd463ad2b1fadb34c22f48e5d160fa60b7cd69a426362e71bde49ebb6d" -dependencies = [ - "async-log-attributes", - "backtrace", - "log", -] - -[[package]] -name = "async-log-attributes" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da97f8e61b19a72f67d8932de8b0905f7d41a1d7b9501b9938c7755f96f6362d" -dependencies = [ - "proc-macro2 0.4.30", - "quote 0.6.13", - "syn 0.15.44", -] - [[package]] name = "async-trait" version = "0.1.77" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -352,8 +330,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdca6a10ecad987bda04e95606ef85a5417dcaac1a78455242d72e031e2b6b62" dependencies = [ "heck", - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -841,8 +819,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" dependencies = [ "heck", - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -1021,8 +999,8 @@ checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2", + "quote", "strsim", "syn 1.0.109", ] @@ -1035,8 +1013,8 @@ checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2", + "quote", "strsim", "syn 2.0.48", ] @@ -1048,7 +1026,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" dependencies = [ "darling_core 0.13.4", - "quote 1.0.35", + "quote", "syn 1.0.109", ] @@ -1059,7 +1037,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core 0.20.3", - "quote 1.0.35", + "quote", "syn 2.0.48", ] @@ -1115,8 +1093,8 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -1150,8 +1128,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74073dd10495ce912909655131925b0459d49363751b93676148d843097fe825" dependencies = [ "darling 0.13.4", - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -1416,8 +1394,8 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -1866,9 +1844,6 @@ name = "log" version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" -dependencies = [ - "value-bag", -] [[package]] name = "log_manager" @@ -1979,8 +1954,8 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b4faf00617defe497754acde3024865bc143d44a86799b24e191ecff91354f" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -2026,8 +2001,8 @@ version = "5.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -2086,8 +2061,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ce75669015c4f47b289fd4d4f56e894e4c96003ffdf3ac51313126f94c6cbb" dependencies = [ "cfg-if", - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -2386,9 +2361,9 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e22670e8eb757cff11d6c199ca7b987f352f0346e0be4dd23869ec72cb53c77" dependencies = [ - "proc-macro2 1.0.78", + "proc-macro2", "proc-macro2-diagnostics", - "quote 1.0.35", + "quote", "syn 2.0.48", ] @@ -2446,8 +2421,8 @@ checksum = "2a31940305ffc96863a735bef7c7994a00b325a7138fdbc5bda0f1a0476d3275" dependencies = [ "pest", "pest_meta", - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -2487,8 +2462,8 @@ version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -2595,8 +2570,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 1.0.109", "version_check", ] @@ -2607,20 +2582,11 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2", + "quote", "version_check", ] -[[package]] -name = "proc-macro2" -version = "0.4.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -dependencies = [ - "unicode-xid 0.1.0", -] - [[package]] name = "proc-macro2" version = "1.0.78" @@ -2636,8 +2602,8 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", "version_check", "yansi 1.0.0-rc.1", @@ -2685,22 +2651,13 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" -[[package]] -name = "quote" -version = "0.6.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" -dependencies = [ - "proc-macro2 0.4.30", -] - [[package]] name = "quote" version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ - "proc-macro2 1.0.78", + "proc-macro2", ] [[package]] @@ -2913,8 +2870,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7229b505ae0706e64f37ffc54a9c163e11022a6636d58fe1f3f52018257ff9f7" dependencies = [ "cfg-if", - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2", + "quote", "rustc_version", "syn 1.0.109", "unicode-ident", @@ -3089,20 +3046,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "sawtooth-publisher" -version = "1.0.0" -dependencies = [ - "async-log", - "env_logger", - "futures", - "futures-timer", - "log", - "mqtt_channel", - "tedge_config", - "tokio", -] - [[package]] name = "schannel" version = "0.1.23" @@ -3172,8 +3115,8 @@ version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -3248,8 +3191,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1b95bb2f4f624565e8fe8140c789af7e2082c0e0561b5a82a1b678baa9703dc" dependencies = [ "proc-macro-error", - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2", + "quote", "rustversion", "syn 1.0.109", ] @@ -3420,8 +3363,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ "heck", - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2", + "quote", "rustversion", "syn 1.0.109", ] @@ -3454,25 +3397,14 @@ dependencies = [ "is-terminal", ] -[[package]] -name = "syn" -version = "0.15.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" -dependencies = [ - "proc-macro2 0.4.30", - "quote 0.6.13", - "unicode-xid 0.1.0", -] - [[package]] name = "syn" version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2", + "quote", "unicode-ident", ] @@ -3482,8 +3414,8 @@ version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2", + "quote", "unicode-ident", ] @@ -3499,10 +3431,10 @@ version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 1.0.109", - "unicode-xid 0.2.4", + "unicode-xid", ] [[package]] @@ -3843,8 +3775,8 @@ version = "1.0.0" dependencies = [ "darling 0.20.3", "heck", - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -3852,8 +3784,8 @@ dependencies = [ name = "tedge_config_macros-macro" version = "1.0.0" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", "tedge_config_macros-impl", ] @@ -4125,8 +4057,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adcb7fd841cd518e279be3d5a3eb0636409487998a4aff22f3de87b81e88384f" dependencies = [ "cfg-if", - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -4136,8 +4068,8 @@ version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", "test-case-core", ] @@ -4168,8 +4100,8 @@ version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -4254,8 +4186,8 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -4412,8 +4344,8 @@ version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -4549,12 +4481,6 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" -[[package]] -name = "unicode-xid" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" - [[package]] name = "unicode-xid" version = "0.2.4" @@ -4626,12 +4552,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" -[[package]] -name = "value-bag" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cdbaf5e132e593e9fc1de6a15bbec912395b11fb9719e061cf64f804524c503" - [[package]] name = "version_check" version = "0.9.4" @@ -4691,8 +4611,8 @@ dependencies = [ "bumpalo", "log", "once_cell", - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", "wasm-bindgen-shared", ] @@ -4715,7 +4635,7 @@ version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" dependencies = [ - "quote 1.0.35", + "quote", "wasm-bindgen-macro-support", ] @@ -4725,8 +4645,8 @@ version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", "wasm-bindgen-backend", "wasm-bindgen-shared", @@ -5045,8 +4965,8 @@ version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ - "proc-macro2 1.0.78", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] diff --git a/ci/package_list.sh b/ci/package_list.sh index 9508384bcf1..07f5c7b1922 100755 --- a/ci/package_list.sh +++ b/ci/package_list.sh @@ -18,9 +18,7 @@ export RELEASE_PACKAGES DEPRECATED_PACKAGES=() export DEPRECATED_PACKAGES -TEST_PACKAGES=( - sawtooth-publisher -) +TEST_PACKAGES=() export TEST_PACKAGES EXTERNAL_ARM_PACKAGES=( diff --git a/configuration/package_manifests/nfpm.sawtooth-publisher.yaml b/configuration/package_manifests/nfpm.sawtooth-publisher.yaml deleted file mode 100644 index 952f9097b23..00000000000 --- a/configuration/package_manifests/nfpm.sawtooth-publisher.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# yaml-language-server: $schema=https://nfpm.goreleaser.com/static/schema.json ---- -name: sawtooth-publisher -description: | - TEST ONLY: sawtooth wave generator -arch: "${PKG_ARCH}" -platform: "linux" -version: "${GIT_SEMVER}" -release: "${RELEASE}" -section: misc -priority: "optional" -maintainer: "thin-edge.io team " -vendor: "thin-edge.io" -homepage: "https://thin-edge.io" -license: "Apache-2.0" - -deb: - fields: - Vcs-Browser: ${CI_PROJECT_URL} - Vcs-Git: ${CI_PROJECT_URL} - compression: xz - -contents: - # binary - - src: .build/sawtooth-publisher - dst: /usr/bin/ diff --git a/crates/tests/sawtooth_publisher/Cargo.toml b/crates/tests/sawtooth_publisher/Cargo.toml deleted file mode 100644 index af36b03ab04..00000000000 --- a/crates/tests/sawtooth_publisher/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "sawtooth-publisher" -version = { workspace = true } -authors = ["thin-edge.io team "] -edition = "2018" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -async-log = { workspace = true } -env_logger = { workspace = true } -futures = { workspace = true } -futures-timer = { workspace = true } -log = { workspace = true } -mqtt_channel = { workspace = true } -tedge_config = { workspace = true } -tokio = { workspace = true, features = ["sync", "macros"] } - -[lints] -workspace = true diff --git a/crates/tests/sawtooth_publisher/src/main.rs b/crates/tests/sawtooth_publisher/src/main.rs deleted file mode 100644 index c30d8ad9b9c..00000000000 --- a/crates/tests/sawtooth_publisher/src/main.rs +++ /dev/null @@ -1,233 +0,0 @@ -use futures::future::FutureExt; -use futures::select; -use futures_timer::Delay; -use log::debug; -use log::error; -use log::info; -use mqtt_channel::Connection; -use mqtt_channel::ErrChannel; -use mqtt_channel::Message; -use mqtt_channel::MqttError; -use mqtt_channel::PubChannel; -use mqtt_channel::SubChannel; -use mqtt_channel::Topic; -use mqtt_channel::TopicFilter; -use std::convert::TryFrom; -use std::env; -use std::fmt::Write as _; -use std::io::Write; -use std::process; -use std::time::Duration; -use std::time::Instant; - -/* - -This is a small and flexible publisher for deterministic test data. - -- TODO: Improve code quality -- TODO: Add different data types for JSON publishing -- TODO: Command line switch to switch between REST and JSON -- TODO: Currently REST sending is disabled and JSON publishing is enabled -- TODO: Add QoS selection -*/ - -// Templates: -// https://cumulocity.com/guides/10.4.6/device-sdk/mqtt/ -// -// Create custom measurement (200) -// Create signal strength measurement (210) -// Create temperature measurement (211) -// Create battery measurement (212) - -// sawtooth-publisher