omni_orchestrator/schemas/v1/api/
deployments.rs

1use std::sync::Arc;
2use crate::DatabaseManager;
3use crate::models::deployment::Deployment;
4use super::super::db::queries as db;
5use rocket::http::Status;
6use rocket::serde::json::{json, Json, Value};
7use rocket::{delete, get, post, put, State};
8use serde::{Deserialize, Serialize};
9
10/// Request body for creating a deployment.
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct CreateDeploymentRequest {
13    pub app_id: i64,
14    pub build_id: i64,
15    pub version: String,
16    pub deployment_strategy: String,
17    pub previous_deployment_id: Option<i64>,
18    pub canary_percentage: Option<i64>,
19    pub environment_variables: Option<serde_json::Value>,
20    pub annotations: Option<serde_json::Value>,
21    pub labels: Option<serde_json::Value>,
22}
23
24/// Request body for updating a deployment's status.
25#[derive(Debug, Clone, Serialize, Deserialize)]
26pub struct UpdateDeploymentStatusRequest {
27    pub status: String,
28    pub error_message: Option<String>,
29}
30
31/// List all deployments with pagination support.
32#[get("/platform/<platform_id>/deployments?<page>&<per_page>")]
33pub async fn list_deployments(
34    platform_id: i64,
35    page: Option<i64>,
36    per_page: Option<i64>,
37    db_manager: &State<Arc<DatabaseManager>>,
38) -> Result<Json<Value>, (Status, Json<Value>)> {
39    // Get platform information
40    let platform = match db::platforms::get_platform_by_id(db_manager.get_main_pool(), platform_id).await {
41        Ok(platform) => platform,
42        Err(_) => {
43            return Err((
44                Status::NotFound,
45                Json(json!({
46                    "error": "Platform not found",
47                    "message": format!("Platform with ID {} does not exist", platform_id)
48                }))
49            ));
50        }
51    };
52
53    // Get platform-specific database pool
54    let pool = match db_manager.get_platform_pool(&platform.name, platform_id).await {
55        Ok(pool) => pool,
56        Err(_) => {
57            return Err((
58                Status::InternalServerError,
59                Json(json!({
60                    "error": "Database error",
61                    "message": "Failed to connect to platform database"
62                }))
63            ));
64        }
65    };
66
67    match (page, per_page) {
68        (Some(p), Some(pp)) => {
69            let deployments = match db::deployment::list_deployments(&pool, p, pp).await {
70                Ok(deployments) => deployments,
71                Err(_) => {
72                    return Err((
73                        Status::InternalServerError,
74                        Json(json!({
75                            "error": "Database error",
76                            "message": "Failed to retrieve deployments"
77                        }))
78                    ));
79                }
80            };
81            
82            let total_count = match db::deployment::count_deployments(&pool).await {
83                Ok(count) => count,
84                Err(_) => {
85                    return Err((
86                        Status::InternalServerError,
87                        Json(json!({
88                            "error": "Database error",
89                            "message": "Failed to count deployments"
90                        }))
91                    ));
92                }
93            };
94            
95            let total_pages = (total_count as f64 / pp as f64).ceil() as i64;
96
97            let response = json!({
98                "deployments": deployments,
99                "pagination": {
100                    "page": p,
101                    "per_page": pp,
102                    "total_count": total_count,
103                    "total_pages": total_pages
104                }
105            });
106
107            Ok(Json(response))
108        }
109        _ => Err((
110            Status::BadRequest,
111            Json(json!({
112                "error": "Missing pagination parameters",
113                "message": "Please provide both 'page' and 'per_page' parameters"
114            }))
115        ))
116    }
117}
118
119/// Count the total number of deployments.
120#[get("/platform/<platform_id>/count/deployments")]
121pub async fn count_deployments(
122    platform_id: i64,
123    db_manager: &State<Arc<DatabaseManager>>
124) -> Result<Json<i64>, (Status, Json<Value>)> {
125    // Get platform information
126    let platform = match db::platforms::get_platform_by_id(db_manager.get_main_pool(), platform_id).await {
127        Ok(platform) => platform,
128        Err(_) => {
129            return Err((
130                Status::NotFound,
131                Json(json!({
132                    "error": "Platform not found",
133                    "message": format!("Platform with ID {} does not exist", platform_id)
134                }))
135            ));
136        }
137    };
138
139    // Get platform-specific database pool
140    let pool = match db_manager.get_platform_pool(&platform.name, platform_id).await {
141        Ok(pool) => pool,
142        Err(_) => {
143            return Err((
144                Status::InternalServerError,
145                Json(json!({
146                    "error": "Database error",
147                    "message": "Failed to connect to platform database"
148                }))
149            ));
150        }
151    };
152
153    match db::deployment::count_deployments(&pool).await {
154        Ok(count) => Ok(Json(count)),
155        Err(_) => Err((
156            Status::InternalServerError,
157            Json(json!({
158                "error": "Database error",
159                "message": "Failed to count deployments"
160            }))
161        )),
162    }
163}
164
165/// Get a specific deployment by ID.
166#[get("/platform/<platform_id>/deployments/<deployment_id>")]
167pub async fn get_deployment(
168    platform_id: i64,
169    deployment_id: i64,
170    db_manager: &State<Arc<DatabaseManager>>
171) -> Result<Json<Deployment>, (Status, Json<Value>)> {
172    // Get platform information
173    let platform = match db::platforms::get_platform_by_id(db_manager.get_main_pool(), platform_id).await {
174        Ok(platform) => platform,
175        Err(_) => {
176            return Err((
177                Status::NotFound,
178                Json(json!({
179                    "error": "Platform not found",
180                    "message": format!("Platform with ID {} does not exist", platform_id)
181                }))
182            ));
183        }
184    };
185
186    // Get platform-specific database pool
187    let pool = match db_manager.get_platform_pool(&platform.name, platform_id).await {
188        Ok(pool) => pool,
189        Err(_) => {
190            return Err((
191                Status::InternalServerError,
192                Json(json!({
193                    "error": "Database error",
194                    "message": "Failed to connect to platform database"
195                }))
196            ));
197        }
198    };
199
200    match db::deployment::get_deployment_by_id(&pool, deployment_id).await {
201        Ok(deployment) => Ok(Json(deployment)),
202        Err(_) => Err((
203            Status::NotFound,
204            Json(json!({
205                "error": "Deployment not found",
206                "message": format!("Deployment with ID {} could not be found", deployment_id)
207            }))
208        )),
209    }
210}
211
212/// List all deployments for a specific application with pagination.
213#[get("/platform/<platform_id>/apps/<app_id>/deployments?<page>&<per_page>")]
214pub async fn list_app_deployments(
215    platform_id: i64,
216    app_id: i64,
217    page: Option<i64>,
218    per_page: Option<i64>,
219    db_manager: &State<Arc<DatabaseManager>>,
220) -> Result<Json<Value>, (Status, Json<Value>)> {
221    // Get platform information
222    let platform = match db::platforms::get_platform_by_id(db_manager.get_main_pool(), platform_id).await {
223        Ok(platform) => platform,
224        Err(_) => {
225            return Err((
226                Status::NotFound,
227                Json(json!({
228                    "error": "Platform not found",
229                    "message": format!("Platform with ID {} does not exist", platform_id)
230                }))
231            ));
232        }
233    };
234
235    // Get platform-specific database pool
236    let pool = match db_manager.get_platform_pool(&platform.name, platform_id).await {
237        Ok(pool) => pool,
238        Err(_) => {
239            return Err((
240                Status::InternalServerError,
241                Json(json!({
242                    "error": "Database error",
243                    "message": "Failed to connect to platform database"
244                }))
245            ));
246        }
247    };
248
249    match (page, per_page) {
250        (Some(p), Some(pp)) => {
251            let deployments = match db::deployment::list_deployments_by_app(&pool, app_id, p, pp).await {
252                Ok(deployments) => deployments,
253                Err(_) => {
254                    return Err((
255                        Status::InternalServerError,
256                        Json(json!({
257                            "error": "Database error",
258                            "message": "Failed to retrieve deployments"
259                        }))
260                    ));
261                }
262            };
263            
264            let total_count = match db::deployment::count_deployments_by_app(&pool, app_id).await {
265                Ok(count) => count,
266                Err(_) => {
267                    return Err((
268                        Status::InternalServerError,
269                        Json(json!({
270                            "error": "Database error",
271                            "message": "Failed to count deployments"
272                        }))
273                    ));
274                }
275            };
276            
277            let total_pages = (total_count as f64 / pp as f64).ceil() as i64;
278
279            let response = json!({
280                "deployments": deployments,
281                "pagination": {
282                    "page": p,
283                    "per_page": pp,
284                    "total_count": total_count,
285                    "total_pages": total_pages
286                }
287            });
288
289            Ok(Json(response))
290        }
291        _ => Err((
292            Status::BadRequest,
293            Json(json!({
294                "error": "Missing pagination parameters",
295                "message": "Please provide both 'page' and 'per_page' parameters"
296            }))
297        ))
298    }
299}
300
301/// Create a new deployment.
302#[post("/platform/<platform_id>/deployments", format = "json", data = "<deployment_request>")]
303pub async fn create_deployment(
304    platform_id: i64,
305    deployment_request: Json<CreateDeploymentRequest>,
306    db_manager: &State<Arc<DatabaseManager>>,
307) -> Result<Json<Deployment>, (Status, Json<Value>)> {
308    // Get platform information
309    let platform = match db::platforms::get_platform_by_id(db_manager.get_main_pool(), platform_id).await {
310        Ok(platform) => platform,
311        Err(_) => {
312            return Err((
313                Status::NotFound,
314                Json(json!({
315                    "error": "Platform not found",
316                    "message": format!("Platform with ID {} does not exist", platform_id)
317                }))
318            ));
319        }
320    };
321
322    // Get platform-specific database pool
323    let pool = match db_manager.get_platform_pool(&platform.name, platform_id).await {
324        Ok(pool) => pool,
325        Err(_) => {
326            return Err((
327                Status::InternalServerError,
328                Json(json!({
329                    "error": "Database error",
330                    "message": "Failed to connect to platform database"
331                }))
332            ));
333        }
334    };
335
336    match db::deployment::create_deployment(
337        &pool,
338        deployment_request.app_id,
339        deployment_request.build_id,
340        &deployment_request.version,
341        &deployment_request.deployment_strategy,
342        deployment_request.previous_deployment_id,
343        deployment_request.canary_percentage,
344        deployment_request.environment_variables.clone(),
345        deployment_request.annotations.clone(),
346        deployment_request.labels.clone(),
347        None, // created_by would typically come from auth middleware
348    ).await {
349        Ok(deployment) => Ok(Json(deployment)),
350        Err(e) => Err((
351            Status::InternalServerError,
352            Json(json!({
353                "error": "Failed to create deployment",
354                "message": e.to_string()
355            }))
356        )),
357    }
358}
359
360/// Update a deployment's status.
361#[put("/platform/<platform_id>/deployments/<deployment_id>/status", format = "json", data = "<status_request>")]
362pub async fn update_deployment_status(
363    platform_id: i64,
364    deployment_id: i64,
365    status_request: Json<UpdateDeploymentStatusRequest>,
366    db_manager: &State<Arc<DatabaseManager>>,
367) -> Result<Json<Deployment>, (Status, Json<Value>)> {
368    // Get platform information
369    let platform = match db::platforms::get_platform_by_id(db_manager.get_main_pool(), platform_id).await {
370        Ok(platform) => platform,
371        Err(_) => {
372            return Err((
373                Status::NotFound,
374                Json(json!({
375                    "error": "Platform not found",
376                    "message": format!("Platform with ID {} does not exist", platform_id)
377                }))
378            ));
379        }
380    };
381
382    // Get platform-specific database pool
383    let pool = match db_manager.get_platform_pool(&platform.name, platform_id).await {
384        Ok(pool) => pool,
385        Err(_) => {
386            return Err((
387                Status::InternalServerError,
388                Json(json!({
389                    "error": "Database error",
390                    "message": "Failed to connect to platform database"
391                }))
392            ));
393        }
394    };
395
396    match db::deployment::update_deployment_status(
397        &pool,
398        deployment_id,
399        &status_request.status,
400        status_request.error_message.as_deref(),
401    ).await {
402        Ok(deployment) => Ok(Json(deployment)),
403        Err(e) => Err((
404            Status::InternalServerError,
405            Json(json!({
406                "error": "Failed to update deployment status",
407                "message": e.to_string()
408            }))
409        )),
410    }
411}
412
413/// Delete a specific deployment.
414#[delete("/platform/<platform_id>/deployments/<deployment_id>")]
415pub async fn delete_deployment(
416    platform_id: i64,
417    deployment_id: i64,
418    db_manager: &State<Arc<DatabaseManager>>,
419) -> Result<Json<Value>, (Status, Json<Value>)> {
420    // Get platform information
421    let platform = match db::platforms::get_platform_by_id(db_manager.get_main_pool(), platform_id).await {
422        Ok(platform) => platform,
423        Err(_) => {
424            return Err((
425                Status::NotFound,
426                Json(json!({
427                    "error": "Platform not found",
428                    "message": format!("Platform with ID {} does not exist", platform_id)
429                }))
430            ));
431        }
432    };
433
434    // Get platform-specific database pool
435    let pool = match db_manager.get_platform_pool(&platform.name, platform_id).await {
436        Ok(pool) => pool,
437        Err(_) => {
438            return Err((
439                Status::InternalServerError,
440                Json(json!({
441                    "error": "Database error",
442                    "message": "Failed to connect to platform database"
443                }))
444            ));
445        }
446    };
447
448    match db::deployment::delete_deployment(&pool, deployment_id).await {
449        Ok(_) => Ok(Json(json!({ "status": "deleted" }))),
450        Err(e) => Err((
451            Status::InternalServerError, 
452            Json(json!({
453                "error": "Database error",
454                "message": e.to_string()
455            }))
456        )),
457    }
458}