Skip to content

Commit

Permalink
feat(aws-codedeploy): Deployment Configuration Construct. (#653)
Browse files Browse the repository at this point in the history
Part of the work on a AWS Construct Library for CodeDeploy.
  • Loading branch information
skinny85 committed Sep 20, 2018
1 parent d68b6c3 commit e6b67ad
Show file tree
Hide file tree
Showing 9 changed files with 365 additions and 18 deletions.
35 changes: 33 additions & 2 deletions packages/@aws-cdk/aws-codedeploy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ To import an already existing Application:

```ts
const application = codedeploy.ServerApplicationRef.import(this, 'ExistingCodeDeployApplication', {
applicationName: new codedeploy.ApplicationName('MyExistingApplication'),
applicationName: 'MyExistingApplication',
});
```

Expand All @@ -39,7 +39,38 @@ To import an already existing Deployment Group:
```ts
const deploymentGroup = codedeploy.ServerDeploymentGroupRef.import(this, 'ExistingCodeDeployDeploymentGroup', {
application,
deploymentGroupName: new codedeploy.DeploymentGroupName('MyExistingDeploymentGroup'),
deploymentGroupName: 'MyExistingDeploymentGroup',
});
```

### Deployment Configurations

You can also pass a Deployment Configuration when creating the Deployment Group:

```ts
const deploymentGroup = new codedeploy.ServerDeploymentGroup(this, 'CodeDeployDeploymentGroup', {
deploymentConfig: codedeploy.ServerDeploymentConfig.AllAtOnce,
});
```

The default Deployment Configuration is `ServerDeploymentConfig.OneAtATime`.

You can also create a custom Deployment Configuration:

```ts
const deploymentConfig = new codedeploy.ServerDeploymentConfig(this, 'DeploymentConfiguration', {
deploymentConfigName: 'MyDeploymentConfiguration', // optional property
// one of these is required, but both cannot be specified at the same time
minHealthyHostCount: 2,
minHealthyHostPercentage: 75,
});
```

Or import an existing one:

```ts
const deploymentConfig = codedeploy.ServerDeploymentConfigRef.import(this, 'ExistingDeploymentConfiguration', {
deploymentConfigName: 'MyExistingDeploymentConfiguration',
});
```

Expand Down
158 changes: 158 additions & 0 deletions packages/@aws-cdk/aws-codedeploy/lib/deployment-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import cdk = require('@aws-cdk/cdk');
import { cloudformation } from './codedeploy.generated';

/**
* The Deployment Configuration of an EC2/on-premise Deployment Group.
* The default, pre-defined Configurations are available as constants on the {@link ServerDeploymentConfig} class
* (`ServerDeploymentConfig.HalfAtATime`, `ServerDeploymentConfig.AllAtOnce`, etc.).
* To create a custom Deployment Configuration,
* instantiate the {@link ServerDeploymentConfig} Construct.
*/
export interface IServerDeploymentConfig {
readonly deploymentConfigName: string;
readonly deploymentConfigArn: string;
}

/**
* Properties of a reference to a CodeDeploy EC2/on-premise Deployment Configuration.
*
* @see ServerDeploymentConfigRef#import
* @see ServerDeploymentConfigRef#export
*/
export interface ServerDeploymentConfigRefProps {
/**
* The physical, human-readable name of the custom CodeDeploy EC2/on-premise Deployment Configuration
* that we are referencing.
*/
deploymentConfigName: string;
}

/**
* Reference to a custom Deployment Configuration for an EC2/on-premise Deployment Group.
*/
export abstract class ServerDeploymentConfigRef extends cdk.Construct implements IServerDeploymentConfig {
/**
* Import a custom Deployment Configuration for an EC2/on-premise Deployment Group defined either outside the CDK,
* or in a different CDK Stack and exported using the {@link #export} method.
*
* @param parent the parent Construct for this new Construct
* @param id the logical ID of this new Construct
* @param props the properties of the referenced custom Deployment Configuration
* @returns a Construct representing a reference to an existing custom Deployment Configuration
*/
public static import(parent: cdk.Construct, id: string, props: ServerDeploymentConfigRefProps):
ServerDeploymentConfigRef {
return new ImportedServerDeploymentConfigRef(parent, id, props);
}

public abstract readonly deploymentConfigName: string;
public abstract readonly deploymentConfigArn: string;

public export(): ServerDeploymentConfigRefProps {
return {
deploymentConfigName: new cdk.Output(this, 'DeploymentConfigName', {
value: this.deploymentConfigName,
}).makeImportValue().toString(),
};
}
}

class ImportedServerDeploymentConfigRef extends ServerDeploymentConfigRef {
public readonly deploymentConfigName: string;
public readonly deploymentConfigArn: string;

constructor(parent: cdk.Construct, id: string, props: ServerDeploymentConfigRefProps) {
super(parent, id);

this.deploymentConfigName = props.deploymentConfigName;
this.deploymentConfigArn = arnForDeploymentConfigName(this.deploymentConfigName);
}
}

class DefaultServerDeploymentConfig implements IServerDeploymentConfig {
public readonly deploymentConfigName: string;
public readonly deploymentConfigArn: string;

constructor(deploymentConfigName: string) {
this.deploymentConfigName = deploymentConfigName;
this.deploymentConfigArn = arnForDeploymentConfigName(this.deploymentConfigName);
}
}

/**
* Construction properties of {@link ServerDeploymentConfig}.
*/
export interface ServerDeploymentConfigProps {
/**
* The physical, human-readable name of the Deployment Configuration.
*
* @default a name will be auto-generated
*/
deploymentConfigName?: string;

/**
* The minimum healhty hosts threshold expressed as an absolute number.
* If you've specified this value,
* you can't specify {@link #minHealthyHostPercentage},
* however one of this or {@link #minHealthyHostPercentage} is required.
*/
minHealthyHostCount?: number;

/**
* The minmum healhty hosts threshold expressed as a percentage of the fleet.
* If you've specified this value,
* you can't specify {@link #minHealthyHostCount},
* however one of this or {@link #minHealthyHostCount} is required.
*/
minHealthyHostPercentage?: number;
}

/**
* A custom Deployment Configuration for an EC2/on-premise Deployment Group.
*/
export class ServerDeploymentConfig extends ServerDeploymentConfigRef {
public static readonly OneAtATime: IServerDeploymentConfig = new DefaultServerDeploymentConfig('CodeDeployDefault.OneAtATime');
public static readonly HalfAtATime: IServerDeploymentConfig = new DefaultServerDeploymentConfig('CodeDeployDefault.HalfAtATime');
public static readonly AllAtOnce: IServerDeploymentConfig = new DefaultServerDeploymentConfig('CodeDeployDefault.AllAtOnce');

public readonly deploymentConfigName: string;
public readonly deploymentConfigArn: string;

constructor(parent: cdk.Construct, id: string, props: ServerDeploymentConfigProps) {
super(parent, id);

const resource = new cloudformation.DeploymentConfigResource(this, 'Resource', {
deploymentConfigName: props.deploymentConfigName,
minimumHealthyHosts: this.minimumHealthyHosts(props),
});

this.deploymentConfigName = resource.ref.toString();
this.deploymentConfigArn = arnForDeploymentConfigName(this.deploymentConfigName);
}

private minimumHealthyHosts(props: ServerDeploymentConfigProps):
cloudformation.DeploymentConfigResource.MinimumHealthyHostsProperty {
if (props.minHealthyHostCount === undefined && props.minHealthyHostPercentage === undefined) {
throw new Error('At least one of minHealthyHostCount or minHealthyHostPercentage must be specified when creating ' +
'a custom Server DeploymentConfig');
}
if (props.minHealthyHostCount !== undefined && props.minHealthyHostPercentage !== undefined) {
throw new Error('Both minHealthyHostCount and minHealthyHostPercentage cannot be specified when creating ' +
'a custom Server DeploymentConfig');
}

return {
type: props.minHealthyHostCount !== undefined ? 'HOST_COUNT' : 'FLEET_PERCENT',
value: props.minHealthyHostCount !== undefined ? props.minHealthyHostCount : props.minHealthyHostPercentage!,
};
}
}

function arnForDeploymentConfigName(name: string): string {
return cdk.ArnUtils.fromComponents({
service: 'codedeploy',
resource: 'deploymentconfig',
resourceName: name,
sep: ':',
});
}
41 changes: 33 additions & 8 deletions packages/@aws-cdk/aws-codedeploy/lib/deployment-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import cdk = require("@aws-cdk/cdk");
import iam = require("../../aws-iam/lib/role");
import { ServerApplication, ServerApplicationRef } from "./application";
import { cloudformation } from './codedeploy.generated';
import { IServerDeploymentConfig, ServerDeploymentConfig } from "./deployment-config";

/**
* Properties of a reference to a CodeDeploy EC2/on-premise Deployment Group.
Expand All @@ -21,6 +22,13 @@ export interface ServerDeploymentGroupRefProps {
* that we are referencing.
*/
deploymentGroupName: string;

/**
* The Deployment Configuration this Deployment Group uses.
*
* @default ServerDeploymentConfig#OneAtATime
*/
deploymentConfig?: IServerDeploymentConfig;
}

