Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into bug/custom-domain-ten…
Browse files Browse the repository at this point in the history
…ant-matching
  • Loading branch information
jarhodes314 committed Jul 17, 2024
2 parents 75084ac + 4916fd0 commit 1c68fab
Show file tree
Hide file tree
Showing 50 changed files with 1,617 additions and 987 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/build-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ jobs:
needs: [approve, check-build]
environment:
name: Test Auto
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
strategy:
matrix:
job:
Expand Down Expand Up @@ -250,7 +250,7 @@ jobs:
path: tests/RobotFramework/output

- name: Send report to commit
uses: joonvena/robotframework-reporter-action@v2.4
uses: joonvena/robotframework-reporter-action@v2.5
if: always() && github.event_name == 'pull_request_target'
with:
gh_access_token: ${{ secrets.GITHUB_TOKEN }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pull-request-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: crate-ci/typos@v1.22.3
- uses: crate-ci/typos@v1.23.2
continue-on-error: true
- run: exit 0

Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions crates/common/tedge_config/src/tedge_config_cli/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ pub enum TEdgeConfigError {

#[error(transparent)]
FromParseHostPortError(#[from] crate::tedge_config_cli::models::host_port::ParseHostPortError),

#[error(transparent)]
FromAtomFileError(#[from] tedge_utils::fs::AtomFileError),
}

impl TEdgeConfigError {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use strum::Display;
/// A flag that switches legacy or advanced software management API.
/// Can be set to auto in the future, see #2778.
#[derive(
Debug, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq, doku::Document, Display,
Debug, Clone, Copy, serde::Serialize, serde::Deserialize, Eq, PartialEq, doku::Document, Display,
)]
#[strum(serialize_all = "camelCase")]
pub enum SoftwareManagementApiFlag {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub use self::templates_set::*;
pub use tedge_utils::timestamp;

#[derive(
Debug, Display, Clone, Eq, PartialEq, doku::Document, serde::Serialize, serde::Deserialize,
Debug, Display, Clone, Copy, Eq, PartialEq, doku::Document, serde::Serialize, serde::Deserialize,
)]
#[serde(rename_all = "kebab-case")]
#[strum(serialize_all = "kebab-case")]
Expand Down
157 changes: 130 additions & 27 deletions crates/common/tedge_utils/src/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,41 +8,111 @@ use std::path::PathBuf;
use tokio::fs as tokio_fs;
use tokio::io::AsyncWriteExt;

#[derive(Debug, thiserror::Error)]
pub enum AtomFileError {
#[error("Writing the content to the file {file:?} failed: {context:?}. source={source:?}")]
WriteError {
file: Box<Path>,
context: String,
source: std::io::Error,
},
}

pub trait ErrContext<T> {
fn with_context(
self,
context: impl Fn() -> String,
file: impl AsRef<Path>,
) -> Result<T, AtomFileError>;
}

impl<T, E: Into<std::io::Error>> ErrContext<T> for Result<T, E> {
fn with_context(
self,
context: impl Fn() -> String,
file: impl AsRef<Path>,
) -> Result<T, AtomFileError> {
self.map_err(|err| AtomFileError::WriteError {
file: Box::from(file.as_ref()),
context: context(),
source: err.into(),
})
}
}

pub struct TempFile(PathBuf);

impl Drop for TempFile {
fn drop(&mut self) {
let _ = std_fs::remove_file(&self.0);
}
}

/// Write file to filesystem atomically using std::fs synchronously.
pub fn atomically_write_file_sync(
dest: impl AsRef<Path>,
mut reader: impl Read,
) -> std::io::Result<()> {
) -> Result<(), AtomFileError> {
let dest_dir = parent_dir(dest.as_ref());
// FIXME: `.with_extension` replaces file extension, so if we used this
// function to write files `file.txt`, `file.bin`, `file.jpg`, etc.
// concurrently, then this will result in an error
let tempfile = PathBuf::from(dest.as_ref()).with_extension("tmp");
let tempfile = TempFile(PathBuf::from(dest.as_ref()).with_extension("tmp"));

// Write the content on a temp file
let mut file = std_fs::OpenOptions::new()
.write(true)
.create_new(true)
.open(&tempfile)?;

if let Err(err) = std::io::copy(&mut reader, &mut file) {
let _ = std_fs::remove_file(tempfile);
return Err(err);
}
.open(&tempfile.0)
.with_context(
|| format!("could not create the temporary file {:?}", tempfile.0),
&dest,
)?;

std::io::copy(&mut reader, &mut file).with_context(
|| {
format!(
"could not copy the content to the temporary file {:?}",
tempfile.0,
)
},
&dest,
)?;

// Ensure the content reach the disk
file.flush()?;
file.sync_all()?;
file.flush().with_context(
|| {
format!(
"could not flush the content of the temporary file {:?}",
tempfile.0,
)
},
&dest,
)?;

file.sync_all().with_context(
|| format!("could not save the temporary file {:?} to disk", tempfile.0,),
&dest,
)?;

// Move the temp file to its destination
if let Err(err) = std_fs::rename(&tempfile, dest) {
let _ = std_fs::remove_file(tempfile);
return Err(err);
}
std_fs::rename(&tempfile.0, &dest).with_context(
|| {
format!(
"could not move the file from {:?} to {:?}",
tempfile.0,
dest.as_ref(),
)
},
&dest,
)?;

// Ensure the new name reach the disk
let dir = std::fs::File::open(dest_dir)?;
dir.sync_all()?;
let dir = std::fs::File::open(dest_dir)
.with_context(|| "could not open the directory".to_string(), &dest)?;

dir.sync_all()
.with_context(|| "could not save the file to disk".to_string(), &dest)?;

Ok(())
}
Expand All @@ -51,7 +121,7 @@ pub fn atomically_write_file_sync(
pub async fn atomically_write_file_async(
dest: impl AsRef<Path>,
content: &[u8],
) -> std::io::Result<()> {
) -> Result<(), AtomFileError> {
let dest_dir = parent_dir(dest.as_ref());
let tempfile = PathBuf::from(dest.as_ref()).with_extension("tmp");

Expand All @@ -60,26 +130,59 @@ pub async fn atomically_write_file_async(
.write(true)
.create_new(true)
.open(&tempfile)
.await?;

if let Err(err) = file.write_all(content).await {
tokio_fs::remove_file(tempfile).await?;
.await
.with_context(
|| format!("could not create the temporary file {tempfile:?}"),
&dest,
)?;

if let Err(err) = file.write_all(content).await.with_context(
|| format!("could not write the content to the temporary file {tempfile:?}",),
&dest,
) {
let _ = tokio_fs::remove_file(&tempfile).await;
return Err(err);
}

// Ensure the content reach the disk
file.flush().await?;
file.sync_all().await?;
if let Err(err) = file.flush().await.with_context(
|| format!("could not flush the content of the temporary file {tempfile:?}",),
&dest,
) {
let _ = tokio_fs::remove_file(&tempfile).await;
return Err(err);
}

if let Err(err) = file.sync_all().await.with_context(
|| format!("could not save the temporary file {tempfile:?} to disk",),
&dest,
) {
let _ = tokio_fs::remove_file(&tempfile).await;
return Err(err);
}

// Move the temp file to its destination
if let Err(err) = tokio_fs::rename(&tempfile, dest).await {
tokio_fs::remove_file(tempfile).await?;
if let Err(err) = tokio_fs::rename(&tempfile, &dest).await.with_context(
|| {
format!(
"could not move the file from {tempfile:?} to {:?}",
dest.as_ref()
)
},
&dest,
) {
let _ = tokio_fs::remove_file(&tempfile).await;
return Err(err);
}

// Ensure the new name reach the disk
let dir = tokio_fs::File::open(dest_dir).await?;
dir.sync_all().await?;
let dir = tokio_fs::File::open(&dest_dir)
.await
.with_context(|| "could not open the directory".to_string(), &dest)?;

dir.sync_all()
.await
.with_context(|| "could not save the file to disk".to_string(), &dest)?;

Ok(())
}
Expand Down
2 changes: 2 additions & 0 deletions crates/core/tedge/src/cli/config/commands/get.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ impl Command for GetConfigCommand {
}
Err(tedge_config::ReadError::ConfigNotSet { .. }) => {
eprintln!("The provided config key: '{}' is not set", self.key);
std::process::exit(1)
}
Err(tedge_config::ReadError::ReadOnlyNotFound { message, key }) => {
eprintln!("The provided config key: '{key}' is not configured: {message}",);
std::process::exit(1)
}
Err(err) => return Err(err.into()),
}
Expand Down
30 changes: 19 additions & 11 deletions crates/core/tedge/tests/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ mod tests {
// We start we no certificate, hence no device id
get_device_id_cmd
.assert()
.success()
.failure()
.stderr(predicate::str::contains("'device.id' is not configured"));

// The create command created a certificate
Expand Down Expand Up @@ -124,7 +124,7 @@ mod tests {
// The remove command also removed the device id from the config
get_device_id_cmd
.assert()
.success()
.failure()
.stderr(predicate::str::contains("device.id"));

// The a new certificate can then be created.
Expand Down Expand Up @@ -152,7 +152,7 @@ mod tests {

get_device_id_cmd
.assert()
.success()
.failure()
.stderr(predicate::str::contains("device.id"));

// forbidden to set read-only key by CLI
Expand Down Expand Up @@ -207,12 +207,16 @@ mod tests {
config_key,
])?;

let get_config_command = get_config_command.assert().success();
let get_config_command = get_config_command.assert();

if is_default {
get_config_command.stdout(predicate::str::contains(default_value_or_error_message));
get_config_command
.stdout(predicate::str::contains(default_value_or_error_message))
.success();
} else {
get_config_command.stderr(predicate::str::contains(default_value_or_error_message));
get_config_command
.stderr(predicate::str::contains(default_value_or_error_message))
.failure();
}

let mut set_config_command = tedge_command_with_test_home([
Expand Down Expand Up @@ -257,12 +261,16 @@ mod tests {
config_key,
])?;

let get_config_command = get_config_command.assert().success();
let get_config_command = get_config_command.assert();

if is_default {
get_config_command.stdout(predicate::str::contains(default_value_or_error_message));
get_config_command
.stdout(predicate::str::contains(default_value_or_error_message))
.success();
} else {
get_config_command.stderr(predicate::str::contains(default_value_or_error_message));
get_config_command
.stderr(predicate::str::contains(default_value_or_error_message))
.failure();
}

Ok(())
Expand All @@ -287,7 +295,7 @@ mod tests {

get_device_id_cmd
.assert()
.success()
.failure()
.stderr(predicate::str::contains("device.id"));

let mut get_cert_path_cmd = tedge_command_with_test_home([
Expand Down Expand Up @@ -326,7 +334,7 @@ mod tests {

get_c8y_url_cmd
.assert()
.success()
.failure()
.stderr(predicate::str::contains(
"The provided config key: 'c8y.url' is not set",
));
Expand Down
3 changes: 3 additions & 0 deletions crates/core/tedge_agent/src/restart_manager/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,7 @@ pub enum RestartManagerError {

#[error("Could not convert {timestamp:?} to unix timestamp. Error message: {error_msg}")]
TimestampConversionError { timestamp: i64, error_msg: String },

#[error(transparent)]
FromAtomFileError(#[from] tedge_utils::fs::AtomFileError),
}
3 changes: 3 additions & 0 deletions crates/core/tedge_agent/src/state_repository/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,7 @@ pub enum StateError {

#[error(transparent)]
FromUtf8Error(#[from] std::string::FromUtf8Error),

#[error(transparent)]
FromAtomFileError(#[from] tedge_utils::fs::AtomFileError),
}
1 change: 1 addition & 0 deletions crates/core/tedge_api/src/mqtt_topics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -771,6 +771,7 @@ impl From<&Channel> for ChannelFilter {
}
}

#[derive(Debug, Clone)]
pub struct IdGenerator {
prefix: String,
}
Expand Down
Loading

0 comments on commit 1c68fab

Please sign in to comment.