From 7c71d83e0fcd1f2de25edae393b6e47521de73c9 Mon Sep 17 00:00:00 2001 From: olivier de Meringo Date: Sat, 14 Dec 2024 23:51:01 +0100 Subject: [PATCH 1/2] feat: return Boavizta API and cloud scanner versions in the json inventory --- CHANGELOG.md | 1 + cloud-scanner-cli/src/boavizta_api_v1.rs | 32 ++++++++++++- cloud-scanner-cli/src/lib.rs | 60 ++++++++++++++---------- cloud-scanner-cli/src/metric_exporter.rs | 19 ++++++-- cloud-scanner-cli/src/model.rs | 16 +++++++ cloud-scanner-cli/src/usage_location.rs | 2 +- 6 files changed, 100 insertions(+), 30 deletions(-) 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))) } } } From e4ec9192b06ee6459fcd4daf42ce93e5b7d71bdb Mon Sep 17 00:00:00 2001 From: olivier de Meringo Date: Sun, 15 Dec 2024 00:04:17 +0100 Subject: [PATCH 2/2] docs: update json inventory schema --- docs/src/reference/openapi.json | 151 +++++++++++++++++++++----------- 1 file changed, 98 insertions(+), 53 deletions(-) diff --git a/docs/src/reference/openapi.json b/docs/src/reference/openapi.json index 4df3508b..0b5c0be7 100644 --- a/docs/src/reference/openapi.json +++ b/docs/src/reference/openapi.json @@ -2,7 +2,7 @@ "openapi": "3.0.0", "info": { "title": "cloud-scanner-cli", - "version": "2.0.5" + "version": "3.2.0-SNAPSHOT" }, "paths": { "/metrics": { @@ -239,7 +239,7 @@ "components": { "schemas": { "Inventory": { - "description": "Inventory: a list of resources", + "description": "A list of cloud resources and metadata that describes the inventory itself", "type": "object", "required": [ "metadata", @@ -254,14 +254,6 @@ "items": { "$ref": "#/components/schemas/CloudResource" } - }, - "execution_statistics": { - "allOf": [ - { - "$ref": "#/components/schemas/ExecutionStatistics" - } - ], - "nullable": true } } }, @@ -270,18 +262,73 @@ "type": "object", "properties": { "inventory_date": { + "description": "The date when the inventory was generated", "type": "string", "format": "date-time", "nullable": true }, "description": { + "description": "A free text description of the inventory", "type": "string", "nullable": true + }, + "cloud_scanner_version": { + "description": "The version of the cloud scanner that generated the inventory", + "type": "string", + "nullable": true + }, + "execution_statistics": { + "description": "Statistics about program execution", + "allOf": [ + { + "$ref": "#/components/schemas/ExecutionStatistics" + } + ], + "nullable": true + } + } + }, + "ExecutionStatistics": { + "description": "Statistics about program execution", + "type": "object", + "required": [ + "impact_estimation_duration", + "inventory_duration", + "total_duration" + ], + "properties": { + "inventory_duration": { + "$ref": "#/components/schemas/Duration" + }, + "impact_estimation_duration": { + "$ref": "#/components/schemas/Duration" + }, + "total_duration": { + "$ref": "#/components/schemas/Duration" + } + } + }, + "Duration": { + "type": "object", + "required": [ + "nanos", + "secs" + ], + "properties": { + "secs": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "nanos": { + "type": "integer", + "format": "uint32", + "minimum": 0.0 } } }, "CloudResource": { - "description": "A cloud resource (could be an instance, function or any other resource)", + "description": "A cloud resource (could be an instance, block storage or any other resource)", "type": "object", "required": [ "id", @@ -298,7 +345,12 @@ "type": "string" }, "location": { - "$ref": "#/components/schemas/UsageLocation" + "description": "The location where cloud resources are running.", + "allOf": [ + { + "$ref": "#/components/schemas/UsageLocation" + } + ] }, "resource_details": { "$ref": "#/components/schemas/ResourceDetails" @@ -471,59 +523,52 @@ } } }, - "ExecutionStatistics": { - "description": "Statistics about program execution", - "type": "object", - "required": [ - "impact_estimation_duration", - "inventory_duration", - "total_duration" - ], - "properties": { - "inventory_duration": { - "$ref": "#/components/schemas/Duration" - }, - "impact_estimation_duration": { - "$ref": "#/components/schemas/Duration" - }, - "total_duration": { - "$ref": "#/components/schemas/Duration" - } - } - }, - "Duration": { - "type": "object", - "required": [ - "nanos", - "secs" - ], - "properties": { - "secs": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "nanos": { - "type": "integer", - "format": "uint32", - "minimum": 0.0 - } - } - }, "EstimatedInventory": { "description": "An estimated inventory: impacting resources with their estimated impacts", "type": "object", "required": [ - "impacting_resources" + "impacting_resources", + "metadata" ], "properties": { + "metadata": { + "$ref": "#/components/schemas/EstimationMetadata" + }, "impacting_resources": { "type": "array", "items": { "$ref": "#/components/schemas/CloudResourceWithImpacts" } + } + } + }, + "EstimationMetadata": { + "description": "Details about the estimation", + "type": "object", + "properties": { + "estimation_date": { + "description": "The date when the estimation was generated", + "type": "string", + "format": "date-time", + "nullable": true + }, + "description": { + "description": "A free text description of the estimation", + "type": "string", + "nullable": true + }, + "cloud_scanner_version": { + "description": "The version of the cloud scanner that provided the estimation", + "type": "string", + "nullable": true + }, + "boavizta_api_version": { + "description": "The version of the Boavizta api that provided the estimation", + "type": "string", + "nullable": true }, "execution_statistics": { + "description": "Statistics about program execution", "allOf": [ { "$ref": "#/components/schemas/ExecutionStatistics" @@ -602,4 +647,4 @@ } } } -} \ No newline at end of file +}