diff --git a/CHANGELOG.md b/CHANGELOG.md index 2325006f..5b397f46 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased _This paragraph may describe WIP/unreleased features. They are merged to main branch but not tagged._ +- [Return API and scanner version in the json output](https://github.com/Boavizta/cloud-scanner/issues/265) - [Upgrade to BoaviztAPI 1.3.3 · Issue #633 · Boavizta/cloud-scanner](https://github.com/Boavizta/cloud-scanner/issues/633) - [chore(deps): bump serde_json from 1.0.132 to 1.0.133](https://github.com/Boavizta/cloud-scanner/issues/#614) - [chore(deps): bump tokio from 1.41.1 to 1.42.0](https://github.com/Boavizta/cloud-scanner/issues/#628) diff --git a/cloud-scanner-cli/src/boavizta_api_v1.rs b/cloud-scanner-cli/src/boavizta_api_v1.rs index 7b051729..9a773f14 100644 --- a/cloud-scanner-cli/src/boavizta_api_v1.rs +++ b/cloud-scanner-cli/src/boavizta_api_v1.rs @@ -4,10 +4,13 @@ use anyhow::Result; use boavizta_api_sdk::apis::cloud_api; use boavizta_api_sdk::apis::component_api; use boavizta_api_sdk::apis::configuration; +use boavizta_api_sdk::apis::utils_api; +use chrono::Utc; use std::time::{Duration, Instant}; use crate::model::{ - CloudResource, EstimatedInventory, ExecutionStatistics, Inventory, ResourceDetails, + CloudResource, EstimatedInventory, EstimationMetadata, ExecutionStatistics, Inventory, + ResourceDetails, }; use boavizta_api_sdk::models::{Cloud, Disk, UsageCloud}; @@ -24,6 +27,17 @@ impl BoaviztaApiV1 { BoaviztaApiV1 { configuration } } + // Returns the version of Boavizta API + async fn get_api_version(&self) -> Option { + let res = utils_api::version_v1_utils_version_get(&self.configuration).await; + if let Ok(serde_json::Value::String(v)) = res { + Some(v) + } else { + error!("Cannot fetch API version"); + None + } + } + // Returns the raw impacts (json) of an instance from Boavizta API for the duration of use (hours) async fn get_raws_impacts( &self, @@ -219,7 +233,13 @@ impl ImpactProvider for BoaviztaApiV1 { let estimated_inventory: EstimatedInventory = EstimatedInventory { impacting_resources: v, - execution_statistics: Some(execution_statistics), + metadata: EstimationMetadata { + estimation_date: Some(Utc::now()), + description: Some("Estimation using Boavizta API".to_string()), + cloud_scanner_version: Some(crate::get_version()), + boavizta_api_version: self.get_api_version().await, + execution_statistics: Some(execution_statistics), + }, }; Ok(estimated_inventory) } @@ -333,6 +353,14 @@ mod tests { println!("{:?}", res); } + #[tokio::test] + async fn get_api_version() { + let api: BoaviztaApiV1 = BoaviztaApiV1::new(TEST_API_URL); + let version = api.get_api_version().await; + let expected = Some("1.3.6".to_owned()); + assert_eq!(version, expected, "Versions do not match"); + } + #[tokio::test] async fn should_retrieve_raw_default_impacts_aws_fr() { let instance1: CloudResource = CloudResource { diff --git a/cloud-scanner-cli/src/lib.rs b/cloud-scanner-cli/src/lib.rs index 0978d180..bd5ba39d 100644 --- a/cloud-scanner-cli/src/lib.rs +++ b/cloud-scanner-cli/src/lib.rs @@ -157,28 +157,40 @@ pub fn get_version() -> String { format!("{}.{}.{}", MAJOR, MINOR, PATCH) } -#[tokio::test] -async fn summary_has_to_contain_a_usage_duration() { - use crate::impact_provider::CloudResourceWithImpacts; - - let resources: Vec = Vec::new(); - - let resources_with_impacts: EstimatedInventory = EstimatedInventory { - impacting_resources: resources, - execution_statistics: None, - }; - - let usage_duration_hours = 1.5; - - let summary: ImpactsSummary = ImpactsSummary::new( - String::from("eu-west-1"), - String::from("IRL"), - &resources_with_impacts, - usage_duration_hours, - ); - - assert_eq!( - summary.duration_of_use_hours, usage_duration_hours, - "Duration of summary should match" - ); +#[cfg(test)] +mod tests { + use super::*; + use crate::model::EstimationMetadata; + + #[tokio::test] + async fn summary_has_to_contain_a_usage_duration() { + use crate::impact_provider::CloudResourceWithImpacts; + + let resources: Vec = Vec::new(); + + let resources_with_impacts: EstimatedInventory = EstimatedInventory { + impacting_resources: resources, + metadata: EstimationMetadata { + description: None, + boavizta_api_version: Some("v1.2.3".to_owned()), + cloud_scanner_version: Some("acb".to_owned()), + estimation_date: None, + execution_statistics: None, + }, + }; + + let usage_duration_hours = 1.5; + + let summary: ImpactsSummary = ImpactsSummary::new( + String::from("eu-west-1"), + String::from("IRL"), + &resources_with_impacts, + usage_duration_hours, + ); + + assert_eq!( + summary.duration_of_use_hours, usage_duration_hours, + "Duration of summary should match" + ); + } } diff --git a/cloud-scanner-cli/src/metric_exporter.rs b/cloud-scanner-cli/src/metric_exporter.rs index d3d3d7c8..82860160 100644 --- a/cloud-scanner-cli/src/metric_exporter.rs +++ b/cloud-scanner-cli/src/metric_exporter.rs @@ -379,7 +379,8 @@ mod tests { use super::*; use crate::impact_provider::ImpactsValues; use crate::model::{ - CloudProvider, CloudResource, CloudResourceTag, InstanceUsage, StorageUsage, + CloudProvider, CloudResource, CloudResourceTag, EstimationMetadata, InstanceUsage, + StorageUsage, }; use crate::usage_location::UsageLocation; @@ -476,8 +477,14 @@ boavizta_gwp_use_kgco2eq{awsregion="eu-west-1",country="IRL"} 0.6 }; let estimated_inventory: EstimatedInventory = EstimatedInventory { + metadata: EstimationMetadata { + description: None, + boavizta_api_version: Some("v1.2.3".to_owned()), + cloud_scanner_version: Some("acb".to_owned()), + estimation_date: None, + execution_statistics: None, + }, impacting_resources: vec![cloud_resource_with_impacts], - execution_statistics: None, }; let summary = ImpactsSummary::new( @@ -587,8 +594,14 @@ boavizta_resource_cpu_load{awsregion="eu-west-3",country="FRA",resource_type="In }; let estimated_inventory: EstimatedInventory = EstimatedInventory { + metadata: EstimationMetadata { + description: None, + boavizta_api_version: Some("v1.2.3".to_owned()), + cloud_scanner_version: Some("acb".to_owned()), + estimation_date: None, + execution_statistics: None, + }, impacting_resources: vec![cloud_resource_with_impacts], - execution_statistics: None, }; let summary = ImpactsSummary::new( diff --git a/cloud-scanner-cli/src/model.rs b/cloud-scanner-cli/src/model.rs index 2d2c48e0..8368678e 100644 --- a/cloud-scanner-cli/src/model.rs +++ b/cloud-scanner-cli/src/model.rs @@ -66,7 +66,23 @@ pub async fn load_inventory_fom_json(json_inventory: &str) -> anyhow::Result, +} + +/// Details about the estimation +#[derive(Clone, Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub struct EstimationMetadata { + /// The date when the estimation was generated + pub estimation_date: Option>, + /// A free text description of the estimation + pub description: Option, + /// The version of the cloud scanner that provided the estimation + pub cloud_scanner_version: Option, + /// The version of the Boavizta api that provided the estimation + pub boavizta_api_version: Option, + /// Statistics about program execution pub execution_statistics: Option, } diff --git a/cloud-scanner-cli/src/usage_location.rs b/cloud-scanner-cli/src/usage_location.rs index 2d2042ed..c6e75318 100644 --- a/cloud-scanner-cli/src/usage_location.rs +++ b/cloud-scanner-cli/src/usage_location.rs @@ -73,7 +73,7 @@ fn get_country_from_aws_region(aws_region: &str) -> Result "Unsupported region: unable to match aws region [{}] to country code", aws_region ); - return Err(RegionError::UnsupportedRegion(String::from(aws_region))); + Err(RegionError::UnsupportedRegion(String::from(aws_region))) } } }