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(codedeploy): referenced Applications are not environment-aware #23405

Merged
merged 8 commits into from
Dec 27, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { ArnFormat, Resource, Stack } from '@aws-cdk/core';
import { Construct } from 'constructs';
import { CfnDeploymentConfig } from './codedeploy.generated';
import { MinimumHealthyHosts } from './host-health-config';
import { arnForDeploymentConfig, validateName } from './private/utils';
import { TrafficRouting } from './traffic-routing-config';
import { arnForDeploymentConfig, validateName } from './utils';

/**
* The base class for ServerDeploymentConfig, EcsDeploymentConfig,
Expand Down
26 changes: 22 additions & 4 deletions packages/@aws-cdk/aws-codedeploy/lib/ecs/application.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ArnFormat, IResource, Resource } from '@aws-cdk/core';
import { ArnFormat, IResource, Resource, Stack, Arn } from '@aws-cdk/core';
import { Construct } from 'constructs';
import { CfnApplication } from '../codedeploy.generated';
import { arnForApplication, validateName } from '../utils';
import { arnForApplication, validateName } from '../private/utils';

/**
* Represents a reference to a CodeDeploy Application deploying to Amazon ECS.
Expand Down Expand Up @@ -42,20 +42,38 @@ export class EcsApplication extends Resource implements IEcsApplication {
/**
* Import an Application defined either outside the CDK, or in a different CDK Stack.
*
* The Application's account and region are assumed to be the same as the stack it is being imported
* into. If not, use `fromEcsApplicationArn`.
*
* @param scope the parent Construct for this new Construct
* @param id the logical ID of this new Construct
* @param ecsApplicationName the name of the application to import
* @returns a Construct representing a reference to an existing Application
*/
public static fromEcsApplicationName(scope: Construct, id: string, ecsApplicationName: string): IEcsApplication {
class Import extends Resource implements IEcsApplication {
public applicationArn = arnForApplication(ecsApplicationName);
public applicationArn = arnForApplication(Stack.of(scope), ecsApplicationName);
public applicationName = ecsApplicationName;
}

return new Import(scope, id);
}

/**
* Import an Application defined either outside the CDK, or in a different CDK Stack, by ARN.
*
* @param scope the parent Construct for this new Construct
* @param id the logical ID of this new Construct
* @param ecsApplicationArn the ARN of the application to import
* @returns a Construct representing a reference to an existing Application
*/
public static fromEcsApplicationArn(scope: Construct, id: string, ecsApplicationArn: string): IEcsApplication {
return new class extends Resource implements IEcsApplication {
public applicationArn = ecsApplicationArn;
public applicationName = Arn.split(ecsApplicationArn, ArnFormat.COLON_RESOURCE_NAME).resourceName ?? '<invalid arn>';
} (scope, id, { environmentFromArn: ecsApplicationArn });
}

public readonly applicationArn: string;
public readonly applicationName: string;

Expand All @@ -70,7 +88,7 @@ export class EcsApplication extends Resource implements IEcsApplication {
});

