Skip to content

Commit

Permalink
Merge pull request #408 from Boavizta/407-expose-resource-tags-in-met…
Browse files Browse the repository at this point in the history
…rics-labels

feat: export resource tags in a metrics label.
  • Loading branch information
demeringo authored Jan 15, 2024
2 parents 7f63f5b + 1162328 commit b1b16cf
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 17 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased
## Unreleased

_This paragraph may describe WIP/unreleased features. They are merged to main branch but not tagged._

### Added

- [Expose resource tags in metrics labels · Issue #407 · Boavizta/cloud-scanner](https://github.com/Boavizta/cloud-scanner/issues/407)

### Changed

- Make _filter tags_ optional in the API routes.
Expand Down
53 changes: 52 additions & 1 deletion cloud-scanner-cli/src/cloud_resource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,21 @@ impl fmt::Display for CloudResource {
}
}

impl CloudResource {
/// Convert tags into a format supported by prometheus metrics label (like `tag_key_1:tag_value_1;tag_key_2:tag_value_2;`)
pub fn tags_as_metric_label_value(&self) -> String {
let mut res = "".to_string();
for tag in self.tags.iter() {
let val = tag.value.clone().unwrap_or("".parse().unwrap());
res.push_str(&tag.key);
res.push(':');
res.push_str(&val);
res.push(';');
}
res
}
}

#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
pub enum CloudProvider {
AWS,
Expand Down Expand Up @@ -149,7 +164,7 @@ mod tests {
}

#[test]
pub fn parse_tags() {
pub fn parse_tag() {
let tag_string = "name1=val1".to_string();
let res = CloudResourceTag::try_from(tag_string).unwrap();
assert_eq!(res.key, "name1", "Wrong key");
Expand All @@ -160,6 +175,13 @@ mod tests {
assert_eq!(res.key, "name1", "Wrong key");
assert_eq!(res.value, None, "Wrong value");
}
#[test]
pub fn parse_tags_with_spaces() {
let tag_string = "name 1=val 1".to_string();
let res = CloudResourceTag::try_from(tag_string).unwrap();
assert_eq!(res.key, "name 1", "Wrong key");
assert_eq!(res.value.unwrap(), "val 1", "Wrong value");
}

#[test]
pub fn match_tags() {
Expand Down Expand Up @@ -265,4 +287,33 @@ mod tests {
"Tags should match (i.e. we should ignore this invalid filter"
);
}
#[test]
pub fn format_tags_as_metric_label() {
let tag1 = CloudResourceTag {
key: "name1".to_string(),
value: Some("value1".to_string()),
};
let tag2 = CloudResourceTag {
key: "name2".to_string(),
value: Some("value2".to_string()),
};

let cr = CloudResource {
provider: CloudProvider::AWS,
id: "123".to_string(),
location: UsageLocation {
aws_region: "eu-west-3".to_string(),
iso_country_code: "FR".to_string(),
},
resource_details: ResourceDetails::ObjectStorage,
tags: vec![tag1, tag2],
};

let tag_label_value = cr.tags_as_metric_label_value();

assert_eq!(
"name1:value1;name2:value2;", tag_label_value,
"could not convert tags to metric label values"
);
}
}
34 changes: 19 additions & 15 deletions cloud-scanner-cli/src/metric_exporter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,18 +58,13 @@ fn build_resource_labels(resource: &CloudResourceWithImpacts) -> ResourceLabels
},
_ => ResourceState::Unknown,
};
// TODO: convert tags to a better format instead of using the default debug string
warn!("Tag strings are not exported as metric labels");
// TODO escape tag strings properly before exporting in label
//let tags_string = format!("{:?}", resource.cloud_resource.tags);
let tags_string = "".into();

ResourceLabels {
awsregion: resource.cloud_resource.location.aws_region.clone(),
country: resource.cloud_resource.location.iso_country_code.clone(),
resource_type,
resource_id: resource.cloud_resource.id.clone(),
resource_tags: tags_string,
resource_tags: resource.cloud_resource.tags_as_metric_label_value(),
resource_state,
}
}
Expand Down Expand Up @@ -333,7 +328,7 @@ fn register_summary_metrics(registry: &mut Registry, summary: &ImpactsSummary) {
#[cfg(test)]
mod tests {
use super::*;
use crate::cloud_resource::{CloudProvider, CloudResource, InstanceUsage};
use crate::cloud_resource::{CloudProvider, CloudResource, CloudResourceTag, InstanceUsage};
use crate::impact_provider::ResourceImpacts;
use crate::usage_location::UsageLocation;

Expand Down Expand Up @@ -392,6 +387,15 @@ boavizta_gwp_use_kgco2eq{awsregion="eu-west-1",country="IRL"} 0.6
}
#[tokio::test]
async fn test_get_all_metrics() {
let tag1 = CloudResourceTag {
key: "tag_key_1".to_string(),
value: Some("tag_value_1".to_string()),
};
let tag2 = CloudResourceTag {
key: "tag_key_2".to_string(),
value: Some("tag_value_2".to_string()),
};

let cloud_resource: CloudResource = CloudResource {
provider: CloudProvider::AWS,
id: "inst-1".to_string(),
Expand All @@ -404,7 +408,7 @@ boavizta_gwp_use_kgco2eq{awsregion="eu-west-1",country="IRL"} 0.6
state: InstanceState::Running,
}),
},
tags: Vec::new(),
tags: vec![tag1, tag2],
};

