Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
The `aws_ec2_metadata` transform now supports additional IMDS instance metadata categories. The following fields can now be requested via the `fields` option: `availability-zone-id`, `partition`, `domain`, `placement-group-name`, `placement-partition-number`, `host-id`, and `autoscaling-target-lifecycle-state`.

These are useful for locating impacted instances (for example, by availability zone ID, which is consistent across accounts, or by Dedicated Host ID) and for correlating EC2 Auto Scaling lifecycle events with on-instance events. As with the existing optional fields, these are only fetched when explicitly listed in `fields`.
103 changes: 103 additions & 0 deletions src/transforms/aws_ec2_metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,31 @@ const SUBNET_ID_KEY: &str = "subnet-id";
const VPC_ID_KEY: &str = "vpc-id";
const ROLE_NAME_KEY: &str = "role-name";
const TAGS_KEY: &str = "tags";
const PARTITION_KEY: &str = "partition";
const DOMAIN_KEY: &str = "domain";
const AVAILABILITY_ZONE_ID_KEY: &str = "availability-zone-id";
const PLACEMENT_GROUP_NAME_KEY: &str = "placement-group-name";
const PLACEMENT_PARTITION_NUMBER_KEY: &str = "placement-partition-number";
const HOST_ID_KEY: &str = "host-id";
const AUTOSCALING_TARGET_LIFECYCLE_STATE_KEY: &str = "autoscaling-target-lifecycle-state";

