mirror of
https://github.com/CloudNebulaProject/reddwarf.git
synced 2026-04-10 21:30:40 +00:00
Implement an in-process broadcast event bus for resource mutations (ADDED/MODIFIED/DELETED) with SSE watch endpoints on all list handlers, following the Kubernetes watch protocol. Add the reddwarf-runtime crate with a trait-based zone runtime abstraction targeting illumos zones, including LX and custom reddwarf brand support, etherstub/direct VNIC networking, ZFS dataset management, and a MockRuntime for testing on non-illumos platforms. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
94 lines
3.1 KiB
Rust
94 lines
3.1 KiB
Rust
use crate::handlers::common::{
|
|
create_resource, delete_resource, get_resource, list_resources, update_resource, ListResponse,
|
|
};
|
|
use crate::response::{status_deleted, ApiResponse};
|
|
use crate::validation::validate_resource;
|
|
use crate::watch::{watch_resource_stream, WatchParams};
|
|
use crate::{AppState, Result};
|
|
use axum::extract::{Path, Query, State};
|
|
use axum::response::{IntoResponse, Response};
|
|
use axum::Json;
|
|
use reddwarf_core::{GroupVersionKind, ResourceKey, Service};
|
|
use reddwarf_storage::KeyEncoder;
|
|
use std::sync::Arc;
|
|
use tracing::info;
|
|
|
|
/// GET /api/v1/namespaces/{namespace}/services/{name}
|
|
pub async fn get_service(
|
|
State(state): State<Arc<AppState>>,
|
|
Path((namespace, name)): Path<(String, String)>,
|
|
) -> Result<Response> {
|
|
let gvk = GroupVersionKind::from_api_version_kind("v1", "Service");
|
|
let key = ResourceKey::new(gvk, namespace, name);
|
|
|
|
let service: Service = get_resource(&state, &key).await?;
|
|
|
|
Ok(ApiResponse::ok(service).into_response())
|
|
}
|
|
|
|
/// GET /api/v1/namespaces/{namespace}/services
|
|
pub async fn list_services(
|
|
State(state): State<Arc<AppState>>,
|
|
Path(namespace): Path<String>,
|
|
Query(params): Query<WatchParams>,
|
|
) -> Result<Response> {
|
|
if params.is_watch() {
|
|
let gvk = GroupVersionKind::from_api_version_kind("v1", "Service");
|
|
return Ok(watch_resource_stream(&state, gvk, Some(namespace)).into_response());
|
|
}
|
|
|
|
let prefix = KeyEncoder::encode_prefix("v1", "Service", Some(&namespace));
|
|
let services: Vec<Service> = list_resources(&state, &prefix).await?;
|
|
|
|
let response = ListResponse::new("v1".to_string(), "ServiceList".to_string(), services);
|
|
|
|
Ok(ApiResponse::ok(response).into_response())
|
|
}
|
|
|
|
/// POST /api/v1/namespaces/{namespace}/services
|
|
pub async fn create_service(
|
|
State(state): State<Arc<AppState>>,
|
|
Path(namespace): Path<String>,
|
|
Json(mut service): Json<Service>,
|
|
) -> Result<Response> {
|
|
info!("Creating service in namespace: {}", namespace);
|
|
|
|
service.metadata.namespace = Some(namespace);
|
|
validate_resource(&service)?;
|
|
|
|
let created = create_resource(&state, service).await?;
|
|
|
|
Ok(ApiResponse::created(created).into_response())
|
|
}
|
|
|
|
/// PUT /api/v1/namespaces/{namespace}/services/{name}
|
|
pub async fn replace_service(
|
|
State(state): State<Arc<AppState>>,
|
|
Path((namespace, name)): Path<(String, String)>,
|
|
Json(mut service): Json<Service>,
|
|
) -> Result<Response> {
|
|
info!("Replacing service: {}/{}", namespace, name);
|
|
|
|
service.metadata.namespace = Some(namespace);
|
|
service.metadata.name = Some(name);
|
|
validate_resource(&service)?;
|
|
|
|
let updated = update_resource(&state, service).await?;
|
|
|
|
Ok(ApiResponse::ok(updated).into_response())
|
|
}
|
|
|
|
/// DELETE /api/v1/namespaces/{namespace}/services/{name}
|
|
pub async fn delete_service(
|
|
State(state): State<Arc<AppState>>,
|
|
Path((namespace, name)): Path<(String, String)>,
|
|
) -> Result<Response> {
|
|
info!("Deleting service: {}/{}", namespace, name);
|
|
|
|
let gvk = GroupVersionKind::from_api_version_kind("v1", "Service");
|
|
let key = ResourceKey::new(gvk, namespace, name.clone());
|
|
|
|
delete_resource(&state, &key).await?;
|
|
|
|
Ok(status_deleted(&name, "Service"))
|
|
}
|