this.applicationName = this.getResourceNameAttribute(resource.ref);
this.applicationArn = this.getResourceArnAttribute(arnForApplication(resource.ref), {
this.applicationArn = this.getResourceArnAttribute(arnForApplication(Stack.of(scope), resource.ref), {
service: 'codedeploy',
resource: 'application',
resourceName: this.physicalName,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Construct } from 'constructs';
import { BaseDeploymentConfig, BaseDeploymentConfigOptions, ComputePlatform, IBaseDeploymentConfig } from '../base-deployment-config';
import { deploymentConfig } from '../private/utils';
import { TrafficRouting } from '../traffic-routing-config';
import { deploymentConfig } from '../utils';

/**
* The Deployment Configuration of an ECS Deployment Group.
Expand Down
44 changes: 18 additions & 26 deletions packages/@aws-cdk/aws-codedeploy/lib/ecs/deployment-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import * as iam from '@aws-cdk/aws-iam';
import * as cdk from '@aws-cdk/core';
import { Construct } from 'constructs';
import { CfnDeploymentGroup } from '../codedeploy.generated';
import { ImportedDeploymentGroupBase, DeploymentGroupBase } from '../private/base-deployment-group';
import { renderAlarmConfiguration, renderAutoRollbackConfiguration } from '../private/utils';
import { AutoRollbackConfig } from '../rollback-config';
import { arnForDeploymentGroup, renderAlarmConfiguration, renderAutoRollbackConfiguration, validateName } from '../utils';
import { IEcsApplication, EcsApplication } from './application';
import { EcsDeploymentConfig, IEcsDeploymentConfig } from './deployment-config';

Expand Down Expand Up @@ -182,9 +183,11 @@ export interface EcsDeploymentGroupProps {
* A CodeDeploy deployment group that orchestrates ECS blue-green deployments.
* @resource AWS::CodeDeploy::DeploymentGroup
*/
export class EcsDeploymentGroup extends cdk.Resource implements IEcsDeploymentGroup {
export class EcsDeploymentGroup extends DeploymentGroupBase implements IEcsDeploymentGroup {
/**
* Import an ECS Deployment Group defined outside the CDK app.
* Reference an ECS Deployment Group defined outside the CDK app.
*
* Account and region for the DeploymentGroup are taken from the application.
*
* @param scope the parent Construct for this new Construct
* @param id the logical ID of this new Construct
Expand All @@ -199,8 +202,6 @@ export class EcsDeploymentGroup extends cdk.Resource implements IEcsDeploymentGr
}

public readonly application: IEcsApplication;
public readonly deploymentGroupName: string;
public readonly deploymentGroupArn: string;
public readonly deploymentConfig: IEcsDeploymentConfig;
/**
* The service Role of this Deployment Group.
Expand All @@ -211,16 +212,15 @@ export class EcsDeploymentGroup extends cdk.Resource implements IEcsDeploymentGr

constructor(scope: Construct, id: string, props: EcsDeploymentGroupProps) {
super(scope, id, {
physicalName: props.deploymentGroupName,
deploymentGroupName: props.deploymentGroupName,
role: props.role,
roleConstructId: 'ServiceRole',
});
this.role = this._role;

this.application = props.application || new EcsApplication(this, 'Application');
this.alarms = props.alarms || [];

this.role = props.role || new iam.Role(this, 'ServiceRole', {
assumedBy: new iam.ServicePrincipal('codedeploy.amazonaws.com'),
});

this.role.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AWSCodeDeployRoleForECS'));
this.deploymentConfig = props.deploymentConfig || EcsDeploymentConfig.ALL_AT_ONCE;

Expand Down Expand Up @@ -261,21 +261,13 @@ export class EcsDeploymentGroup extends cdk.Resource implements IEcsDeploymentGr
autoRollbackConfiguration: cdk.Lazy.any({ produce: () => renderAutoRollbackConfiguration(this.alarms, props.autoRollback) }),
});

this.deploymentGroupName = this.getResourceNameAttribute(resource.ref);
this.deploymentGroupArn = this.getResourceArnAttribute(arnForDeploymentGroup(this.application.applicationName, resource.ref), {
service: 'codedeploy',
resource: 'deploymentgroup',
resourceName: `${this.application.applicationName}/${this.physicalName}`,
arnFormat: cdk.ArnFormat.COLON_RESOURCE_NAME,
});
this._setNameAndArn(resource, this.application);

// If the deployment config is a construct, add a dependency to ensure the deployment config
// is created before the deployment group is.
if (Construct.isConstruct(this.deploymentConfig)) {
this.node.addDependency(this.deploymentConfig);
}

this.node.addValidation({ validate: () => validateName('Deployment group', this.physicalName) });
}

/**
Expand Down Expand Up @@ -355,17 +347,17 @@ export interface EcsDeploymentGroupAttributes {
readonly deploymentConfig?: IEcsDeploymentConfig;
}

class ImportedEcsDeploymentGroup extends cdk.Resource implements IEcsDeploymentGroup {
class ImportedEcsDeploymentGroup extends ImportedDeploymentGroupBase implements IEcsDeploymentGroup {
public readonly application: IEcsApplication;
public readonly deploymentGroupName: string;
public readonly deploymentGroupArn: string;
public readonly deploymentConfig: IEcsDeploymentConfig;

constructor(scope:Construct, id: string, props: EcsDeploymentGroupAttributes) {
super(scope, id);
constructor(scope: Construct, id: string, props: EcsDeploymentGroupAttributes) {
super(scope, id, {
application: props.application,
deploymentGroupName: props.deploymentGroupName,
});

this.application = props.application;
this.deploymentGroupName = props.deploymentGroupName;
this.deploymentGroupArn = arnForDeploymentGroup(props.application.applicationName, props.deploymentGroupName);
this.deploymentConfig = props.deploymentConfig || EcsDeploymentConfig.ALL_AT_ONCE;
}
}
26 changes: 22 additions & 4 deletions packages/@aws-cdk/aws-codedeploy/lib/lambda/application.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ArnFormat, IResource, Resource } from '@aws-cdk/core';
import { ArnFormat, IResource, Resource, Stack, Arn } from '@aws-cdk/core';
import { Construct } from 'constructs';
import { CfnApplication } from '../codedeploy.generated';
import { arnForApplication, validateName } from '../utils';
import { arnForApplication, validateName } from '../private/utils';

/**
* Represents a reference to a CodeDeploy Application deploying to AWS Lambda.
Expand Down Expand Up @@ -42,20 +42,38 @@ export class LambdaApplication extends Resource implements ILambdaApplication {
/**
* Import an Application defined either outside the CDK, or in a different CDK Stack.
*
* The Application's account and region are assumed to be the same as the stack it is being imported
* into. If not, use `fromLambdaApplicationArn`.
*
* @param scope the parent Construct for this new Construct
* @param id the logical ID of this new Construct
* @param lambdaApplicationName the name of the application to import
* @returns a Construct representing a reference to an existing Application
*/
public static fromLambdaApplicationName(scope: Construct, id: string, lambdaApplicationName: string): ILambdaApplication {
class Import extends Resource implements ILambdaApplication {
public applicationArn = arnForApplication(lambdaApplicationName);
public applicationArn = arnForApplication(Stack.of(scope), lambdaApplicationName);
public applicationName = lambdaApplicationName;
}

return new Import(scope, id);
}

/**
* Import an Application defined either outside the CDK, or in a different CDK Stack, by ARN.
*
* @param scope the parent Construct for this new Construct
* @param id the logical ID of this new Construct
* @param lambdaApplicationArn the ARN of the application to import
* @returns a Construct representing a reference to an existing Application
*/
public static fromLambdaApplicationArn(scope: Construct, id: string, lambdaApplicationArn: string): ILambdaApplication {
return new class extends Resource implements ILambdaApplication {
public applicationArn = lambdaApplicationArn;
public applicationName = Arn.split(lambdaApplicationArn, ArnFormat.COLON_RESOURCE_NAME).resourceName ?? '<invalid arn>';
}(scope, id, { environmentFromArn: lambdaApplicationArn });
}

public readonly applicationArn: string;
public readonly applicationName: string;

Expand All @@ -70,7 +88,7 @@ export class LambdaApplication extends Resource implements ILambdaApplication {
});

this.applicationName = this.getResourceNameAttribute(resource.ref);
this.applicationArn = this.getResourceArnAttribute(arnForApplication(resource.ref), {
this.applicationArn = this.getResourceArnAttribute(arnForApplication(Stack.of(this), resource.ref), {
service: 'codedeploy',
resource: 'application',
resourceName: this.physicalName,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Duration, Names, Resource } from '@aws-cdk/core';
import { AwsCustomResource, AwsCustomResourcePolicy, PhysicalResourceId } from '@aws-cdk/custom-resources';
import { Construct } from 'constructs';
import { arnForDeploymentConfig, validateName } from '../utils';
import { arnForDeploymentConfig, validateName } from '../private/utils';
import { ILambdaDeploymentConfig } from './deployment-config';

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Construct } from 'constructs';
import { BaseDeploymentConfig, BaseDeploymentConfigOptions, ComputePlatform, IBaseDeploymentConfig } from '../base-deployment-config';
import { deploymentConfig } from '../private/utils';
import { TrafficRouting } from '../traffic-routing-config';
import { deploymentConfig } from '../utils';

/**
* The Deployment Configuration of a Lambda Deployment Group.
Expand Down
45 changes: 20 additions & 25 deletions packages/@aws-cdk/aws-codedeploy/lib/lambda/deployment-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import * as lambda from '@aws-cdk/aws-lambda';
import * as cdk from '@aws-cdk/core';
import { Construct } from 'constructs';
import { CfnDeploymentGroup } from '../codedeploy.generated';
import { ImportedDeploymentGroupBase, DeploymentGroupBase } from '../private/base-deployment-group';
import { renderAlarmConfiguration, renderAutoRollbackConfiguration } from '../private/utils';
import { AutoRollbackConfig } from '../rollback-config';
import { arnForDeploymentGroup, renderAlarmConfiguration, renderAutoRollbackConfiguration, validateName } from '../utils';
import { ILambdaApplication, LambdaApplication } from './application';
import { ILambdaDeploymentConfig, LambdaDeploymentConfig } from './deployment-config';

Expand Down Expand Up @@ -120,10 +121,12 @@ export interface LambdaDeploymentGroupProps {
/**
* @resource AWS::CodeDeploy::DeploymentGroup
*/
export class LambdaDeploymentGroup extends cdk.Resource implements ILambdaDeploymentGroup {
export class LambdaDeploymentGroup extends DeploymentGroupBase implements ILambdaDeploymentGroup {
/**
* Import an Lambda Deployment Group defined either outside the CDK app, or in a different AWS region.
*
* Account and region for the DeploymentGroup are taken from the application.
*
* @param scope the parent Construct for this new Construct
* @param id the logical ID of this new Construct
* @param attrs the properties of the referenced Deployment Group
Expand All @@ -137,9 +140,10 @@ export class LambdaDeploymentGroup extends cdk.Resource implements ILambdaDeploy
}

public readonly application: ILambdaApplication;
public readonly deploymentGroupName: string;
public readonly deploymentGroupArn: string;
public readonly deploymentConfig: ILambdaDeploymentConfig;
/**
* The service Role of this Deployment Group.
*/
public readonly role: iam.IRole;

private readonly alarms: cloudwatch.IAlarm[];
Expand All @@ -148,16 +152,15 @@ export class LambdaDeploymentGroup extends cdk.Resource implements ILambdaDeploy

constructor(scope: Construct, id: string, props: LambdaDeploymentGroupProps) {
super(scope, id, {
physicalName: props.deploymentGroupName,
deploymentGroupName: props.deploymentGroupName,
role: props.role,
roleConstructId: 'ServiceRole',
});
this.role = this._role;

this.application = props.application || new LambdaApplication(this, 'Application');
this.alarms = props.alarms || [];

this.role = props.role || new iam.Role(this, 'ServiceRole', {
assumedBy: new iam.ServicePrincipal('codedeploy.amazonaws.com'),
});

this.role.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSCodeDeployRoleForLambdaLimited'));
this.deploymentConfig = props.deploymentConfig || LambdaDeploymentConfig.CANARY_10PERCENT_5MINUTES;

Expand All @@ -174,13 +177,7 @@ export class LambdaDeploymentGroup extends cdk.Resource implements ILambdaDeploy
autoRollbackConfiguration: cdk.Lazy.any({ produce: () => renderAutoRollbackConfiguration(this.alarms, props.autoRollback) }),
});

this.deploymentGroupName = this.getResourceNameAttribute(resource.ref);
this.deploymentGroupArn = this.getResourceArnAttribute(arnForDeploymentGroup(this.application.applicationName, resource.ref), {
service: 'codedeploy',
resource: 'deploymentgroup',
resourceName: `${this.application.applicationName}/${this.physicalName}`,
arnFormat: cdk.ArnFormat.COLON_RESOURCE_NAME,
});
this._setNameAndArn(resource, this.application);

if (props.preHook) {
this.addPreHook(props.preHook);
Expand All @@ -203,8 +200,6 @@ export class LambdaDeploymentGroup extends cdk.Resource implements ILambdaDeploy
if (this.deploymentConfig instanceof Construct) {
this.node.addDependency(this.deploymentConfig);
}

this.node.addValidation({ validate: () => validateName('Deployment group', this.physicalName) });
}

/**
Expand Down Expand Up @@ -284,17 +279,17 @@ export interface LambdaDeploymentGroupAttributes {
readonly deploymentConfig?: ILambdaDeploymentConfig;
}

class ImportedLambdaDeploymentGroup extends cdk.Resource implements ILambdaDeploymentGroup {
class ImportedLambdaDeploymentGroup extends ImportedDeploymentGroupBase implements ILambdaDeploymentGroup {
public readonly application: ILambdaApplication;
public readonly deploymentGroupName: string;
public readonly deploymentGroupArn: string;
public readonly deploymentConfig: ILambdaDeploymentConfig;

constructor(scope:Construct, id: string, props: LambdaDeploymentGroupAttributes) {
super(scope, id);
constructor(scope: Construct, id: string, props: LambdaDeploymentGroupAttributes) {
super(scope, id, {
application: props.application,
deploymentGroupName: props.deploymentGroupName,
});

this.application = props.application;
this.deploymentGroupName = props.deploymentGroupName;
this.deploymentGroupArn = arnForDeploymentGroup(props.application.applicationName, props.deploymentGroupName);
this.deploymentConfig = props.deploymentConfig || LambdaDeploymentConfig.CANARY_10PERCENT_5MINUTES;
}
}
Loading