add nproc, update rollback, s3 (WIP)
This commit is contained in:
parent
6d215292bd
commit
73d5cdd171
8 changed files with 1962 additions and 59 deletions
112
src/api.rs
112
src/api.rs
|
|
@ -1,12 +1,14 @@
|
|||
use aws_sdk_s3::operation::list_objects_v2::ListObjectsV2Output;
|
||||
use axum::{
|
||||
Router,
|
||||
body::Body,
|
||||
extract::{Path, Query, State},
|
||||
http::StatusCode,
|
||||
response::{IntoResponse, Json, Response},
|
||||
routing::{get, post},
|
||||
routing::{delete, get, post, put},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::sync::Arc;
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
use tokio::sync::Mutex;
|
||||
use tower::ServiceBuilder;
|
||||
use tower_http::{
|
||||
|
|
@ -30,6 +32,8 @@ pub struct ApiServer {
|
|||
discovery: Arc<ContainerDiscovery>,
|
||||
storage: Arc<Storage>,
|
||||
log_manager: Arc<LogManager>,
|
||||
s3_client: aws_sdk_s3::Client,
|
||||
garage_endpoint: String,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
@ -38,6 +42,10 @@ pub struct AppState {
|
|||
pub discovery: Arc<ContainerDiscovery>,
|
||||
pub storage: Arc<Storage>,
|
||||
pub log_manager: Arc<LogManager>,
|
||||
|
||||
// garage
|
||||
pub s3_client: aws_sdk_s3::Client,
|
||||
pub garage_endpoint: String,
|
||||
}
|
||||
|
||||
impl ApiServer {
|
||||
|
|
@ -47,6 +55,8 @@ impl ApiServer {
|
|||
discovery: Arc<ContainerDiscovery>,
|
||||
storage: Arc<Storage>,
|
||||
log_manager: Arc<LogManager>,
|
||||
s3_client: aws_sdk_s3::Client,
|
||||
garage_endpoint: String,
|
||||
) -> Self {
|
||||
Self {
|
||||
port,
|
||||
|
|
@ -54,6 +64,8 @@ impl ApiServer {
|
|||
discovery,
|
||||
storage,
|
||||
log_manager,
|
||||
s3_client,
|
||||
garage_endpoint,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -63,6 +75,8 @@ impl ApiServer {
|
|||
discovery: self.discovery,
|
||||
storage: self.storage,
|
||||
log_manager: self.log_manager.clone(),
|
||||
s3_client: self.s3_client,
|
||||
garage_endpoint: self.garage_endpoint,
|
||||
};
|
||||
|
||||
let app = Router::new()
|
||||
|
|
@ -74,6 +88,7 @@ impl ApiServer {
|
|||
.route("/api/containers/{id}", get(get_container))
|
||||
.route("/api/containers/{id}/update", post(trigger_update))
|
||||
.route("/api/containers/{id}/force-update", post(force_update))
|
||||
.route("/api/containers/{id}/rollback", post(force_rollback))
|
||||
// Discovery endpoints
|
||||
.route("/api/discovery/scan", post(force_discovery))
|
||||
.route("/api/discovery/containers", get(get_discovered_containers))
|
||||
|
|
@ -84,6 +99,14 @@ impl ApiServer {
|
|||
.route("/api/logs/dates", get(get_log_dates))
|
||||
// Bulk operations
|
||||
.route("/api/bulk/update-check", post(bulk_update_check))
|
||||
// TODO: communicate with garage s3
|
||||
// .route("/api/s3/{bucket}", get(handler))
|
||||
// .route("/api/s3/{bucket}", put(handler))
|
||||
// .route("/api/s3/{bucket}", delete(handler))
|
||||
// .route("/api/s3/{bucket}/{key}", get(handler))
|
||||
// .route("/api/s3/{bucket}/{key}", put(handler))
|
||||
// .route("/api/s3/{bucket}/{key}", delete(handler))
|
||||
// TODO: Online installations
|
||||
.with_state(state)
|
||||
.layer(
|
||||
ServiceBuilder::new()
|
||||
|
|
@ -214,8 +237,8 @@ async fn system_status(State(state): State<AppState>) -> Json<ApiResponse<System
|
|||
};
|
||||
|
||||
let status = SystemStatusResponse {
|
||||
service: "Docker Update Manager".to_string(),
|
||||
version: "1.0.0".to_string(),
|
||||
service: "Silserv".to_string(),
|
||||
version: "0.1.1".to_string(),
|
||||
managed_containers: containers.len(),
|
||||
discovered_containers: discovered.len(),
|
||||
active_updates,
|
||||
|
|
@ -335,6 +358,33 @@ async fn force_discovery(
|
|||
Ok(Json(ApiResponse::success(response)))
|
||||
}
|
||||
|
||||
async fn force_rollback(
|
||||
Path(id): Path<String>,
|
||||
State(state): State<AppState>,
|
||||
) -> Result<Json<ApiResponse<RollbackResponse>>, ApiError> {
|
||||
// find images with format of <name>-backup-<timestamp>
|
||||
{
|
||||
let mgr = state.update_manager.lock().await;
|
||||
let container = mgr.get_container(&id).await;
|
||||
|
||||
match container {
|
||||
Ok(mut c) => {
|
||||
mgr.attempt_rollback(&mut c).await?;
|
||||
}
|
||||
Err(err) => {
|
||||
error!("Failed to get container: {}", err);
|
||||
return Ok(Json(ApiResponse::error(err.to_string())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let success = RollbackResponse {
|
||||
message: "Rollback completed successfully".to_string(),
|
||||
};
|
||||
|
||||
Ok(Json(ApiResponse::success(success)))
|
||||
}
|
||||
|
||||
async fn get_discovered_containers(
|
||||
State(state): State<AppState>,
|
||||
) -> Result<Json<ApiResponse<Vec<String>>>, ApiError> {
|
||||
|
|
@ -459,6 +509,55 @@ async fn bulk_update_check(
|
|||
Ok(Json(ApiResponse::success(response)))
|
||||
}
|
||||
|
||||
// get object list
|
||||
async fn list_objects(
|
||||
State(state): State<AppState>,
|
||||
Path(bucket): Path<String>,
|
||||
Query(params): Query<std::collections::HashMap<String, String>>,
|
||||
) -> Result<Json<ApiResponse<serde_json::Value>>, ApiError> {
|
||||
let mut list_request = state.s3_client.list_objects_v2().bucket(&bucket);
|
||||
|
||||
if let Some(prefix) = params.get("prefix") {
|
||||
list_request = list_request.prefix(prefix);
|
||||
}
|
||||
|
||||
let response: ListObjectsV2Output = list_request.send().await?;
|
||||
|
||||
if response.contents.is_some() {
|
||||
let mapped = response
|
||||
.contents()
|
||||
.iter()
|
||||
.map(|obj| {
|
||||
let mut hashmap = HashMap::new();
|
||||
hashmap.insert("Key".to_string(), obj.key().unwrap().to_string());
|
||||
hashmap.insert("Size".to_string(), obj.size().unwrap().to_string());
|
||||
hashmap.insert(
|
||||
"LastModified".to_string(),
|
||||
obj.last_modified().unwrap().to_string(),
|
||||
);
|
||||
hashmap.insert("ETag".to_string(), obj.e_tag().unwrap().to_string());
|
||||
hashmap.insert(
|
||||
"StorageClass".to_string(),
|
||||
obj.storage_class().unwrap().to_string(),
|
||||
);
|
||||
hashmap.insert(
|
||||
"Owner".to_string(),
|
||||
obj.owner().unwrap().id().unwrap().to_string(),
|
||||
);
|
||||
hashmap
|
||||
})
|
||||
.collect::<Vec<HashMap<String, String>>>();
|
||||
|
||||
// let mut response = Response::builder()
|
||||
// .status(StatusCode::OK)
|
||||
// .body(Body::new(mapped))
|
||||
// .unwrap();
|
||||
Ok(Json(ApiResponse::success(serde_json::json!(mapped))))
|
||||
} else {
|
||||
Ok(Json(ApiResponse::success(serde_json::json!({}))))
|
||||
}
|
||||
}
|
||||
|
||||
// Request/Response types
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
|
|
@ -546,6 +645,11 @@ struct BulkUpdateResult {
|
|||
error: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
struct RollbackResponse {
|
||||
message: String,
|
||||
}
|
||||
|
||||
// Error handling
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue