Skip to content

Commit ad89f01

Browse files
authored
fix(apprunner): incorrect serviceName (#26015)
The AppRunner `Service` L2 construct returns `serviceArn` attribute as the `serviceName`. As Cloudformation does not return serivceName attribute(see [return values](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apprunner-service.html#aws-resource-apprunner-service-return-values)). This PR splits the serviceArn to extract the serviceName instead. Closes #26002 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 37e0c43 commit ad89f01

File tree

9 files changed

+155
-17
lines changed

9 files changed

+155
-17
lines changed

packages/@aws-cdk/aws-apprunner-alpha/lib/service.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,7 +1041,6 @@ export class Service extends cdk.Resource {
10411041

10421042
/**
10431043
* The name of the service.
1044-
* @attribute
10451044
*/
10461045
readonly serviceName: string;
10471046

@@ -1106,7 +1105,15 @@ export class Service extends cdk.Resource {
11061105
this.serviceId = resource.attrServiceId;
11071106
this.serviceUrl = resource.attrServiceUrl;
11081107
this.serviceStatus = resource.attrStatus;
1109-
this.serviceName = resource.ref;
1108+
/**
1109+
* Cloudformaton does not return the serviceName attribute so we extract it from the serviceArn.
1110+
* The ARN comes with this format:
1111+
* arn:aws:apprunner:us-east-1:123456789012:service/SERVICE_NAME/SERVICE_ID
1112+
*/
1113+
// First, get the last element by splitting with ':'
1114+
const resourceFullName = cdk.Fn.select(5, cdk.Fn.split(':', this.serviceArn));
1115+
// Now, split the resourceFullName with '/' to get the serviceName
1116+
this.serviceName = cdk.Fn.select(1, cdk.Fn.split('/', resourceFullName));
11101117
}
11111118

11121119
/**
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"version":"31.0.0"}
1+
{"version":"32.0.0"}

packages/@aws-cdk/aws-apprunner-alpha/test/integ.service-ecr-public.js.snapshot/integ-apprunner-ecr-public.assets.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
{
2-
"version": "31.0.0",
2+
"version": "32.0.0",
33
"files": {
4-
"f00e06a7824495556404fb0a324a2b16e71836ea8aee2588858ad09bad6da100": {
4+
"798d29f00c3d8f856bf85b7138c6e647084b39d095a48e9fe00157a314591215": {
55
"source": {
66
"path": "integ-apprunner-ecr-public.template.json",
77
"packaging": "file"
88
},
99
"destinations": {
1010
"current_account-current_region": {
1111
"bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
12-
"objectKey": "f00e06a7824495556404fb0a324a2b16e71836ea8aee2588858ad09bad6da100.json",
12+
"objectKey": "798d29f00c3d8f856bf85b7138c6e647084b39d095a48e9fe00157a314591215.json",
1313
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
1414
}
1515
}

packages/@aws-cdk/aws-apprunner-alpha/test/integ.service-ecr-public.js.snapshot/integ-apprunner-ecr-public.template.json

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,58 @@
3939
]
4040
]
4141
}
42+
},
43+
"ServiceName": {
44+
"Value": {
45+
"Fn::Select": [
46+
1,
47+
{
48+
"Fn::Split": [
49+
"/",
50+
{
51+
"Fn::Select": [
52+
5,
53+
{
54+
"Fn::Split": [
55+
":",
56+
{
57+
"Fn::GetAtt": [
58+
"Service1EDCC8134",
59+
"ServiceArn"
60+
]
61+
}
62+
]
63+
}
64+
]
65+
}
66+
]
67+
}
68+
]
69+
}
70+
},
71+
"ServiceId": {
72+
"Value": {
73+
"Fn::GetAtt": [
74+
"Service1EDCC8134",
75+
"ServiceId"
76+
]
77+
}
78+
},
79+
"ServiceStatus": {
80+
"Value": {
81+
"Fn::GetAtt": [
82+
"Service1EDCC8134",
83+
"Status"
84+
]
85+
}
86+
},
87+
"ServiceArn": {
88+
"Value": {
89+
"Fn::GetAtt": [
90+
"Service1EDCC8134",
91+
"ServiceArn"
92+
]
93+
}
4294
}
4395
},
4496
"Parameters": {

packages/@aws-cdk/aws-apprunner-alpha/test/integ.service-ecr-public.js.snapshot/integ.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version": "31.0.0",
2+
"version": "32.0.0",
33
"testCases": {
44
"integ.service-ecr-public": {
55
"stacks": [

packages/@aws-cdk/aws-apprunner-alpha/test/integ.service-ecr-public.js.snapshot/manifest.json

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version": "31.0.0",
2+
"version": "32.0.0",
33
"artifacts": {
44
"integ-apprunner-ecr-public.assets": {
55
"type": "cdk:asset-manifest",
@@ -17,7 +17,7 @@
1717
"validateOnSynth": false,
1818
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}",
1919
"cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}",
20-
"stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/f00e06a7824495556404fb0a324a2b16e71836ea8aee2588858ad09bad6da100.json",
20+
"stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/798d29f00c3d8f856bf85b7138c6e647084b39d095a48e9fe00157a314591215.json",
2121
"requiresBootstrapStackVersion": 6,
2222
"bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version",
2323
"additionalDependencies": [
@@ -45,6 +45,30 @@
4545
"data": "URL1"
4646
}
4747
],
48+
"/integ-apprunner-ecr-public/ServiceName": [
49+
{
50+
"type": "aws:cdk:logicalId",
51+
"data": "ServiceName"
52+
}
53+
],
54+
"/integ-apprunner-ecr-public/ServiceId": [
55+
{
56+
"type": "aws:cdk:logicalId",
57+
"data": "ServiceId"
58+
}
59+
],
60+
"/integ-apprunner-ecr-public/ServiceStatus": [
61+
{
62+
"type": "aws:cdk:logicalId",
63+
"data": "ServiceStatus"
64+
}
65+
],
66+
"/integ-apprunner-ecr-public/ServiceArn": [
67+
{
68+
"type": "aws:cdk:logicalId",
69+
"data": "ServiceArn"
70+
}
71+
],
4872
"/integ-apprunner-ecr-public/BootstrapVersion": [
4973
{
5074
"type": "aws:cdk:logicalId",

packages/@aws-cdk/aws-apprunner-alpha/test/integ.service-ecr-public.js.snapshot/tree.json

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,43 +38,75 @@
3838
}
3939
},
4040
"constructInfo": {
41-
"fqn": "@aws-cdk/aws-apprunner.CfnService",
41+
"fqn": "aws-cdk-lib.aws_apprunner.CfnService",
4242
"version": "0.0.0"
4343
}
4444
}
4545
},
4646
"constructInfo": {
47-
"fqn": "@aws-cdk/aws-apprunner.Service",
47+
"fqn": "@aws-cdk/aws-apprunner-alpha.Service",
4848
"version": "0.0.0"
4949
}
5050
},
5151
"URL1": {
5252
"id": "URL1",
5353
"path": "integ-apprunner-ecr-public/URL1",
5454
"constructInfo": {
55-
"fqn": "@aws-cdk/core.CfnOutput",
55+
"fqn": "aws-cdk-lib.CfnOutput",
56+
"version": "0.0.0"
57+
}
58+
},
59+
"ServiceName": {
60+
"id": "ServiceName",
61+
"path": "integ-apprunner-ecr-public/ServiceName",
62+
"constructInfo": {
63+
"fqn": "aws-cdk-lib.CfnOutput",
64+
"version": "0.0.0"
65+
}
66+
},
67+
"ServiceId": {
68+
"id": "ServiceId",
69+
"path": "integ-apprunner-ecr-public/ServiceId",
70+
"constructInfo": {
71+
"fqn": "aws-cdk-lib.CfnOutput",
72+
"version": "0.0.0"
73+
}
74+
},
75+
"ServiceStatus": {
76+
"id": "ServiceStatus",
77+
"path": "integ-apprunner-ecr-public/ServiceStatus",
78+
"constructInfo": {
79+
"fqn": "aws-cdk-lib.CfnOutput",
80+
"version": "0.0.0"
81+
}
82+
},
83+
"ServiceArn": {
84+
"id": "ServiceArn",
85+
"path": "integ-apprunner-ecr-public/ServiceArn",
86+
"constructInfo": {
87+
"fqn": "aws-cdk-lib.CfnOutput",
5688
"version": "0.0.0"
5789
}
5890
},
5991
"BootstrapVersion": {
6092
"id": "BootstrapVersion",
6193
"path": "integ-apprunner-ecr-public/BootstrapVersion",
6294
"constructInfo": {
63-
"fqn": "@aws-cdk/core.CfnParameter",
95+
"fqn": "aws-cdk-lib.CfnParameter",
6496
"version": "0.0.0"
6597
}
6698
},
6799
"CheckBootstrapVersion": {
68100
"id": "CheckBootstrapVersion",
69101
"path": "integ-apprunner-ecr-public/CheckBootstrapVersion",
70102
"constructInfo": {
71-
"fqn": "@aws-cdk/core.CfnRule",
103+
"fqn": "aws-cdk-lib.CfnRule",
72104
"version": "0.0.0"
73105
}
74106
}
75107
},
76108
"constructInfo": {
77-
"fqn": "@aws-cdk/core.Stack",
109+
"fqn": "aws-cdk-lib.Stack",
78110
"version": "0.0.0"
79111
}
80112
},
@@ -83,12 +115,12 @@
83115
"path": "Tree",
84116
"constructInfo": {
85117
"fqn": "constructs.Construct",
86-
"version": "10.1.252"
118+
"version": "10.2.52"
87119
}
88120
}
89121
},
90122
"constructInfo": {
91-
"fqn": "@aws-cdk/core.App",
123+
"fqn": "aws-cdk-lib.App",
92124
"version": "0.0.0"
93125
}
94126
}

packages/@aws-cdk/aws-apprunner-alpha/test/integ.service-ecr-public.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,7 @@ const service1 = new Service(stack, 'Service1', {
1616
autoDeploymentsEnabled: false,
1717
});
1818
new cdk.CfnOutput(stack, 'URL1', { value: `https://${service1.serviceUrl}` });
19+
new cdk.CfnOutput(stack, 'ServiceName', { value: service1.serviceName });
20+
new cdk.CfnOutput(stack, 'ServiceId', { value: service1.serviceId });
21+
new cdk.CfnOutput(stack, 'ServiceStatus', { value: service1.serviceStatus });
22+
new cdk.CfnOutput(stack, 'ServiceArn', { value: service1.serviceArn });

packages/@aws-cdk/aws-apprunner-alpha/test/service.test.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -809,6 +809,25 @@ test('import from service attributes', () => {
809809
expect(svc).toHaveProperty('serviceUrl');
810810
});
811811

812+
test('serviceName validation', () => {
813+
// GIVEN
814+
const app = new cdk.App();
815+
const stack = new cdk.Stack(app, 'demo-stack');
816+
// WHEN
817+
const svc = new apprunner.Service(stack, 'CustomService', {
818+
source: apprunner.Source.fromEcrPublic({
819+
imageConfiguration: { port: 8000 },
820+
imageIdentifier: 'public.ecr.aws/aws-containers/hello-app-runner:latest',
821+
}),
822+
});
823+
824+
// THEN
825+
// the serviceName should not be the resource.ref
826+
expect(svc.serviceName).not.toEqual((svc.node.defaultChild as cdk.CfnResource).ref);
827+
// serviceName and serviceArn should be different
828+
expect(svc.serviceName).not.toEqual(svc.serviceArn);
829+
});
830+
812831
test('undefined imageConfiguration port is allowed', () => {
813832
// GIVEN
814833
const app = new cdk.App();

0 commit comments

Comments
 (0)