4 Commits

Author SHA1 Message Date
GW_MC
3c5485c449 Merge branch 'feature/nginx-config-handler'
All checks were successful
Test / get-ci-image (push) Successful in 25s
Test / test-frontend (push) Successful in 28s
Test / lint-frontend (push) Successful in 32s
Verify / get-ci-image (push) Successful in 6s
Test / frontend-build (push) Successful in 17s
Test / lint-crates (push) Successful in 8m38s
Test / test-crates (push) Successful in 9m0s
Verify / verify-generated-db-entities (push) Successful in 9m47s
2026-07-18 05:52:03 +00:00
GW_MC
076e87695d refactor: clean up unused code and improve conditionals in various modules 2026-07-18 05:07:10 +00:00
GW_MC
83037f3ee2 refactor(tests): remove unused test cases and related code 2026-07-18 04:54:35 +00:00
GW_MC
2c20d08127 fmt: format 2026-07-18 04:54:29 +00:00
31 changed files with 123 additions and 273 deletions

View File

@@ -80,34 +80,6 @@ mod tests {
assert!(result.is_ok()); assert!(result.is_ok());
} }
fn create_exec_file(path: &Path) {
write_file(path);
let metadata = fs::metadata(path);
assert!(metadata.is_ok());
let metadata = metadata.ok();
assert!(metadata.is_some());
let metadata = metadata.unwrap_or_else(|| unreachable!());
let mut perms = metadata.permissions();
perms.set_mode(0o755);
let result = fs::set_permissions(path, perms);
assert!(result.is_ok());
}
fn create_non_exec_file(path: &Path) {
write_file(path);
let metadata = fs::metadata(path);
assert!(metadata.is_ok());
let metadata = metadata.ok();
assert!(metadata.is_some());
let metadata = metadata.unwrap_or_else(|| unreachable!());
let mut perms = metadata.permissions();
perms.set_mode(0o644);
let result = fs::set_permissions(path, perms);
assert!(result.is_ok());
}
fn valid_tls_raw_paths(temp_dir: &TempDir) -> (PathBuf, PathBuf, PathBuf) { fn valid_tls_raw_paths(temp_dir: &TempDir) -> (PathBuf, PathBuf, PathBuf) {
let ca_path = temp_dir.path().join("ca.pem"); let ca_path = temp_dir.path().join("ca.pem");
let cert_path = temp_dir.path().join("cert.pem"); let cert_path = temp_dir.path().join("cert.pem");

View File

@@ -1,7 +1,3 @@
use std::sync::Arc;
use tokio::sync::Mutex;
pub mod ssh; pub mod ssh;
pub type AgentClient = pub type AgentClient =
@@ -47,8 +43,6 @@ mod tests {
atomic::{AtomicBool, Ordering}, atomic::{AtomicBool, Ordering},
}; };
use tokio::sync::Mutex;
use crate::config::settings::{ use crate::config::settings::{
GrpcSettings, LogSettings, MAuthSettings, Settings, TLSSettings, GrpcSettings, LogSettings, MAuthSettings, Settings, TLSSettings,
}; };

View File

@@ -1,8 +1,6 @@
use std::sync::{Arc, Weak}; use std::sync::Weak;
use nxmesh_proto::{ use nxmesh_proto::{ConfigUpdate, MasterMessage, command::Command, master_message::Payload};
AgentMessage, ConfigUpdate, MasterMessage, command::Command, master_message::Payload,
};
use crate::service::master_handler::{MasterHandlerError, MessageResult}; use crate::service::master_handler::{MasterHandlerError, MessageResult};

View File

@@ -2,7 +2,7 @@ use std::sync::Arc;
use thiserror::Error; use thiserror::Error;
use tokio::process::Command; use tokio::process::Command;
use tracing::{debug, warn}; use tracing::debug;
use crate::{config::settings::NginxSettings, service::master_handler::MasterHandlerError}; use crate::{config::settings::NginxSettings, service::master_handler::MasterHandlerError};
@@ -120,10 +120,7 @@ impl CommandHandler for CommandHandlerImpl {
if !output.status.success() { if !output.status.success() {
let error_info = String::from_utf8_lossy(&output.stderr); let error_info = String::from_utf8_lossy(&output.stderr);
return Err(CommandHandlerError::CommandExecutionError( return Err(CommandHandlerError::CommandExecutionError(
std::io::Error::new( std::io::Error::other(format!("Failed to reload nginx: {}", error_info.trim())),
std::io::ErrorKind::Other,
format!("Failed to reload nginx: {}", error_info.trim()),
),
)); ));
} }
let success_info = String::from_utf8_lossy(&output.stdout); let success_info = String::from_utf8_lossy(&output.stdout);
@@ -142,10 +139,7 @@ impl CommandHandler for CommandHandlerImpl {
if !output.status.success() { if !output.status.success() {
let error_info = String::from_utf8_lossy(&output.stderr); let error_info = String::from_utf8_lossy(&output.stderr);
return Err(CommandHandlerError::CommandExecutionError( return Err(CommandHandlerError::CommandExecutionError(
std::io::Error::new( std::io::Error::other(format!("Failed to stop nginx: {}", error_info.trim())),
std::io::ErrorKind::Other,
format!("Failed to stop nginx: {}", error_info.trim()),
),
)); ));
} }
let success_info = String::from_utf8_lossy(&output.stdout); let success_info = String::from_utf8_lossy(&output.stdout);
@@ -171,10 +165,10 @@ impl CommandHandler for CommandHandlerImpl {
if !output.status.success() { if !output.status.success() {
let error_info = String::from_utf8_lossy(&output.stderr); let error_info = String::from_utf8_lossy(&output.stderr);
return Err(CommandHandlerError::CommandExecutionError( return Err(CommandHandlerError::CommandExecutionError(
std::io::Error::new( std::io::Error::other(format!(
std::io::ErrorKind::Other, "Failed to validate nginx config: {}",
format!("Failed to validate nginx config: {}", error_info.trim()), error_info.trim()
), )),
)); ));
} }
let success_info = String::from_utf8_lossy(&output.stdout); let success_info = String::from_utf8_lossy(&output.stdout);
@@ -191,10 +185,10 @@ impl CommandHandler for CommandHandlerImpl {
if !output.status.success() { if !output.status.success() {
let error_info = String::from_utf8_lossy(&output.stderr); let error_info = String::from_utf8_lossy(&output.stderr);
return Err(CommandHandlerError::CommandExecutionError( return Err(CommandHandlerError::CommandExecutionError(
std::io::Error::new( std::io::Error::other(format!(
std::io::ErrorKind::Other, "Failed to get nginx version: {}",
format!("Failed to get nginx version: {}", error_info.trim()), error_info.trim()
), )),
)); ));
} }
@@ -211,10 +205,7 @@ impl CommandHandler for CommandHandlerImpl {
if !output.status.success() { if !output.status.success() {
let error_info = String::from_utf8_lossy(&output.stderr); let error_info = String::from_utf8_lossy(&output.stderr);
return Err(CommandHandlerError::CommandExecutionError( return Err(CommandHandlerError::CommandExecutionError(
std::io::Error::new( std::io::Error::other(format!("Failed to get nginx status: {}", error_info.trim())),
std::io::ErrorKind::Other,
format!("Failed to get nginx status: {}", error_info.trim()),
),
)); ));
} }

View File

@@ -2,7 +2,7 @@ use std::sync::Arc;
use fs4::tokio::AsyncFileExt; use fs4::tokio::AsyncFileExt;
use thiserror::Error; use thiserror::Error;
use tokio::{io::AsyncWriteExt, process::Command}; use tokio::io::AsyncWriteExt;
use tracing::warn; use tracing::warn;
use crate::{config::settings::NginxSettings, service::master_handler::MasterHandlerError}; use crate::{config::settings::NginxSettings, service::master_handler::MasterHandlerError};
@@ -222,19 +222,19 @@ impl FsHandler for FsHandlerImpl {
let mut entries = tokio::fs::read_dir(&deployment_dir).await?; let mut entries = tokio::fs::read_dir(&deployment_dir).await?;
let mut candidates: Vec<(std::path::PathBuf, std::time::SystemTime)> = Vec::new(); let mut candidates: Vec<(std::path::PathBuf, std::time::SystemTime)> = Vec::new();
while let Some(entry) = entries.next_entry().await? { while let Some(entry) = entries.next_entry().await? {
if entry.file_type().await.map_or(false, |t| t.is_dir()) { if entry.file_type().await.is_ok_and(|t| t.is_dir())
if let Ok(mtime) = entry.metadata().await.and_then(|m| m.modified()) { && let Ok(mtime) = entry.metadata().await.and_then(|m| m.modified())
{
candidates.push((entry.path(), mtime)); candidates.push((entry.path(), mtime));
} }
} }
}
// sort descending by mtime (newest first) // sort descending by mtime (newest first)
candidates.sort_by(|a, b| b.1.cmp(&a.1)); candidates.sort_by_key(|b| std::cmp::Reverse(b.1));
for (dir, _) in &candidates { for (dir, _) in &candidates {
let mut dir_entries = tokio::fs::read_dir(dir).await?; let mut dir_entries = tokio::fs::read_dir(dir).await?;
while let Some(file) = dir_entries.next_entry().await? { while let Some(file) = dir_entries.next_entry().await? {
if file.file_type().await.map_or(false, |t| t.is_file()) { if file.file_type().await.is_ok_and(|t| t.is_file()) {
let name = file.file_name().to_string_lossy().to_string(); let name = file.file_name().to_string_lossy().to_string();
if name == "nginx.conf" || name.ends_with(".conf") { if name == "nginx.conf" || name.ends_with(".conf") {
let path = file.path().to_string_lossy().to_string(); let path = file.path().to_string_lossy().to_string();

View File

@@ -107,7 +107,9 @@ impl OnConfigUpdateHandler for NginxMasterMessageHandlerImpl {
// apply reload on the root config // apply reload on the root config
self.command_handler.reload(Some(&root_config_path)).await?; self.command_handler.reload(Some(&root_config_path)).await?;
// persist deployment path so Reload/Test commands survive agent restarts // persist deployment path so Reload/Test commands survive agent restarts
self.fs_handler.save_last_deployment(&root_config_path).await?; self.fs_handler
.save_last_deployment(&root_config_path)
.await?;
info!("Persisted last deployment path: {}", root_config_path); info!("Persisted last deployment path: {}", root_config_path);
// Reply the master to confirm the config update is successful // Reply the master to confirm the config update is successful
self.master_handler self.master_handler

View File

@@ -1,7 +1,6 @@
use std::sync::Arc; use std::sync::Arc;
use sea_orm::DatabaseConnection; use sea_orm::DatabaseConnection;
use tonic::transport::Server;
pub mod ssh; pub mod ssh;

View File

@@ -54,7 +54,9 @@ mod tests {
proxy_setting_service: Arc::new(proxy_setting::MockProxySettingService::new()), proxy_setting_service: Arc::new(proxy_setting::MockProxySettingService::new()),
rewrite_rule_service: Arc::new(rewrite_rule::MockRewriteRuleService::new()), rewrite_rule_service: Arc::new(rewrite_rule::MockRewriteRuleService::new()),
ssl_certificate_service: Arc::new(ssl_certificate::MockSslCertificateService::new()), ssl_certificate_service: Arc::new(ssl_certificate::MockSslCertificateService::new()),
config_inheritance_service: Arc::new(config_inheritance::MockConfigInheritanceService::new()), config_inheritance_service: Arc::new(
config_inheritance::MockConfigInheritanceService::new(),
),
}); });
get_router().await.with_state(state) get_router().await.with_state(state)
} }

View File

@@ -33,11 +33,11 @@ pub async fn update_agent_handler(
Path(id): Path<uuid::Uuid>, Path(id): Path<uuid::Uuid>,
Json(body): Json<UpdateAgentRequest>, Json(body): Json<UpdateAgentRequest>,
) -> Result<impl IntoResponse, AppError> { ) -> Result<impl IntoResponse, AppError> {
if let Some(ref name) = body.name { if let Some(ref name) = body.name
if name.trim().is_empty() { && name.trim().is_empty()
{
return Err(AppError::BadRequest("name must not be empty".to_string())); return Err(AppError::BadRequest("name must not be empty".to_string()));
} }
}
let rec = UpdateAgentRecord { let rec = UpdateAgentRecord {
name: body.name, name: body.name,

View File

@@ -9,7 +9,7 @@ use axum::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use uuid::Uuid; use uuid::Uuid;
use crate::routes::api::{AppError, ApiRouter}; use crate::routes::api::{ApiRouter, AppError};
use crate::service::proxy::access_rule::{ use crate::service::proxy::access_rule::{
AccessRuleService, CreateAccessRuleParams, UpdateAccessRuleParams, AccessRuleService, CreateAccessRuleParams, UpdateAccessRuleParams,
}; };
@@ -151,10 +151,7 @@ pub(super) fn routes() -> ApiRouter {
"/locations/{location_id}/access-rules", "/locations/{location_id}/access-rules",
axum::routing::get(list_access_rules_by_location), axum::routing::get(list_access_rules_by_location),
) )
.route( .route("/access-rules", axum::routing::post(create_access_rule))
"/access-rules",
axum::routing::post(create_access_rule),
)
.route( .route(
"/access-rules/{id}", "/access-rules/{id}",
axum::routing::get(get_access_rule) axum::routing::get(get_access_rule)

View File

@@ -9,7 +9,7 @@ use axum::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use uuid::Uuid; use uuid::Uuid;
use crate::routes::api::{AppError, ApiRouter}; use crate::routes::api::{ApiRouter, AppError};
use crate::service::proxy::{ProxyServiceTrait, types::AgentConfigBinding}; use crate::service::proxy::{ProxyServiceTrait, types::AgentConfigBinding};
use super::configs::ProxyConfigResponse; use super::configs::ProxyConfigResponse;
@@ -56,7 +56,10 @@ async fn bind_agent(
Json(body): Json<BindAgentRequest>, Json(body): Json<BindAgentRequest>,
) -> Result<impl IntoResponse, AppError> { ) -> Result<impl IntoResponse, AppError> {
let binding = svc.bind_agent(agent_id, body.config_id).await?; let binding = svc.bind_agent(agent_id, body.config_id).await?;
Ok((StatusCode::CREATED, Json(AgentConfigResponse::from(binding)))) Ok((
StatusCode::CREATED,
Json(AgentConfigResponse::from(binding)),
))
} }
async fn unbind_agent( async fn unbind_agent(
@@ -72,8 +75,7 @@ async fn unbind_agent(
} }
pub(super) fn routes() -> ApiRouter { pub(super) fn routes() -> ApiRouter {
ApiRouter::new() ApiRouter::new().route(
.route(
"/agents/{agent_id}/config", "/agents/{agent_id}/config",
axum::routing::get(get_active_agent_config) axum::routing::get(get_active_agent_config)
.post(bind_agent) .post(bind_agent)

View File

@@ -9,7 +9,7 @@ use axum::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use uuid::Uuid; use uuid::Uuid;
use crate::routes::api::{AppError, ApiRouter}; use crate::routes::api::{ApiRouter, AppError};
use crate::service::proxy::cache_zone::{ use crate::service::proxy::cache_zone::{
CacheZoneService, CreateCacheZoneParams, UpdateCacheZoneParams, CacheZoneService, CreateCacheZoneParams, UpdateCacheZoneParams,
}; };

View File

@@ -9,7 +9,7 @@ use axum::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use uuid::Uuid; use uuid::Uuid;
use crate::routes::api::{AppError, ApiRouter}; use crate::routes::api::{ApiRouter, AppError};
use crate::service::proxy::config_inheritance::{ use crate::service::proxy::config_inheritance::{
AddInheritanceParams, ConfigInheritanceRecord, ConfigInheritanceService, AddInheritanceParams, ConfigInheritanceRecord, ConfigInheritanceService,
}; };
@@ -100,8 +100,5 @@ pub(super) fn routes() -> ApiRouter {
"/configs/{id}/parents/{parent_id}", "/configs/{id}/parents/{parent_id}",
axum::routing::delete(remove_parent), axum::routing::delete(remove_parent),
) )
.route( .route("/configs/{id}/children", axum::routing::get(list_children))
"/configs/{id}/children",
axum::routing::get(list_children),
)
} }

View File

@@ -9,7 +9,7 @@ use axum::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use uuid::Uuid; use uuid::Uuid;
use crate::routes::api::{AppError, ApiRouter}; use crate::routes::api::{ApiRouter, AppError};
use crate::service::proxy::{ use crate::service::proxy::{
ProxyServiceTrait, ProxyServiceTrait,
types::{CreateProxyConfigParams, ProxyConfigSummary, UpdateProxyConfigParams}, types::{CreateProxyConfigParams, ProxyConfigSummary, UpdateProxyConfigParams},
@@ -93,7 +93,7 @@ async fn get_config(
Path(id): Path<Uuid>, Path(id): Path<Uuid>,
) -> Result<Json<serde_json::Value>, AppError> { ) -> Result<Json<serde_json::Value>, AppError> {
let config = svc.get_proxy_config(id).await?; let config = svc.get_proxy_config(id).await?;
Ok(Json(serde_json::to_value(&config.id).unwrap_or_default())) Ok(Json(serde_json::to_value(config.id).unwrap_or_default()))
} }
async fn update_config( async fn update_config(
@@ -136,7 +136,10 @@ async fn render_config(
pub(super) fn routes() -> ApiRouter { pub(super) fn routes() -> ApiRouter {
ApiRouter::new() ApiRouter::new()
.route("/configs", axum::routing::get(list_configs).post(create_config)) .route(
"/configs",
axum::routing::get(list_configs).post(create_config),
)
.route( .route(
"/configs/{id}", "/configs/{id}",
axum::routing::get(get_config) axum::routing::get(get_config)

View File

@@ -9,7 +9,7 @@ use axum::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use uuid::Uuid; use uuid::Uuid;
use crate::routes::api::{AppError, ApiRouter}; use crate::routes::api::{ApiRouter, AppError};
use crate::service::proxy::limit_rule::{ use crate::service::proxy::limit_rule::{
CreateLimitRuleParams, LimitRuleService, UpdateLimitRuleParams, CreateLimitRuleParams, LimitRuleService, UpdateLimitRuleParams,
}; };
@@ -131,10 +131,7 @@ pub(super) fn routes() -> ApiRouter {
"/locations/{location_id}/limit-rules", "/locations/{location_id}/limit-rules",
axum::routing::get(list_limit_rules_by_location), axum::routing::get(list_limit_rules_by_location),
) )
.route( .route("/limit-rules", axum::routing::post(create_limit_rule))
"/limit-rules",
axum::routing::post(create_limit_rule),
)
.route( .route(
"/limit-rules/{id}", "/limit-rules/{id}",
axum::routing::get(get_limit_rule) axum::routing::get(get_limit_rule)

View File

@@ -9,7 +9,7 @@ use axum::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use uuid::Uuid; use uuid::Uuid;
use crate::routes::api::{AppError, ApiRouter}; use crate::routes::api::{ApiRouter, AppError};
use crate::service::proxy::limit_zone::{ use crate::service::proxy::limit_zone::{
CreateLimitZoneParams, LimitZoneService, UpdateLimitZoneParams, CreateLimitZoneParams, LimitZoneService, UpdateLimitZoneParams,
}; };

View File

@@ -9,7 +9,7 @@ use axum::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use uuid::Uuid; use uuid::Uuid;
use crate::routes::api::{AppError, ApiRouter}; use crate::routes::api::{ApiRouter, AppError};
use crate::service::proxy::location_block::{ use crate::service::proxy::location_block::{
CreateLocationBlockParams, LocationBlockService, UpdateLocationBlockParams, CreateLocationBlockParams, LocationBlockService, UpdateLocationBlockParams,
}; };
@@ -95,7 +95,10 @@ async fn create_location(
let mut params = CreateLocationBlockParams::from(body); let mut params = CreateLocationBlockParams::from(body);
params.server_id = server_id; params.server_id = server_id;
let location = svc.create(params).await?; let location = svc.create(params).await?;
Ok((StatusCode::CREATED, Json(LocationBlockResponse::from(location)))) Ok((
StatusCode::CREATED,
Json(LocationBlockResponse::from(location)),
))
} }
async fn get_location( async fn get_location(

View File

@@ -9,7 +9,7 @@ use axum::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use uuid::Uuid; use uuid::Uuid;
use crate::routes::api::{AppError, ApiRouter}; use crate::routes::api::{ApiRouter, AppError};
use crate::service::proxy::log_setting::{ use crate::service::proxy::log_setting::{
CreateLogSettingParams, LogSettingService, UpdateLogSettingParams, CreateLogSettingParams, LogSettingService, UpdateLogSettingParams,
}; };

View File

@@ -9,7 +9,7 @@ use axum::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use uuid::Uuid; use uuid::Uuid;
use crate::routes::api::{AppError, ApiRouter}; use crate::routes::api::{ApiRouter, AppError};
use crate::service::proxy::proxy_setting::{ use crate::service::proxy::proxy_setting::{
CreateProxySettingParams, ProxySettingService, UpdateProxySettingParams, CreateProxySettingParams, ProxySettingService, UpdateProxySettingParams,
}; };
@@ -107,7 +107,10 @@ async fn create_proxy_setting(
let mut params = CreateProxySettingParams::from(body); let mut params = CreateProxySettingParams::from(body);
params.location_id = location_id; params.location_id = location_id;
let setting = svc.create(params).await?; let setting = svc.create(params).await?;
Ok((StatusCode::CREATED, Json(ProxySettingResponse::from(setting)))) Ok((
StatusCode::CREATED,
Json(ProxySettingResponse::from(setting)),
))
} }
async fn get_proxy_setting( async fn get_proxy_setting(

View File

@@ -9,7 +9,7 @@ use axum::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use uuid::Uuid; use uuid::Uuid;
use crate::routes::api::{AppError, ApiRouter}; use crate::routes::api::{ApiRouter, AppError};
use crate::service::proxy::rewrite_rule::{ use crate::service::proxy::rewrite_rule::{
CreateRewriteRuleParams, RewriteRuleService, UpdateRewriteRuleParams, CreateRewriteRuleParams, RewriteRuleService, UpdateRewriteRuleParams,
}; };

View File

@@ -9,7 +9,7 @@ use axum::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use uuid::Uuid; use uuid::Uuid;
use crate::routes::api::{AppError, ApiRouter}; use crate::routes::api::{ApiRouter, AppError};
use crate::service::proxy::server_block::{ use crate::service::proxy::server_block::{
CreateServerBlockParams, ServerBlockService, UpdateServerBlockParams, CreateServerBlockParams, ServerBlockService, UpdateServerBlockParams,
}; };

View File

@@ -9,7 +9,7 @@ use axum::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use uuid::Uuid; use uuid::Uuid;
use crate::routes::api::{AppError, ApiRouter}; use crate::routes::api::{ApiRouter, AppError};
use crate::service::proxy::ssl_certificate::{ use crate::service::proxy::ssl_certificate::{
CreateSslCertificateParams, SslCertificateService, UpdateSslCertificateParams, CreateSslCertificateParams, SslCertificateService, UpdateSslCertificateParams,
}; };
@@ -86,7 +86,10 @@ async fn create_ssl_certificate(
Json(body): Json<CreateSslCertificateRequest>, Json(body): Json<CreateSslCertificateRequest>,
) -> Result<impl IntoResponse, AppError> { ) -> Result<impl IntoResponse, AppError> {
let cert = svc.create(body.into()).await?; let cert = svc.create(body.into()).await?;
Ok((StatusCode::CREATED, Json(SslCertificateResponse::from(cert)))) Ok((
StatusCode::CREATED,
Json(SslCertificateResponse::from(cert)),
))
} }
async fn get_ssl_certificate( async fn get_ssl_certificate(

View File

@@ -5,18 +5,12 @@ use axum_test::TestServer;
use crate::routes::api::{ApiState, LocalApiState}; use crate::routes::api::{ApiState, LocalApiState};
use crate::service::proxy::*; use crate::service::proxy::*;
use crate::service::proxy::{ use crate::service::proxy::{
access_rule::MockAccessRuleService, access_rule::MockAccessRuleService, cache_zone::MockCacheZoneService,
cache_zone::MockCacheZoneService, config_inheritance::MockConfigInheritanceService, limit_rule::MockLimitRuleService,
config_inheritance::MockConfigInheritanceService, limit_zone::MockLimitZoneService, location_block::MockLocationBlockService,
limit_rule::MockLimitRuleService, log_setting::MockLogSettingService, proxy_setting::MockProxySettingService,
limit_zone::MockLimitZoneService, rewrite_rule::MockRewriteRuleService, server_block::MockServerBlockService,
location_block::MockLocationBlockService, ssl_certificate::MockSslCertificateService, upstream::MockUpstreamService,
log_setting::MockLogSettingService,
proxy_setting::MockProxySettingService,
rewrite_rule::MockRewriteRuleService,
server_block::MockServerBlockService,
ssl_certificate::MockSslCertificateService,
upstream::MockUpstreamService,
}; };
pub(crate) struct TestProxyApiBuilder { pub(crate) struct TestProxyApiBuilder {
@@ -121,31 +115,41 @@ impl TestProxyApiBuilder {
pub async fn build(self) -> TestServer { pub async fn build(self) -> TestServer {
let state = ApiState { let state = ApiState {
proxy_service: Arc::new(self.proxy_service.unwrap_or_else(MockProxyServiceTrait::new)), proxy_service: Arc::new(
self.proxy_service
.unwrap_or_else(MockProxyServiceTrait::new),
),
server_block_service: Arc::new( server_block_service: Arc::new(
self.server_block_service.unwrap_or_else(MockServerBlockService::new), self.server_block_service
.unwrap_or_else(MockServerBlockService::new),
), ),
upstream_service: Arc::new( upstream_service: Arc::new(
self.upstream_service.unwrap_or_else(MockUpstreamService::new), self.upstream_service
.unwrap_or_else(MockUpstreamService::new),
), ),
location_block_service: Arc::new( location_block_service: Arc::new(
self.location_block_service self.location_block_service
.unwrap_or_else(MockLocationBlockService::new), .unwrap_or_else(MockLocationBlockService::new),
), ),
access_rule_service: Arc::new( access_rule_service: Arc::new(
self.access_rule_service.unwrap_or_else(MockAccessRuleService::new), self.access_rule_service
.unwrap_or_else(MockAccessRuleService::new),
), ),
cache_zone_service: Arc::new( cache_zone_service: Arc::new(
self.cache_zone_service.unwrap_or_else(MockCacheZoneService::new), self.cache_zone_service
.unwrap_or_else(MockCacheZoneService::new),
), ),
limit_rule_service: Arc::new( limit_rule_service: Arc::new(
self.limit_rule_service.unwrap_or_else(MockLimitRuleService::new), self.limit_rule_service
.unwrap_or_else(MockLimitRuleService::new),
), ),
limit_zone_service: Arc::new( limit_zone_service: Arc::new(
self.limit_zone_service.unwrap_or_else(MockLimitZoneService::new), self.limit_zone_service
.unwrap_or_else(MockLimitZoneService::new),
), ),
log_setting_service: Arc::new( log_setting_service: Arc::new(
self.log_setting_service.unwrap_or_else(MockLogSettingService::new), self.log_setting_service
.unwrap_or_else(MockLogSettingService::new),
), ),
proxy_setting_service: Arc::new( proxy_setting_service: Arc::new(
self.proxy_setting_service self.proxy_setting_service

View File

@@ -9,10 +9,10 @@ use axum::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use uuid::Uuid; use uuid::Uuid;
use crate::routes::api::{AppError, ApiRouter}; use crate::routes::api::{ApiRouter, AppError};
use crate::service::proxy::types::UpstreamConfig; use crate::service::proxy::types::UpstreamConfig;
use crate::service::proxy::upstream::{ use crate::service::proxy::upstream::{
CreateUpstreamParams, UpstreamService, UpdateUpstreamParams, CreateUpstreamParams, UpdateUpstreamParams, UpstreamService,
}; };
#[derive(Serialize)] #[derive(Serialize)]

View File

@@ -36,7 +36,9 @@ mod tests {
proxy_setting_service: Arc::new(proxy_setting::MockProxySettingService::new()), proxy_setting_service: Arc::new(proxy_setting::MockProxySettingService::new()),
rewrite_rule_service: Arc::new(rewrite_rule::MockRewriteRuleService::new()), rewrite_rule_service: Arc::new(rewrite_rule::MockRewriteRuleService::new()),
ssl_certificate_service: Arc::new(ssl_certificate::MockSslCertificateService::new()), ssl_certificate_service: Arc::new(ssl_certificate::MockSslCertificateService::new()),
config_inheritance_service: Arc::new(config_inheritance::MockConfigInheritanceService::new()), config_inheritance_service: Arc::new(
config_inheritance::MockConfigInheritanceService::new(),
),
}); });
let router = get_root_router(state).await; let router = get_root_router(state).await;
let server = TestServer::new(router); let server = TestServer::new(router);
@@ -61,7 +63,9 @@ mod tests {
proxy_setting_service: Arc::new(proxy_setting::MockProxySettingService::new()), proxy_setting_service: Arc::new(proxy_setting::MockProxySettingService::new()),
rewrite_rule_service: Arc::new(rewrite_rule::MockRewriteRuleService::new()), rewrite_rule_service: Arc::new(rewrite_rule::MockRewriteRuleService::new()),
ssl_certificate_service: Arc::new(ssl_certificate::MockSslCertificateService::new()), ssl_certificate_service: Arc::new(ssl_certificate::MockSslCertificateService::new()),
config_inheritance_service: Arc::new(config_inheritance::MockConfigInheritanceService::new()), config_inheritance_service: Arc::new(
config_inheritance::MockConfigInheritanceService::new(),
),
}); });
let router = get_root_router(state).await; let router = get_root_router(state).await;
let server = TestServer::new(router); let server = TestServer::new(router);

View File

@@ -131,7 +131,7 @@ impl CertificateService for CertificateServiceImpl {
.collect::<Vec<SanType>>(), .collect::<Vec<SanType>>(),
san_dns san_dns
.into_iter() .into_iter()
.map(|dns| SanType::DnsName(dns)) .map(SanType::DnsName)
.collect::<Vec<SanType>>(), .collect::<Vec<SanType>>(),
] ]
.concat(); .concat();

View File

@@ -60,22 +60,18 @@ pub async fn start_master_server(
db_connection.clone(), db_connection.clone(),
)), )),
server_block_service: Arc::new( server_block_service: Arc::new(
crate::service::proxy::server_block::ServerBlockServiceImpl::new( crate::service::proxy::server_block::ServerBlockServiceImpl::new(db_connection.clone()),
),
upstream_service: Arc::new(crate::service::proxy::upstream::UpstreamServiceImpl::new(
db_connection.clone(), db_connection.clone(),
), )),
),
upstream_service: Arc::new(
crate::service::proxy::upstream::UpstreamServiceImpl::new(db_connection.clone()),
),
location_block_service: Arc::new( location_block_service: Arc::new(
crate::service::proxy::location_block::LocationBlockServiceImpl::new( crate::service::proxy::location_block::LocationBlockServiceImpl::new(
db_connection.clone(), db_connection.clone(),
), ),
), ),
access_rule_service: Arc::new( access_rule_service: Arc::new(
crate::service::proxy::access_rule::AccessRuleServiceImpl::new( crate::service::proxy::access_rule::AccessRuleServiceImpl::new(db_connection.clone()),
db_connection.clone(),
),
), ),
cache_zone_service: Arc::new( cache_zone_service: Arc::new(
crate::service::proxy::cache_zone::CacheZoneServiceImpl::new(db_connection.clone()), crate::service::proxy::cache_zone::CacheZoneServiceImpl::new(db_connection.clone()),
@@ -87,9 +83,7 @@ pub async fn start_master_server(
crate::service::proxy::limit_zone::LimitZoneServiceImpl::new(db_connection.clone()), crate::service::proxy::limit_zone::LimitZoneServiceImpl::new(db_connection.clone()),
), ),
log_setting_service: Arc::new( log_setting_service: Arc::new(
crate::service::proxy::log_setting::LogSettingServiceImpl::new( crate::service::proxy::log_setting::LogSettingServiceImpl::new(db_connection.clone()),
db_connection.clone(),
),
), ),
proxy_setting_service: Arc::new( proxy_setting_service: Arc::new(
crate::service::proxy::proxy_setting::ProxySettingServiceImpl::new( crate::service::proxy::proxy_setting::ProxySettingServiceImpl::new(
@@ -97,9 +91,7 @@ pub async fn start_master_server(
), ),
), ),
rewrite_rule_service: Arc::new( rewrite_rule_service: Arc::new(
crate::service::proxy::rewrite_rule::RewriteRuleServiceImpl::new( crate::service::proxy::rewrite_rule::RewriteRuleServiceImpl::new(db_connection.clone()),
db_connection.clone(),
),
), ),
ssl_certificate_service: Arc::new( ssl_certificate_service: Arc::new(
crate::service::proxy::ssl_certificate::SslCertificateServiceImpl::new( crate::service::proxy::ssl_certificate::SslCertificateServiceImpl::new(

View File

@@ -16,11 +16,11 @@ impl std::fmt::Display for ProxySettingRender<'_> {
if let Some(buffer) = self.setting.buffer_size { if let Some(buffer) = self.setting.buffer_size {
writeln!(f, " proxy_buffer_size {};", buffer)?; writeln!(f, " proxy_buffer_size {};", buffer)?;
} }
if self.setting.cache_enabled.unwrap_or(false) { if self.setting.cache_enabled.unwrap_or(false)
if let Some(zone_name) = self.cache_zone_name { && let Some(zone_name) = self.cache_zone_name
{
writeln!(f, " proxy_cache {};", zone_name)?; writeln!(f, " proxy_cache {};", zone_name)?;
} }
}
Ok(()) Ok(())
} }
} }

View File

@@ -18,11 +18,11 @@ impl std::fmt::Display for ServerBlockRender<'_> {
writeln!(f, " listen {};", self.block.listen_port)?; writeln!(f, " listen {};", self.block.listen_port)?;
} }
if let Some(ref names) = self.block.server_name { if let Some(ref names) = self.block.server_name
if !names.is_empty() { && !names.is_empty()
{
writeln!(f, " server_name {};", names.join(" "))?; writeln!(f, " server_name {};", names.join(" "))?;
} }
}
if let Some(cert) = self.ssl_cert { if let Some(cert) = self.ssl_cert {
writeln!(f, "{}", cert)?; writeln!(f, "{}", cert)?;

View File

@@ -1,9 +1,7 @@
use sea_orm::{ActiveModelTrait, ActiveValue::Set, DatabaseConnection, EntityTrait, prelude::*}; use sea_orm::{ActiveModelTrait, ActiveValue::Set, DatabaseConnection, EntityTrait, prelude::*};
use uuid::Uuid; use uuid::Uuid;
use crate::service::proxy::types::{ use crate::service::proxy::types::{ProxyServiceError, ProxyServiceResult, UpstreamConfig};
ProxyServiceError, ProxyServiceResult, UpstreamConfig,
};
pub struct CreateUpstreamParams { pub struct CreateUpstreamParams {
pub config_id: Uuid, pub config_id: Uuid,

View File

@@ -12,114 +12,3 @@ pub use agent::*;
pub mod auth; pub mod auth;
#[allow(ambiguous_glob_reexports)] #[allow(ambiguous_glob_reexports)]
pub use tonic_async_interceptor::*; pub use tonic_async_interceptor::*;
#[cfg(test)]
mod tests {
use prost::Message;
use crate::agent::{
AgentMessage, ConfigApplyStatus, ConfigStatus, DeploymentMode, Error, MasterMessage,
MetricType, RegistrationRequest, agent_message, master_message,
};
#[test]
fn agent_message_round_trip_with_registration_payload() {
let msg = AgentMessage {
agent_id: "agent-1".to_string(),
timestamp: 123,
payload: Some(agent_message::Payload::Registration(RegistrationRequest {
hostname: "node-1".to_string(),
ip_address: "127.0.0.1".to_string(),
version: "1.0.0".to_string(),
capabilities: vec!["reload".to_string(), "metrics".to_string()],
labels: std::collections::HashMap::from([
("region".to_string(), "dev".to_string()),
("tier".to_string(), "edge".to_string()),
]),
deployment_mode: DeploymentMode::Standalone as i32,
})),
};
let encoded = msg.encode_to_vec();
let decoded = AgentMessage::decode(encoded.as_slice());
assert!(decoded.is_ok());
let decoded = decoded.unwrap_or_else(|_| unreachable!());
assert_eq!(decoded.agent_id, "agent-1");
assert_eq!(decoded.timestamp, 123);
match decoded.payload {
Some(agent_message::Payload::Registration(payload)) => {
assert_eq!(payload.hostname, "node-1");
assert_eq!(payload.ip_address, "127.0.0.1");
assert_eq!(payload.version, "1.0.0");
assert_eq!(payload.capabilities.len(), 2);
assert_eq!(payload.labels.get("region"), Some(&"dev".to_string()));
assert_eq!(payload.deployment_mode, DeploymentMode::Standalone as i32);
}
_ => unreachable!(),
}
}
#[test]
fn master_message_round_trip_with_error_payload() {
let msg = MasterMessage {
timestamp: 999,
payload: Some(master_message::Payload::Error(Error {
code: "E_CONFIG_INVALID".to_string(),
message: "invalid config".to_string(),
details: std::collections::HashMap::from([
("file".to_string(), "site.conf".to_string()),
("line".to_string(), "42".to_string()),
]),
})),
};
let encoded = msg.encode_to_vec();
let decoded = MasterMessage::decode(encoded.as_slice());
assert!(decoded.is_ok());
let decoded = decoded.unwrap_or_else(|_| unreachable!());
assert_eq!(decoded.timestamp, 999);
match decoded.payload {
Some(master_message::Payload::Error(err)) => {
assert_eq!(err.code, "E_CONFIG_INVALID");
assert_eq!(err.message, "invalid config");
assert_eq!(err.details.get("line"), Some(&"42".to_string()));
}
_ => unreachable!(),
}
}
#[test]
fn enum_integer_mappings_are_stable() {
assert_eq!(DeploymentMode::Unspecified as i32, 0);
assert_eq!(DeploymentMode::DockerSidecar as i32, 1);
assert_eq!(DeploymentMode::KubernetesSidecar as i32, 2);
assert_eq!(DeploymentMode::Standalone as i32, 3);
assert_eq!(ConfigApplyStatus::Unspecified as i32, 0);
assert_eq!(ConfigApplyStatus::Pending as i32, 1);
assert_eq!(ConfigApplyStatus::Validating as i32, 2);
assert_eq!(ConfigApplyStatus::Applying as i32, 3);
assert_eq!(ConfigApplyStatus::Success as i32, 4);
assert_eq!(ConfigApplyStatus::Failed as i32, 5);
assert_eq!(ConfigApplyStatus::RolledBack as i32, 6);
assert_eq!(MetricType::Unspecified as i32, 0);
assert_eq!(MetricType::Gauge as i32, 1);
assert_eq!(MetricType::Counter as i32, 2);
assert_eq!(MetricType::Histogram as i32, 3);
}
#[test]
fn config_status_defaults_are_proto3_zero_values() {
let status = ConfigStatus::default();
assert_eq!(status.config_id, "");
assert_eq!(status.version, 0);
assert_eq!(status.status, ConfigApplyStatus::Unspecified as i32);
assert_eq!(status.error_message, "");
assert_eq!(status.applied_at, 0);
}
}