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