summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPradeepKiruvale <pradeepkumar.kj@softwareag.com>2022-06-29 16:46:40 +0530
committerGitHub <noreply@github.com>2022-06-29 16:46:40 +0530
commitddd2f09972f1c67ee562a3ccf5c22c92890b4eaa (patch)
tree4893ee865cf68ffb282079683b7993a4452a893a
parent9b8d8c8ecb081176350adefb9d3d2d468ba625d5 (diff)
c8y_configuration_plugin --init and c8y_log_plugin --init are overwriting exiting files (#1217)
--init should not overwrite the existing files Signed-off-by: Pradeep Kumar K J <pradeepkumar.kj@softwareag.com>
-rw-r--r--crates/common/tedge_utils/src/file.rs83
-rw-r--r--crates/core/tedge_mapper/src/c8y/mapper.rs2
-rw-r--r--plugins/c8y_configuration_plugin/src/main.rs27
-rw-r--r--plugins/c8y_log_plugin/src/main.rs55
4 files changed, 92 insertions, 75 deletions
diff --git a/crates/common/tedge_utils/src/file.rs b/crates/common/tedge_utils/src/file.rs
index 6b714750..902d10c0 100644
--- a/crates/common/tedge_utils/src/file.rs
+++ b/crates/common/tedge_utils/src/file.rs
@@ -1,5 +1,5 @@
use nix::unistd::*;
-use std::fs::File;
+use std::io::Write;
use std::os::linux::fs::MetadataExt;
use std::os::unix::fs::PermissionsExt;
use std::path::{Path, PathBuf};
@@ -28,6 +28,9 @@ pub enum FileError {
#[error("The path is not accessible. {path:?}")]
PathNotAccessible { path: PathBuf },
+
+ #[error("Writing the content to the file failed: {file:?}.")]
+ WriteContentFailed { file: String, from: std::io::Error },
}
pub fn create_directory_with_user_group(
@@ -37,14 +40,12 @@ pub fn create_directory_with_user_group(
mode: u32,
) -> Result<(), FileError> {
let perm_entry = PermissionEntry::new(Some(user.into()), Some(group.into()), Some(mode));
- let () = perm_entry.create_directory(Path::new(dir))?;
- Ok(())
+ perm_entry.create_directory(Path::new(dir))
}
pub fn create_directory_with_mode(dir: &str, mode: u32) -> Result<(), FileError> {
let perm_entry = PermissionEntry::new(None, None, Some(mode));
- let () = perm_entry.create_directory(Path::new(dir))?;
- Ok(())
+ perm_entry.create_directory(Path::new(dir))
}
pub fn create_file_with_user_group(
@@ -52,16 +53,10 @@ pub fn create_file_with_user_group(
user: &str,
group: &str,
mode: u32,
+ default_content: Option<&str>,
) -> Result<(), FileError> {
let perm_entry = PermissionEntry::new(Some(user.into()), Some(group.into()), Some(mode));
- let () = perm_entry.create_file(Path::new(file))?;
- Ok(())
-}
-
-pub fn create_file_with_mode(file: &str, mode: u32) -> Result<(), FileError> {
- let perm_entry = PermissionEntry::new(None, None, Some(mode));
- let () = perm_entry.create_file(Path::new(file))?;
- Ok(())
+ perm_entry.create_file(Path::new(file), default_content)
}
#[derive(Debug, PartialEq, Eq, Default, Clone)]
@@ -111,12 +106,31 @@ impl PermissionEntry {
}
}
- fn create_file(&self, file: &Path) -> Result<(), FileError> {
- match File::create(file) {
- Ok(_) => {
+ /// This function creates a file with a given path, specific access privileges and with the given content.
+ /// If the file already exists, then it will not be re-created and it will not overwrite/append the contents of the file.
+ /// This method returns
+ /// Ok() when file is created and the content is written successfully into the file.
+ /// Ok() when the file aleady exists
+ /// Err(_) When it can not create the file with the appropriate owner and access permissions.
+ fn create_file(&self, file: &Path, default_content: Option<&str>) -> Result<(), FileError> {
+ match fs::OpenOptions::new()
+ .create_new(true)
+ .write(true)
+ .open(file)
+ {
+ Ok(mut f) => {
let () = self.apply(file)?;
+ if let Some(default_content) = default_content {
+ f.write(default_content.as_bytes()).map_err(|e| {
+ FileError::WriteContentFailed {
+ file: file.display().to_string(),
+ from: e,
+ }
+ })?;
+ }
Ok(())
}
+
Err(e) if e.kind() == io::ErrorKind::AlreadyExists => Ok(()),
Err(e) => Err(FileError::FileCreateFailed {
file: file.display().to_string(),
@@ -229,7 +243,7 @@ mod tests {
let file_path = temp_dir.path().join("file").display().to_string();
let user = whoami::username();
- let _ = create_file_with_user_group(file_path.as_str(), &user, &user, 0o644).unwrap();
+ let _ = create_file_with_user_group(file_path.as_str(), &user, &user, 0o644, None).unwrap();
assert!(Path::new(file_path.as_str()).exists());
let meta = std::fs::metadata(file_path.as_str()).unwrap();
let perm = meta.permissions();
@@ -238,13 +252,38 @@ mod tests {
}
#[test]
+ fn create_file_with_default_content() {
+ let temp_dir = TempDir::new().unwrap();
+ let file_path = temp_dir.path().join("file").display().to_string();
+ let user = whoami::username();
+
+ let example_config = r#"# Add the configurations to be managed by c8y-configuration-plugin
+ files = [
+ # { path = '/etc/tedge/tedge.toml' },
+ ]"#;
+
+ // Create a new file with default content
+ create_file_with_user_group(
+ file_path.as_str(),
+ &user,
+ &user,
+ 0o775,
+ Some(&example_config.to_string()),
+ )
+ .unwrap();
+
+ let content = fs::read(file_path).unwrap();
+ assert_eq!(example_config.as_bytes(), content);
+ }
+
+ #[test]
fn create_file_wrong_user() {
let temp_dir = TempDir::new().unwrap();
let file_path = temp_dir.path().join("file").display().to_string();
let user = whoami::username();
- let err =
- create_file_with_user_group(file_path.as_str(), "test", &user, 0o775).unwrap_err();
+ let err = create_file_with_user_group(file_path.as_str(), "test", &user, 0o775, None)
+ .unwrap_err();
assert!(err.to_string().contains("User not found"));
}
@@ -255,8 +294,8 @@ mod tests {
let file_path = temp_dir.path().join("file").display().to_string();
let user = whoami::username();
- let err =
- create_file_with_user_group(file_path.as_str(), &user, "test", 0o775).unwrap_err();
+ let err = create_file_with_user_group(file_path.as_str(), &user, "test", 0o775, None)
+ .unwrap_err();
assert!(err.to_string().contains("Group not found"));
fs::remove_file(file_path.as_str()).unwrap();
@@ -309,7 +348,7 @@ mod tests {
let file_path = temp_dir.path().join("file").display().to_string();
let user = whoami::username();
- let _ = create_file_with_user_group(file_path.as_str(), &user, &user, 0o644).unwrap();
+ let _ = create_file_with_user_group(file_path.as_str(), &user, &user, 0o644, None).unwrap();
assert!(Path::new(file_path.as_str()).exists());
let meta = fs::metadata(file_path.as_str()).unwrap();
diff --git a/crates/core/tedge_mapper/src/c8y/mapper.rs b/crates/core/tedge_mapper/src/c8y/mapper.rs
index 8ea3b4fc..81068adb 100644
--- a/crates/core/tedge_mapper/src/c8y/mapper.rs
+++ b/crates/core/tedge_mapper/src/c8y/mapper.rs
@@ -110,12 +110,14 @@ fn create_directories(config_dir: &str) -> Result<(), anyhow::Error> {
"tedge",
"tedge",
0o644,
+ None,
)?;
create_file_with_user_group(
&format!("{config_dir}/operations/c8y/c8y_Restart"),
"tedge",
"tedge",
0o644,
+ None,
)?;
Ok(())
}
diff --git a/plugins/c8y_configuration_plugin/src/main.rs b/plugins/c8y_configuration_plugin/src/main.rs
index 96d2b020..45128f85 100644
--- a/plugins/c8y_configuration_plugin/src/main.rs
+++ b/plugins/c8y_configuration_plugin/src/main.rs
@@ -14,7 +14,6 @@ use c8y_smartrest::smartrest_deserializer::{
use c8y_smartrest::topic::C8yTopic;
use clap::Parser;
use mqtt_channel::{Message, SinkExt, StreamExt, Topic};
-use std::fs;
use std::path::{Path, PathBuf};
use tedge_config::{
ConfigRepository, ConfigSettingAccessor, MqttPortSetting, TEdgeConfig, TmpPathSetting,
@@ -212,26 +211,24 @@ fn init(cfg_dir: PathBuf) -> Result<(), anyhow::Error> {
}
fn create_operation_files(config_dir: &str) -> Result<(), anyhow::Error> {
- create_directory_with_user_group(&format!("{config_dir}/c8y"), "root", "root", 0o775)?;
+ create_directory_with_user_group(&format!("{config_dir}/c8y"), "root", "root", 0o1777)?;
+ 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_user_group(
&format!("{config_dir}/c8y/c8y-configuration-plugin.toml"),
"root",
"root",
0o644,
+ Some(example_config),
)?;
- 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 }
-]"#;
- fs::write(
- &format!("{config_dir}/c8y/c8y-configuration-plugin.toml"),
- example_config,
- )?;
create_directory_with_user_group(
&format!("{config_dir}/operations/c8y"),
"tedge",
@@ -243,12 +240,14 @@ files = [
"tedge",
"tedge",
0o644,
+ None,
)?;
create_file_with_user_group(
&format!("{config_dir}/operations/c8y/c8y_DownloadConfigFile"),
"tedge",
"tedge",
0o644,
+ None,
)?;
Ok(())
}
diff --git a/plugins/c8y_log_plugin/src/main.rs b/plugins/c8y_log_plugin/src/main.rs
index 42e28053..acee7dbf 100644
--- a/plugins/c8y_log_plugin/src/main.rs
+++ b/plugins/c8y_log_plugin/src/main.rs
@@ -11,11 +11,7 @@ use clap::Parser;
use inotify::{EventMask, EventStream};
use inotify::{Inotify, WatchMask};
use mqtt_channel::{Connection, StreamExt};
-use std::{
- fs::OpenOptions,
- io::Write,
- path::{Path, PathBuf},
-};
+use std::path::{Path, PathBuf};
use tedge_config::{
ConfigRepository, ConfigSettingAccessor, LogPathSetting, MqttPortSetting, TEdgeConfig,
DEFAULT_TEDGE_CONFIG_PATH,
@@ -191,27 +187,6 @@ fn init(config_dir: &Path, logs_dir: &Path) -> Result<(), anyhow::Error> {
Ok(())
}
-/// append the log plugin file with software-management logs
-/// assumes file is already created.
-fn create_default_log_plugin_file(path_to_toml: &str, logs_dir: &str) -> Result<(), anyhow::Error> {
- let logs_path = format!("{logs_dir}/tedge/agent/software-*");
- let data = toml::toml! {
- files = [
- { type = "software-management", path = logs_path }
- ]
- };
-
- let mut toml_file = OpenOptions::new()
- .append(true)
- .create(false)
- .open(path_to_toml)
- .map_err(|error| {
- anyhow::anyhow!("Unable to open file: {}. Error: {}", path_to_toml, error)
- })?;
- toml_file.write_all(data.to_string().as_bytes())?;
- Ok(())
-}
-
/// for the log plugin to work the following directories and files are needed:
///
/// Directories:
@@ -221,7 +196,7 @@ fn create_default_log_plugin_file(path_to_toml: &str, logs_dir: &str) -> Result<
///
/// Files:
/// - CONFIG_DIR/operations/c8y/c8y_LogfileRequest
-/// - CONFIG_DIR/c8y/log/c8y-log-plugin.toml
+/// - CONFIG_DIR/c8y/c8y-log-plugin.toml
fn create_init_logs_directories_and_files(
config_dir: &str,
logs_dir: &str,
@@ -242,24 +217,26 @@ fn create_init_logs_directories_and_files(
&format!("{config_dir}/operations/c8y/c8y_LogfileRequest"),
"tedge",
"tedge",
- 0o755,
+ 0o644,
+ None,
)?;
// creating c8y directory
- create_directory_with_user_group(&format!("{config_dir}/c8y"), "tedge", "tedge", 0o755)?;
- // creating c8y-log-plugin.toml
+ create_directory_with_user_group(&format!("{config_dir}/c8y"), "root", "root", 0o1777)?;
- // NOTE: file needs 775 permission or inotify can not watch for changes inside the file
+ // creating c8y-log-plugin.toml
+ let logs_path = format!("{logs_dir}/tedge/agent/software-*");
+ let data = toml::toml! {
+ files = [
+ { type = "software-management", path = logs_path }
+ ]
+ };
create_file_with_user_group(
&format!("{config_dir}/{DEFAULT_PLUGIN_CONFIG_FILE}"),
- "tedge",
- "tedge",
- 0o775,
+ "root",
+ "root",
+ 0o644,
+ Some(&data.to_string()),
)?;
- // append default content to c8y-log-plugin.toml
- create_default_log_plugin_file(
- &format!("{config_dir}/{DEFAULT_PLUGIN_CONFIG_FILE}"),
- logs_dir,
- )?;
Ok(())
}