Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(appconfig-alpha): extensions always create cdk diff #28264

Merged
merged 6 commits into from
Dec 9, 2023
Merged
Show file tree
Hide file tree
Changes from 2 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
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-appconfig-alpha/lib/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ export class Application extends ApplicationBase {
resourceName: this.applicationId,
});

this.extensible = new ExtensibleBase(scope, this.applicationArn, this.name);
this.extensible = new ExtensibleBase(this, this.applicationArn, this.name);
}
}

Expand Down
4 changes: 2 additions & 2 deletions packages/@aws-cdk/aws-appconfig-alpha/lib/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@ export class HostedConfiguration extends ConfigurationBase {
resource: 'application',
resourceName: `${this.applicationId}/configurationprofile/${this.configurationProfileId}`,
});
this.extensible = new ExtensibleBase(scope, this.configurationProfileArn, this.name);
this.extensible = new ExtensibleBase(this, this.configurationProfileArn, this.name);

this.content = props.content.content;
this.contentType = props.content.contentType;
Expand Down Expand Up @@ -608,7 +608,7 @@ export class SourcedConfiguration extends ConfigurationBase {
resource: 'application',
resourceName: `${this.applicationId}/configurationprofile/${this.configurationProfileId}`,
});
this.extensible = new ExtensibleBase(scope, this.configurationProfileArn, this.name);
this.extensible = new ExtensibleBase(this, this.configurationProfileArn, this.name);

this.addExistingEnvironmentsToApplication();
this.deployConfigToEnvironments();
Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-appconfig-alpha/lib/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ export class Environment extends EnvironmentBase {
resource: 'application',
resourceName: `${this.applicationId}/environment/${this.environmentId}`,
});
this.extensible = new ExtensibleBase(scope, this.environmentArn, this.name);
this.extensible = new ExtensibleBase(this, this.environmentArn, this.name);

this.application.addExistingEnvironment(this);
}
Expand Down
42 changes: 27 additions & 15 deletions packages/@aws-cdk/aws-appconfig-alpha/lib/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ export class LambdaDestination implements IEventDestination {
this.policyDocument = new iam.PolicyDocument({
statements: [policy],
});

if (!func.permissionsNode.tryFindChild('AppConfigPermission')) {
func.addPermission('AppConfigPermission', {
principal: new iam.ServicePrincipal('appconfig.amazonaws.com'),
});
}
}
}

