feat: added config update message handling
This commit is contained in:
@@ -1,19 +1,42 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use fs4::tokio::AsyncFileExt;
|
||||
use thiserror::Error;
|
||||
use tokio::{io::AsyncWriteExt, process::Command};
|
||||
use tracing::{debug, warn};
|
||||
use tracing::warn;
|
||||
|
||||
use crate::config::settings::NginxSettings;
|
||||
use crate::{config::settings::NginxSettings, service::master_handler::MasterHandlerError};
|
||||
|
||||
#[cfg(test)]
|
||||
use mockall::predicate::*;
|
||||
// TODO: custom error type
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum FsHandlerError {
|
||||
#[error("Invalid output path: {0}")]
|
||||
InvalidOutputPath(String),
|
||||
#[error("IO error: {0}")]
|
||||
IoError(#[from] std::io::Error),
|
||||
}
|
||||
|
||||
impl From<FsHandlerError> for MasterHandlerError {
|
||||
fn from(err: FsHandlerError) -> Self {
|
||||
MasterHandlerError::MessageHandlingError(format!("File system handling error: {}", err))
|
||||
}
|
||||
}
|
||||
|
||||
pub type FsResult<T> = std::result::Result<T, FsHandlerError>;
|
||||
type Result<T> = FsResult<T>;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
#[cfg_attr(test, mockall::automock)]
|
||||
pub trait FsHandler: Send + Sync + 'static {
|
||||
fn get_deployment_id(config_id: &str, version: &str) -> String
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
format!("{}-{}", config_id, version)
|
||||
}
|
||||
// Write a new config file for nginx.
|
||||
// The output_path is a relative path to the nginx config directory of the deployment folder. The actual path to the config should not be assumed by the caller, as it can be different in different environments, but will be promised to be relative to the deployment folder for each the corresponding deployment_id. Path traversal is not allowed.
|
||||
async fn write_config(
|
||||
@@ -46,10 +69,16 @@ impl FsHandlerImpl {
|
||||
|
||||
fn validate_config_path(config_path: &str) -> Result<()> {
|
||||
if !std::path::Path::new(config_path).exists() {
|
||||
anyhow::bail!("Config file not found at path: {}", config_path);
|
||||
return Err(FsHandlerError::InvalidOutputPath(format!(
|
||||
"Config file not found at path: {}",
|
||||
config_path
|
||||
)));
|
||||
}
|
||||
if !std::path::Path::new(config_path).is_file() {
|
||||
anyhow::bail!("Config path is not a file: {}", config_path);
|
||||
return Err(FsHandlerError::InvalidOutputPath(format!(
|
||||
"Config path is not a file: {}",
|
||||
config_path
|
||||
)));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -70,13 +99,17 @@ impl FsHandlerImpl {
|
||||
) -> Result<std::path::PathBuf> {
|
||||
let output_path_obj = std::path::Path::new(output_path);
|
||||
if output_path_obj.is_absolute() {
|
||||
anyhow::bail!("Output path must be a relative path");
|
||||
return Err(FsHandlerError::InvalidOutputPath(
|
||||
"Output path must be a relative path".into(),
|
||||
));
|
||||
}
|
||||
if output_path_obj
|
||||
.components()
|
||||
.any(|comp| comp == std::path::Component::ParentDir)
|
||||
{
|
||||
anyhow::bail!("Output path must not contain parent directory traversal");
|
||||
return Err(FsHandlerError::InvalidOutputPath(
|
||||
"Output path must not contain parent directory traversal".into(),
|
||||
));
|
||||
}
|
||||
|
||||
let deployment_config_dir = self.get_deployment_dir_path(deployment_id);
|
||||
@@ -103,9 +136,12 @@ impl FsHandler for FsHandlerImpl {
|
||||
let full_output_path = self
|
||||
.get_deployment_config_path(deployment_id, output_path, true)
|
||||
.await?;
|
||||
let parent_dir = full_output_path
|
||||
.parent()
|
||||
.context("Failed to get parent directory of the config file")?;
|
||||
let parent_dir = full_output_path.parent().ok_or_else(|| {
|
||||
FsHandlerError::InvalidOutputPath(format!(
|
||||
"Failed to get parent directory of output path: {:?}",
|
||||
full_output_path
|
||||
))
|
||||
})?;
|
||||
// ensure the parent directory exists before creating the file
|
||||
tokio::fs::create_dir_all(parent_dir).await?;
|
||||
let mut file = tokio::fs::OpenOptions::new()
|
||||
|
||||
Reference in New Issue
Block a user