omni_orchestrator/schemas/v1/api/cost/
metrics.rs1use super::super::super::db::queries as db;
2use super::types::CreateCostMetricRequest;
3use rocket::http::Status;
4use rocket::serde::json::{json, Json, Value};
5use rocket::{delete, get, post, State};
6use std::sync::Arc;
7use crate::DatabaseManager;
8use chrono::{DateTime, Utc};
9
10use libomni::types::db::v1 as types;
11use types::cost::{CostMetric, CostMetricWithType};
12
13#[get("/platform/<platform_id>/cost_metrics?<page>&<per_page>&<resource_type_id>&<provider_id>&<app_id>&<start_date>&<end_date>&<billing_period>")]
15pub async fn list_cost_metrics(
16 platform_id: i64,
17 page: Option<i64>,
18 per_page: Option<i64>,
19 resource_type_id: Option<i32>,
20 provider_id: Option<i64>,
21 app_id: Option<i64>,
22 start_date: Option<String>,
23 end_date: Option<String>,
24 billing_period: Option<String>,
25 db_manager: &State<Arc<DatabaseManager>>,
26) -> Result<Json<Value>, (Status, Json<Value>)> {
27 let platform = match db::platforms::get_platform_by_id(db_manager.get_main_pool(), platform_id).await {
29 Ok(platform) => platform,
30 Err(_) => {
31 return Err((
32 Status::NotFound,
33 Json(json!({
34 "error": "Platform not found",
35 "message": format!("Platform with ID {} does not exist", platform_id)
36 }))
37 ));
38 }
39 };
40
41 let pool = match db_manager.get_platform_pool(&platform.name, platform_id).await {
43 Ok(pool) => pool,
44 Err(_) => {
45 return Err((
46 Status::InternalServerError,
47 Json(json!({
48 "error": "Database error",
49 "message": "Failed to connect to platform database"
50 }))
51 ));
52 }
53 };
54
55 use chrono::TimeZone;
56
57 let parsed_start_date = match start_date {
59 Some(ref s) => match DateTime::parse_from_rfc3339(s) {
60 Ok(dt) => Some(dt.with_timezone(&Utc)),
61 Err(_) => None,
62 },
63 None => None,
64 };
65 let parsed_end_date = match end_date {
66 Some(ref s) => match DateTime::parse_from_rfc3339(s) {
67 Ok(dt) => Some(dt.with_timezone(&Utc)),
68 Err(_) => None,
69 },
70 None => None,
71 };
72
73 match (page, per_page) {
74 (Some(p), Some(pp)) => {
75 let cost_metrics = match db::cost::list_cost_metrics(
76 &pool, p, pp, resource_type_id, provider_id, app_id, parsed_start_date, parsed_end_date, billing_period.as_deref()
77 ).await {
78 Ok(metrics) => metrics,
79 Err(_) => {
80 return Err((
81 Status::InternalServerError,
82 Json(json!({
83 "error": "Database error",
84 "message": "Failed to retrieve cost metrics"
85 }))
86 ));
87 }
88 };
89
90 let total_count = match db::cost::count_cost_metrics(
91 &pool, resource_type_id, provider_id, app_id, parsed_start_date, parsed_end_date, billing_period.as_deref()
92 ).await {
93 Ok(count) => count,
94 Err(_) => {
95 return Err((
96 Status::InternalServerError,
97 Json(json!({
98 "error": "Database error",
99 "message": "Failed to count cost metrics"
100 }))
101 ));
102 }
103 };
104
105 let total_pages = (total_count as f64 / pp as f64).ceil() as i64;
106
107 let response = json!({
108 "cost_metrics": cost_metrics,
109 "pagination": {
110 "page": p,
111 "per_page": pp,
112 "total_count": total_count,
113 "total_pages": total_pages
114 }
115 });
116
117 Ok(Json(response))
118 }
119 _ => Err((
120 Status::BadRequest,
121 Json(json!({
122 "error": "Missing pagination parameters",
123 "message": "Please provide both 'page' and 'per_page' parameters"
124 }))
125 ))
126 }
127}
128
129#[get("/platform/<platform_id>/cost_metrics/<id>")]
131pub async fn get_cost_metric(
132 platform_id: i64,
133 id: i64,
134 db_manager: &State<Arc<DatabaseManager>>,
135) -> Result<Json<CostMetricWithType>, (Status, Json<Value>)> {
136 let platform = match db::platforms::get_platform_by_id(db_manager.get_main_pool(), platform_id).await {
138 Ok(platform) => platform,
139 Err(_) => {
140 return Err((
141 Status::NotFound,
142 Json(json!({
143 "error": "Platform not found",
144 "message": format!("Platform with ID {} does not exist", platform_id)
145 }))
146 ));
147 }
148 };
149
150 let pool = match db_manager.get_platform_pool(&platform.name, platform_id).await {
152 Ok(pool) => pool,
153 Err(_) => {
154 return Err((
155 Status::InternalServerError,
156 Json(json!({
157 "error": "Database error",
158 "message": "Failed to connect to platform database"
159 }))
160 ));
161 }
162 };
163
164 match db::cost::get_cost_metric_by_id(&pool, id).await {
165 Ok(cost_metric) => Ok(Json(cost_metric)),
166 Err(e) => Err((
167 Status::NotFound,
168 Json(json!({
169 "error": "Cost metric not found",
170 "message": format!("Cost metric with ID {} could not be found: {}", id, e)
171 }))
172 )),
173 }
174}
175
176#[post("/platform/<platform_id>/cost_metrics", format = "json", data = "<request>")]
178pub async fn create_cost_metric(
179 platform_id: i64,
180 request: Json<CreateCostMetricRequest>,
181 db_manager: &State<Arc<DatabaseManager>>,
182) -> Result<Json<CostMetric>, (Status, Json<Value>)> {
183 let platform = match db::platforms::get_platform_by_id(db_manager.get_main_pool(), platform_id).await {
185 Ok(platform) => platform,
186 Err(_) => {
187 return Err((
188 Status::NotFound,
189 Json(json!({
190 "error": "Platform not found",
191 "message": format!("Platform with ID {} does not exist", platform_id)
192 }))
193 ));
194 }
195 };
196
197 let pool = match db_manager.get_platform_pool(&platform.name, platform_id).await {
199 Ok(pool) => pool,
200 Err(_) => {
201 return Err((
202 Status::InternalServerError,
203 Json(json!({
204 "error": "Database error",
205 "message": "Failed to connect to platform database"
206 }))
207 ));
208 }
209 };
210
211 match db::cost::create_cost_metric(
212 &pool,
213 request.resource_type_id,
214 request.provider_id,
215 request.region_id,
216 request.app_id,
217 request.worker_id,
218 request.org_id,
219 request.start_time,
220 request.end_time,
221 request.usage_quantity,
222 request.unit_cost,
223 &request.currency,
224 request.total_cost,
225 request.discount_percentage,
226 request.discount_reason.as_deref(),
227 request.billing_period.as_deref(),
228 ).await {
229 Ok(cost_metric) => Ok(Json(cost_metric)),
230 Err(e) => Err((
231 Status::InternalServerError,
232 Json(json!({
233 "error": "Failed to create cost metric",
234 "message": format!("{}", e)
235 }))
236 )),
237 }
238}
239
240#[delete("/platform/<platform_id>/cost_metrics/<id>")]
242pub async fn delete_cost_metric(
243 platform_id: i64,
244 id: i64,
245 db_manager: &State<Arc<DatabaseManager>>,
246) -> Result<Json<Value>, (Status, Json<Value>)> {
247 let platform = match db::platforms::get_platform_by_id(db_manager.get_main_pool(), platform_id).await {
249 Ok(platform) => platform,
250 Err(_) => {
251 return Err((
252 Status::NotFound,
253 Json(json!({
254 "error": "Platform not found",
255 "message": format!("Platform with ID {} does not exist", platform_id)
256 }))
257 ));
258 }
259 };
260
261 let pool = match db_manager.get_platform_pool(&platform.name, platform_id).await {
263 Ok(pool) => pool,
264 Err(_) => {
265 return Err((
266 Status::InternalServerError,
267 Json(json!({
268 "error": "Database error",
269 "message": "Failed to connect to platform database"
270 }))
271 ));
272 }
273 };
274
275 match db::cost::delete_cost_metric(&pool, id).await {
276 Ok(_) => Ok(Json(json!({ "status": "deleted" }))),
277 Err(e) => Err((
278 Status::InternalServerError,
279 Json(json!({
280 "error": "Failed to delete cost metric",
281 "message": format!("{}", e)
282 }))
283 )),
284 }
285}