Expand Down Expand Up @@ -500,21 +506,19 @@ export class Extension extends Resource implements IExtension {
this.parameters = props.parameters;

const resource = new CfnExtension(this, 'Resource', {
actions: this.actions.reduce((acc: {[key: string]: {[key: string]: string}[]}, cur: Action) => {
actions: this.actions.reduce((acc: {[key: string]: {[key: string]: string}[]}, cur: Action, index) => {
chenjane-dev marked this conversation as resolved.
Show resolved Hide resolved
const extensionUri = cur.eventDestination.extensionUri;
const sourceType = cur.eventDestination.type;
this.executionRole = cur.executionRole;
const name = cur.name ?? `${this.name}-${index}`;
cur.actionPoints.forEach((actionPoint) => {
acc[actionPoint] = [
{
Name: cur.name || Names.uniqueResourceName(this, {
maxLength: 64,
separator: '-',
}),
Name: name,
Uri: extensionUri,
...(sourceType === SourceType.EVENTS || cur.invokeWithoutExecutionRole
? {}
: { RoleArn: this.executionRole?.roleArn || this.getExecutionRole(cur.eventDestination).roleArn }),
: { RoleArn: this.executionRole?.roleArn || this.getExecutionRole(cur.eventDestination, name).roleArn }),
...(cur.description ? { Description: cur.description } : {}),
},
];
Expand Down Expand Up @@ -543,8 +547,10 @@ export class Extension extends Resource implements IExtension {
});
}

private getExecutionRole(eventDestination: IEventDestination): iam.IRole {
this.executionRole = new iam.Role(this, `Role${getHash(eventDestination.extensionUri)}`, {
private getExecutionRole(eventDestination: IEventDestination, actionName: string): iam.IRole {
const versionNumber = this.latestVersionNumber ? this.latestVersionNumber + 1 : 1;
const combinedObjects = stringifyObjects(this.name, versionNumber, actionName);
this.executionRole = new iam.Role(this, `Role${getHash(combinedObjects)}`, {
roleName: PhysicalName.GENERATE_IF_NEEDED,
assumedBy: new iam.ServicePrincipal('appconfig.amazonaws.com'),
inlinePolicies: {
Expand Down Expand Up @@ -658,7 +664,12 @@ export class ExtensibleBase implements IExtensible {
}

private getExtensionForActionPoint(eventDestination: IEventDestination, actionPoint: ActionPoint, options?: ExtensionOptions) {
const extension = new Extension(this.scope, `Extension${this.getExtensionHash(eventDestination, actionPoint, options)}`, {
const name = options?.name || Names.uniqueResourceName(this.scope, {
maxLength: 54,
separator: '-',
}) + '-Extension';
const versionNumber = options?.latestVersionNumber ? options?.latestVersionNumber + 1 : 1;
const extension = new Extension(this.scope, `Extension${this.getExtensionHash(name, versionNumber)}`, {
actions: [
new Action({
eventDestination,
Expand All @@ -667,16 +678,17 @@ export class ExtensibleBase implements IExtensible {
],
}),
],
name,
...(options?.description ? { description: options.description } : {}),
...(options?.latestVersionNumber ? { latestVersionNumber: options.latestVersionNumber } : {}),
...(options?.name ? { name: options.name } : {}),
...(options?.parameters ? { parameters: options.parameters } : {}),
});
this.addExtensionAssociation(extension, options);
}

private addExtensionAssociation(extension: IExtension, options?: ExtensionOptions) {
new CfnExtensionAssociation(this.scope, `AssociationResource${this.getExtensionAssociationHash(extension)}`, {
const versionNumber = options?.latestVersionNumber ? options?.latestVersionNumber + 1 : 1;
new CfnExtensionAssociation(this.scope, `AssociationResource${this.getExtensionAssociationHash(extension.name!, versionNumber)}`, {
chenjane-dev marked this conversation as resolved.
Show resolved Hide resolved
extensionIdentifier: extension.extensionId,
resourceIdentifier: this.resourceArn,
extensionVersionNumber: extension.extensionVersionNumber,
Expand All @@ -689,14 +701,14 @@ export class ExtensibleBase implements IExtensible {
});
}

private getExtensionHash(eventDestination: IEventDestination, actionPoint: ActionPoint, options?: ExtensionOptions) {
const combinedString = stringifyObjects(eventDestination, actionPoint, options);
private getExtensionHash(name: string, versionNumber: number) {
const combinedString = stringifyObjects(name, versionNumber);
return getHash(combinedString);
}

private getExtensionAssociationHash(extension: IExtension) {
private getExtensionAssociationHash(name: string, versionNumber: number) {
const resourceIdentifier = this.resourceName ? this.resourceName : this.resourceArn;
chenjane-dev marked this conversation as resolved.
Show resolved Hide resolved
const combinedString = stringifyObjects(resourceIdentifier, extension.name, extension.extensionVersionNumber);
const combinedString = stringifyObjects(resourceIdentifier, name, versionNumber);
return getHash(combinedString);
}
}
Expand Down
90 changes: 42 additions & 48 deletions packages/@aws-cdk/aws-appconfig-alpha/test/application.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,37 +64,34 @@ describe('appconfig', () => {
});
});

test('pre create hosted configuration version', () => {
test('specifying action point for extensible action on', () => {
const stack = new cdk.Stack();
const appconfig = new Application(stack, 'MyAppConfig');
const func = new Function(stack, 'MyFunc', {
handler: 'index.handler',
runtime: Runtime.PYTHON_3_7,
code: Code.fromInline('# this is my code'),
});
Object.defineProperty(func, 'functionArn', {
value: 'arn:lambda:us-east-1:123456789012:function:my-function',
});
appconfig.on(ActionPoint.ON_DEPLOYMENT_STEP, new LambdaDestination(func));

Template.fromStack(stack).hasResourceProperties('AWS::AppConfig::Extension', {
Name: 'Extension28486',
Name: 'MyAppConfig-Extension',
Actions: {
ON_DEPLOYMENT_STEP: [
{
Name: 'Extension28486',
RoleArn: { 'Fn::GetAtt': ['Extension28486RoleFD36712B5D791', 'Arn'] },
Uri: 'arn:lambda:us-east-1:123456789012:function:my-function',
Name: 'MyAppConfig-Extension-0',
RoleArn: { 'Fn::GetAtt': ['MyAppConfigExtensionF845ERole0D30970E5A7E5', 'Arn'] },
Uri: { 'Fn::GetAtt': ['MyFunc8A243A2C', 'Arn'] },
},
],
},
});
Template.fromStack(stack).hasResourceProperties('AWS::AppConfig::ExtensionAssociation', {
ExtensionIdentifier: {
'Fn::GetAtt': ['Extension28486EB468E25', 'Id'],
'Fn::GetAtt': ['MyAppConfigExtensionF845EC11D4079', 'Id'],
},
ExtensionVersionNumber: {
'Fn::GetAtt': ['Extension28486EB468E25', 'VersionNumber'],
'Fn::GetAtt': ['MyAppConfigExtensionF845EC11D4079', 'VersionNumber'],
},
ResourceIdentifier: {
'Fn::Join': [
Expand Down Expand Up @@ -122,9 +119,6 @@ describe('appconfig', () => {
runtime: Runtime.PYTHON_3_7,
code: Code.fromInline('# this is my code'),
});
Object.defineProperty(func, 'functionArn', {
value: 'arn:lambda:us-east-1:123456789012:function:my-function',
});
appconfig.preCreateHostedConfigurationVersion(new LambdaDestination(func), {
description: 'This is my description',
name: 'MyExtension',
Expand All @@ -141,9 +135,9 @@ describe('appconfig', () => {
Actions: {
PRE_CREATE_HOSTED_CONFIGURATION_VERSION: [
{
Name: 'Extension8D9D7',
RoleArn: { 'Fn::GetAtt': ['Extension8D9D7RoleFD367F4FA01C5', 'Arn'] },
Uri: 'arn:lambda:us-east-1:123456789012:function:my-function',
Name: 'MyExtension-0',
RoleArn: { 'Fn::GetAtt': ['MyAppConfigExtensionE4CCERole467D69791333F', 'Arn'] },
Uri: { 'Fn::GetAtt': ['MyFunc8A243A2C', 'Arn'] },
},
],
},
Expand All @@ -153,10 +147,10 @@ describe('appconfig', () => {
});
Template.fromStack(stack).hasResourceProperties('AWS::AppConfig::ExtensionAssociation', {
ExtensionIdentifier: {
'Fn::GetAtt': ['Extension8D9D75657615A', 'Id'],
'Fn::GetAtt': ['MyAppConfigExtensionE4CCE34485313', 'Id'],
},
ExtensionVersionNumber: {
'Fn::GetAtt': ['Extension8D9D75657615A', 'VersionNumber'],
'Fn::GetAtt': ['MyAppConfigExtensionE4CCE34485313', 'VersionNumber'],
},
Parameters: {
myparam: 'val',
Expand Down Expand Up @@ -193,23 +187,23 @@ describe('appconfig', () => {
appconfig.preStartDeployment(new LambdaDestination(func));

Template.fromStack(stack).hasResourceProperties('AWS::AppConfig::Extension', {
Name: 'Extension6253E',
Name: 'MyAppConfig-Extension',
Actions: {
PRE_START_DEPLOYMENT: [
{
Name: 'Extension6253E',
RoleArn: { 'Fn::GetAtt': ['Extension6253ERoleFD367F586E17D', 'Arn'] },
Name: 'MyAppConfig-Extension-0',
RoleArn: { 'Fn::GetAtt': ['MyAppConfigExtensionF845ERole0D30970E5A7E5', 'Arn'] },
Uri: 'arn:lambda:us-east-1:123456789012:function:my-function',
},
],
},
});
Template.fromStack(stack).hasResourceProperties('AWS::AppConfig::ExtensionAssociation', {
ExtensionIdentifier: {
'Fn::GetAtt': ['Extension6253ED4CE66CE', 'Id'],
'Fn::GetAtt': ['MyAppConfigExtensionF845EC11D4079', 'Id'],
},
ExtensionVersionNumber: {
'Fn::GetAtt': ['Extension6253ED4CE66CE', 'VersionNumber'],
'Fn::GetAtt': ['MyAppConfigExtensionF845EC11D4079', 'VersionNumber'],
},
ResourceIdentifier: {
'Fn::Join': [
Expand Down Expand Up @@ -246,23 +240,23 @@ describe('appconfig', () => {
appconfig.onDeploymentStart(new LambdaDestination(func));

Template.fromStack(stack).hasResourceProperties('AWS::AppConfig::Extension', {
Name: 'ExtensionB65DC',
Name: 'MyAppConfig-Extension',
Actions: {
ON_DEPLOYMENT_START: [
{
Name: 'ExtensionB65DC',
RoleArn: { 'Fn::GetAtt': ['ExtensionB65DCRoleFD3677AFA6FE0', 'Arn'] },
Name: 'MyAppConfig-Extension-0',
RoleArn: { 'Fn::GetAtt': ['MyAppConfigExtensionF845ERole0D30970E5A7E5', 'Arn'] },
Uri: 'arn:lambda:us-east-1:123456789012:function:my-function',
},
],
},
});
Template.fromStack(stack).hasResourceProperties('AWS::AppConfig::ExtensionAssociation', {
ExtensionIdentifier: {
'Fn::GetAtt': ['ExtensionB65DC00D22C6E', 'Id'],
'Fn::GetAtt': ['MyAppConfigExtensionF845EC11D4079', 'Id'],
},
ExtensionVersionNumber: {
'Fn::GetAtt': ['ExtensionB65DC00D22C6E', 'VersionNumber'],
'Fn::GetAtt': ['MyAppConfigExtensionF845EC11D4079', 'VersionNumber'],
},
ResourceIdentifier: {
'Fn::Join': [
Expand Down Expand Up @@ -296,23 +290,23 @@ describe('appconfig', () => {
appconfig.onDeploymentStep(new LambdaDestination(func));

Template.fromStack(stack).hasResourceProperties('AWS::AppConfig::Extension', {
Name: 'Extension28486',
Name: 'MyAppConfig-Extension',
Actions: {
ON_DEPLOYMENT_STEP: [
{
Name: 'Extension28486',
RoleArn: { 'Fn::GetAtt': ['Extension28486RoleFD36712B5D791', 'Arn'] },
Name: 'MyAppConfig-Extension-0',
RoleArn: { 'Fn::GetAtt': ['MyAppConfigExtensionF845ERole0D30970E5A7E5', 'Arn'] },
Uri: 'arn:lambda:us-east-1:123456789012:function:my-function',
},
],
},
});
Template.fromStack(stack).hasResourceProperties('AWS::AppConfig::ExtensionAssociation', {
ExtensionIdentifier: {
'Fn::GetAtt': ['Extension28486EB468E25', 'Id'],
'Fn::GetAtt': ['MyAppConfigExtensionF845EC11D4079', 'Id'],
},
ExtensionVersionNumber: {
'Fn::GetAtt': ['Extension28486EB468E25', 'VersionNumber'],
'Fn::GetAtt': ['MyAppConfigExtensionF845EC11D4079', 'VersionNumber'],
},
ResourceIdentifier: {
'Fn::Join': [
Expand Down Expand Up @@ -346,23 +340,23 @@ describe('appconfig', () => {
appconfig.onDeploymentComplete(new LambdaDestination(func));

Template.fromStack(stack).hasResourceProperties('AWS::AppConfig::Extension', {
Name: 'Extension32166',
Name: 'MyAppConfig-Extension',
Actions: {
ON_DEPLOYMENT_COMPLETE: [
{
Name: 'Extension32166',
RoleArn: { 'Fn::GetAtt': ['Extension32166RoleFD367EE1FF117', 'Arn'] },
Name: 'MyAppConfig-Extension-0',
RoleArn: { 'Fn::GetAtt': ['MyAppConfigExtensionF845ERole0D30970E5A7E5', 'Arn'] },
Uri: 'arn:lambda:us-east-1:123456789012:function:my-function',
},
],
},
});
Template.fromStack(stack).hasResourceProperties('AWS::AppConfig::ExtensionAssociation', {
ExtensionIdentifier: {
'Fn::GetAtt': ['Extension32166E58405A0', 'Id'],
'Fn::GetAtt': ['MyAppConfigExtensionF845EC11D4079', 'Id'],
},
ExtensionVersionNumber: {
'Fn::GetAtt': ['Extension32166E58405A0', 'VersionNumber'],
'Fn::GetAtt': ['MyAppConfigExtensionF845EC11D4079', 'VersionNumber'],
},
ResourceIdentifier: {
'Fn::Join': [
Expand Down Expand Up @@ -396,23 +390,23 @@ describe('appconfig', () => {
appconfig.onDeploymentBaking(new LambdaDestination(func));

Template.fromStack(stack).hasResourceProperties('AWS::AppConfig::Extension', {
Name: 'Extension1CAD4',
Name: 'MyAppConfig-Extension',
Actions: {
ON_DEPLOYMENT_BAKING: [
{
Name: 'Extension1CAD4',
RoleArn: { 'Fn::GetAtt': ['Extension1CAD4RoleFD367FC09E8DE', 'Arn'] },
Name: 'MyAppConfig-Extension-0',
RoleArn: { 'Fn::GetAtt': ['MyAppConfigExtensionF845ERole0D30970E5A7E5', 'Arn'] },
Uri: 'arn:lambda:us-east-1:123456789012:function:my-function',
},
],
},
});
Template.fromStack(stack).hasResourceProperties('AWS::AppConfig::ExtensionAssociation', {
ExtensionIdentifier: {
'Fn::GetAtt': ['Extension1CAD47F07C609', 'Id'],
'Fn::GetAtt': ['MyAppConfigExtensionF845EC11D4079', 'Id'],
},
ExtensionVersionNumber: {
'Fn::GetAtt': ['Extension1CAD47F07C609', 'VersionNumber'],
'Fn::GetAtt': ['MyAppConfigExtensionF845EC11D4079', 'VersionNumber'],
},
ResourceIdentifier: {
'Fn::Join': [
Expand Down Expand Up @@ -446,23 +440,23 @@ describe('appconfig', () => {
appconfig.onDeploymentRolledBack(new LambdaDestination(func));

Template.fromStack(stack).hasResourceProperties('AWS::AppConfig::Extension', {
Name: 'ExtensionC8347',
Name: 'MyAppConfig-Extension',
Actions: {
ON_DEPLOYMENT_ROLLED_BACK: [
{
Name: 'ExtensionC8347',
RoleArn: { 'Fn::GetAtt': ['ExtensionC8347RoleFD36716A1DE61', 'Arn'] },
Name: 'MyAppConfig-Extension-0',
RoleArn: { 'Fn::GetAtt': ['MyAppConfigExtensionF845ERole0D30970E5A7E5', 'Arn'] },
Uri: 'arn:lambda:us-east-1:123456789012:function:my-function',
},
],
},
});
Template.fromStack(stack).hasResourceProperties('AWS::AppConfig::ExtensionAssociation', {
ExtensionIdentifier: {
'Fn::GetAtt': ['ExtensionC83470CE85F6C', 'Id'],
'Fn::GetAtt': ['MyAppConfigExtensionF845EC11D4079', 'Id'],
},
ExtensionVersionNumber: {
'Fn::GetAtt': ['ExtensionC83470CE85F6C', 'VersionNumber'],
'Fn::GetAtt': ['MyAppConfigExtensionF845EC11D4079', 'VersionNumber'],
},
ResourceIdentifier: {
'Fn::Join': [
Expand Down
Loading