summaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
authorRina Fujino <18257209+rina23q@users.noreply.github.com>2022-05-18 01:22:31 +0200
committerRina Fujino <18257209+rina23q@users.noreply.github.com>2022-05-18 01:22:31 +0200
commit88ef4b2fd0076811687a0b23ec21edad1ca2e0af (patch)
treed188a55087072d0f8c9ef05e89e34b4ac0126e0c /plugins
parent7e6d95fa0d0289885df2cd533318c9afdd3e5e69 (diff)
Add user, group, mode support
Signed-off-by: Rina Fujino <18257209+rina23q@users.noreply.github.com>
Diffstat (limited to 'plugins')
-rw-r--r--plugins/c8y_configuration_plugin/src/config.rs145
-rw-r--r--plugins/c8y_configuration_plugin/src/download.rs170
-rw-r--r--plugins/c8y_configuration_plugin/src/error.rs16
-rw-r--r--plugins/c8y_configuration_plugin/src/main.rs11
-rw-r--r--plugins/c8y_configuration_plugin/src/upload.rs13
5 files changed, 216 insertions, 139 deletions
diff --git a/plugins/c8y_configuration_plugin/src/config.rs b/plugins/c8y_configuration_plugin/src/config.rs
index 839eab6d..0c42a804 100644
--- a/plugins/c8y_configuration_plugin/src/config.rs
+++ b/plugins/c8y_configuration_plugin/src/config.rs
@@ -7,6 +7,7 @@ use std::collections::HashSet;
use std::fs;
use std::hash::{Hash, Hasher};
use std::path::Path;
+use tedge_utils::file::FilePermissions;
use tracing::{info, warn};
#[derive(Deserialize, Debug, Default)]
@@ -21,6 +22,9 @@ pub struct RawFileEntry {
pub path: String,
#[serde(rename = "type")]
config_type: Option<String>,
+ user: Option<String>,
+ group: Option<String>,
+ mode: Option<u32>,
}
#[derive(Debug, Eq, PartialEq, Default, Clone)]
@@ -32,6 +36,7 @@ pub struct PluginConfig {
pub struct FileEntry {
pub path: String,
config_type: String,
+ pub file_permissions: FilePermissions,
}
impl Hash for FileEntry {
@@ -53,8 +58,18 @@ impl Borrow<String> for FileEntry {
}
impl FileEntry {
- pub fn new(path: String, config_type: String) -> Self {
- Self { path, config_type }
+ pub fn new(
+ path: String,
+ config_type: String,
+ user: Option<String>,
+ group: Option<String>,
+ mode: Option<u32>,
+ ) -> Self {
+ Self {
+ path,
+ config_type,
+ file_permissions: FilePermissions { user, group, mode },
+ }
}
}
@@ -65,16 +80,13 @@ impl RawPluginConfig {
match fs::read_to_string(config_file_path) {
Ok(contents) => match toml::from_str(contents.as_str()) {
Ok(config) => config,
- _ => {
- warn!("The config file {} is malformed.", path_str);
+ Err(err) => {
+ warn!("The config file {path_str} is malformed. {err}");
Self::default()
}
},
- Err(_) => {
- warn!(
- "The config file {} does not exist or is not readable.",
- path_str
- );
+ Err(err) => {
+ warn!("The config file {path_str} does not exist or is not readable. {err}");
Self::default()
}
}
@@ -92,6 +104,9 @@ impl PluginConfig {
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]),
@@ -104,7 +119,22 @@ impl PluginConfig {
let config_type = raw_entry
.config_type
.unwrap_or_else(|| raw_entry.path.clone());
- let entry = FileEntry::new(raw_entry.path, config_type.clone());
+
+ if config_type.contains(&['+', '#']) {
+ warn!(
+ "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) {
warn!("The config file has the duplicated type '{}'.", config_type);
return original_plugin_config;
@@ -125,7 +155,10 @@ impl PluginConfig {
.collect::<Vec<_>>()
}
- pub fn get_path_from_type(&self, config_type: &str) -> Result<String, ConfigManagementError> {
+ pub fn get_file_entry_from_type(
+ &self,
+ config_type: &str,
+ ) -> Result<FileEntry, ConfigManagementError> {
let file_entry = self
.files
.get(&config_type.to_string())
@@ -133,7 +166,7 @@ impl PluginConfig {
config_type: config_type.to_owned(),
})?
.to_owned();
- Ok(file_entry.path)
+ Ok(file_entry)
}
// 119,typeA,typeB,...
@@ -181,23 +214,23 @@ mod tests {
assert_eq!(
config.files,
vec![
- RawFileEntry::new(
+ RawFileEntry::new_with_path_and_type(
"/etc/tedge/tedge.toml".to_string(),
Some("tedge.toml".to_string())
),
- RawFileEntry::new(
+ RawFileEntry::new_with_path_and_type(
"/etc/tedge/tedge.toml".to_string(),
Some("tedge.toml".to_string())
),
- RawFileEntry::new(
+ RawFileEntry::new_with_path_and_type(
"/etc/tedge/mosquitto-conf/c8y-bridge.conf".to_string(),
None
),
- RawFileEntry::new(
+ RawFileEntry::new_with_path_and_type(
"/etc/tedge/mosquitto-conf/tedge-mosquitto.conf".to_string(),
Some("\"double quotation\"".to_string())
),
- RawFileEntry::new(
+ RawFileEntry::new_with_path_and_type(
"/etc/mosquitto/mosquitto.conf".to_string(),
Some("'single quotation'".to_string())
)
@@ -223,23 +256,23 @@ mod tests {
assert_eq!(
config.files,
vec![
- RawFileEntry::new(
+ RawFileEntry::new_with_path_and_type(
"/etc/tedge/tedge.toml".to_string(),
Some("tedge.toml".to_string())
),
- RawFileEntry::new(
+ RawFileEntry::new_with_path_and_type(
"/etc/tedge/tedge.toml".to_string(),
Some("tedge.toml".to_string())
),
- RawFileEntry::new(
+ RawFileEntry::new_with_path_and_type(
"/etc/tedge/mosquitto-conf/c8y-bridge.conf".to_string(),
None
),
- RawFileEntry::new(
+ RawFileEntry::new_with_path_and_type(
"/etc/tedge/mosquitto-conf/tedge-mosquitto.conf".to_string(),
Some("\"double quotation\"".to_string())
),
- RawFileEntry::new(
+ RawFileEntry::new_with_path_and_type(
"/etc/mosquitto/mosquitto.conf".to_string(),
Some("'single quotation'".to_string())
)
@@ -257,8 +290,8 @@ mod tests {
"#,
PluginConfig {
files: HashSet::from([
- FileEntry::new("/etc/tedge/tedge.toml".to_string(), "tedge".to_string()),
- FileEntry::new("/etc/tedge/mosquitto-conf/c8y-bridge.conf".to_string(), "/etc/tedge/mosquitto-conf/c8y-bridge.conf".to_string()),
+ FileEntry::new_with_path_and_type("/etc/tedge/tedge.toml".to_string(), "tedge".to_string()),
+ FileEntry::new_with_path_and_type("/etc/tedge/mosquitto-conf/c8y-bridge.conf".to_string(), "/etc/tedge/mosquitto-conf/c8y-bridge.conf".to_string()),
])
}; "standard case"
)]
@@ -273,8 +306,8 @@ mod tests {
"#,
PluginConfig {
files: HashSet::from([
- FileEntry::new("/etc/tedge/tedge.toml".to_string(), "tedge".to_string()),
- FileEntry::new("/etc/tedge/tedge.toml".to_string(), "tedge2".to_string()),
+ FileEntry::new_with_path_and_type("/etc/tedge/tedge.toml".to_string(), "tedge".to_string()),
+ FileEntry::new_with_path_and_type("/etc/tedge/tedge.toml".to_string(), "tedge2".to_string()),
])
}; "file path duplication"
)]
@@ -288,14 +321,36 @@ mod tests {
type = "tedge"
"#,
PluginConfig {
- files: HashSet::new()
- }; "file type duplication"
+ files: HashSet::new()
+ }; "file type duplication"
)]
#[test_case(
- r#"files = []"#,
+ r#"
+ [[files]]
+ path = "/etc/tedge/tedge.toml"
+ type = "tedge#"
+ "#,
PluginConfig {
files: HashSet::new()
}
+ ;"type contains sharp"
+ )]
+ #[test_case(
+ r#"
+ [[files]]
+ path = "/etc/tedge/tedge.toml"
+ type = "tedge+"
+ "#,
+ PluginConfig {
+ files: HashSet::new()
+ }
+ ;"type contains plus"
+ )]
+ #[test_case(
+ r#"files = []"#,
+ PluginConfig {
+ files: HashSet::new()
+ }
;"empty case"
)]
#[test_case(
@@ -338,8 +393,24 @@ mod tests {
}
impl RawFileEntry {
- pub fn new(path: String, config_type: Option<String>) -> Self {
- Self { path, config_type }
+ pub fn new_with_path_and_type(path: String, config_type: Option<String>) -> Self {
+ Self {
+ path,
+ config_type,
+ user: None,
+ group: None,
+ mode: None,
+ }
+ }
+ }
+
+ impl FileEntry {
+ pub fn new_with_path_and_type(path: String, config_type: String) -> Self {
+ Self {
+ path,
+ config_type,
+ file_permissions: FilePermissions::default(),
+ }
}
}
@@ -347,7 +418,7 @@ mod tests {
impl PluginConfig {
fn add_file_entry(&self, path: String, config_type: String) -> Self {
let mut files = self.files.clone();
- let _ = files.insert(FileEntry::new(path, config_type));
+ let _ = files.insert(FileEntry::new(path, config_type, None, None, None));
Self { files }
}
}
@@ -357,7 +428,7 @@ mod tests {
let temp_dir = TempDir::new()?;
let config_root = temp_dir.path().to_path_buf();
let config_file_path = config_root.join(PLUGIN_CONFIG_FILE);
- let mut file = std::fs::File::create(config_file_path.as_path())?;
+ let mut file = fs::File::create(config_file_path.as_path())?;
file.write_all(content.as_bytes())?;
Ok((temp_dir, config_root))
}
@@ -365,7 +436,7 @@ mod tests {
#[test]
fn get_smartrest_single_type() {
let plugin_config = PluginConfig {
- files: HashSet::from([FileEntry::new(
+ files: HashSet::from([FileEntry::new_with_path_and_type(
"/path/to/file".to_string(),
"typeA".to_string(),
)]),
@@ -378,9 +449,9 @@ mod tests {
fn get_smartrest_multiple_types() {
let plugin_config = PluginConfig {
files: HashSet::from([
- FileEntry::new("path1".to_string(), "typeA".to_string()),
- FileEntry::new("path2".to_string(), "typeB".to_string()),
- FileEntry::new("path3".to_string(), "typeC".to_string()),
+ FileEntry::new_with_path_and_type("path1".to_string(), "typeA".to_string()),
+ FileEntry::new_with_path_and_type("path2".to_string(), "typeB".to_string()),
+ FileEntry::new_with_path_and_type("path3".to_string(), "typeC".to_string()),
]),
};
let output = plugin_config.to_smartrest_payload();
diff --git a/plugins/c8y_configuration_plugin/src/download.rs b/plugins/c8y_configuration_plugin/src/download.rs
index e58ef1f6..9a345385 100644
--- a/plugins/c8y_configuration_plugin/src/download.rs
+++ b/plugins/c8y_configuration_plugin/src/download.rs
@@ -10,11 +10,11 @@ use c8y_smartrest::smartrest_serializer::{
};
use download::{Auth, DownloadInfo, Downloader};
use mqtt_channel::{Connection, Message, SinkExt, Topic};
-use serde::{Deserialize, Serialize};
use serde_json::json;
use std::fs;
use std::os::unix::fs::PermissionsExt;
-use std::path::{Path, PathBuf};
+use std::path::PathBuf;
+use tedge_utils::file::{get_filename, get_metadata, FilePermissions};
use tracing::{info, warn};
pub async fn handle_config_download_request(
@@ -27,21 +27,31 @@ pub async fn handle_config_download_request(
let executing_message = DownloadConfigFileStatusMessage::executing()?;
let () = mqtt_client.published.send(executing_message).await?;
- let changed_config_type = smartrest_request.config_type.clone();
-
- match download_config_file(plugin_config, smartrest_request, tmp_dir, http_client).await {
+ let target_config_type = smartrest_request.config_type.clone();
+ let target_file_entry = plugin_config.get_file_entry_from_type(&target_config_type)?;
+
+ match download_config_file(
+ smartrest_request.url.as_str(),
+ PathBuf::from(&target_file_entry.path),
+ tmp_dir,
+ target_file_entry.file_permissions,
+ http_client,
+ )
+ .await
+ {
Ok(_) => {
- info!("The configuration download for '{changed_config_type}' is successful.");
+ info!("The configuration download for '{target_config_type}' is successful.");
let successful_message = DownloadConfigFileStatusMessage::successful(None)?;
let () = mqtt_client.published.send(successful_message).await?;
- let notification_message = get_file_change_notification_message(changed_config_type);
+ let notification_message =
+ get_file_change_notification_message(&target_file_entry.path, &target_config_type);
let () = mqtt_client.published.send(notification_message).await?;
Ok(())
}
Err(err) => {
- error!("The configuration download for '{changed_config_type}' is failed.",);
+ error!("The configuration download for '{target_config_type}' is failed.",);
let failed_message = DownloadConfigFileStatusMessage::failed(err.to_string())?;
let () = mqtt_client.published.send(failed_message).await?;
@@ -51,14 +61,15 @@ pub async fn handle_config_download_request(
}
async fn download_config_file(
- plugin_config: &PluginConfig,
- smartrest_request: SmartRestConfigDownloadRequest,
+ download_url: &str,
+ file_path: PathBuf,
tmp_dir: PathBuf,
+ file_permissions: FilePermissions,
http_client: &mut impl C8YHttpProxy,
) -> Result<(), anyhow::Error> {
// Convert smartrest request to config download request struct
let mut config_download_request =
- ConfigDownloadRequest::try_new(smartrest_request, plugin_config, tmp_dir)?;
+ ConfigDownloadRequest::try_new(download_url, file_path, tmp_dir, file_permissions)?;
// Confirm that the file has write access before any http request attempt
let () = config_download_request.has_write_access()?;
@@ -81,55 +92,59 @@ async fn download_config_file(
Ok(())
}
-#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
+#[derive(Debug, Clone, PartialEq)]
pub struct ConfigDownloadRequest {
pub download_info: DownloadInfo,
- pub destination_path: PathBuf,
+ pub file_path: PathBuf,
pub tmp_dir: PathBuf,
+ pub file_permissions: FilePermissions,
pub file_name: String,
}
impl ConfigDownloadRequest {
fn try_new(
- request: SmartRestConfigDownloadRequest,
- plugin_config: &PluginConfig,
+ download_url: &str,
+ file_path: PathBuf,
tmp_dir: PathBuf,
+ file_permissions: FilePermissions,
) -> Result<Self, ConfigManagementError> {
- let destination_path_string = plugin_config.get_path_from_type(&request.config_type)?;
- let destination_path = PathBuf::from(destination_path_string);
- let file_name = Self::get_filename(destination_path.clone())?;
+ let file_name = get_filename(file_path.clone()).ok_or_else(|| {
+ ConfigManagementError::FileNameNotFound {
+ path: file_path.clone(),
+ }
+ })?;
Ok(Self {
download_info: DownloadInfo {
- url: request.url,
+ url: download_url.into(),
auth: None,
},
- destination_path,
+ file_path,
tmp_dir,
+ file_permissions,
file_name,
})
}
- fn get_filename(path: PathBuf) -> Result<String, ConfigManagementError> {
- let filename = path
- .file_name()
- .ok_or_else(|| ConfigManagementError::FileNameNotFound { path: path.clone() })?
- .to_str()
- .ok_or_else(|| ConfigManagementError::InvalidFileName { path: path.clone() })?
- .to_string();
- Ok(filename)
- }
-
fn has_write_access(&self) -> Result<(), ConfigManagementError> {
// The file does not exist before downloading a file
- if !&self.destination_path.is_file() {
- return Ok(());
- }
- // Need a permission check when the file exists already
- let metadata = Self::get_metadata(&self.destination_path)?;
+ let metadata =
+ if self.file_path.is_file() {
+ get_metadata(&self.file_path)?
+ } else {
+ // If the file does not exist before downloading file, check the directory perms
+ let parent_dir = &self.file_path.parent().ok_or_else(|| {
+ ConfigManagementError::NoWriteAccess {
+ path: self.file_path.clone(),
+ }
+ })?;
+ get_metadata(parent_dir)?
+ };
+
+ // Write permission check
if metadata.permissions().readonly() {
- Err(error::ConfigManagementError::ReadOnlyFile {
- path: self.destination_path.clone(),
+ Err(ConfigManagementError::NoWriteAccess {
+ path: self.file_path.clone(),
})
} else {
Ok(())
@@ -140,19 +155,13 @@ impl ConfigDownloadRequest {
Downloader::new(&self.file_name, &None, &self.tmp_dir)
}
- fn get_metadata(path: &Path) -> Result<std::fs::Metadata, ConfigManagementError> {
- fs::metadata(&path).map_err(|_| ConfigManagementError::FileNotAccessible {
- path: path.to_path_buf(),
- })
- }
-
fn move_file(&self) -> Result<(), ConfigManagementError> {
let src = &self.tmp_dir.join(&self.file_name);
- let dest = &self.destination_path;
+ let dest = &self.file_path;
- let original_permission_mode = match self.destination_path.is_file() {
+ let original_permission_mode = match self.file_path.is_file() {
true => {
- let metadata = Self::get_metadata(&self.destination_path)?;
+ let metadata = get_metadata(&self.file_path)?;
let mode = metadata.permissions().mode();
Some(mode)
}
@@ -164,19 +173,22 @@ impl ConfigDownloadRequest {
dest: dest.to_path_buf(),
})?;
- // Change the file permission back to the original one
- if let Some(mode) = original_permission_mode {
- let mut permissions = Self::get_metadata(&self.destination_path)?.permissions();
- let _ = permissions.set_mode(mode);
- let _ = std::fs::set_permissions(&self.destination_path, permissions);
- }
+ let file_permissions = if let Some(mode) = original_permission_mode {
+ // Use the same file permission as the original one
+ FilePermissions::new(None, None, Some(mode))
+ } else {
+ // Set the user, group, and mode as given for a new file
+ self.file_permissions.clone()
+ };
+
+ let () = file_permissions.change_permissions(&self.file_path.display().to_string())?;
Ok(())
}
}
-pub fn get_file_change_notification_message(config_type: String) -> Message {
- let notification = json!({ "changedFile": config_type }).to_string();
+pub fn get_file_change_notification_message(file_path: &str, config_type: &str) -> Message {
+ 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.");
@@ -212,29 +224,17 @@ impl TryIntoOperationStatusMessage for DownloadConfigFileStatusMessage {
#[cfg(test)]
mod tests {
use super::*;
- use crate::config::FileEntry;
use assert_matches::*;
- use c8y_smartrest::smartrest_deserializer::SmartRestRequestGeneric;
- use std::collections::HashSet;
#[test]
fn create_config_download_request() -> Result<(), anyhow::Error> {
- let payload = "524,rina0005,https://test.cumulocity.com/inventory/binaries/70208,tedge";
- let smartrest_request = SmartRestConfigDownloadRequest::from_smartrest(payload)?;
- let plugin_config = PluginConfig {
- files: HashSet::from([
- FileEntry::new("/etc/tedge/tedge.toml".to_string(), "tedge".to_string()),
- FileEntry::new(
- "/etc/tedge/mosquitto-conf/c8y-bridge.conf".to_string(),
- "c8y-bridge".to_string(),
- ),
- ]),
- };
let config_download_request = ConfigDownloadRequest::try_new(
- smartrest_request,
- &plugin_config,
+ "https://test.cumulocity.com/inventory/binaries/70208",
+ PathBuf::from("/etc/tedge/tedge.toml"),
PathBuf::from("/tmp"),
+ FilePermissions::default(),
)?;
+
assert_eq!(
config_download_request,
ConfigDownloadRequest {
@@ -242,8 +242,9 @@ mod tests {
url: "https://test.cumulocity.com/inventory/binaries/70208".to_string(),
auth: None
},
- destination_path: PathBuf::from("/etc/tedge/tedge.toml"),
+ file_path: PathBuf::from("/etc/tedge/tedge.toml"),
tmp_dir: PathBuf::from("/tmp"),
+ file_permissions: FilePermissions::new(None, None, None),
file_name: "tedge.toml".to_string()
}
);
@@ -251,25 +252,16 @@ mod tests {
}
#[test]
- fn requested_config_does_not_match_config_plugin() -> Result<(), anyhow::Error> {
- let payload =
- "524,rina0005,https://test.cumulocity.com/inventory/binaries/70208,not_in_config.toml";
- let smartrest_request = SmartRestConfigDownloadRequest::from_smartrest(payload)?;
- let plugin_config = PluginConfig {
- files: HashSet::from([FileEntry::new(
- "/etc/tedge/tedge.toml".to_string(),
- "tedge".to_string(),
- )]),
- };
- let config_download_request = ConfigDownloadRequest::try_new(
- smartrest_request,
- &plugin_config,
+ fn create_config_download_request_without_file_name() -> Result<(), anyhow::Error> {
+ let error = ConfigDownloadRequest::try_new(
+ "https://test.cumulocity.com/inventory/binaries/70208",
+ PathBuf::from("/"),
PathBuf::from("/tmp"),
- );
- assert_matches!(
- config_download_request,
- Err(ConfigManagementError::InvalidRequestedConfigType { .. })
- );
+ FilePermissions::default(),
+ )
+ .unwrap_err();
+
+ assert_matches!(error, ConfigManagementError::FileNameNotFound { .. });
Ok(())
}
diff --git a/plugins/c8y_configuration_plugin/src/error.rs b/plugins/c8y_configuration_plugin/src/error.rs
index efcb0913..a8841788 100644
--- a/plugins/c8y_configuration_plugin/src/error.rs
+++ b/plugins/c8y_configuration_plugin/src/error.rs
@@ -1,19 +1,14 @@
use std::path::PathBuf;
+use tedge_utils::file::FileError;
#[derive(thiserror::Error, Debug)]
pub enum ConfigManagementError {
- #[error("The file is read-only {path:?}")]
- ReadOnlyFile { path: PathBuf },
+ #[error("No write access to {path:?}")]
+ NoWriteAccess { path: PathBuf },
- #[error("The file name is not found from {path:?}")]
+ #[error("The file name is not found or invalid: {path:?}")]
FileNameNotFound { path: PathBuf },
- #[error("The file name is invalid. {path:?}")]
- InvalidFileName { path: PathBuf },
-
- #[error("The file is not accessible. {path:?}")]
- FileNotAccessible { path: PathBuf },
-
#[error("Failed to copy a file from {src:?} to {dest:?}")]
FileCopyFailed { src: PathBuf, dest: PathBuf },
@@ -27,4 +22,7 @@ pub enum ConfigManagementError {
#[error(transparent)]
FromConfigSetting(#[from] tedge_config::ConfigSettingError),
+
+ #[error(transparent)]
+ FromFile(#[from] FileError),
}
diff --git a/plugins/c8y_configuration_plugin/src/main.rs b/plugins/c8y_configuration_plugin/src/main.rs
index 0616a836..71b1d9ea 100644
--- a/plugins/c8y_configuration_plugin/src/main.rs
+++ b/plugins/c8y_configuration_plugin/src/main.rs
@@ -13,7 +13,7 @@ use c8y_smartrest::smartrest_deserializer::{
};
use c8y_smartrest::topic::C8yTopic;
use clap::Parser;
-use mqtt_channel::{SinkExt, StreamExt};
+use mqtt_channel::{Message, SinkExt, StreamExt, Topic};
use std::path::{Path, PathBuf};
use tedge_config::{
ConfigRepository, ConfigSettingAccessor, MqttPortSetting, TEdgeConfig, TmpPathSetting,
@@ -128,6 +128,13 @@ async fn run(
debug!("Plugin init message: {:?}", msg);
let () = mqtt_client.published.send(msg).await?;
+ // Get pending operations
+ let msg = Message::new(
+ &Topic::new_unchecked(C8yTopic::SmartRestResponse.as_str()),
+ "500",
+ );
+ let () = mqtt_client.published.send(msg).await?;
+
// Mqtt message loop
while let Some(message) = mqtt_client.received.next().await {
debug!("Received {:?}", message);
@@ -236,7 +243,7 @@ mod tests {
let test_config_type = "config_type";
let plugin_config = PluginConfig {
- files: HashSet::from([FileEntry::new(
+ files: HashSet::from([FileEntry::new_with_path_and_type(
test_config_path.to_string(),
test_config_type.to_string(),
)]),
diff --git a/plugins/c8y_configuration_plugin/src/upload.rs b/plugins/c8y_configuration_plugin/src/upload.rs
index af676ffb..585c54de 100644
--- a/plugins/c8y_configuration_plugin/src/upload.rs
+++ b/plugins/c8y_configuration_plugin/src/upload.rs
@@ -12,6 +12,7 @@ use c8y_smartrest::{
};
use mqtt_channel::{Connection, SinkExt};
use std::path::Path;
+use tracing::{error, info};
struct UploadConfigFileStatusMessage {}
@@ -52,7 +53,9 @@ pub async fn handle_config_upload_request(
let msg = UploadConfigFileStatusMessage::executing()?;
let () = mqtt_client.published.send(msg).await?;
- let config_file_path = plugin_config.get_path_from_type(&config_upload_request.config_type)?;
+ let config_file_path = plugin_config
+ .get_file_entry_from_type(&config_upload_request.config_type)?
+ .path;
let upload_result = upload_config_file(
Path::new(config_file_path.as_str()),
&config_upload_request.config_type,
@@ -60,13 +63,19 @@ pub async fn handle_config_upload_request(
)
.await;
+ 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))?;
let () = mqtt_client.published.send(successful_message).await?;
}
Err(err) => {
+ error!("The configuration upload for '{target_config_type}' is failed.",);
+
let failed_message = UploadConfigFileStatusMessage::failed(err.to_string())?;
let () = mqtt_client.published.send(failed_message).await?;
}
@@ -179,7 +188,7 @@ mod tests {
};
let plugin_config = PluginConfig {
- files: HashSet::from([FileEntry::new(
+ files: HashSet::from([FileEntry::new_with_path_and_type(
"/some/test/config".to_string(),
"config_type".to_string(),
)]),