diff --git a/src/rndc_parser.rs b/src/rndc_parser.rs index 6b58a80..1511274 100644 --- a/src/rndc_parser.rs +++ b/src/rndc_parser.rs @@ -150,6 +150,7 @@ fn primary_list(input: &str) -> IResult<&str, Vec> { /// Statement types within a zone configuration #[derive(Debug)] +#[allow(dead_code)] enum ZoneStatement { // Core Type(ZoneType), diff --git a/src/rndc_types_tests.rs b/src/rndc_types_tests.rs index df98198..9ec5753 100644 --- a/src/rndc_types_tests.rs +++ b/src/rndc_types_tests.rs @@ -6,7 +6,6 @@ #[cfg(test)] mod tests { use crate::rndc_types::*; - use std::collections::HashMap; // ========== Enum Tests ========== diff --git a/src/types.rs b/src/types.rs index 6e558c3..3005500 100644 --- a/src/types.rs +++ b/src/types.rs @@ -44,6 +44,9 @@ pub enum ApiError { #[error("Zone not found: {0}")] ZoneNotFound(String), + #[error("Zone already exists: {0}")] + ZoneAlreadyExists(String), + #[error("Internal server error: {0}")] InternalError(String), } @@ -55,6 +58,7 @@ impl IntoResponse for ApiError { ApiError::RndcError(_) => (StatusCode::INTERNAL_SERVER_ERROR, self.to_string()), ApiError::InvalidRequest(_) => (StatusCode::BAD_REQUEST, self.to_string()), ApiError::ZoneNotFound(_) => (StatusCode::NOT_FOUND, self.to_string()), + ApiError::ZoneAlreadyExists(_) => (StatusCode::CONFLICT, self.to_string()), ApiError::InternalError(_) => (StatusCode::INTERNAL_SERVER_ERROR, self.to_string()), }; diff --git a/src/types_test.rs b/src/types_test.rs index 1e3465e..e628ef3 100644 --- a/src/types_test.rs +++ b/src/types_test.rs @@ -91,6 +91,15 @@ fn test_api_error_zone_not_found() { assert_eq!(response.status(), StatusCode::NOT_FOUND); } +#[test] +fn test_api_error_zone_already_exists() { + let error = ApiError::ZoneAlreadyExists("example.com".to_string()); + assert_eq!(error.to_string(), "Zone already exists: example.com"); + + let response = error.into_response(); + assert_eq!(response.status(), StatusCode::CONFLICT); +} + #[test] fn test_api_error_internal_error() { let error = ApiError::InternalError("Database connection failed".to_string()); @@ -110,6 +119,7 @@ fn test_api_error_display() { ApiError::RndcError("rndc error".to_string()), ApiError::InvalidRequest("invalid".to_string()), ApiError::ZoneNotFound("test.com".to_string()), + ApiError::ZoneAlreadyExists("test.com".to_string()), ApiError::InternalError("internal".to_string()), ]; diff --git a/src/zones.rs b/src/zones.rs index 187730e..66e69f0 100644 --- a/src/zones.rs +++ b/src/zones.rs @@ -301,6 +301,7 @@ pub struct ZoneListResponse { responses( (status = 201, description = "Zone created successfully", body = ZoneResponse), (status = 400, description = "Invalid request"), + (status = 409, description = "Zone already exists"), (status = 500, description = "RNDC command failed"), (status = 500, description = "Internal server error") ), @@ -441,7 +442,14 @@ pub async fn create_zone( .map_err(|e| { error!("RNDC addzone failed for {}: {}", request.zone_name, e); metrics::record_zone_operation("create", false); - ApiError::RndcError(e.to_string()) + + // Check if zone already exists + let error_msg = e.to_string(); + if error_msg.contains("already exists") { + ApiError::ZoneAlreadyExists(request.zone_name.clone()) + } else { + ApiError::RndcError(error_msg) + } })?; info!("Zone {} created successfully", request.zone_name);