static AVAILABILITY_ZONE: LazyLock<PathAndQuery> =
LazyLock::new(|| PathAndQuery::from_static("/latest/meta-data/placement/availability-zone"));
static AVAILABILITY_ZONE_ID: LazyLock<PathAndQuery> =
LazyLock::new(|| PathAndQuery::from_static("/latest/meta-data/placement/availability-zone-id"));
static PARTITION: LazyLock<PathAndQuery> =
LazyLock::new(|| PathAndQuery::from_static("/latest/meta-data/services/partition"));
static DOMAIN: LazyLock<PathAndQuery> =
LazyLock::new(|| PathAndQuery::from_static("/latest/meta-data/services/domain"));
static PLACEMENT_GROUP_NAME: LazyLock<PathAndQuery> =
LazyLock::new(|| PathAndQuery::from_static("/latest/meta-data/placement/group-name"));
static PLACEMENT_PARTITION_NUMBER: LazyLock<PathAndQuery> =
LazyLock::new(|| PathAndQuery::from_static("/latest/meta-data/placement/partition-number"));
static HOST_ID: LazyLock<PathAndQuery> =
LazyLock::new(|| PathAndQuery::from_static("/latest/meta-data/placement/host-id"));
static AUTOSCALING_TARGET_LIFECYCLE_STATE: LazyLock<PathAndQuery> = LazyLock::new(|| {
PathAndQuery::from_static("/latest/meta-data/autoscaling/target-lifecycle-state")
});
static LOCAL_HOSTNAME: LazyLock<PathAndQuery> =
LazyLock::new(|| PathAndQuery::from_static("/latest/meta-data/local-hostname"));
static LOCAL_IPV4: LazyLock<PathAndQuery> =
Expand Down Expand Up @@ -185,13 +207,20 @@ struct Keys {
account_id_key: MetadataKey,
ami_id_key: MetadataKey,
availability_zone_key: MetadataKey,
availability_zone_id_key: MetadataKey,
instance_id_key: MetadataKey,
instance_type_key: MetadataKey,
local_hostname_key: MetadataKey,
local_ipv4_key: MetadataKey,
public_hostname_key: MetadataKey,
public_ipv4_key: MetadataKey,
region_key: MetadataKey,
partition_key: MetadataKey,
domain_key: MetadataKey,
placement_group_name_key: MetadataKey,
placement_partition_number_key: MetadataKey,
host_id_key: MetadataKey,
autoscaling_target_lifecycle_state_key: MetadataKey,
subnet_id_key: MetadataKey,
vpc_id_key: MetadataKey,
role_name_key: MetadataKey,
Expand Down Expand Up @@ -263,13 +292,20 @@ impl TransformConfig for Ec2Metadata {
&added_keys.account_id_key.log_path,
&added_keys.ami_id_key.log_path,
&added_keys.availability_zone_key.log_path,
&added_keys.availability_zone_id_key.log_path,
&added_keys.instance_id_key.log_path,
&added_keys.instance_type_key.log_path,
&added_keys.local_hostname_key.log_path,
&added_keys.local_ipv4_key.log_path,
&added_keys.public_hostname_key.log_path,
&added_keys.public_ipv4_key.log_path,
&added_keys.region_key.log_path,
&added_keys.partition_key.log_path,
&added_keys.domain_key.log_path,
&added_keys.placement_group_name_key.log_path,
&added_keys.placement_partition_number_key.log_path,
&added_keys.host_id_key.log_path,
&added_keys.autoscaling_target_lifecycle_state_key.log_path,
&added_keys.subnet_id_key.log_path,
&added_keys.vpc_id_key.log_path,
&added_keys.role_name_key.log_path,
Expand Down Expand Up @@ -487,6 +523,63 @@ impl MetadataClient {
new_state.push((self.keys.availability_zone_key.clone(), availability_zone));
}

if self.fields.contains(AVAILABILITY_ZONE_ID_KEY)
&& let Some(availability_zone_id) = self.get_metadata(&AVAILABILITY_ZONE_ID).await?
{
new_state.push((
self.keys.availability_zone_id_key.clone(),
availability_zone_id,
));
}

if self.fields.contains(PARTITION_KEY)
&& let Some(partition) = self.get_metadata(&PARTITION).await?
{
new_state.push((self.keys.partition_key.clone(), partition));
}

if self.fields.contains(DOMAIN_KEY)
&& let Some(domain) = self.get_metadata(&DOMAIN).await?
{
new_state.push((self.keys.domain_key.clone(), domain));
}

if self.fields.contains(PLACEMENT_GROUP_NAME_KEY)
&& let Some(placement_group_name) = self.get_metadata(&PLACEMENT_GROUP_NAME).await?
{
new_state.push((
self.keys.placement_group_name_key.clone(),
placement_group_name,
));
}

if self.fields.contains(PLACEMENT_PARTITION_NUMBER_KEY)
&& let Some(placement_partition_number) =
self.get_metadata(&PLACEMENT_PARTITION_NUMBER).await?
{
new_state.push((
self.keys.placement_partition_number_key.clone(),
placement_partition_number,
));
}

if self.fields.contains(HOST_ID_KEY)
&& let Some(host_id) = self.get_metadata(&HOST_ID).await?
{
new_state.push((self.keys.host_id_key.clone(), host_id));
}

if self.fields.contains(AUTOSCALING_TARGET_LIFECYCLE_STATE_KEY)
&& let Some(autoscaling_target_lifecycle_state) = self
.get_metadata(&AUTOSCALING_TARGET_LIFECYCLE_STATE)
.await?
{
new_state.push((
self.keys.autoscaling_target_lifecycle_state_key.clone(),
autoscaling_target_lifecycle_state,
));
}

if self.fields.contains(LOCAL_HOSTNAME_KEY)
&& let Some(local_hostname) = self.get_metadata(&LOCAL_HOSTNAME).await?
{
Expand Down Expand Up @@ -669,13 +762,23 @@ impl Keys {
account_id_key: create_key(&namespace, ACCOUNT_ID_KEY),
ami_id_key: create_key(&namespace, AMI_ID_KEY),
availability_zone_key: create_key(&namespace, AVAILABILITY_ZONE_KEY),
availability_zone_id_key: create_key(&namespace, AVAILABILITY_ZONE_ID_KEY),
instance_id_key: create_key(&namespace, INSTANCE_ID_KEY),
instance_type_key: create_key(&namespace, INSTANCE_TYPE_KEY),
local_hostname_key: create_key(&namespace, LOCAL_HOSTNAME_KEY),
local_ipv4_key: create_key(&namespace, LOCAL_IPV4_KEY),
public_hostname_key: create_key(&namespace, PUBLIC_HOSTNAME_KEY),
public_ipv4_key: create_key(&namespace, PUBLIC_IPV4_KEY),
region_key: create_key(&namespace, REGION_KEY),
partition_key: create_key(&namespace, PARTITION_KEY),
domain_key: create_key(&namespace, DOMAIN_KEY),
placement_group_name_key: create_key(&namespace, PLACEMENT_GROUP_NAME_KEY),
placement_partition_number_key: create_key(&namespace, PLACEMENT_PARTITION_NUMBER_KEY),
host_id_key: create_key(&namespace, HOST_ID_KEY),
autoscaling_target_lifecycle_state_key: create_key(
&namespace,
AUTOSCALING_TARGET_LIFECYCLE_STATE_KEY,
),
subnet_id_key: create_key(&namespace, SUBNET_ID_KEY),
vpc_id_key: create_key(&namespace, VPC_ID_KEY),
role_name_key: create_key(&namespace, ROLE_NAME_KEY),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,62 @@ components: transforms: aws_ec2_metadata: {
examples: ["us-east-1"]
}
}
"availability-zone-id": {
description: "The `availability-zone-id` that the current EC2 instance is running in. Unlike `availability-zone`, this ID is consistent across AWS accounts."
required: false
type: string: {
default: null
examples: ["use1-az1"]
}
}
"partition": {
description: "The AWS partition (from `services/partition`) that the current EC2 instance is running in."
required: false
type: string: {
default: null
examples: ["aws"]
}
}
"domain": {
description: "The AWS region domain (from `services/domain`) for the current EC2 instance."
required: false
type: string: {
default: null
examples: ["amazonaws.com"]
}
}
"placement-group-name": {
description: "The name of the placement group (from `placement/group-name`) that the current EC2 instance is in, if any."
required: false
type: string: {
default: null
examples: ["my-placement-group"]
}
}
"placement-partition-number": {
description: "The number of the partition (from `placement/partition-number`) within the placement group that the current EC2 instance is in, if any."
required: false
type: string: {
default: null
examples: ["1"]
}
}
"host-id": {
description: "The ID of the Dedicated Host (from `placement/host-id`) that the current EC2 instance is running on, if any."
required: false
type: string: {
default: null
examples: ["h-0123456789abcdef0"]
}
}
"autoscaling-target-lifecycle-state": {
description: "The EC2 Auto Scaling target lifecycle state (from `autoscaling/target-lifecycle-state`) of the current EC2 instance, if it is part of an Auto Scaling group."
required: false
type: string: {
default: null
examples: ["InService"]
}
}
"role-name": {
description: "The `role-name` that the current EC2 instance is using."
required: true
Expand Down
Loading