Skip to content

Commit f4f9555

Browse files
authored
fix(toolkit-lib): transform ProxyConfigurationProperties to properties for ECS (#1008)
CloudFormation uses ProxyConfigurationProperties but the ECS SDK expects properties. This renames the property before transformation to ensure hotswap deployments work correctly with App Mesh proxy configurations. Fixes aws/aws-cdk#36368 --- By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license
1 parent a9d5b84 commit f4f9555

File tree

2 files changed

+105
-0
lines changed

2 files changed

+105
-0
lines changed

packages/@aws-cdk/toolkit-lib/lib/api/hotswap/ecs-services.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ export async function isHotswappableEcsServiceChange(
106106

107107
// The SDK requires more properties here than its worth doing explicit typing for
108108
// instead, just use all the old values in the diff to fill them in implicitly
109+
renameCfnPropertiesToSdkProperties(taskDefinitionResource);
109110
const lowercasedTaskDef = transformObjectKeys(taskDefinitionResource, lowerCaseFirstCharacter, {
110111
// All the properties that take arbitrary string as keys i.e. { "string" : "string" }
111112
// https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_RegisterTaskDefinition.html#API_RegisterTaskDefinition_RequestSyntax
@@ -169,6 +170,14 @@ interface EcsService {
169170
readonly serviceArn: string;
170171
}
171172

173+
function renameCfnPropertiesToSdkProperties(object: any): void {
174+
// CloudFormation uses ProxyConfigurationProperties but SDK expects properties
175+
if (object.ProxyConfiguration?.ProxyConfigurationProperties !== undefined) {
176+
object.ProxyConfiguration.properties = object.ProxyConfiguration.ProxyConfigurationProperties;
177+
delete object.ProxyConfiguration.ProxyConfigurationProperties;
178+
}
179+
}
180+
172181
async function prepareTaskDefinitionChange(
173182
evaluateCfnTemplate: EvaluateCloudFormationTemplate,
174183
logicalId: string,

packages/@aws-cdk/toolkit-lib/test/api/hotswap/ecs-services-hotswap-deployments.test.ts

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,102 @@ describe.each([HotswapMode.FALL_BACK, HotswapMode.HOTSWAP_ONLY])('%p mode', (hot
638638
forceNewDeployment: true,
639639
});
640640
});
641+
642+
test(
643+
'should correctly transform ProxyConfiguration.ProxyConfigurationProperties to proxyConfiguration.properties',
644+
async () => {
645+
// GIVEN
646+
setup.setCurrentCfnStackTemplate({
647+
Resources: {
648+
TaskDef: {
649+
Type: 'AWS::ECS::TaskDefinition',
650+
Properties: {
651+
Family: 'my-task-def',
652+
ContainerDefinitions: [{ Image: 'image1' }],
653+
ProxyConfiguration: {
654+
ContainerName: 'FargateApplication',
655+
ProxyConfigurationProperties: [
656+
{ Name: 'AppPorts', Value: '8080' },
657+
{ Name: 'IgnoredUID', Value: '1337' },
658+
],
659+
Type: 'APPMESH',
660+
},
661+
},
662+
},
663+
Service: {
664+
Type: 'AWS::ECS::Service',
665+
Properties: {
666+
TaskDefinition: { Ref: 'TaskDef' },
667+
},
668+
},
669+
},
670+
});
671+
setup.pushStackResourceSummaries(
672+
setup.stackSummaryOf(
673+
'Service',
674+
'AWS::ECS::Service',
675+
'arn:aws:ecs:region:account:service/my-cluster/my-service',
676+
),
677+
);
678+
mockECSClient.on(RegisterTaskDefinitionCommand).resolves({
679+
taskDefinition: {
680+
taskDefinitionArn: 'arn:aws:ecs:region:account:task-definition/my-task-def:3',
681+
},
682+
});
683+
const cdkStackArtifact = setup.cdkStackArtifactOf({
684+
template: {
685+
Resources: {
686+
TaskDef: {
687+
Type: 'AWS::ECS::TaskDefinition',
688+
Properties: {
689+
Family: 'my-task-def',
690+
ContainerDefinitions: [{ Image: 'image2' }],
691+
ProxyConfiguration: {
692+
ContainerName: 'FargateApplication',
693+
ProxyConfigurationProperties: [
694+
{ Name: 'AppPorts', Value: '8080' },
695+
{ Name: 'IgnoredUID', Value: '1337' },
696+
],
697+
Type: 'APPMESH',
698+
},
699+
},
700+
},
701+
Service: {
702+
Type: 'AWS::ECS::Service',
703+
Properties: {
704+
TaskDefinition: { Ref: 'TaskDef' },
705+
},
706+
},
707+
},
708+
},
709+
});
710+
// WHEN
711+
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(hotswapMode, cdkStackArtifact);
712+
// THEN
713+
expect(deployStackResult).not.toBeUndefined();
714+
expect(mockECSClient).toHaveReceivedCommandWith(RegisterTaskDefinitionCommand, {
715+
family: 'my-task-def',
716+
containerDefinitions: [{ image: 'image2' }],
717+
proxyConfiguration: {
718+
containerName: 'FargateApplication',
719+
properties: [
720+
{ name: 'AppPorts', value: '8080' },
721+
{ name: 'IgnoredUID', value: '1337' },
722+
],
723+
type: 'APPMESH',
724+
},
725+
});
726+
expect(mockECSClient).toHaveReceivedCommandWith(UpdateServiceCommand, {
727+
service: 'arn:aws:ecs:region:account:service/my-cluster/my-service',
728+
cluster: 'my-cluster',
729+
taskDefinition: 'arn:aws:ecs:region:account:task-definition/my-task-def:3',
730+
deploymentConfiguration: {
731+
minimumHealthyPercent: 0,
732+
},
733+
forceNewDeployment: true,
734+
});
735+
},
736+
);
641737
});
642738

643739
describe.each([

0 commit comments

Comments
 (0)