let cloud_resource_with_impacts = CloudResourceWithImpacts {
Expand Down Expand Up @@ -472,25 +476,25 @@ boavizta_gwp_manufacture_kgco2eq{awsregion="eu-west-1",country="IRL"} 0.5
boavizta_gwp_use_kgco2eq{awsregion="eu-west-1",country="IRL"} 0.6
# HELP boavizta_resource_duration_of_use_hours Use duration considered to estimate impacts.
# TYPE boavizta_resource_duration_of_use_hours gauge
boavizta_resource_duration_of_use_hours{awsregion="eu-west-3",country="FRA",resource_type="Instance",resource_id="inst-1",resource_tags="",resource_state="Running"} 1.0
boavizta_resource_duration_of_use_hours{awsregion="eu-west-3",country="FRA",resource_type="Instance",resource_id="inst-1",resource_tags="tag_key_1:tag_value_1;tag_key_2:tag_value_2;",resource_state="Running"} 1.0
# HELP boavizta_resource_pe_embodied_megajoules Energy consumed for manufacture.
# TYPE boavizta_resource_pe_embodied_megajoules gauge
boavizta_resource_pe_embodied_megajoules{awsregion="eu-west-3",country="FRA",resource_type="Instance",resource_id="inst-1",resource_tags="",resource_state="Running"} 0.3
boavizta_resource_pe_embodied_megajoules{awsregion="eu-west-3",country="FRA",resource_type="Instance",resource_id="inst-1",resource_tags="tag_key_1:tag_value_1;tag_key_2:tag_value_2;",resource_state="Running"} 0.3
# HELP boavizta_resource_pe_use_megajoules Energy consumed during use.
# TYPE boavizta_resource_pe_use_megajoules gauge
boavizta_resource_pe_use_megajoules{awsregion="eu-west-3",country="FRA",resource_type="Instance",resource_id="inst-1",resource_tags="",resource_state="Running"} 0.4
boavizta_resource_pe_use_megajoules{awsregion="eu-west-3",country="FRA",resource_type="Instance",resource_id="inst-1",resource_tags="tag_key_1:tag_value_1;tag_key_2:tag_value_2;",resource_state="Running"} 0.4
# HELP boavizta_resource_adp_embodied_kgsbeq Abiotic resources depletion potential of embodied impacts.
# TYPE boavizta_resource_adp_embodied_kgsbeq gauge
boavizta_resource_adp_embodied_kgsbeq{awsregion="eu-west-3",country="FRA",resource_type="Instance",resource_id="inst-1",resource_tags="",resource_state="Running"} 0.1
boavizta_resource_adp_embodied_kgsbeq{awsregion="eu-west-3",country="FRA",resource_type="Instance",resource_id="inst-1",resource_tags="tag_key_1:tag_value_1;tag_key_2:tag_value_2;",resource_state="Running"} 0.1
# HELP boavizta_resource_adp_use_kgsbeq Abiotic resources depletion potential of use.
# TYPE boavizta_resource_adp_use_kgsbeq gauge
boavizta_resource_adp_use_kgsbeq{awsregion="eu-west-3",country="FRA",resource_type="Instance",resource_id="inst-1",resource_tags="",resource_state="Running"} 0.2
boavizta_resource_adp_use_kgsbeq{awsregion="eu-west-3",country="FRA",resource_type="Instance",resource_id="inst-1",resource_tags="tag_key_1:tag_value_1;tag_key_2:tag_value_2;",resource_state="Running"} 0.2
# HELP boavizta_resource_gwp_embodied_kgco2eq Global Warming Potential of embodied impacts.
# TYPE boavizta_resource_gwp_embodied_kgco2eq gauge
boavizta_resource_gwp_embodied_kgco2eq{awsregion="eu-west-3",country="FRA",resource_type="Instance",resource_id="inst-1",resource_tags="",resource_state="Running"} 0.5
boavizta_resource_gwp_embodied_kgco2eq{awsregion="eu-west-3",country="FRA",resource_type="Instance",resource_id="inst-1",resource_tags="tag_key_1:tag_value_1;tag_key_2:tag_value_2;",resource_state="Running"} 0.5
# HELP boavizta_resource_gwp_use_kgco2eq Global Warming Potential of use.
# TYPE boavizta_resource_gwp_use_kgco2eq gauge
boavizta_resource_gwp_use_kgco2eq{awsregion="eu-west-3",country="FRA",resource_type="Instance",resource_id="inst-1",resource_tags="",resource_state="Running"} 0.6
boavizta_resource_gwp_use_kgco2eq{awsregion="eu-west-3",country="FRA",resource_type="Instance",resource_id="inst-1",resource_tags="tag_key_1:tag_value_1;tag_key_2:tag_value_2;",resource_state="Running"} 0.6
# EOF
"#;

Expand Down

0 comments on commit b1b16cf

Please sign in to comment.