From 1e0ffa7957a936cdf64531310b551f1539522d1b Mon Sep 17 00:00:00 2001 From: Adam Ruka Date: Mon, 20 Aug 2018 18:08:48 -0700 Subject: [PATCH] feat(aws-codedeploy): first classes for the CodeDeploy Construct Library. Includes ServerApplication and ServerDeploymentGroup. --- packages/@aws-cdk/aws-codedeploy/README.md | 46 +++++- .../aws-codedeploy/lib/application.ts | 106 +++++++++++++ .../aws-codedeploy/lib/deployment-group.ts | 144 ++++++++++++++++++ packages/@aws-cdk/aws-codedeploy/lib/index.ts | 2 + .../integ.pipeline-code-deploy.expected.json | 12 +- .../test/integ.pipeline-code-deploy.ts | 14 +- 6 files changed, 306 insertions(+), 18 deletions(-) create mode 100644 packages/@aws-cdk/aws-codedeploy/lib/application.ts create mode 100644 packages/@aws-cdk/aws-codedeploy/lib/deployment-group.ts diff --git a/packages/@aws-cdk/aws-codedeploy/README.md b/packages/@aws-cdk/aws-codedeploy/README.md index 00dc75bbcab9e..93f9d31630ee6 100644 --- a/packages/@aws-cdk/aws-codedeploy/README.md +++ b/packages/@aws-cdk/aws-codedeploy/README.md @@ -1,13 +1,55 @@ ## The CDK Construct Library for AWS CodeDeploy +### Applications + +To create a new CodeDeploy Application that deploys to EC2/on-premise instances: + +```ts +import codedeploy = require('@aws-cdk/aws-codedeploy'); + +const application = new codedeploy.ServerApplication(this, 'CodeDeployApplication', { + applicationName: 'MyApplication', // optional property +}); +``` + +To import an already existing Application: + +```ts +const application = codedeploy.ServerApplicationRef.import(this, 'ExistingCodeDeployApplication', { + applicationName: new codedeploy.ApplicationName('MyExistingApplication'), +}); +``` + +### Deployment Groups + +To create a new CodeDeploy Deployment Group that deploys to EC2/on-premise instances: + +```ts +const deploymentGroup = new codedeploy.ServerDeploymentGroup(this, 'CodeDeployDeploymentGroup', { + application, + deploymentGroupName: 'MyDeploymentGroup', +}); +``` + +All properties are optional - if you don't provide an Application, +one will be automatically created. + +To import an already existing Deployment Group: + +```ts +const deploymentGroup = codedeploy.ServerDeploymentGroupRef.import(this, 'ExistingCodeDeployDeploymentGroup', { + application, + deploymentGroupName: new codedeploy.DeploymentGroupName('MyExistingDeploymentGroup'), +}); +``` + ### Use in CodePipeline -This module contains an Action that allows you to use CodeDeploy with AWS CodePipeline. +This module also contains an Action that allows you to use CodeDeploy with AWS CodePipeline. Example: ```ts -import codedeploy = require('@aws-cdk/aws-codedeploy'); import codepipeline = require('@aws-cdk/aws-codepipeline'); const pipeline = new codepipeline.Pipeline(this, 'MyPipeline', { diff --git a/packages/@aws-cdk/aws-codedeploy/lib/application.ts b/packages/@aws-cdk/aws-codedeploy/lib/application.ts new file mode 100644 index 0000000000000..21a84ae618505 --- /dev/null +++ b/packages/@aws-cdk/aws-codedeploy/lib/application.ts @@ -0,0 +1,106 @@ +import cdk = require('@aws-cdk/cdk'); +import { ApplicationName, cloudformation } from './codedeploy.generated'; + +export class ApplicationArn extends cdk.Arn {} + +/** + * Properties of a reference to a CodeDeploy EC2/on-premise Application. + * + * @see ServerApplicationRef#import + * @see ServerApplicationRef#export + */ +export interface ServerApplicationRefProps { + /** + * The physical, human-readable name of the CodeDeploy EC2/on-premise Application we're referencing. + * The Application must be in the same account and region as the root Stack. + */ + applicationName: ApplicationName; +} + +/** + * Represents a reference to a CodeDeploy Application deploying to EC2/on-premise instances. + * + * If you're managing the Application alongside the rest of your CDK resources, + * use the {@link ServerApplication} class. + * + * If you want to reference an already existing Application, + * or one defined in a different CDK Stack, + * use the {@link #import} method. + */ +export abstract class ServerApplicationRef extends cdk.Construct { + /** + * Import an Application 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 Application + * @returns a Construct representing a reference to an existing Application + */ + public static import(parent: cdk.Construct, id: string, props: ServerApplicationRefProps): ServerApplicationRef { + return new ImportedServerApplicationRef(parent, id, props); + } + + public abstract readonly applicationArn: ApplicationArn; + + public abstract readonly applicationName: ApplicationName; + + public export(): ServerApplicationRefProps { + return { + applicationName: new cdk.Output(this, 'ApplicationName', { value: this.applicationName }).makeImportValue(), + }; + } +} + +class ImportedServerApplicationRef extends ServerApplicationRef { + public readonly applicationArn: ApplicationArn; + public readonly applicationName: ApplicationName; + + constructor(parent: cdk.Construct, id: string, props: ServerApplicationRefProps) { + super(parent, id); + + this.applicationName = props.applicationName; + this.applicationArn = applicationName2Arn(this.applicationName); + } +} + +/** + * Construction properties for {@link ServerApplication}. + */ +export interface ServerApplicationProps { + /** + * The physical, human-readable name of the CodeDeploy Application. + * + * @default an auto-generated name will be used + */ + applicationName?: string; +} + +/** + * A CodeDeploy Application that deploys to EC2/on-premise instances. + */ +export class ServerApplication extends ServerApplicationRef { + public readonly applicationArn: ApplicationArn; + public readonly applicationName: ApplicationName; + + constructor(parent: cdk.Construct, id: string, props?: ServerApplicationProps) { + super(parent, id); + + const resource = new cloudformation.ApplicationResource(this, 'Resource', { + applicationName: props && props.applicationName, + computePlatform: 'Server', + }); + + this.applicationName = resource.ref; + this.applicationArn = applicationName2Arn(this.applicationName); + } +} + +function applicationName2Arn(applicationName: ApplicationName): ApplicationArn { + return cdk.Arn.fromComponents({ + service: 'codedeploy', + resource: 'application', + resourceName: applicationName, + sep: ':', + }); +} diff --git a/packages/@aws-cdk/aws-codedeploy/lib/deployment-group.ts b/packages/@aws-cdk/aws-codedeploy/lib/deployment-group.ts new file mode 100644 index 0000000000000..1af30ed1fa941 --- /dev/null +++ b/packages/@aws-cdk/aws-codedeploy/lib/deployment-group.ts @@ -0,0 +1,144 @@ +import cdk = require("@aws-cdk/cdk"); +import iam = require("../../aws-iam/lib/role"); +import { ServerApplication, ServerApplicationRef } from "./application"; +import { ApplicationName, cloudformation, DeploymentGroupName } from './codedeploy.generated'; + +export class DeploymentGroupArn extends cdk.Arn {} + +/** + * Properties of a reference to a CodeDeploy EC2/on-premise Deployment Group. + * + * @see ServerDeploymentGroupRef#import + * @see ServerDeploymentGroupRef#export + */ +export interface ServerDeploymentGroupRefProps { + /** + * The reference to the CodeDeploy EC2/on-premise Application + * that this Deployment Group belongs to. + */ + application: ServerApplicationRef; + + /** + * The physical, human-readable name of the CodeDeploy EC2/on-premise Deployment Group + * that we are referencing. + */ + deploymentGroupName: DeploymentGroupName; +} + +/** + * Represents a reference to a CodeDeploy EC2/on-premise Deployment Group. + * + * If you're managing the Deployment Group alongside the rest of your CDK resources, + * use the {@link ServerDeploymentGroup} class. + * + * If you want to reference an already existing Deployment Group, + * or one defined in a different CDK Stack, + * use the {@link #import} method. + */ +export abstract class ServerDeploymentGroupRef extends cdk.Construct { + /** + * Import 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 Deployment Group + * @returns a Construct representing a reference to an existing Deployment Group + */ + public static import(parent: cdk.Construct, id: string, props: ServerDeploymentGroupRefProps): ServerDeploymentGroupRef { + return new ImportedServerDeploymentGroupRef(parent, id, props); + } + + public abstract readonly application: ServerApplicationRef; + public abstract readonly deploymentGroupName: DeploymentGroupName; + public abstract readonly deploymentGroupArn: DeploymentGroupArn; + + public export(): ServerDeploymentGroupRefProps { + return { + application: this.application, + deploymentGroupName: new cdk.Output(this, 'DeploymentGroupName', { + value: this.deploymentGroupName + }).makeImportValue(), + }; + } +} + +class ImportedServerDeploymentGroupRef extends ServerDeploymentGroupRef { + public readonly application: ServerApplicationRef; + public readonly deploymentGroupName: DeploymentGroupName; + public readonly deploymentGroupArn: DeploymentGroupArn; + + constructor(parent: cdk.Construct, id: string, props: ServerDeploymentGroupRefProps) { + super(parent, id); + + this.application = props.application; + this.deploymentGroupName = props.deploymentGroupName; + this.deploymentGroupArn = deploymentGroupName2Arn(props.application.applicationName, + props.deploymentGroupName); + } +} + +/** + * Construction properties for {@link ServerDeploymentGroup}. + */ +export interface ServerDeploymentGroupProps { + /** + * The CodeDeploy EC2/on-premise Application this Deployment Group belongs to. + * If you don't provide one, a new Application will be created. + */ + application?: ServerApplicationRef; + + /** + * The service Role of this Deployment Group. + * If you don't provide one, a new Role will be created. + */ + role?: iam.Role; + + /** + * The physical, human-readable name of the CodeDeploy Deployment Group. + * + * @default an auto-generated name will be used + */ + deploymentGroupName?: string; +} + +/** + * A CodeDeploy Deployment Group that deploys to EC2/on-premise instances. + */ +export class ServerDeploymentGroup extends ServerDeploymentGroupRef { + public readonly application: ServerApplicationRef; + public readonly role: iam.Role; + public readonly deploymentGroupArn: DeploymentGroupArn; + public readonly deploymentGroupName: DeploymentGroupName; + + constructor(parent: cdk.Construct, id: string, props: ServerDeploymentGroupProps) { + super(parent, id); + + this.application = props.application || new ServerApplication(this, 'Application'); + + 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.deploymentGroupName, + serviceRoleArn: this.role.roleArn, + }); + + this.deploymentGroupName = resource.ref; + this.deploymentGroupArn = deploymentGroupName2Arn(this.application.applicationName, + this.deploymentGroupName); + } +} + +function deploymentGroupName2Arn(applicationName: ApplicationName, + deploymentGroupName: DeploymentGroupName): DeploymentGroupArn { + return cdk.Arn.fromComponents({ + service: 'codedeploy', + resource: 'deploymentgroup', + resourceName: new cdk.FnJoin('/', [applicationName, deploymentGroupName]), + sep: ':', + }); +} diff --git a/packages/@aws-cdk/aws-codedeploy/lib/index.ts b/packages/@aws-cdk/aws-codedeploy/lib/index.ts index d5ae70c073569..862add5a074ec 100644 --- a/packages/@aws-cdk/aws-codedeploy/lib/index.ts +++ b/packages/@aws-cdk/aws-codedeploy/lib/index.ts @@ -1,3 +1,5 @@ +export * from './application'; +export * from './deployment-group'; export * from './pipeline-action'; // AWS::CodeDeploy CloudFormation Resources: diff --git a/packages/@aws-cdk/aws-codepipeline/test/integ.pipeline-code-deploy.expected.json b/packages/@aws-cdk/aws-codepipeline/test/integ.pipeline-code-deploy.expected.json index ddc8233557d86..3fb62e98b05eb 100644 --- a/packages/@aws-cdk/aws-codepipeline/test/integ.pipeline-code-deploy.expected.json +++ b/packages/@aws-cdk/aws-codepipeline/test/integ.pipeline-code-deploy.expected.json @@ -1,13 +1,13 @@ { "Resources": { - "CodeDeployApplication": { + "CodeDeployApplicationE587C27C": { "Type": "AWS::CodeDeploy::Application", "Properties": { "ApplicationName": "IntegTestDeployApp", "ComputePlatform": "Server" } }, - "CodeDeployGroupRole9EDBB624": { + "CodeDeployGroupRole1D304F7A": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { @@ -27,13 +27,15 @@ ] } }, - "CodeDeployGroup": { + "CodeDeployGroup58220FC8": { "Type": "AWS::CodeDeploy::DeploymentGroup", "Properties": { - "ApplicationName": "IntegTestDeployApp", + "ApplicationName": { + "Ref": "CodeDeployApplicationE587C27C" + }, "ServiceRoleArn": { "Fn::GetAtt": [ - "CodeDeployGroupRole9EDBB624", + "CodeDeployGroupRole1D304F7A", "Arn" ] }, diff --git a/packages/@aws-cdk/aws-codepipeline/test/integ.pipeline-code-deploy.ts b/packages/@aws-cdk/aws-codepipeline/test/integ.pipeline-code-deploy.ts index b3346adf3efaf..25630491b79ce 100644 --- a/packages/@aws-cdk/aws-codepipeline/test/integ.pipeline-code-deploy.ts +++ b/packages/@aws-cdk/aws-codepipeline/test/integ.pipeline-code-deploy.ts @@ -1,5 +1,4 @@ import codedeploy = require('@aws-cdk/aws-codedeploy'); -import iam = require('@aws-cdk/aws-iam'); import s3 = require('@aws-cdk/aws-s3'); import cdk = require('@aws-cdk/cdk'); import codepipeline = require('../lib'); @@ -8,19 +7,12 @@ const app = new cdk.App(process.argv); const stack = new cdk.Stack(app, 'aws-cdk-codepipeline-codedeploy'); -new codedeploy.cloudformation.ApplicationResource(stack, 'CodeDeployApplication', { +const application = new codedeploy.ServerApplication(stack, 'CodeDeployApplication', { applicationName: 'IntegTestDeployApp', - computePlatform: 'Server', }); -const deploymentGroupRole = new iam.Role(stack, 'CodeDeployGroupRole', { - assumedBy: new cdk.ServicePrincipal('codedeploy.amazonaws.com'), - managedPolicyArns: ['arn:aws:iam::aws:policy/service-role/AWSCodeDeployRole'], -}); - -new codedeploy.cloudformation.DeploymentGroupResource(stack, 'CodeDeployGroup', { - applicationName: 'IntegTestDeployApp', - serviceRoleArn: deploymentGroupRole.roleArn, +new codedeploy.ServerDeploymentGroup(stack, 'CodeDeployGroup', { + application, deploymentGroupName: 'IntegTestDeploymentGroup', });