From a5fc325fe840f95e375d55fc46f8aa1a1722fd5f Mon Sep 17 00:00:00 2001 From: yingdong chen Date: Thu, 4 May 2023 23:22:15 -0700 Subject: [PATCH] Revert "fix(servicecatalogappregistry): Remove deprecated resource in Application Construct (#25095)" This reverts commit 9222f217aa5f199dd88addc9d0dee0f3f900b5a2. --- .../lib/application.ts | 52 ++++++++ .../test/application.test.ts | 86 +++++++++++++ ...catalogappregistry-application.assets.json | 4 +- ...talogappregistry-application.template.json | 55 +++++++++ .../manifest.json | 20 ++- .../integ.application.js.snapshot/tree.json | 115 ++++++++++++++++-- .../test/integ.application.ts | 22 ++++ 7 files changed, 338 insertions(+), 16 deletions(-) diff --git a/packages/@aws-cdk/aws-servicecatalogappregistry-alpha/lib/application.ts b/packages/@aws-cdk/aws-servicecatalogappregistry-alpha/lib/application.ts index c0a85c9278fc..1adbea95e543 100644 --- a/packages/@aws-cdk/aws-servicecatalogappregistry-alpha/lib/application.ts +++ b/packages/@aws-cdk/aws-servicecatalogappregistry-alpha/lib/application.ts @@ -56,6 +56,13 @@ export interface IApplication extends cdk.IResource { */ readonly applicationName?: string; + /** + * Associate this application with an attribute group. + * + * @param attributeGroup AppRegistry attribute group + */ + associateAttributeGroup(attributeGroup: IAttributeGroup): void; + /** * Create an attribute group and associate this application with the created attribute group. * @@ -63,6 +70,15 @@ export interface IApplication extends cdk.IResource { * @param attributeGroupProps AppRegistry attribute group props */ addAttributeGroup(id: string, attributeGroupProps: AttributeGroupAssociationProps): IAttributeGroup; + + /** + * Associate this application with a CloudFormation stack. + * + * @deprecated Use `associateApplicationWithStack` instead. + * @param stack a CFN stack + */ + associateStack(stack: cdk.Stack): void; + /** * Associate a Cloudformation statck with the application in the given stack. * @@ -112,6 +128,23 @@ abstract class ApplicationBase extends cdk.Resource implements IApplication { private readonly associatedAttributeGroups: Set = new Set(); private readonly associatedResources: Set = new Set(); + /** + * Associate an attribute group with application + * If the attribute group is already associated, it will ignore duplicate request. + * + * @deprecated Use `AttributeGroup.associateWith` instead. + */ + public associateAttributeGroup(attributeGroup: IAttributeGroup): void { + if (!this.associatedAttributeGroups.has(attributeGroup.node.addr)) { + const hashId = this.generateUniqueHash(attributeGroup.node.addr); + new CfnAttributeGroupAssociation(this, `AttributeGroupAssociation${hashId}`, { + application: this.applicationId, + attributeGroup: attributeGroup.attributeGroupId, + }); + this.associatedAttributeGroups.add(attributeGroup.node.addr); + } + } + /** * Create an attribute group and associate this application with the created attribute group. */ @@ -129,6 +162,25 @@ abstract class ApplicationBase extends cdk.Resource implements IApplication { return attributeGroup; } + /** + * Associate a stack with the application + * If the resource is already associated, it will ignore duplicate request. + * A stack can only be associated with one application. + * + * @deprecated Use `associateApplicationWithStack` instead. + */ + public associateStack(stack: cdk.Stack): void { + if (!this.associatedResources.has(stack.node.addr)) { + const hashId = this.generateUniqueHash(stack.node.addr); + new CfnResourceAssociation(this, `ResourceAssociation${hashId}`, { + application: this.applicationId, + resource: stack.stackId, + resourceType: 'CFN_STACK', + }); + this.associatedResources.add(stack.node.addr); + } + } + /** * Associate stack with the application in the stack passed as parameter. * diff --git a/packages/@aws-cdk/aws-servicecatalogappregistry-alpha/test/application.test.ts b/packages/@aws-cdk/aws-servicecatalogappregistry-alpha/test/application.test.ts index 5d6e4e8fe365..7bf61b5d60c1 100644 --- a/packages/@aws-cdk/aws-servicecatalogappregistry-alpha/test/application.test.ts +++ b/packages/@aws-cdk/aws-servicecatalogappregistry-alpha/test/application.test.ts @@ -146,6 +146,20 @@ describe('Application', () => { }); }); + test('associate attribute group', () => { + const attributeGroup = new appreg.AttributeGroup(stack, 'AttributeGroup', { + attributeGroupName: 'AttributeGroupName', + attributes: {}, + }); + + application.associateAttributeGroup(attributeGroup); + + Template.fromStack(stack).hasResourceProperties('AWS::ServiceCatalogAppRegistry::AttributeGroupAssociation', { + Application: { 'Fn::GetAtt': ['MyApplication5C63EC1D', 'Id'] }, + AttributeGroup: { 'Fn::GetAtt': ['AttributeGroup409C6335', 'Id'] }, + }); + }), + test('associate new attribute group', () => { application.addAttributeGroup('AttributeGroup', { attributeGroupName: 'AttributeGroupName', @@ -169,6 +183,78 @@ describe('Application', () => { }, }, }); + }), + + test('duplicate attribute group association are idempotent', () => { + const attributeGroup = new appreg.AttributeGroup(stack, 'AttributeGroup', { + attributeGroupName: 'attributeGroupName', + attributes: { key: 'value' }, + }); + + // If these were not idempotent, the second call would produce an error for duplicate construct ID. + application.associateAttributeGroup(attributeGroup); + application.associateAttributeGroup(attributeGroup); + + Template.fromStack(stack).resourceCountIs('AWS::ServiceCatalogAppRegistry::AttributeGroupAssociation', 1); + }), + + test('multiple applications and attribute groups can associate', () => { + const application2 = new appreg.Application(stack, 'MyApplication2', { + applicationName: 'MyApplication2', + }); + + const attributeGroup1 = new appreg.AttributeGroup(stack, 'AttributeGroup', { + attributeGroupName: 'attributeGroupName', + attributes: { key: 'value' }, + }); + + const attributeGroup2 = new appreg.AttributeGroup(stack, 'AttributeGroup2', { + attributeGroupName: 'attributeGroupName2', + attributes: { key: 'value' }, + }); + + application.associateAttributeGroup(attributeGroup1); + application.associateAttributeGroup(attributeGroup2); + + application2.associateAttributeGroup(attributeGroup1); + application2.associateAttributeGroup(attributeGroup2); + + Template.fromStack(stack).resourceCountIs('AWS::ServiceCatalogAppRegistry::AttributeGroupAssociation', 4); + }), + + test('associate resource', () => { + const resource = new cdk.Stack(stack, 'MyStack'); + + application.associateStack(resource); + + Template.fromStack(stack).hasResourceProperties('AWS::ServiceCatalogAppRegistry::ResourceAssociation', { + Application: { 'Fn::GetAtt': ['MyApplication5C63EC1D', 'Id'] }, + Resource: { 'Fn::ImportValue': 'MyStack:ExportsOutputRefAWSStackIdB2DD5BAA' }, + }); + }), + + test('associate resource on imported application', () => { + const resource = new cdk.Stack(stack, 'MyStack'); + + const importedApplication = appreg.Application.fromApplicationArn(stack, 'ImportedApplication', + 'arn:aws:servicecatalog:us-east-1:123456789012:/applications/0bqmvxvgmry0ecc4mjhwypun6i'); + + importedApplication.associateStack(resource); + + Template.fromStack(stack).hasResourceProperties('AWS::ServiceCatalogAppRegistry::ResourceAssociation', { + Application: '0bqmvxvgmry0ecc4mjhwypun6i', + Resource: { 'Fn::ImportValue': 'MyStack:ExportsOutputRefAWSStackIdB2DD5BAA' }, + }); + }), + + test('duplicate resource assocations are idempotent', () => { + const resource = new cdk.Stack(stack, 'MyStack'); + + // If these were not idempotent, the second call would produce an error for duplicate construct ID. + application.associateStack(resource); + application.associateStack(resource); + + Template.fromStack(stack).resourceCountIs('AWS::ServiceCatalogAppRegistry::ResourceAssociation', 1); }); }); diff --git a/packages/@aws-cdk/aws-servicecatalogappregistry-alpha/test/integ.application.js.snapshot/integ-servicecatalogappregistry-application.assets.json b/packages/@aws-cdk/aws-servicecatalogappregistry-alpha/test/integ.application.js.snapshot/integ-servicecatalogappregistry-application.assets.json index 89e6c3f35953..4b0a52bc75b1 100644 --- a/packages/@aws-cdk/aws-servicecatalogappregistry-alpha/test/integ.application.js.snapshot/integ-servicecatalogappregistry-application.assets.json +++ b/packages/@aws-cdk/aws-servicecatalogappregistry-alpha/test/integ.application.js.snapshot/integ-servicecatalogappregistry-application.assets.json @@ -1,7 +1,7 @@ { "version": "31.0.0", "files": { - "f45a8edb41940665356c72f600a1955d3c2799708e54040592669f4fcaec6500": { + "461d235e9497deb16b9209be4a927c7d0dc7aa06d668e38bfb19a90db8e4a4b2": { "source": { "path": "integ-servicecatalogappregistry-application.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "f45a8edb41940665356c72f600a1955d3c2799708e54040592669f4fcaec6500.json", + "objectKey": "461d235e9497deb16b9209be4a927c7d0dc7aa06d668e38bfb19a90db8e4a4b2.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk/aws-servicecatalogappregistry-alpha/test/integ.application.js.snapshot/integ-servicecatalogappregistry-application.template.json b/packages/@aws-cdk/aws-servicecatalogappregistry-alpha/test/integ.application.js.snapshot/integ-servicecatalogappregistry-application.template.json index dd4ef7d0f612..7562f4a54b88 100644 --- a/packages/@aws-cdk/aws-servicecatalogappregistry-alpha/test/integ.application.js.snapshot/integ-servicecatalogappregistry-application.template.json +++ b/packages/@aws-cdk/aws-servicecatalogappregistry-alpha/test/integ.application.js.snapshot/integ-servicecatalogappregistry-application.template.json @@ -7,6 +7,38 @@ "Description": "My application description" } }, + "TestApplicationResourceAssociationd232b63e52a8414E905D": { + "Type": "AWS::ServiceCatalogAppRegistry::ResourceAssociation", + "Properties": { + "Application": { + "Fn::GetAtt": [ + "TestApplication2FBC585F", + "Id" + ] + }, + "Resource": { + "Ref": "AWS::StackId" + }, + "ResourceType": "CFN_STACK" + } + }, + "TestApplicationAttributeGroupAssociation4ba7f5842818B8EE1C6F": { + "Type": "AWS::ServiceCatalogAppRegistry::AttributeGroupAssociation", + "Properties": { + "Application": { + "Fn::GetAtt": [ + "TestApplication2FBC585F", + "Id" + ] + }, + "AttributeGroup": { + "Fn::GetAtt": [ + "TestAttributeGroupB1CB284F", + "Id" + ] + } + } + }, "TestApplicationmyAnotherAttributeGroup375F79DB": { "Type": "AWS::ServiceCatalogAppRegistry::AttributeGroup", "Properties": { @@ -84,6 +116,29 @@ ] } }, + "TestAttributeGroupB1CB284F": { + "Type": "AWS::ServiceCatalogAppRegistry::AttributeGroup", + "Properties": { + "Attributes": { + "stage": "alpha", + "teamMembers": [ + "markI", + "markII", + "markIII" + ], + "public": false, + "publishYear": 2021, + "plannedRoadMap": { + "alpha": "some time", + "beta": "another time", + "gamma": "penultimate time", + "release": "go time" + } + }, + "Name": "myAttributeGroup", + "Description": "my attribute group description" + } + }, "MyRoleF48FFE04": { "Type": "AWS::IAM::Role", "Properties": { diff --git a/packages/@aws-cdk/aws-servicecatalogappregistry-alpha/test/integ.application.js.snapshot/manifest.json b/packages/@aws-cdk/aws-servicecatalogappregistry-alpha/test/integ.application.js.snapshot/manifest.json index 086506594d70..a78c95594594 100644 --- a/packages/@aws-cdk/aws-servicecatalogappregistry-alpha/test/integ.application.js.snapshot/manifest.json +++ b/packages/@aws-cdk/aws-servicecatalogappregistry-alpha/test/integ.application.js.snapshot/manifest.json @@ -17,7 +17,7 @@ "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/f45a8edb41940665356c72f600a1955d3c2799708e54040592669f4fcaec6500.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/461d235e9497deb16b9209be4a927c7d0dc7aa06d668e38bfb19a90db8e4a4b2.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -39,6 +39,18 @@ "data": "TestApplication2FBC585F" } ], + "/integ-servicecatalogappregistry-application/TestApplication/ResourceAssociationd232b63e52a8": [ + { + "type": "aws:cdk:logicalId", + "data": "TestApplicationResourceAssociationd232b63e52a8414E905D" + } + ], + "/integ-servicecatalogappregistry-application/TestApplication/AttributeGroupAssociation4ba7f5842818": [ + { + "type": "aws:cdk:logicalId", + "data": "TestApplicationAttributeGroupAssociation4ba7f5842818B8EE1C6F" + } + ], "/integ-servicecatalogappregistry-application/TestApplication/myAnotherAttributeGroup/Resource": [ { "type": "aws:cdk:logicalId", @@ -57,6 +69,12 @@ "data": "TestApplicationMyShareIdE1044482" } ], + "/integ-servicecatalogappregistry-application/TestAttributeGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "TestAttributeGroupB1CB284F" + } + ], "/integ-servicecatalogappregistry-application/MyRole/Resource": [ { "type": "aws:cdk:logicalId", diff --git a/packages/@aws-cdk/aws-servicecatalogappregistry-alpha/test/integ.application.js.snapshot/tree.json b/packages/@aws-cdk/aws-servicecatalogappregistry-alpha/test/integ.application.js.snapshot/tree.json index 659f2448f6ff..4cf5dc181776 100644 --- a/packages/@aws-cdk/aws-servicecatalogappregistry-alpha/test/integ.application.js.snapshot/tree.json +++ b/packages/@aws-cdk/aws-servicecatalogappregistry-alpha/test/integ.application.js.snapshot/tree.json @@ -23,7 +23,55 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_servicecatalogappregistry.CfnApplication", + "fqn": "@aws-cdk/aws-servicecatalogappregistry.CfnApplication", + "version": "0.0.0" + } + }, + "ResourceAssociationd232b63e52a8": { + "id": "ResourceAssociationd232b63e52a8", + "path": "integ-servicecatalogappregistry-application/TestApplication/ResourceAssociationd232b63e52a8", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ServiceCatalogAppRegistry::ResourceAssociation", + "aws:cdk:cloudformation:props": { + "application": { + "Fn::GetAtt": [ + "TestApplication2FBC585F", + "Id" + ] + }, + "resource": { + "Ref": "AWS::StackId" + }, + "resourceType": "CFN_STACK" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-servicecatalogappregistry.CfnResourceAssociation", + "version": "0.0.0" + } + }, + "AttributeGroupAssociation4ba7f5842818": { + "id": "AttributeGroupAssociation4ba7f5842818", + "path": "integ-servicecatalogappregistry-application/TestApplication/AttributeGroupAssociation4ba7f5842818", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ServiceCatalogAppRegistry::AttributeGroupAssociation", + "aws:cdk:cloudformation:props": { + "application": { + "Fn::GetAtt": [ + "TestApplication2FBC585F", + "Id" + ] + }, + "attributeGroup": { + "Fn::GetAtt": [ + "TestAttributeGroupB1CB284F", + "Id" + ] + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-servicecatalogappregistry.CfnAttributeGroupAssociation", "version": "0.0.0" } }, @@ -58,13 +106,13 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_servicecatalogappregistry.CfnAttributeGroup", + "fqn": "@aws-cdk/aws-servicecatalogappregistry.CfnAttributeGroup", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-servicecatalogappregistry-alpha.AttributeGroup", + "fqn": "@aws-cdk/aws-servicecatalogappregistry.AttributeGroup", "version": "0.0.0" } }, @@ -89,7 +137,7 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_servicecatalogappregistry.CfnAttributeGroupAssociation", + "fqn": "@aws-cdk/aws-servicecatalogappregistry.CfnAttributeGroupAssociation", "version": "0.0.0" } }, @@ -134,13 +182,54 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_ram.CfnResourceShare", + "fqn": "@aws-cdk/aws-ram.CfnResourceShare", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-servicecatalogappregistry.Application", + "version": "0.0.0" + } + }, + "TestAttributeGroup": { + "id": "TestAttributeGroup", + "path": "integ-servicecatalogappregistry-application/TestAttributeGroup", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-servicecatalogappregistry-application/TestAttributeGroup/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ServiceCatalogAppRegistry::AttributeGroup", + "aws:cdk:cloudformation:props": { + "attributes": { + "stage": "alpha", + "teamMembers": [ + "markI", + "markII", + "markIII" + ], + "public": false, + "publishYear": 2021, + "plannedRoadMap": { + "alpha": "some time", + "beta": "another time", + "gamma": "penultimate time", + "release": "go time" + } + }, + "name": "myAttributeGroup", + "description": "my attribute group description" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-servicecatalogappregistry.CfnAttributeGroup", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-servicecatalogappregistry-alpha.Application", + "fqn": "@aws-cdk/aws-servicecatalogappregistry.AttributeGroup", "version": "0.0.0" } }, @@ -152,7 +241,7 @@ "id": "ImportMyRole", "path": "integ-servicecatalogappregistry-application/MyRole/ImportMyRole", "constructInfo": { - "fqn": "aws-cdk-lib.Resource", + "fqn": "@aws-cdk/core.Resource", "version": "0.0.0" } }, @@ -192,13 +281,13 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_iam.CfnRole", + "fqn": "@aws-cdk/aws-iam.CfnRole", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_iam.Role", + "fqn": "@aws-cdk/aws-iam.Role", "version": "0.0.0" } }, @@ -206,7 +295,7 @@ "id": "BootstrapVersion", "path": "integ-servicecatalogappregistry-application/BootstrapVersion", "constructInfo": { - "fqn": "aws-cdk-lib.CfnParameter", + "fqn": "@aws-cdk/core.CfnParameter", "version": "0.0.0" } }, @@ -214,13 +303,13 @@ "id": "CheckBootstrapVersion", "path": "integ-servicecatalogappregistry-application/CheckBootstrapVersion", "constructInfo": { - "fqn": "aws-cdk-lib.CfnRule", + "fqn": "@aws-cdk/core.CfnRule", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "aws-cdk-lib.Stack", + "fqn": "@aws-cdk/core.Stack", "version": "0.0.0" } }, @@ -234,7 +323,7 @@ } }, "constructInfo": { - "fqn": "aws-cdk-lib.App", + "fqn": "@aws-cdk/core.App", "version": "0.0.0" } } diff --git a/packages/@aws-cdk/aws-servicecatalogappregistry-alpha/test/integ.application.ts b/packages/@aws-cdk/aws-servicecatalogappregistry-alpha/test/integ.application.ts index ad9f7ef161e8..998f831c76da 100644 --- a/packages/@aws-cdk/aws-servicecatalogappregistry-alpha/test/integ.application.ts +++ b/packages/@aws-cdk/aws-servicecatalogappregistry-alpha/test/integ.application.ts @@ -10,7 +10,29 @@ const application = new appreg.Application(stack, 'TestApplication', { description: 'My application description', }); +const attributeGroup = new appreg.AttributeGroup(stack, 'TestAttributeGroup', { + attributeGroupName: 'myAttributeGroup', + description: 'my attribute group description', + attributes: { + stage: 'alpha', + teamMembers: [ + 'markI', + 'markII', + 'markIII', + ], + public: false, + publishYear: 2021, + plannedRoadMap: { + alpha: 'some time', + beta: 'another time', + gamma: 'penultimate time', + release: 'go time', + }, + }, +}); +application.associateStack(stack); +application.associateAttributeGroup(attributeGroup); application.addAttributeGroup('myAnotherAttributeGroup', { attributeGroupName: 'myAnotherAttributeGroup', attributes: {