/**
Expand Down Expand Up @@ -50,11 +58,19 @@ export abstract class ServerDeploymentGroupRef extends cdk.Construct {
public abstract readonly application: ServerApplicationRef;
public abstract readonly deploymentGroupName: string;
public abstract readonly deploymentGroupArn: string;
public readonly deploymentConfig: IServerDeploymentConfig;

constructor(parent: cdk.Construct, id: string, deploymentConfig?: IServerDeploymentConfig) {
super(parent, id);
this.deploymentConfig = deploymentConfig || ServerDeploymentConfig.OneAtATime;
}

public export(): ServerDeploymentGroupRefProps {
return {
application: this.application,
deploymentGroupName: new cdk.Output(this, 'DeploymentGroupName', { value: this.deploymentGroupName }).makeImportValue().toString()
deploymentGroupName: new cdk.Output(this, 'DeploymentGroupName', {
value: this.deploymentGroupName
}).makeImportValue().toString(),
};
}
}
Expand All @@ -65,7 +81,7 @@ class ImportedServerDeploymentGroupRef extends ServerDeploymentGroupRef {
public readonly deploymentGroupArn: string;

constructor(parent: cdk.Construct, id: string, props: ServerDeploymentGroupRefProps) {
super(parent, id);
super(parent, id, props.deploymentConfig);

this.application = props.application;
this.deploymentGroupName = props.deploymentGroupName;
Expand Down Expand Up @@ -96,6 +112,13 @@ export interface ServerDeploymentGroupProps {
* @default an auto-generated name will be used
*/
deploymentGroupName?: string;

