omni_orchestrator/schemas/v1/api/
providers.rs

1//! Provider management module for handeling CRUD operations on providers.
2//! 
3//! This module provides functionality to create, read, update, and delete providers in the system. It includes API endpoints for managing providers and their associated resources.
4//! It also includes a function to retrieve a paginated list of providers from the database.
5//! It is designed to be used primarily by the dashboard to add new providers and manage existing ones.
6//! The resulting database table is read at runtime by the various directories to determine which provider configs they need to have access to.
7
8use crate::models::provider::{ProviderAuditLog, Provider};
9use crate::schemas::v1::db::queries::{self as db};
10use rocket::serde::json::{Json, Value};
11use crate::models::instance::Instance;
12use rocket::http::Status;
13use serde_json::json;
14use std::sync::Arc;
15use crate::DatabaseManager;
16
17/// List all providers in the system with pagination support.
18/// 
19/// # Arguments
20/// * `platform_id` - The ID of the platform to retrieve providers for.
21/// * `page` - The page number to retrieve.
22/// * `per_page` - The number of providers to retrieve per page.
23/// * `db_manager` - The database manager for accessing platform-specific database pools.
24/// 
25/// # Returns
26/// A JSON response containing the list of providers and pagination information.
27#[get("/platform/<platform_id>/providers?<page>&<per_page>")]
28pub async fn list_providers(
29    platform_id: i64,
30    page: Option<i64>,
31    per_page: Option<i64>,
32    db_manager: &rocket::State<Arc<DatabaseManager>>,
33) -> Result<Json<Value>, (Status, Json<Value>)> {
34    // Get platform information
35    let platform = match db::platforms::get_platform_by_id(db_manager.get_main_pool(), platform_id).await {
36        Ok(platform) => platform,
37        Err(_) => {
38            return Err((
39                Status::NotFound,
40                Json(json!({
41                    "error": "Platform not found",
42                    "message": format!("Platform with ID {} does not exist", platform_id)
43                }))
44            ));
45        }
46    };
47
48    // Get platform-specific database pool
49    let pool = match db_manager.get_platform_pool(&platform.name, platform_id).await {
50        Ok(pool) => pool,
51        Err(_) => {
52            return Err((
53                Status::InternalServerError,
54                Json(json!({
55                    "error": "Database error",
56                    "message": "Failed to connect to platform database"
57                }))
58            ));
59        }
60    };
61
62    let page = page.unwrap_or(0);
63    let per_page = per_page.unwrap_or(10);
64
65    let providers: Vec<Provider> = match db::provider::get_providers_paginated(&pool, page, per_page).await {
66        Ok(providers) => providers,
67        Err(e) => {
68            tracing::error!("Failed to fetch providers: {}", e);
69            return Err((
70                Status::InternalServerError,
71                Json(json!({
72                    "error": "Database error",
73                    "message": "Failed to fetch providers"
74                }))
75            ));
76        }
77    };
78
79    let total_count = match db::provider::get_provider_count(&pool).await {
80        Ok(count) => count,
81        Err(e) => {
82            tracing::error!("Failed to fetch provider count: {}", e);
83            return Err((
84                Status::InternalServerError,
85                Json(json!({
86                    "error": "Database error",
87                    "message": "Failed to count providers"
88                }))
89            ));
90        }
91    };
92
93    let total_pages = (total_count as f64 / per_page as f64).ceil() as i64;
94
95    // Pagination format as the standard for all paginated responses from the API
96    let response = json!({
97        "providers": providers,
98        "pagination": {
99            "page": page,
100            "per_page": per_page,
101            "total_count": total_count,
102            "total_pages": total_pages
103        }
104    });
105
106    Ok(Json(response))
107}
108
109/// Retrieves a paginated list of audit logs for a specific provider.
110#[get("/platform/<platform_id>/providers/<provider_id>/audit_logs?<page>&<per_page>")]
111pub async fn get_provider_audit_logs_paginated(
112    platform_id: i64,
113    provider_id: i64,
114    page: Option<i64>,
115    per_page: Option<i64>,
116    db_manager: &rocket::State<Arc<DatabaseManager>>,
117) -> Result<Json<Value>, (Status, Json<Value>)> {
118    // Get platform information
119    let platform = match db::platforms::get_platform_by_id(db_manager.get_main_pool(), platform_id).await {
120        Ok(platform) => platform,
121        Err(_) => {
122            return Err((
123                Status::NotFound,
124                Json(json!({
125                    "error": "Platform not found",
126                    "message": format!("Platform with ID {} does not exist", platform_id)
127                }))
128            ));
129        }
130    };
131
132    // Get platform-specific database pool
133    let pool = match db_manager.get_platform_pool(&platform.name, platform_id).await {
134        Ok(pool) => pool,
135        Err(_) => {
136            return Err((
137                Status::InternalServerError,
138                Json(json!({
139                    "error": "Database error",
140                    "message": "Failed to connect to platform database"
141                }))
142            ));
143        }
144    };
145
146    let page = page.unwrap_or(0);
147    let per_page = per_page.unwrap_or(10);
148
149    let audit_logs: Vec<ProviderAuditLog> = match db::provider::get_provider_audit_logs_paginated(&pool, provider_id, page, per_page).await {
150        Ok(audit_logs) => audit_logs,
151        Err(e) => {
152            tracing::error!("Failed to fetch provider audit logs: {}", e);
153            return Err((
154                Status::InternalServerError,
155                Json(json!({
156                    "error": "Database error",
157                    "message": "Failed to fetch provider audit logs"
158                }))
159            ));
160        }
161    };
162
163    let total_count = match db::provider::get_provider_audit_log_count(&pool, provider_id).await {
164        Ok(count) => count,
165        Err(e) => {
166            tracing::error!("Failed to fetch provider audit log count: {}", e);
167            return Err((
168                Status::InternalServerError,
169                Json(json!({
170                    "error": "Database error",
171                    "message": "Failed to count provider audit logs"
172                }))
173            ));
174        }
175    };
176
177    let total_pages = (total_count as f64 / per_page as f64).ceil() as i64;
178
179    let response = json!({
180        "audit_logs": audit_logs,
181        "pagination": {
182            "page": page,
183            "per_page": per_page,
184            "total_count": total_count,
185            "total_pages": total_pages
186        }
187    });
188
189    Ok(Json(response))
190}
191
192/// Fetch all instances for a given provider.
193#[get("/platform/<platform_id>/providers/<provider_id>/instances?<page>&<per_page>")]
194pub async fn get_provider_instances(
195    platform_id: i64,
196    provider_id: i64,
197    page: Option<i64>,
198    per_page: Option<i64>,
199    db_manager: &rocket::State<Arc<DatabaseManager>>,
200) -> Result<Json<Value>, (Status, Json<Value>)> {
201    // Get platform information
202    let platform = match db::platforms::get_platform_by_id(db_manager.get_main_pool(), platform_id).await {
203        Ok(platform) => platform,
204        Err(_) => {
205            return Err((
206                Status::NotFound,
207                Json(json!({
208                    "error": "Platform not found",
209                    "message": format!("Platform with ID {} does not exist", platform_id)
210                }))
211            ));
212        }
213    };
214
215    // Get platform-specific database pool
216    let pool = match db_manager.get_platform_pool(&platform.name, platform_id).await {
217        Ok(pool) => pool,
218        Err(_) => {
219            return Err((
220                Status::InternalServerError,
221                Json(json!({
222                    "error": "Database error",
223                    "message": "Failed to connect to platform database"
224                }))
225            ));
226        }
227    };
228
229    let page = page.unwrap_or(0);
230    let per_page = per_page.unwrap_or(10);
231
232    tracing::info!("Fetching instances for provider {} (page: {}, per_page: {})", provider_id, page, per_page);
233
234    let instances: Vec<Instance> = match db::provider::get_provider_instances(&pool, provider_id, page, per_page).await {
235        Ok(instances) => {
236            tracing::debug!("Retrieved {} instances", instances.len());
237            instances
238        }
239        Err(e) => {
240            tracing::error!("Failed to fetch provider instances: {}", e);
241            return Err((
242                Status::InternalServerError,
243                Json(json!({
244                    "error": "Database error",
245                    "message": "Failed to fetch provider instances"
246                }))
247            ));
248        }
249    };
250
251    let total_count = match db::provider::get_provider_instance_count(&pool, provider_id).await {
252        Ok(count) => {
253            tracing::debug!("Total instance count: {}", count);
254            count
255        }
256        Err(e) => {
257            tracing::error!("Failed to get provider instance count: {}", e);
258            return Err((
259                Status::InternalServerError,
260                Json(json!({
261                    "error": "Database error",
262                    "message": "Failed to count provider instances"
263                }))
264            ));
265        }
266    };
267
268    let total_pages = (total_count as f64 / per_page as f64).ceil() as i64;
269    tracing::debug!("Total pages: {}", total_pages);
270
271    let response = json!({
272        "instances": instances,
273        "pagination": {
274            "page": page,
275            "per_page": per_page,
276            "total_count": total_count,
277            "total_pages": total_pages
278        }
279    });
280
281    tracing::info!("Successfully retrieved instances for provider {}", provider_id);
282    Ok(Json(response))
283}