Skip to content

Commit b7ebf71

Browse files
fix: flush data for write on fs crate (#2092)
* fix: flush data for write on fs crate * flush on e2e runner
1 parent d8c8fa1 commit b7ebf71

File tree

10 files changed

+79
-59
lines changed

10 files changed

+79
-59
lines changed

agent-control/src/cli/on_host/config_gen.rs

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use crate::cli::{
1010
proxy_config::ProxyConfig,
1111
},
1212
};
13+
use fs::file::{LocalFile, writer::FileWriter};
1314
use std::{collections::HashMap, path::PathBuf};
1415
use tracing::info;
1516

@@ -154,7 +155,7 @@ fn write_config_and_generate_system_identity(args: &Args) -> Result<(), CliError
154155

155156
let yaml = generate_config_and_system_identity(args, provide_identity)?;
156157

157-
std::fs::write(&args.output_path, yaml).map_err(|err| {
158+
LocalFile.write(&args.output_path, yaml).map_err(|err| {
158159
CliError::Command(format!(
159160
"error writing the configuration file to '{}': {}",
160161
args.output_path.to_string_lossy(),
@@ -176,13 +177,14 @@ fn write_env_var_config(args: &Args) -> Result<(), CliError> {
176177

177178
let yaml = generate_env_var_config(args)?;
178179

179-
std::fs::write(path, yaml).map_err(|err| {
180+
LocalFile.write(path, yaml).map_err(|err| {
180181
CliError::Command(format!(
181182
"error writing the environment variables file to '{}': {}",
182183
path.display(),
183184
err
184185
))
185186
})?;
187+
186188
info!(env_vars_path=%path.display(), "Environment variables file generated successfully");
187189

188190
Ok(())
@@ -215,7 +217,7 @@ fn generate_env_var_config(args: &Args) -> Result<String, CliError> {
215217
fn generate_config_and_system_identity<F>(
216218
args: &Args,
217219
provide_identity_fn: F,
218-
) -> Result<Vec<u8>, CliError>
220+
) -> Result<String, CliError>
219221
where
220222
F: Fn(&Args) -> Result<Identity, CliError>,
221223
{
@@ -249,10 +251,8 @@ where
249251
agents: args.agent_set.into(),
250252
};
251253

252-
let mut buffer = Vec::new();
253-
serde_yaml::to_writer(&mut buffer, &config)
254-
.map_err(|err| CliError::Command(format!("failed to serialize configuration: {err}")))?;
255-
Ok(buffer)
254+
serde_yaml::to_string(&config)
255+
.map_err(|err| CliError::Command(format!("failed to serialize configuration: {err}")))
256256
}
257257

258258
#[cfg(test)]
@@ -375,11 +375,8 @@ mod tests {
375375
) {
376376
let args = create_test_args(fleet_enabled, region, agent_set, proxy_config);
377377

378-
let yaml = String::from_utf8(
379-
generate_config_and_system_identity(&args, identity_provider_mock)
380-
.expect("result expected to be OK"),
381-
)
382-
.unwrap();
378+
let yaml = generate_config_and_system_identity(&args, identity_provider_mock)
379+
.expect("result expected to be OK");
383380

384381
// Check that the config can be used in Agent Control
385382
let _: AgentControlConfig =

agent-control/src/cli/on_host/host_monitoring_gen/otel_config_gen.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ use crate::agent_control::defaults::{
44
};
55
use crate::cli::error::CliError;
66
use crate::on_host::file_store::build_config_name;
7+
use fs::file::LocalFile;
8+
use fs::file::writer::FileWriter;
79
use std::path::PathBuf;
810
use tracing::info;
911

@@ -65,8 +67,10 @@ impl OtelConfigGen {
6567
.collect::<Vec<_>>()
6668
.join("\n");
6769

68-
std::fs::write(file_path, modified_content)
70+
LocalFile
71+
.write(&file_path, modified_content)
6972
.map_err(|err| CliError::Command(format!("error writing otel values file: {err}")))?;
73+
7074
Ok(())
7175
}
7276
}

agent-control/tests/on_host/tools/config.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
use std::fs::{File, create_dir_all};
2-
use std::io::Write;
1+
use std::fs::create_dir_all;
32
use std::path::PathBuf;
43
use std::sync::Arc;
54

5+
use fs::file::LocalFile;
6+
use fs::file::writer::FileWriter;
67
use newrelic_agent_control::agent_control::agent_id::AgentID;
78
use newrelic_agent_control::agent_control::defaults::{
89
AGENT_CONTROL_ID, FOLDER_NAME_FLEET_DATA, FOLDER_NAME_LOCAL_DATA, STORE_KEY_LOCAL_DATA_CONFIG,
@@ -67,8 +68,9 @@ agents: {}
6768
pub fn create_file(content: String, path: PathBuf) {
6869
create_dir_all(path.parent().unwrap()).unwrap();
6970

70-
let mut local_file = File::create(path).expect("failed to create local config file");
71-
write!(local_file, "{content}").unwrap();
71+
LocalFile
72+
.write(&path, content)
73+
.expect("failed to create file");
7274
}
7375

7476
/// Creates local values config for the agent_id provided on the base_dir

agent-control/tests/on_host/tools/custom_agent_type.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use std::fmt::Display;
2-
use std::fs::File;
3-
use std::io::Write;
42
use std::path::PathBuf;
53

4+
use fs::file::LocalFile;
5+
use fs::file::writer::FileWriter;
66
use newrelic_agent_control::agent_control::run::on_host::AGENT_CONTROL_MODE_ON_HOST;
77
use newrelic_agent_control::agent_type::agent_type_id::AgentTypeID;
88
use newrelic_agent_control::agent_type::definition::AgentTypeDefinition;
@@ -232,9 +232,9 @@ regex: \d+\.\d+\.\d+
232232
);
233233

234234
std::fs::create_dir_all(agent_type_file_path.parent().unwrap()).unwrap();
235-
let mut local_file =
236-
File::create(agent_type_file_path.clone()).expect("failed to create local config file");
237-
write!(local_file, "{self}").expect("failed to write custom agent type");
235+
LocalFile
236+
.write(&agent_type_file_path, self.to_string())
237+
.expect("failed to write custom agent type");
238238
self.agent_type_id.to_string()
239239
}
240240
}

fs/src/file/writer.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,14 @@ impl FileWriter for LocalFile {
2727
file_options.mode(LocalFile::get_file_permissions().mode());
2828
}
2929

30-
file_options.open(path)?.write_all(content.as_bytes())?;
30+
let mut file = file_options.open(path)?;
31+
file.write_all(content.as_bytes())?;
3132

3233
#[cfg(target_family = "windows")]
3334
crate::win_permissions::set_file_permissions_for_administrator(path)
3435
.map_err(io::Error::other)?;
3536

37+
file.sync_all()?;
3638
Ok(())
3739
}
3840
}

test/e2e-runner/src/linux/scenarios/migration.rs

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{fs, time::Duration};
1+
use std::time::Duration;
22

33
use tracing::{debug, info};
44

@@ -9,7 +9,7 @@ use crate::{
99
install::{Args, RecipeData, install_agent_control_from_recipe},
1010
service,
1111
},
12-
tools::{config, nrql, test::retry},
12+
tools::{config, file::write, nrql, test::retry},
1313
};
1414

1515
pub fn test_migration(args: Args) {
@@ -90,7 +90,7 @@ curl -Ls https://download.newrelic.com/install/newrelic-cli/scripts/install.sh |
9090
debug!("Output:\n{output}");
9191

9292
// Update infra-agent configuration
93-
fs::write(
93+
write(
9494
"/etc/newrelic-infra.yml",
9595
format!(
9696
r#"
@@ -101,10 +101,7 @@ license_key: {}
101101
"#,
102102
args.nr_license_key
103103
),
104-
)
105-
.unwrap_or_else(|err| {
106-
panic!("Error updating infra-agent config: {err}");
107-
});
104+
);
108105

109106
// Run a mysql service and install the nri-mysql integration
110107
let docker_command =
@@ -120,7 +117,7 @@ license_key: {}
120117
panic!("Could not install nri-mysql: {err}");
121118
});
122119

123-
fs::write(
120+
write(
124121
"/etc/newrelic-infra/integrations.d/nri-mysql-config.yml",
125122
format!(
126123
r#"
@@ -139,10 +136,7 @@ integrations:
139136
inventory_source: config/mysql
140137
"#
141138
),
142-
)
143-
.unwrap_or_else(|err| {
144-
panic!("Error writing nri-mysql config: {err}");
145-
});
139+
);
146140

147141
service::restart_service("newrelic-infra");
148142
}

test/e2e-runner/src/tools.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use tracing::warn;
55
use crate::tools::test::TestResult;
66

77
pub mod config;
8+
pub mod file;
89
pub mod logs;
910
pub mod nrql;
1011
pub mod test;

test/e2e-runner/src/tools/config.rs

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use serde_yaml::Value;
2-
use std::{fs, io::Write, path::PathBuf, thread, time::Duration};
2+
use std::{fs, io::Write, path::PathBuf};
33
use tracing::info;
44

5+
use crate::tools::file::write;
6+
57
pub const LOCAL_CONFIG_FILE_NAME: &str = "local_config.yaml";
68

79
/// Updates the agent control config in `config_path` to include the content specified in `new_content`
@@ -31,12 +33,7 @@ pub fn update_config(config_path: &str, new_content: &str) {
3133

3234
info!("Updating configuration to: \n---\n{}\n---", updated_content);
3335

34-
fs::write(config_path, updated_content).unwrap_or_else(|e| {
35-
panic!("failed to write YAML configuration: {}", e);
36-
});
37-
38-
// Wait a few seconds to prevent doing anything before the configuration is written
39-
thread::sleep(Duration::from_secs(3));
36+
write(config_path, updated_content);
4037
}
4138

4239
/// Merges two YAML values, with `new` taking precedence over `base`
@@ -77,11 +74,7 @@ pub fn write_agent_local_config(config_dir: &str, content: String) {
7774
fs::create_dir_all(&path).unwrap_or_else(|err| {
7875
panic!("Error creating local config: {err}");
7976
});
80-
fs::write(path.join(LOCAL_CONFIG_FILE_NAME), content).unwrap_or_else(|err| {
81-
panic!("Error writing local config: {err}");
82-
});
83-
// Wait a few seconds to prevent doing anything before the configuration is written
84-
thread::sleep(Duration::from_secs(3));
77+
write(path.join(LOCAL_CONFIG_FILE_NAME), content);
8578
}
8679

8780
/// Replaces all the occurrences of `old` to `new` in the provided `config_path`.
@@ -91,12 +84,7 @@ pub fn replace_string_in_file(config_path: &str, old: &str, new: &str) {
9184

9285
let updated_content = config_content.replace(old, new);
9386

94-
fs::write(config_path, updated_content).unwrap_or_else(|err| {
95-
panic!("Error writing to {config_path}: {err}");
96-
});
97-
98-
// Wait a few seconds to prevent doing anything before the configuration is written
99-
thread::sleep(Duration::from_secs(3));
87+
write(config_path, updated_content);
10088
}
10189

10290
/// Appends `content` to the configuration file in `config_path`
@@ -110,6 +98,7 @@ pub fn append_to_config_file(config_path: &str, content: &str) {
11098
writeln!(config_file, "{content}").unwrap_or_else(|err| {
11199
panic!("Error appending content to '{config_path}' file: {err}");
112100
});
113-
// Wait a few seconds to prevent doing anything before the configuration is written
114-
thread::sleep(Duration::from_secs(3));
101+
config_file.sync_data().unwrap_or_else(|err| {
102+
panic!("Error syncing data to disk for '{config_path}' file: {err}");
103+
});
115104
}

test/e2e-runner/src/tools/file.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
use std::fs::OpenOptions;
2+
use std::io::Write;
3+
use std::path::Path;
4+
5+
/// Writes contents to a file and ensures data is flushed to disk before returning.
6+
/// If the file does not exist, it will be created. If it does exist, it will be truncated.
7+
pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) {
8+
let mut file_options = OpenOptions::new();
9+
file_options.write(true).create(true).truncate(true);
10+
11+
let mut file = file_options.open(path.as_ref()).unwrap_or_else(|err| {
12+
panic!(
13+
"Could not open file for writing: {}: {}",
14+
path.as_ref().display(),
15+
err
16+
)
17+
});
18+
file.write_all(contents.as_ref()).unwrap_or_else(|err| {
19+
panic!(
20+
"Could not write to file: {}: {}",
21+
path.as_ref().display(),
22+
err
23+
)
24+
});
25+
file.sync_data().unwrap_or_else(|err| {
26+
panic!(
27+
"Could not sync data to disk for file: {}: {}",
28+
path.as_ref().display(),
29+
err
30+
)
31+
});
32+
}

test/e2e-runner/src/windows/install.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
use std::{fs, path::PathBuf, process::Command, time::Duration};
1+
use std::{path::PathBuf, process::Command, time::Duration};
22

33
use tempfile::tempdir;
44
use tracing::{debug, info};
55

66
use crate::{
7-
tools::test::retry,
7+
tools::{file::write, test::retry},
88
windows::powershell::{exec_powershell_cmd, exec_powershell_command},
99
};
1010

@@ -179,8 +179,7 @@ $env:NEW_RELIC_AGENT_CONTROL_SKIP_BINARY_SIGNATURE_VALIDATION='true'; `
179179
debug!("Install script content: \n{install_command}");
180180
let script_dir = tempdir().expect("failed to create temp dir for script");
181181
let script_path = script_dir.path().join("install_command.ps1");
182-
fs::write(&script_path, &install_command)
183-
.unwrap_or_else(|err| panic!("failed to write install script: {err}"));
182+
write(&script_path, &install_command);
184183

185184
info!("Executing install script to install Agent Control through the recipe");
186185
let output = retry(3, Duration::from_secs(30), "recipe installation", || {

0 commit comments

Comments
 (0)