From 7359839c7515115711b2d2683a7ebd936cbfdec7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=C3=A1n=20Whelan?= Date: Thu, 13 Aug 2026 16:14:20 +0100 Subject: [PATCH] data-plane-controller: pass through aws_resource_tags stack config field BYOC customers enrolled in AWS's Migration Acceleration Program need a cost-allocation tag (e.g. map-migrated) applied to every AWS resource of their data-plane, including hosts est-dry-dock replaces over time via Pulumi's provider default_tags. data-plane-controller re-serializes data_planes.config into the Pulumi stack config with no serde catch-all, so a field added only on the est-dry-dock/Pydantic side would be silently dropped before Pulumi ever sees it. This adds the Rust side of that field so it survives the round trip; it must ship and deploy before the est-dry-dock change. --- .../data-plane-controller/src/shared/stack.rs | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/crates/data-plane-controller/src/shared/stack.rs b/crates/data-plane-controller/src/shared/stack.rs index a9642ebb41f..8d9454a7ecc 100644 --- a/crates/data-plane-controller/src/shared/stack.rs +++ b/crates/data-plane-controller/src/shared/stack.rs @@ -152,6 +152,13 @@ pub struct DataPlane { // IP at S3 changes from the NAT EIP to the private-subnet IP. #[serde(default, skip_serializing_if = "is_false")] pub s3_endpoint_on_private_subnet: bool, + // Extra tags applied to every AWS resource of the data-plane, through the + // Pulumi AWS provider's `default_tags`. Used for customer cost-allocation + // schemes which require a tag on resources we create and replace over + // time, such as the `map-migrated` tag of the AWS Migration Acceleration + // Program. AWS only; Azure and GCP deployments ignore it. + #[serde(default, skip_serializing_if = "std::collections::BTreeMap::is_empty")] + pub aws_resource_tags: std::collections::BTreeMap, pub deployments: Vec, #[serde(default, skip_serializing_if = "Option::is_none")] pub connector_limits: Option, @@ -729,6 +736,40 @@ mod test { ); } + // We deserialize `data_planes.config` and re-serialize it into the Pulumi + // stack config, so `aws_resource_tags` reaches est-dry-dock only if it + // survives that round trip. An absent map must stay absent, so that + // data-planes which set no tags see no change to their stack config. + #[test] + fn aws_resource_tags_round_trip() { + let State { stack, .. } = serde_json::from_str(include_str!("state_fixture.json")).unwrap(); + + assert!(stack.config.model.aws_resource_tags.is_empty()); + assert_eq!( + serde_json::to_value(&stack.config.model) + .unwrap() + .get("aws_resource_tags"), + None, + ); + + let tagged = serde_json::to_value(DataPlane { + aws_resource_tags: [("map-migrated".to_string(), "migAQWO5XH8V0".to_string())].into(), + ..stack.config.model.clone() + }) + .unwrap(); + + assert_eq!( + tagged.get("aws_resource_tags").unwrap(), + &serde_json::json!({"map-migrated": "migAQWO5XH8V0"}), + ); + assert_eq!( + serde_json::from_value::(tagged) + .unwrap() + .aws_resource_tags, + [("map-migrated".to_string(), "migAQWO5XH8V0".to_string())].into(), + ); + } + // The wire shape est-dry-dock parses: `id` is a sibling of the flattened // link config, omitted when None, and round-trips losslessly. #[test]