/**
* The EC2/on-premise Deployment Configuration to use for this Deployment Group.
*
* @default ServerDeploymentConfig#OneAtATime
*/
deploymentConfig?: IServerDeploymentConfig;
}

/**
Expand All @@ -107,23 +130,25 @@ export class ServerDeploymentGroup extends ServerDeploymentGroupRef {
public readonly deploymentGroupArn: string;
public readonly deploymentGroupName: string;

constructor(parent: cdk.Construct, id: string, props?: ServerDeploymentGroupProps) {
super(parent, id);
constructor(parent: cdk.Construct, id: string, props: ServerDeploymentGroupProps = {}) {
super(parent, id, props && props.deploymentConfig);

this.application = (props && props.application) || new ServerApplication(this, 'Application');
this.application = props.application || new ServerApplication(this, 'Application');

this.role = (props && props.role) || new iam.Role(this, 'Role', {
this.role = props.role || new iam.Role(this, 'Role', {
assumedBy: new cdk.ServicePrincipal('codedeploy.amazonaws.com'),
managedPolicyArns: ['arn:aws:iam::aws:policy/service-role/AWSCodeDeployRole'],
});

const resource = new cloudformation.DeploymentGroupResource(this, 'Resource', {
applicationName: this.application.applicationName,
deploymentGroupName: props && props.deploymentGroupName,
deploymentGroupName: props.deploymentGroupName,
serviceRoleArn: this.role.roleArn,
deploymentConfigName: props.deploymentConfig &&
props.deploymentConfig.deploymentConfigName,
});

this.deploymentGroupName = resource.ref;
this.deploymentGroupName = resource.deploymentGroupName;
this.deploymentGroupArn = deploymentGroupName2Arn(this.application.applicationName,
this.deploymentGroupName);
}
Expand Down
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-codedeploy/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './application';
export * from './deployment-config';
export * from './deployment-group';
export * from './pipeline-action';

Expand Down
8 changes: 0 additions & 8 deletions packages/@aws-cdk/aws-codedeploy/test/test.codedeploy.ts

This file was deleted.

Loading

0 comments on commit e6b67ad

Please sign in to comment.