use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize)]
pub struct AzureDateRange {
pub start: String, pub end: String, }
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(rename_all = "PascalCase")]
pub enum AzureReportType {
OverallSummaryReport,
#[default]
MonthlySummaryReport,
TopItemsSummaryReport,
TopItemsMonthlySummaryReport,
ItemDetailsReport,
}
impl AzureReportType {
pub fn as_str(&self) -> &'static str {
match self {
AzureReportType::OverallSummaryReport => "OverallSummaryReport",
AzureReportType::MonthlySummaryReport => "MonthlySummaryReport",
AzureReportType::TopItemsSummaryReport => "TopItemsSummaryReport",
AzureReportType::TopItemsMonthlySummaryReport => "TopItemsMonthlySummaryReport",
AzureReportType::ItemDetailsReport => "ItemDetailsReport",
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub enum AzureCarbonScope {
Scope1,
Scope2,
Scope3,
Location,
Service,
}
impl AzureCarbonScope {
pub fn as_str(&self) -> &'static str {
match self {
AzureCarbonScope::Scope1 => "Scope1",
AzureCarbonScope::Scope2 => "Scope2",
AzureCarbonScope::Scope3 => "Scope3",
AzureCarbonScope::Location => "Location",
AzureCarbonScope::Service => "Service",
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub enum AzureSortDirection {
Asc,
Desc,
}
impl AzureSortDirection {
pub fn as_str(&self) -> &'static str {
match self {
AzureSortDirection::Asc => "Asc",
AzureSortDirection::Desc => "Desc",
}
}
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct AzureConfig {
pub access_token: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AzureQueryConfig {
pub report_type: AzureReportType,
#[serde(skip_serializing_if = "Option::is_none")]
pub carbon_scope_list: Option<Vec<AzureCarbonScope>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub category_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub order_by: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub page_size: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub sort_direction: Option<AzureSortDirection>,
#[serde(skip_serializing_if = "Option::is_none")]
pub top_items: Option<i32>,
pub subscription_list: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub resource_group_url_list: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub resource_type_list: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub skip_token: Option<String>,
}
impl Default for AzureQueryConfig {
fn default() -> Self {
Self {
report_type: AzureReportType::default(),
subscription_list: vec![],
carbon_scope_list: Some(vec![
AzureCarbonScope::Scope1,
AzureCarbonScope::Scope2,
AzureCarbonScope::Scope3,
]),
category_type: None,
order_by: None,
page_size: None,
sort_direction: None,
top_items: None,
resource_group_url_list: None,
resource_type_list: None,
skip_token: None,
}
}
}
impl AzureQueryConfig {
pub fn validate(&self) -> Result<(), String> {
if self.subscription_list.is_empty() {
return Err("subscription_list is required and cannot be empty".to_string());
}
match &self.report_type {
AzureReportType::ItemDetailsReport => {
if self.category_type.is_none() {
return Err("category_type is required for ItemDetailsReport".to_string());
}
if self.order_by.is_none() {
return Err("order_by is required for ItemDetailsReport".to_string());
}
if self.page_size.is_none() {
return Err("page_size is required for ItemDetailsReport".to_string());
}
let page_size = self.page_size.unwrap();
if !(1..=5000).contains(&page_size) {
return Err(
"page_size must be between 1 and 5000 for ItemDetailsReport".to_string()
);
}
if self.sort_direction.is_none() {
return Err("sort_direction is required for ItemDetailsReport".to_string());
}
}
AzureReportType::TopItemsSummaryReport => {
if self.category_type.is_none() {
return Err("category_type is required for TopItemsSummaryReport".to_string());
}
if self.top_items.is_none() {
return Err("top_items is required for TopItemsSummaryReport".to_string());
}
let top_items = self.top_items.unwrap();
if !(1..=10).contains(&top_items) {
return Err(
"top_items must be between 1 and 10 for TopItemsSummaryReport".to_string(),
);
}
}
AzureReportType::TopItemsMonthlySummaryReport => {
if self.category_type.is_none() {
return Err(
"category_type is required for TopItemsMonthlySummaryReport".to_string()
);
}
if self.top_items.is_none() {
return Err(
"top_items is required for TopItemsMonthlySummaryReport".to_string()
);
}
let top_items = self.top_items.unwrap();
if !(1..=10).contains(&top_items) {
return Err(
"top_items must be between 1 and 10 for TopItemsMonthlySummaryReport"
.to_string(),
);
}
}
_ => {
}
}
Ok(())
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AzureCarbonEmissionReportRequest {
pub(super) carbon_scope_list: Vec<String>,
pub(super) date_range: AzureDateRange,
pub(super) report_type: String,
pub(super) subscription_list: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(super) category_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(super) order_by: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(super) page_size: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(super) sort_direction: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(super) top_items: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(super) location_list: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(super) resource_group_url_list: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(super) resource_type_list: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(super) skip_token: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AzureSubscriptionAccessDecision {
pub(super) subscription_id: String,
pub(super) decision: String,
#[serde(default)]
pub(super) denial_reason: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AzureEmissionData {
pub(super) data_type: String,
pub(super) latest_month_emissions: f64,
pub(super) previous_month_emissions: f64,
pub(super) month_over_month_emissions_change_ratio: f64,
pub(super) monthly_emissions_change_value: f64,
#[serde(default)]
pub(super) date: Option<String>, #[serde(default)]
pub(super) carbon_intensity: Option<f64>, #[serde(default)]
pub(super) item_name: Option<String>, #[serde(default)]
pub(super) category_type: Option<String>, }
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AzureCarbonEmissionReportResponse {
#[serde(default)]
pub(super) subscription_access_decision_list: Option<Vec<AzureSubscriptionAccessDecision>>,
pub(super) value: Vec<AzureEmissionData>,
}