diff --git a/docs/src/aws-construct-lib.rst b/docs/src/aws-construct-lib.rst index 9804dc9eb5f24..84c6b4ceb4ca8 100644 --- a/docs/src/aws-construct-lib.rst +++ b/docs/src/aws-construct-lib.rst @@ -39,7 +39,7 @@ function. Furthermore, most AWS Constructs expose ``grant*`` methods which allow intent-based permission definitions. For example, the AWS S3 :py:class:`Bucket <@aws-cdk/aws-s3.Bucket>` -construct has a :py:meth:`grantRead(principal) <@aws-cdk/aws-s3.BucketRef.grantRead>` +construct has a :py:meth:`grantRead(principal) <@aws-cdk/aws-s3.IBucket.grantRead>` method which accepts an AWS IAM :py:class:`Principal <@aws-cdk/aws-iam.IPrincipal>` such as a :py:class:`User <@aws-cdk/aws-iam.User>` or a :py:class:`Role <@aws-cdk/aws-iam.Role>`, and will modify their policy to allow the principal to read objects from the bucket. @@ -52,7 +52,7 @@ Event-Driven APIs Many of the AWS constructs include ``on*`` methods which can be used to react to events emitted by the construct. For example, the AWS CodeCommit :py:mod:`Repository <@aws-cdk/aws-codecommit.Repository>` construct has an -:py:meth:`onCommit <@aws-cdk/aws-codecommit.RepositoryRef.onCommit>` method. +:py:meth:`onCommit <@aws-cdk/aws-codecommit.IRepository.onCommit>` method. AWS Constructs that can be used as targets for various event providers implement interfaces such as :py:mod:`IEventRuleTarget <@aws-cdk/aws-events.IEventRuleTarget>` @@ -84,7 +84,7 @@ Many AWS resources emit AWS CloudWatch metrics as part of their normal operation be used to setup :py:mod:`Alarms <@aws-cdk/aws-cloudwatch.Alarm>` or included in :py:mod:`Dashboards <@aws-cdk/aws-cloudwatch.Dashboard>`. :py:mod:`Metric <@aws-cdk/aws-cloudwatch.Metric>` objects for AWS Constructs can be obtained -via ``metricXxx()`` methods. For example, the :py:meth:`metricDuration() <@aws-cdk/aws-lambda.FunctionRef.metricDuration>` +via ``metricXxx()`` methods. For example, the :py:meth:`metricDuration() <@aws-cdk/aws-lambda.IFunction.metricDuration>` method reports the execution time of an AWS Lambda function. For more information see the :doc:`refs/_aws-cdk_aws-cloudwatch` documentation. @@ -95,12 +95,15 @@ Imports ======= If you need to reference a resource which is defined outside of your CDK app (e.g. a bucket, a VPC, etc), -you can use the ``Xxxx.import(...)`` static methods which are available on AWS Constructs. For example, -the :py:meth:`Bucket.import() <@aws-cdk/aws-s3.BucketRef.import>` method can be used to obtain -a :py:mod:`BucketRef <@aws-cdk/aws-s3.BucketRef>` object which can be used in most places where +you can use the ``Xxxx.import(...)`` static methods which are available on AWS Constructs. + +For example, the :py:meth:`Bucket.import() <@aws-cdk/aws-s3.Bucket.import>` method can be used to obtain +an :py:mod:`IBucket <@aws-cdk/aws-s3.IBucket>` object which can be used in most places where a bucket is required. This patterns allows treating resources defined outside your app as if they were part of your app. + + .. _cloudformation_layer: Access the AWS CloudFormation Layer diff --git a/docs/src/passing-in-data.rst b/docs/src/passing-in-data.rst index 5f146e8a74a36..0a04174b40a02 100644 --- a/docs/src/passing-in-data.rst +++ b/docs/src/passing-in-data.rst @@ -174,15 +174,15 @@ in the stack property. class HelloCdkStack extends cdk.Stack { // Property that defines the stack you are exporting from - public readonly myBucketRefProps: s3.BucketRefProps; + public readonly myBucketAttributes: s3.BucketAttributes; constructor(parent: cdk.App, name: string, props?: cdk.StackProps) { super(parent, name, props); const mybucket = new s3.Bucket(this, "MyFirstBucket"); - // Save bucket's *BucketRefProps* - this.myBucketRefProps = mybucket.export(); + // Save bucket's *BucketAttributes* + this.myBucketAttributes = mybucket.export(); } } @@ -193,7 +193,7 @@ We use this interface to pass the bucket properties between the two stacks. // Interface we'll use to pass the bucket's properties to another stack interface MyCdkStackProps { - theBucketRefProps: s3.BucketRefProps; + theBucketAttributes: s3.BucketAttributes; } Create the second stack that gets a reference to the other bucket @@ -206,7 +206,7 @@ from the properties passed in through the constructor. constructor(parent: cdk.App, name: string, props: MyCdkStackProps) { super(parent, name); - const myOtherBucket = s3.Bucket.import(this, "MyOtherBucket", props.theBucketRefProps); + const myOtherBucket = s3.Bucket.import(this, "MyOtherBucket", props.theBucketAttributes); // Do something with myOtherBucket } @@ -221,7 +221,7 @@ Finally, connect the dots in your app. const myStack = new HelloCdkStack(app, "HelloCdkStack"); new MyCdkStack(app, "MyCdkStack", { - theBucketRefProps: myStack.myBucketRefProps + theBucketAttributes: myStack.myBucketAttributes }); app.run(); diff --git a/examples/cdk-examples-typescript/bucket-import-export/index.ts b/examples/cdk-examples-typescript/bucket-import-export/index.ts index ca3139123773b..32ecea2465819 100644 --- a/examples/cdk-examples-typescript/bucket-import-export/index.ts +++ b/examples/cdk-examples-typescript/bucket-import-export/index.ts @@ -3,11 +3,11 @@ import s3 = require('@aws-cdk/aws-s3'); import cdk = require('@aws-cdk/cdk'); // Define a stack with an S3 bucket and export it using `bucket.export()`. -// bucket.export returns a `BucketRef` object which can later be used in +// bucket.export returns an `IBucket` object which can later be used in // `Bucket.import`. class Producer extends cdk.Stack { - public readonly myBucketRef: s3.BucketRefProps; + public readonly myBucketRef: s3.BucketImportProps; constructor(parent: cdk.App, name: string) { super(parent, name); @@ -18,7 +18,7 @@ class Producer extends cdk.Stack { } interface ConsumerConstructProps { - bucket: s3.BucketRef; + bucket: s3.IBucket; } class ConsumerConstruct extends cdk.Construct { @@ -29,13 +29,13 @@ class ConsumerConstruct extends cdk.Construct { } } -// Define a stack that requires a BucketRef as an input and uses `Bucket.import` +// Define a stack that requires an IBucket as an input and uses `Bucket.import` // to create a `Bucket` object that represents this external bucket. Grant a // user principal created within this consuming stack read/write permissions to // this bucket and contents. interface ConsumerProps { - userBucketRef: s3.BucketRefProps; + userBucketRef: s3.BucketImportProps; } class Consumer extends cdk.Stack { diff --git a/examples/cdk-examples-typescript/chat-app/index.ts b/examples/cdk-examples-typescript/chat-app/index.ts index 98b2d31d1f69b..e2cad596456aa 100644 --- a/examples/cdk-examples-typescript/chat-app/index.ts +++ b/examples/cdk-examples-typescript/chat-app/index.ts @@ -12,7 +12,7 @@ class MyStack extends cdk.Stack { new CognitoChatRoomPool(this, 'UserPool'); - const bucket = s3.BucketRef.import(this, 'DougsBucket', { + const bucket = s3.Bucket.import(this, 'DougsBucket', { bucketName: 'dougs-chat-app' }); @@ -69,7 +69,7 @@ class MyStack extends cdk.Stack { } interface ChatAppFuncProps { - bucket: s3.BucketRef; + bucket: s3.IBucket; zipFile: string; } diff --git a/examples/cdk-examples-typescript/ec2/index.ts b/examples/cdk-examples-typescript/ec2/index.ts index 4d54db5723741..a94323c79e0af 100644 --- a/examples/cdk-examples-typescript/ec2/index.ts +++ b/examples/cdk-examples-typescript/ec2/index.ts @@ -52,7 +52,7 @@ class MyApp extends cdk.Stack { } class CommonInfrastructure extends cdk.Stack { - public vpc: ec2.VpcNetworkRefProps; + public vpc: ec2.VpcNetworkImportProps; constructor(parent: cdk.App, name: string, props?: cdk.StackProps) { super(parent, name, props); diff --git a/examples/cdk-examples-typescript/use-vpc-from-another-stack/index.ts b/examples/cdk-examples-typescript/use-vpc-from-another-stack/index.ts index af3e7df400718..212891ad6c70a 100644 --- a/examples/cdk-examples-typescript/use-vpc-from-another-stack/index.ts +++ b/examples/cdk-examples-typescript/use-vpc-from-another-stack/index.ts @@ -17,7 +17,7 @@ const exportedVpc = new ec2.VpcNetwork(vpcStack, 'VPC', { const appStack = new cdk.Stack(app, 'AppStack'); -const importedVpc = ec2.VpcNetworkRef.import(appStack, 'VPC', exportedVpc.export()); +const importedVpc = ec2.VpcNetwork.import(appStack, 'VPC', exportedVpc.export()); const asg = new autoscaling.AutoScalingGroup(appStack, 'ASG', { vpc: importedVpc, diff --git a/packages/@aws-cdk/assets-docker/lib/adopted-repository.ts b/packages/@aws-cdk/assets-docker/lib/adopted-repository.ts index 3467bd8a94510..49fe6bfcce726 100644 --- a/packages/@aws-cdk/assets-docker/lib/adopted-repository.ts +++ b/packages/@aws-cdk/assets-docker/lib/adopted-repository.ts @@ -29,7 +29,7 @@ export class AdoptedRepository extends ecr.RepositoryBase { private readonly policyDocument = new iam.PolicyDocument(); - constructor(parent: cdk.Construct, id: string, props: AdoptedRepositoryProps) { + constructor(parent: cdk.Construct, id: string, private readonly props: AdoptedRepositoryProps) { super(parent, id); const fn = new lambda.SingletonFunction(this, 'Function', { @@ -70,6 +70,13 @@ export class AdoptedRepository extends ecr.RepositoryBase { this.repositoryArn = ecr.Repository.arnForLocalRepository(this.repositoryName); } + /** + * Export this repository from the stack + */ + public export() { + return this.props; + } + /** * Adds a statement to the repository resource policy. * diff --git a/packages/@aws-cdk/assets/lib/asset.ts b/packages/@aws-cdk/assets/lib/asset.ts index c20f87265d35f..ff047f80ee4ad 100644 --- a/packages/@aws-cdk/assets/lib/asset.ts +++ b/packages/@aws-cdk/assets/lib/asset.ts @@ -68,7 +68,7 @@ export class Asset extends cdk.Construct { /** * The S3 bucket in which this asset resides. */ - public readonly bucket: s3.BucketRef; + public readonly bucket: s3.IBucket; /** * Indicates if this asset is a zip archive. Allows constructs to ensure that the @@ -114,7 +114,7 @@ export class Asset extends cdk.Construct { const s3Filename = cdk.Fn.select(1, cdk.Fn.split(cxapi.ASSET_PREFIX_SEPARATOR, keyParam.valueAsString)).toString(); this.s3ObjectKey = `${this.s3Prefix}${s3Filename}`; - this.bucket = s3.BucketRef.import(this, 'AssetBucket', { + this.bucket = s3.Bucket.import(this, 'AssetBucket', { bucketName: this.s3BucketName }); diff --git a/packages/@aws-cdk/aws-apigateway/lib/deployment.ts b/packages/@aws-cdk/aws-apigateway/lib/deployment.ts index e5a371650e141..b4b04159f952b 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/deployment.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/deployment.ts @@ -1,13 +1,13 @@ import cdk = require('@aws-cdk/cdk'); import crypto = require('crypto'); import { CfnDeployment, CfnDeploymentProps } from './apigateway.generated'; -import { RestApiRef } from './restapi-ref'; +import { IRestApi } from './restapi'; export interface DeploymentProps { /** * The Rest API to deploy. */ - api: RestApiRef; + api: IRestApi; /** * A description of the purpose of the API Gateway deployment. @@ -56,7 +56,7 @@ export interface DeploymentProps { */ export class Deployment extends cdk.Construct implements cdk.IDependable { public readonly deploymentId: string; - public readonly api: RestApiRef; + public readonly api: IRestApi; /** * Allows taking a dependency on this construct. diff --git a/packages/@aws-cdk/aws-apigateway/lib/index.ts b/packages/@aws-cdk/aws-apigateway/lib/index.ts index b36594885a3d4..4cce185dd3fe0 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/index.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/index.ts @@ -1,5 +1,4 @@ export * from './restapi'; -export * from './restapi-ref'; export * from './resource'; export * from './method'; export * from './integration'; diff --git a/packages/@aws-cdk/aws-apigateway/lib/integrations/lambda.ts b/packages/@aws-cdk/aws-apigateway/lib/integrations/lambda.ts index 72dde50ef2f1e..1970b71923455 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/integrations/lambda.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/integrations/lambda.ts @@ -34,10 +34,10 @@ export interface LambdaIntegrationOptions extends IntegrationOptions { * */ export class LambdaIntegration extends AwsIntegration { - private readonly handler: lambda.FunctionRef; + private readonly handler: lambda.IFunction; private readonly enableTest: boolean; - constructor(handler: lambda.FunctionRef, options: LambdaIntegrationOptions = { }) { + constructor(handler: lambda.IFunction, options: LambdaIntegrationOptions = { }) { const proxy = options.proxy === undefined ? true : options.proxy; super({ diff --git a/packages/@aws-cdk/aws-apigateway/lib/method.ts b/packages/@aws-cdk/aws-apigateway/lib/method.ts index efc39df09f01d..711abf00c2d56 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/method.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/method.ts @@ -23,7 +23,7 @@ export interface MethodOptions { * If `authorizationType` is `Custom`, this specifies the ID of the method * authorizer resource. * - * NOTE: in the future this will be replaced with an `AuthorizerRef` + * NOTE: in the future this will be replaced with an `IAuthorizer` * construct. */ authorizerId?: string; diff --git a/packages/@aws-cdk/aws-apigateway/lib/restapi-ref.ts b/packages/@aws-cdk/aws-apigateway/lib/restapi-ref.ts index 37f0af148f620..e69de29bb2d1d 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/restapi-ref.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/restapi-ref.ts @@ -1,46 +0,0 @@ -import cdk = require('@aws-cdk/cdk'); - -export interface RestApiRefProps { - /** - * The REST API ID of an existing REST API resource. - */ - restApiId: string; -} - -export abstract class RestApiRef extends cdk.Construct { - - /** - * Imports an existing REST API resource. - * @param parent Parent construct - * @param id Construct ID - * @param props Imported rest API properties - */ - public static import(parent: cdk.Construct, id: string, props: RestApiRefProps): RestApiRef { - return new ImportedRestApi(parent, id, props); - } - - /** - * The ID of this API Gateway RestApi. - */ - public readonly abstract restApiId: string; - - /** - * Exports a REST API resource from this stack. - * @returns REST API props that can be imported to another stack. - */ - public export(): RestApiRefProps { - return { - restApiId: new cdk.Output(this, 'RestApiId', { value: this.restApiId }).makeImportValue().toString() - }; - } -} - -class ImportedRestApi extends RestApiRef { - public restApiId: string; - - constructor(parent: cdk.Construct, id: string, props: RestApiRefProps) { - super(parent, id); - - this.restApiId = props.restApiId; - } -} diff --git a/packages/@aws-cdk/aws-apigateway/lib/restapi.ts b/packages/@aws-cdk/aws-apigateway/lib/restapi.ts index e5ea1172c130b..35304e1b88766 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/restapi.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/restapi.ts @@ -5,9 +5,28 @@ import { Deployment } from './deployment'; import { Integration } from './integration'; import { Method, MethodOptions } from './method'; import { IRestApiResource, ProxyResource, Resource, ResourceOptions } from './resource'; -import { RestApiRef } from './restapi-ref'; import { Stage, StageOptions } from './stage'; +export interface RestApiImportProps { + /** + * The REST API ID of an existing REST API resource. + */ + restApiId: string; +} + +export interface IRestApi { + /** + * The ID of this API Gateway RestApi. + */ + readonly restApiId: string; + + /** + * Exports a REST API resource from this stack. + * @returns REST API props that can be imported to another stack. + */ + export(): RestApiImportProps; +} + export interface RestApiProps extends ResourceOptions { /** * Indicates if a Deployment should be automatically created for this API, @@ -118,7 +137,7 @@ export interface RestApiProps extends ResourceOptions { /** * The ID of the API Gateway RestApi resource that you want to clone. */ - cloneFrom?: RestApiRef; + cloneFrom?: IRestApi; /** * Automatically configure an AWS CloudWatch role for API Gateway. @@ -135,7 +154,17 @@ export interface RestApiProps extends ResourceOptions { * By default, the API will automatically be deployed and accessible from a * public endpoint. */ -export class RestApi extends RestApiRef implements cdk.IDependable { +export class RestApi extends cdk.Construct implements cdk.IDependable, IRestApi { + /** + * Imports an existing REST API resource. + * @param parent Parent construct + * @param id Construct ID + * @param props Imported rest API properties + */ + public static import(parent: cdk.Construct, id: string, props: RestApiImportProps): IRestApi { + return new ImportedRestApi(parent, id, props); + } + /** * The ID of this API Gateway RestApi. */ @@ -224,6 +253,16 @@ export class RestApi extends RestApiRef implements cdk.IDependable { }; } + /** + * Exports a REST API resource from this stack. + * @returns REST API props that can be imported to another stack. + */ + public export(): RestApiImportProps { + return { + restApiId: new cdk.Output(this, 'RestApiId', { value: this.restApiId }).makeImportValue().toString() + }; + } + /** * The deployed root URL of this REST API. */ @@ -366,3 +405,17 @@ export enum EndpointType { } export class RestApiUrl extends cdk.CloudFormationToken { } + +class ImportedRestApi extends cdk.Construct implements IRestApi { + public restApiId: string; + + constructor(parent: cdk.Construct, id: string, private readonly props: RestApiImportProps) { + super(parent, id); + + this.restApiId = props.restApiId; + } + + public export() { + return this.props; + } +} diff --git a/packages/@aws-cdk/aws-apigateway/lib/stage.ts b/packages/@aws-cdk/aws-apigateway/lib/stage.ts index a2bac5bf90e2b..7f6970772e3e7 100644 --- a/packages/@aws-cdk/aws-apigateway/lib/stage.ts +++ b/packages/@aws-cdk/aws-apigateway/lib/stage.ts @@ -1,7 +1,7 @@ import cdk = require('@aws-cdk/cdk'); import { CfnStage } from './apigateway.generated'; import { Deployment } from './deployment'; -import { RestApiRef } from './restapi-ref'; +import { IRestApi } from './restapi'; import { parseMethodOptionsPath } from './util'; export interface StageOptions extends MethodDeploymentOptions { @@ -130,7 +130,7 @@ export class Stage extends cdk.Construct implements cdk.IDependable { public readonly stageName: string; public readonly dependencyElements = new Array(); - private readonly restApi: RestApiRef; + private readonly restApi: IRestApi; constructor(parent: cdk.Construct, id: string, props: StageProps) { super(parent, id); diff --git a/packages/@aws-cdk/aws-apigateway/test/test.restapi.ts b/packages/@aws-cdk/aws-apigateway/test/test.restapi.ts index c15df7a2b486e..b6531ae26f0b2 100644 --- a/packages/@aws-cdk/aws-apigateway/test/test.restapi.ts +++ b/packages/@aws-cdk/aws-apigateway/test/test.restapi.ts @@ -379,20 +379,20 @@ export = { const imported = apigateway.RestApi.import(stack, 'imported-api', { restApiId: 'api-rxt4498f' }); - const exported = imported.export(); + + const api = new apigateway.RestApi(stack, 'MyRestApi'); + api.root.addMethod('GET'); + + const exported = api.export(); // THEN - expect(stack).toMatch({ - Outputs: { - importedapiRestApiIdC00F155A: { - Value: "api-rxt4498f", - Export: { - Name: "importedapiRestApiIdC00F155A" - } - } - } + stack.validateTree(); + test.deepEqual(stack.toCloudFormation().Outputs.MyRestApiRestApiIdB93C5C2D, { + Value: { Ref: 'MyRestApi2D1F47A9' }, + Export: { Name: 'MyRestApiRestApiIdB93C5C2D' } }); - test.deepEqual(cdk.resolve(exported), { restApiId: { 'Fn::ImportValue': 'importedapiRestApiIdC00F155A' } }); + test.deepEqual(cdk.resolve(imported.restApiId), 'api-rxt4498f'); + test.deepEqual(cdk.resolve(exported), { restApiId: { 'Fn::ImportValue': 'MyRestApiRestApiIdB93C5C2D' } }); test.done(); }, diff --git a/packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts b/packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts index 5a91728d53d70..e1b926d6d240b 100644 --- a/packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts +++ b/packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts @@ -60,7 +60,7 @@ export interface AutoScalingGroupProps { /** * VPC to launch these instances in. */ - vpc: ec2.VpcNetworkRef; + vpc: ec2.IVpcNetwork; /** * Where to place instances within the VPC @@ -71,7 +71,7 @@ export interface AutoScalingGroupProps { * SNS topic to send notifications about fleet changes * @default No fleet change notifications will be sent. */ - notificationsTopic?: sns.TopicRef; + notificationsTopic?: sns.ITopic; /** * Whether the instances can initiate connections to anywhere by default @@ -190,8 +190,8 @@ export class AutoScalingGroup extends cdk.Construct implements IAutoScalingGroup private readonly userDataLines = new Array(); private readonly autoScalingGroup: CfnAutoScalingGroup; - private readonly securityGroup: ec2.SecurityGroupRef; - private readonly securityGroups: ec2.SecurityGroupRef[] = []; + private readonly securityGroup: ec2.ISecurityGroup; + private readonly securityGroups: ec2.ISecurityGroup[] = []; private readonly loadBalancerNames: string[] = []; private readonly targetGroupArns: string[] = []; private albTargetGroup?: elbv2.ApplicationTargetGroup; @@ -285,9 +285,9 @@ export class AutoScalingGroup extends cdk.Construct implements IAutoScalingGroup * Add the security group to all instances via the launch configuration * security groups array. * - * @param securityGroup: The SecurityGroupRef to add + * @param securityGroup: The security group to add */ - public addSecurityGroup(securityGroup: ec2.SecurityGroupRef): void { + public addSecurityGroup(securityGroup: ec2.ISecurityGroup): void { this.securityGroups.push(securityGroup); } diff --git a/packages/@aws-cdk/aws-autoscaling/test/test.auto-scaling-group.ts b/packages/@aws-cdk/aws-autoscaling/test/test.auto-scaling-group.ts index 5186e6e6eae36..a4dbb1bf20aed 100644 --- a/packages/@aws-cdk/aws-autoscaling/test/test.auto-scaling-group.ts +++ b/packages/@aws-cdk/aws-autoscaling/test/test.auto-scaling-group.ts @@ -417,7 +417,7 @@ function mockVpc(stack: cdk.Stack) { } function mockSecurityGroup(stack: cdk.Stack) { - return ec2.SecurityGroupRef.import(stack, 'MySG', { + return ec2.SecurityGroup.import(stack, 'MySG', { securityGroupId: 'most-secure', }); } diff --git a/packages/@aws-cdk/aws-certificatemanager/lib/certificate-ref.ts b/packages/@aws-cdk/aws-certificatemanager/lib/certificate-ref.ts deleted file mode 100644 index c0aa51dd3c872..0000000000000 --- a/packages/@aws-cdk/aws-certificatemanager/lib/certificate-ref.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { Construct, Output } from "@aws-cdk/cdk"; - -/** - * Interface for certificate-like objects - */ -export abstract class CertificateRef extends Construct { - /** - * Import a certificate - */ - public static import(parent: Construct, name: string, props: CertificateRefProps): CertificateRef { - return new ImportedCertificate(parent, name, props); - } - - public abstract readonly certificateArn: string; - - /** - * Export this certificate from the stack - */ - public export(): CertificateRefProps { - return { - certificateArn: new Output(this, 'Arn', { value: this.certificateArn }).makeImportValue().toString() - }; - } -} - -/** - * A Certificate that has been imported from another stack - */ -class ImportedCertificate extends CertificateRef { - public readonly certificateArn: string; - - constructor(parent: Construct, name: string, props: CertificateRefProps) { - super(parent, name); - - this.certificateArn = props.certificateArn; - } -} - -/** - * Reference to an existing Certificate - */ -export interface CertificateRefProps { - /** - * The certificate's ARN - */ - certificateArn: string; -} diff --git a/packages/@aws-cdk/aws-certificatemanager/lib/certificate.ts b/packages/@aws-cdk/aws-certificatemanager/lib/certificate.ts index c3fac839df84f..32acc34ae7cd0 100644 --- a/packages/@aws-cdk/aws-certificatemanager/lib/certificate.ts +++ b/packages/@aws-cdk/aws-certificatemanager/lib/certificate.ts @@ -1,8 +1,29 @@ -import { Construct } from '@aws-cdk/cdk'; -import { CertificateRef } from './certificate-ref'; +import { Construct, Output } from '@aws-cdk/cdk'; import { CfnCertificate } from './certificatemanager.generated'; import { apexDomain } from './util'; +export interface ICertificate { + /** + * The certificate's ARN + */ + readonly certificateArn: string; + + /** + * Export this certificate from the stack + */ + export(): CertificateImportProps; +} + +/** + * Reference to an existing Certificate + */ +export interface CertificateImportProps { + /** + * The certificate's ARN + */ + certificateArn: string; +} + /** * Properties for your certificate */ @@ -48,7 +69,14 @@ export interface CertificateProps { * * For every domain that you register. */ -export class Certificate extends CertificateRef { +export class Certificate extends Construct implements ICertificate { + /** + * Import a certificate + */ + public static import(parent: Construct, name: string, props: CertificateImportProps): ICertificate { + return new ImportedCertificate(parent, name, props); + } + /** * The certificate's ARN */ @@ -81,4 +109,29 @@ export class Certificate extends CertificateRef { } } + /** + * Export this certificate from the stack + */ + public export(): CertificateImportProps { + return { + certificateArn: new Output(this, 'Arn', { value: this.certificateArn }).makeImportValue().toString() + }; + } +} + +/** + * A Certificate that has been imported from another stack + */ +class ImportedCertificate extends Construct implements ICertificate { + public readonly certificateArn: string; + + constructor(parent: Construct, name: string, private readonly props: CertificateImportProps) { + super(parent, name); + + this.certificateArn = props.certificateArn; + } + + public export() { + return this.props; + } } diff --git a/packages/@aws-cdk/aws-certificatemanager/lib/index.ts b/packages/@aws-cdk/aws-certificatemanager/lib/index.ts index 758cc2f3e0b24..50873fe8ee56f 100644 --- a/packages/@aws-cdk/aws-certificatemanager/lib/index.ts +++ b/packages/@aws-cdk/aws-certificatemanager/lib/index.ts @@ -1,5 +1,4 @@ export * from './certificate'; -export * from './certificate-ref'; // AWS::CertificateManager CloudFormation Resources: export * from './certificatemanager.generated'; diff --git a/packages/@aws-cdk/aws-certificatemanager/test/test.certificate.ts b/packages/@aws-cdk/aws-certificatemanager/test/test.certificate.ts index b7cbadc90d752..b8237a6708cb8 100644 --- a/packages/@aws-cdk/aws-certificatemanager/test/test.certificate.ts +++ b/packages/@aws-cdk/aws-certificatemanager/test/test.certificate.ts @@ -1,7 +1,7 @@ import { expect, haveResource } from '@aws-cdk/assert'; import { Stack } from '@aws-cdk/cdk'; import { Test } from 'nodeunit'; -import { Certificate, CertificateRef } from '../lib'; +import { Certificate } from '../lib'; export = { 'apex domain selection by default'(test: Test) { @@ -49,7 +49,7 @@ export = { domainName: 'hello.com', }).export(); - CertificateRef.import(stack, 'Imported', refProps); + Certificate.import(stack, 'Imported', refProps); test.done(); } diff --git a/packages/@aws-cdk/aws-cloudformation/lib/custom-resource.ts b/packages/@aws-cdk/aws-cloudformation/lib/custom-resource.ts index 475ba73f8afa5..656cf77e13387 100644 --- a/packages/@aws-cdk/aws-cloudformation/lib/custom-resource.ts +++ b/packages/@aws-cdk/aws-cloudformation/lib/custom-resource.ts @@ -19,14 +19,14 @@ export interface CustomResourceProps { * * Optional, exactly one of lamdaProvider or topicProvider must be set. */ - lambdaProvider?: lambda.FunctionRef; + lambdaProvider?: lambda.IFunction; /** * The SNS Topic for the provider that implements this custom resource. * * Optional, exactly one of lamdaProvider or topicProvider must be set. */ - topicProvider?: sns.TopicRef; + topicProvider?: sns.ITopic; /** * Properties to pass to the Lambda diff --git a/packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts b/packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts index e5b15fddd4721..cd75a92c2e7a0 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts @@ -110,7 +110,7 @@ export interface LoggingConfiguration { * * @default A logging bucket is automatically created */ - readonly bucket?: s3.BucketRef, + readonly bucket?: s3.IBucket, /** * Whether to include the cookies in the logs @@ -489,7 +489,7 @@ export class CloudFrontWebDistribution extends cdk.Construct implements route53. * The logging bucket for this CloudFront distribution. * If logging is not enabled for this distribution - this property will be undefined. */ - public readonly loggingBucket?: s3.BucketRef; + public readonly loggingBucket?: s3.IBucket; /** * The domain name created by CloudFront for this distribution. diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-alias-target.ts b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-alias-target.ts index 1f15c3408a374..f7629bdfe774a 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-alias-target.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-alias-target.ts @@ -25,6 +25,7 @@ const distribution = new cloudfront.CloudFrontWebDistribution(stack, 'MyDistribu }); new route53.AliasRecord(zone, 'Alias', { + zone, recordName: '_foo', target: distribution }); diff --git a/packages/@aws-cdk/aws-cloudtrail/lib/index.ts b/packages/@aws-cdk/aws-cloudtrail/lib/index.ts index cdbe5749261cd..07d9f8dcd5d8f 100644 --- a/packages/@aws-cdk/aws-cloudtrail/lib/index.ts +++ b/packages/@aws-cdk/aws-cloudtrail/lib/index.ts @@ -65,7 +65,7 @@ export interface CloudTrailProps { /** The AWS Key Management Service (AWS KMS) key ID that you want to use to encrypt CloudTrail logs. * @default none */ - kmsKey?: kms.EncryptionKeyRef; + kmsKey?: kms.IEncryptionKey; /** The name of an Amazon SNS topic that is notified when new log files are published. * @default none diff --git a/packages/@aws-cdk/aws-codebuild/lib/artifacts.ts b/packages/@aws-cdk/aws-codebuild/lib/artifacts.ts index c7302042d946c..e8d44528bf015 100644 --- a/packages/@aws-cdk/aws-codebuild/lib/artifacts.ts +++ b/packages/@aws-cdk/aws-codebuild/lib/artifacts.ts @@ -79,7 +79,7 @@ export interface S3BucketBuildArtifactsProps extends BuildArtifactsProps { /** * The name of the output bucket. */ - bucket: s3.BucketRef; + bucket: s3.IBucket; /** * The path inside of the bucket for the build output .zip file or folder. diff --git a/packages/@aws-cdk/aws-codebuild/lib/pipeline-actions.ts b/packages/@aws-cdk/aws-codebuild/lib/pipeline-actions.ts index 368bb68eadcdc..721e402147dc0 100644 --- a/packages/@aws-cdk/aws-codebuild/lib/pipeline-actions.ts +++ b/packages/@aws-cdk/aws-codebuild/lib/pipeline-actions.ts @@ -1,7 +1,7 @@ import codepipeline = require('@aws-cdk/aws-codepipeline-api'); import iam = require('@aws-cdk/aws-iam'); import cdk = require('@aws-cdk/cdk'); -import { ProjectRef } from './project'; +import { IProject } from './project'; /** * Common construction properties of all CodeBuild Pipeline Actions. @@ -23,7 +23,7 @@ export interface CommonCodeBuildActionProps { /** * Common properties for creating {@link PipelineBuildAction} - * either directly, through its constructor, - * or through {@link ProjectRef#addToPipeline}. + * or through {@link IProject#addToPipeline}. */ export interface CommonPipelineBuildActionProps extends CommonCodeBuildActionProps, codepipeline.CommonActionProps { @@ -50,7 +50,7 @@ export interface PipelineBuildActionProps extends CommonPipelineBuildActionProps /** * The build project */ - project: ProjectRef; + project: IProject; } /** @@ -109,7 +109,7 @@ export class PipelineBuildAction extends codepipeline.BuildAction { /** * Common properties for creating {@link PipelineTestAction} - * either directly, through its constructor, - * or through {@link ProjectRef#addToPipelineAsTest}. + * or through {@link IProject#addToPipelineAsTest}. */ export interface CommonPipelineTestActionProps extends CommonCodeBuildActionProps, codepipeline.CommonActionProps { @@ -139,7 +139,7 @@ export interface PipelineTestActionProps extends CommonPipelineTestActionProps, /** * The build Project. */ - project: ProjectRef; + project: IProject; } export class PipelineTestAction extends codepipeline.TestAction { @@ -192,7 +192,7 @@ export class PipelineTestAction extends codepipeline.TestAction { } } -function setCodeBuildNeededPermissions(stage: codepipeline.IStage, project: ProjectRef, +function setCodeBuildNeededPermissions(stage: codepipeline.IStage, project: IProject, needsPipelineBucketWrite: boolean) { // grant the Pipeline role the required permissions to this Project stage.pipeline.role.addToPolicy(new iam.PolicyStatement() diff --git a/packages/@aws-cdk/aws-codebuild/lib/project.ts b/packages/@aws-cdk/aws-codebuild/lib/project.ts index 4ce51ac2412e0..a3021c83ae132 100644 --- a/packages/@aws-cdk/aws-codebuild/lib/project.ts +++ b/packages/@aws-cdk/aws-codebuild/lib/project.ts @@ -20,13 +20,150 @@ const CODEPIPELINE_TYPE = 'CODEPIPELINE'; const S3_BUCKET_ENV = 'SCRIPT_S3_BUCKET'; const S3_KEY_ENV = 'SCRIPT_S3_KEY'; +export interface IProject extends events.IEventRuleTarget { + /** The ARN of this Project. */ + readonly projectArn: string; + + /** The human-visible name of this Project. */ + readonly projectName: string; + + /** The IAM service Role of this Project. Undefined for imported Projects. */ + readonly role?: iam.Role; + + /** + * Convenience method for creating a new {@link PipelineBuildAction} build Action, + * and adding it to the given Stage. + * + * @param stage the Pipeline Stage to add the new Action to + * @param name the name of the newly created Action + * @param props the properties of the new Action + * @returns the newly created {@link PipelineBuildAction} build Action + */ + addToPipeline(stage: codepipeline.IStage, name: string, props?: CommonPipelineBuildActionProps): PipelineBuildAction; + + /** + * Convenience method for creating a new {@link PipelineTestAction} test Action, + * and adding it to the given Stage. + * + * @param stage the Pipeline Stage to add the new Action to + * @param name the name of the newly created Action + * @param props the properties of the new Action + * @returns the newly created {@link PipelineBuildAction} test Action + */ + addToPipelineAsTest(stage: codepipeline.IStage, name: string, props?: CommonPipelineTestActionProps): PipelineTestAction; + + /** + * Defines a CloudWatch event rule triggered when the build project state + * changes. You can filter specific build status events using an event + * pattern filter on the `build-status` detail field: + * + * const rule = project.onStateChange('OnBuildStarted', target); + * rule.addEventPattern({ + * detail: { + * 'build-status': [ + * "IN_PROGRESS", + * "SUCCEEDED", + * "FAILED", + * "STOPPED" + * ] + * } + * }); + * + * You can also use the methods `onBuildFailed` and `onBuildSucceeded` to define rules for + * these specific state changes. + * + * @see https://docs.aws.amazon.com/codebuild/latest/userguide/sample-build-notifications.html + */ + onStateChange(name: string, target?: events.IEventRuleTarget, options?: events.EventRuleProps): events.EventRule; + + /** + * Defines a CloudWatch event rule that triggers upon phase change of this + * build project. + * + * @see https://docs.aws.amazon.com/codebuild/latest/userguide/sample-build-notifications.html + */ + onPhaseChange(name: string, target?: events.IEventRuleTarget, options?: events.EventRuleProps): events.EventRule; + + /** + * Defines an event rule which triggers when a build starts. + */ + onBuildStarted(name: string, target?: events.IEventRuleTarget, options?: events.EventRuleProps): events.EventRule; + + /** + * Defines an event rule which triggers when a build fails. + */ + onBuildFailed(name: string, target?: events.IEventRuleTarget, options?: events.EventRuleProps): events.EventRule; + + /** + * Defines an event rule which triggers when a build completes successfully. + */ + onBuildSucceeded(name: string, target?: events.IEventRuleTarget, options?: events.EventRuleProps): events.EventRule; + + /** + * @returns a CloudWatch metric associated with this build project. + * @param metricName The name of the metric + * @param props Customization properties + */ + metric(metricName: string, props: cloudwatch.MetricCustomization): cloudwatch.Metric; + + /** + * Measures the number of builds triggered. + * + * Units: Count + * + * Valid CloudWatch statistics: Sum + * + * @default sum over 5 minutes + */ + metricBuilds(props?: cloudwatch.MetricCustomization): cloudwatch.Metric; + + /** + * Measures the duration of all builds over time. + * + * Units: Seconds + * + * Valid CloudWatch statistics: Average (recommended), Maximum, Minimum + * + * @default average over 5 minutes + */ + metricDuration(props?: cloudwatch.MetricCustomization): cloudwatch.Metric; + + /** + * Measures the number of successful builds. + * + * Units: Count + * + * Valid CloudWatch statistics: Sum + * + * @default sum over 5 minutes + */ + metricSucceededBuilds(props?: cloudwatch.MetricCustomization): cloudwatch.Metric; + + /** + * Measures the number of builds that failed because of client error or + * because of a timeout. + * + * Units: Count + * + * Valid CloudWatch statistics: Sum + * + * @default sum over 5 minutes + */ + metricFailedBuilds(props?: cloudwatch.MetricCustomization): cloudwatch.Metric; + + /** + * Export this Project. Allows referencing this Project in a different CDK Stack. + */ + export(): ProjectImportProps; +} + /** * Properties of a reference to a CodeBuild Project. * - * @see ProjectRef.import - * @see ProjectRef.export + * @see Project.import + * @see Project.export */ -export interface ProjectRefProps { +export interface ProjectImportProps { /** * The human-readable name of the CodeBuild Project we're referencing. * The Project must be in the same account and region as the root Stack. @@ -44,26 +181,7 @@ export interface ProjectRefProps { * (or one defined in a different CDK Stack), * use the {@link import} method. */ -export abstract class ProjectRef extends cdk.Construct implements events.IEventRuleTarget { - /** - * Import a Project defined either outside the CDK, - * or in a different CDK Stack - * (and exported using the {@link export} method). - * - * @note if you're importing a CodeBuild Project for use - * in a CodePipeline, make sure the existing Project - * has permissions to access the S3 Bucket of that Pipeline - - * otherwise, builds in that Pipeline will always fail. - * - * @param parent the parent Construct for this Construct - * @param name the logical name of this Construct - * @param props the properties of the referenced Project - * @returns a reference to the existing Project - */ - public static import(parent: cdk.Construct, name: string, props: ProjectRefProps): ProjectRef { - return new ImportedProjectRef(parent, name, props); - } - +export abstract class ProjectBase extends cdk.Construct implements IProject { /** The ARN of this Project. */ public abstract readonly projectArn: string; @@ -76,14 +194,7 @@ export abstract class ProjectRef extends cdk.Construct implements events.IEventR /** A role used by CloudWatch events to trigger a build */ private eventsRole?: iam.Role; - /** - * Export this Project. Allows referencing this Project in a different CDK Stack. - */ - public export(): ProjectRefProps { - return { - projectName: new cdk.Output(this, 'ProjectName', { value: this.projectName }).makeImportValue().toString(), - }; - } + public abstract export(): ProjectImportProps; /** * Convenience method for creating a new {@link PipelineBuildAction} build Action, @@ -317,12 +428,12 @@ export abstract class ProjectRef extends cdk.Construct implements events.IEventR } } -class ImportedProjectRef extends ProjectRef { +class ImportedProject extends ProjectBase { public readonly projectArn: string; public readonly projectName: string; public readonly role?: iam.Role = undefined; - constructor(parent: cdk.Construct, name: string, props: ProjectRefProps) { + constructor(parent: cdk.Construct, name: string, private readonly props: ProjectImportProps) { super(parent, name); this.projectArn = cdk.ArnUtils.fromComponents({ @@ -333,6 +444,10 @@ class ImportedProjectRef extends ProjectRef { this.projectName = props.projectName; } + + public export() { + return this.props; + } } export interface CommonProjectProps { @@ -378,13 +493,13 @@ export interface CommonProjectProps { * Encryption key to use to read and write artifacts * If not specified, a role will be created. */ - encryptionKey?: kms.EncryptionKeyRef; + encryptionKey?: kms.IEncryptionKey; /** * Bucket to store cached source artifacts * If not specified, source artifacts will not be cached. */ - cacheBucket?: s3.BucketRef; + cacheBucket?: s3.IBucket; /** * Subdirectory to store cached artifacts @@ -461,7 +576,26 @@ export interface ProjectProps extends CommonProjectProps { /** * A representation of a CodeBuild Project. */ -export class Project extends ProjectRef { +export class Project extends ProjectBase { + /** + * Import a Project defined either outside the CDK, + * or in a different CDK Stack + * (and exported using the {@link export} method). + * + * @note if you're importing a CodeBuild Project for use + * in a CodePipeline, make sure the existing Project + * has permissions to access the S3 Bucket of that Pipeline - + * otherwise, builds in that Pipeline will always fail. + * + * @param parent the parent Construct for this Construct + * @param name the logical name of this Construct + * @param props the properties of the referenced Project + * @returns a reference to the existing Project + */ + public static import(parent: cdk.Construct, name: string, props: ProjectImportProps): IProject { + return new ImportedProject(parent, name, props); + } + /** * The IAM role for this project. */ @@ -589,6 +723,15 @@ export class Project extends ProjectRef { return ret; } + /** + * Export this Project. Allows referencing this Project in a different CDK Stack. + */ + public export(): ProjectImportProps { + return { + projectName: new cdk.Output(this, 'ProjectName', { value: this.projectName }).makeImportValue().toString(), + }; + } + /** * Add a permission only if there's a policy attached. * @param statement The permissions statement to add diff --git a/packages/@aws-cdk/aws-codebuild/lib/source.ts b/packages/@aws-cdk/aws-codebuild/lib/source.ts index 3d06591b38c23..c0ff41efb3a43 100644 --- a/packages/@aws-cdk/aws-codebuild/lib/source.ts +++ b/packages/@aws-cdk/aws-codebuild/lib/source.ts @@ -75,7 +75,7 @@ export class NoSource extends BuildSource { * Construction properties for {@link CodeCommitSource}. */ export interface CodeCommitSourceProps extends BuildSourceProps { - repository: codecommit.RepositoryRef; + repository: codecommit.IRepository; } /** @@ -83,7 +83,7 @@ export interface CodeCommitSourceProps extends BuildSourceProps { */ export class CodeCommitSource extends BuildSource { public readonly type: SourceType = SourceType.CodeCommit; - private readonly repo: codecommit.RepositoryRef; + private readonly repo: codecommit.IRepository; constructor(props: CodeCommitSourceProps) { super(props); @@ -108,7 +108,7 @@ export class CodeCommitSource extends BuildSource { * Construction properties for {@link S3BucketSource}. */ export interface S3BucketSourceProps extends BuildSourceProps { - bucket: s3.BucketRef; + bucket: s3.IBucket; path: string; } @@ -117,7 +117,7 @@ export interface S3BucketSourceProps extends BuildSourceProps { */ export class S3BucketSource extends BuildSource { public readonly type: SourceType = SourceType.S3; - private readonly bucket: s3.BucketRef; + private readonly bucket: s3.IBucket; private readonly path: string; constructor(props: S3BucketSourceProps) { diff --git a/packages/@aws-cdk/aws-codecommit/lib/pipeline-action.ts b/packages/@aws-cdk/aws-codecommit/lib/pipeline-action.ts index 95f9b3b304453..0fa65e3699bcd 100644 --- a/packages/@aws-cdk/aws-codecommit/lib/pipeline-action.ts +++ b/packages/@aws-cdk/aws-codecommit/lib/pipeline-action.ts @@ -1,12 +1,12 @@ import codepipeline = require('@aws-cdk/aws-codepipeline-api'); import iam = require('@aws-cdk/aws-iam'); import cdk = require('@aws-cdk/cdk'); -import { RepositoryRef } from './repository'; +import { IRepository } from './repository'; /** * Common properties for creating {@link PipelineSourceAction} - * either directly, through its constructor, - * or through {@link RepositoryRef#addToPipeline}. + * or through {@link IRepository#addToPipeline}. */ export interface CommonPipelineSourceActionProps extends codepipeline.CommonActionProps { /** @@ -39,7 +39,7 @@ export interface PipelineSourceActionProps extends CommonPipelineSourceActionPro /** * The CodeCommit repository. */ - repository: RepositoryRef; + repository: IRepository; } /** diff --git a/packages/@aws-cdk/aws-codecommit/lib/repository.ts b/packages/@aws-cdk/aws-codecommit/lib/repository.ts index c28be77131b21..b1718363eb60b 100644 --- a/packages/@aws-cdk/aws-codecommit/lib/repository.ts +++ b/packages/@aws-cdk/aws-codecommit/lib/repository.ts @@ -4,10 +4,94 @@ import cdk = require('@aws-cdk/cdk'); import { CfnRepository } from './codecommit.generated'; import { CommonPipelineSourceActionProps, PipelineSourceAction } from './pipeline-action'; +export interface IRepository { + /** The ARN of this Repository. */ + readonly repositoryArn: string; + + /** The human-visible name of this Repository. */ + readonly repositoryName: string; + + /** The HTTP clone URL */ + readonly repositoryCloneUrlHttp: string; + + /** The SSH clone URL */ + readonly repositoryCloneUrlSsh: string; + + /** + * Convenience method for creating a new {@link PipelineSourceAction}, + * and adding it to the given Stage. + * + * @param stage the Pipeline Stage to add the new Action to + * @param name the name of the newly created Action + * @param props the properties of the new Action + * @returns the newly created {@link PipelineSourceAction} + */ + addToPipeline(stage: actions.IStage, name: string, props?: CommonPipelineSourceActionProps): PipelineSourceAction; + + /** + * Defines a CloudWatch event rule which triggers for repository events. Use + * `rule.addEventPattern(pattern)` to specify a filter. + */ + onEvent(name: string, target?: events.IEventRuleTarget, options?: events.EventRuleProps): events.EventRule; + + /** + * Defines a CloudWatch event rule which triggers when a "CodeCommit + * Repository State Change" event occurs. + */ + onStateChange(name: string, target?: events.IEventRuleTarget, options?: events.EventRuleProps): events.EventRule; + + /** + * Defines a CloudWatch event rule which triggers when a reference is + * created (i.e. a new branch/tag is created) to the repository. + */ + onReferenceCreated(name: string, target?: events.IEventRuleTarget, options?: events.EventRuleProps): events.EventRule; + + /** + * Defines a CloudWatch event rule which triggers when a reference is + * updated (i.e. a commit is pushed to an existing or new branch) from the repository. + */ + onReferenceUpdated(name: string, target?: events.IEventRuleTarget, options?: events.EventRuleProps): events.EventRule; + + /** + * Defines a CloudWatch event rule which triggers when a reference is + * delete (i.e. a branch/tag is deleted) from the repository. + */ + onReferenceDeleted(name: string, target?: events.IEventRuleTarget, options?: events.EventRuleProps): events.EventRule; + + /** + * Defines a CloudWatch event rule which triggers when a pull request state is changed. + */ + onPullRequestStateChange(name: string, target?: events.IEventRuleTarget, options?: events.EventRuleProps): events.EventRule; + + /** + * Defines a CloudWatch event rule which triggers when a comment is made on a pull request. + */ + onCommentOnPullRequest(name: string, target?: events.IEventRuleTarget, options?: events.EventRuleProps): events.EventRule; + + /** + * Defines a CloudWatch event rule which triggers when a comment is made on a commit. + */ + onCommentOnCommit(name: string, target?: events.IEventRuleTarget, options?: events.EventRuleProps): events.EventRule; + + /** + * Defines a CloudWatch event rule which triggers when a commit is pushed to a branch. + * @param target The target of the event + * @param branch The branch to monitor. Defaults to all branches. + */ + onCommit(name: string, target?: events.IEventRuleTarget, branch?: string): events.EventRule; + + /** + * Exports this Repository. Allows the same Repository to be used in 2 different Stacks. + * + * @see import + */ + export(): RepositoryImportProps; +} + /** - * Properties for the {@link RepositoryRef.import} method. + * Properties for the {@link Repository.import} method. */ -export interface RepositoryRefProps { +export interface RepositoryImportProps { /** * The name of an existing CodeCommit Repository that we are referencing. * Must be in the same account and region as the root Stack. @@ -22,42 +106,22 @@ export interface RepositoryRefProps { * use the {@link Repository} class. * * If you want to reference an already existing Repository, - * use the {@link RepositoryRef.import} method. + * use the {@link Repository.import} method. */ -export abstract class RepositoryRef extends cdk.Construct { - /** - * Import a Repository defined either outside the CDK, or in a different Stack - * (exported with the {@link export} method). - * - * @param parent the parent Construct for the Repository - * @param name the name of the Repository Construct - * @param props the properties used to identify the existing Repository - * @returns a reference to the existing Repository - */ - public static import(parent: cdk.Construct, name: string, props: RepositoryRefProps): RepositoryRef { - return new ImportedRepositoryRef(parent, name, props); - } - +export abstract class RepositoryBase extends cdk.Construct implements IRepository { /** The ARN of this Repository. */ public abstract readonly repositoryArn: string; /** The human-visible name of this Repository. */ public abstract readonly repositoryName: string; + /** The HTTP clone URL */ public abstract readonly repositoryCloneUrlHttp: string; + /** The SSH clone URL */ public abstract readonly repositoryCloneUrlSsh: string; - /** - * Exports this Repository. Allows the same Repository to be used in 2 different Stacks. - * - * @see import - */ - public export(): RepositoryRefProps { - return { - repositoryName: new cdk.Output(this, 'RepositoryName', { value: this.repositoryName }).makeImportValue().toString() - }; - } + public abstract export(): RepositoryImportProps; /** * Convenience method for creating a new {@link PipelineSourceAction}, @@ -173,11 +237,11 @@ export abstract class RepositoryRef extends cdk.Construct { } } -class ImportedRepositoryRef extends RepositoryRef { +class ImportedRepository extends RepositoryBase { public readonly repositoryArn: string; public readonly repositoryName: string; - constructor(parent: cdk.Construct, name: string, props: RepositoryRefProps) { + constructor(parent: cdk.Construct, name: string, private readonly props: RepositoryImportProps) { super(parent, name); this.repositoryArn = cdk.ArnUtils.fromComponents({ @@ -187,6 +251,10 @@ class ImportedRepositoryRef extends RepositoryRef { this.repositoryName = props.repositoryName; } + public export() { + return this.props; + } + public get repositoryCloneUrlHttp() { return this.repositoryCloneUrl('https'); } @@ -216,7 +284,20 @@ export interface RepositoryProps { /** * Provides a CodeCommit Repository */ -export class Repository extends RepositoryRef { +export class Repository extends RepositoryBase { + /** + * Import a Repository defined either outside the CDK, or in a different Stack + * (exported with the {@link export} method). + * + * @param parent the parent Construct for the Repository + * @param name the name of the Repository Construct + * @param props the properties used to identify the existing Repository + * @returns a reference to the existing Repository + */ + public static import(parent: cdk.Construct, name: string, props: RepositoryImportProps): IRepository { + return new ImportedRepository(parent, name, props); + } + private readonly repository: CfnRepository; private readonly triggers = new Array(); @@ -246,6 +327,17 @@ export class Repository extends RepositoryRef { return this.repository.repositoryName; } + /** + * Exports this Repository. Allows the same Repository to be used in 2 different Stacks. + * + * @see import + */ + public export(): RepositoryImportProps { + return { + repositoryName: new cdk.Output(this, 'RepositoryName', { value: this.repositoryName }).makeImportValue().toString() + }; + } + /** * Create a trigger to notify another service to run actions on repository events. * @param arn Arn of the resource that repository events will notify diff --git a/packages/@aws-cdk/aws-codedeploy/README.md b/packages/@aws-cdk/aws-codedeploy/README.md index 415024f7e7bc6..6bb1f64527847 100644 --- a/packages/@aws-cdk/aws-codedeploy/README.md +++ b/packages/@aws-cdk/aws-codedeploy/README.md @@ -15,7 +15,7 @@ const application = new codedeploy.ServerApplication(this, 'CodeDeployApplicatio To import an already existing Application: ```ts -const application = codedeploy.ServerApplicationRef.import(this, 'ExistingCodeDeployApplication', { +const application = codedeploy.ServerApplication.import(this, 'ExistingCodeDeployApplication', { applicationName: 'MyExistingApplication', }); ``` @@ -75,7 +75,7 @@ one will be automatically created. To import an already existing Deployment Group: ```ts -const deploymentGroup = codedeploy.ServerDeploymentGroupRef.import(this, 'ExistingCodeDeployDeploymentGroup', { +const deploymentGroup = codedeploy.ServerDeploymentGroup.import(this, 'ExistingCodeDeployDeploymentGroup', { application, deploymentGroupName: 'MyExistingDeploymentGroup', }); @@ -151,7 +151,7 @@ const deploymentConfig = new codedeploy.ServerDeploymentConfig(this, 'Deployment Or import an existing one: ```ts -const deploymentConfig = codedeploy.ServerDeploymentConfigRef.import(this, 'ExistingDeploymentConfiguration', { +const deploymentConfig = codedeploy.ServerDeploymentConfig.import(this, 'ExistingDeploymentConfiguration', { deploymentConfigName: 'MyExistingDeploymentConfiguration', }); ``` diff --git a/packages/@aws-cdk/aws-codedeploy/lib/application.ts b/packages/@aws-cdk/aws-codedeploy/lib/application.ts index fb5c7f2049c51..d5442ee21f0e1 100644 --- a/packages/@aws-cdk/aws-codedeploy/lib/application.ts +++ b/packages/@aws-cdk/aws-codedeploy/lib/application.ts @@ -1,20 +1,6 @@ import cdk = require('@aws-cdk/cdk'); import { CfnApplication } from './codedeploy.generated'; -/** - * 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: string; -} - /** * Represents a reference to a CodeDeploy Application deploying to EC2/on-premise instances. * @@ -25,41 +11,42 @@ export interface ServerApplicationRefProps { * 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); - } +export interface IServerApplication { + readonly applicationArn: string; - public abstract readonly applicationArn: string; + readonly applicationName: string; - public abstract readonly applicationName: string; + export(): ServerApplicationImportProps; +} - public export(): ServerApplicationRefProps { - return { - applicationName: new cdk.Output(this, 'ApplicationName', { value: this.applicationName }).makeImportValue().toString() - }; - } +/** + * Properties of a reference to a CodeDeploy EC2/on-premise Application. + * + * @see ServerApplication#import + * @see ServerApplication#export + */ +export interface ServerApplicationImportProps { + /** + * 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: string; } -class ImportedServerApplicationRef extends ServerApplicationRef { +class ImportedServerApplication extends cdk.Construct implements IServerApplication { public readonly applicationArn: string; public readonly applicationName: string; - constructor(parent: cdk.Construct, id: string, props: ServerApplicationRefProps) { + constructor(parent: cdk.Construct, id: string, private readonly props: ServerApplicationImportProps) { super(parent, id); this.applicationName = props.applicationName; this.applicationArn = applicationName2Arn(this.applicationName); } + + public export() { + return this.props; + } } /** @@ -77,7 +64,20 @@ export interface ServerApplicationProps { /** * A CodeDeploy Application that deploys to EC2/on-premise instances. */ -export class ServerApplication extends ServerApplicationRef { +export class ServerApplication extends cdk.Construct implements IServerApplication { + /** + * 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: ServerApplicationImportProps): IServerApplication { + return new ImportedServerApplication(parent, id, props); + } + public readonly applicationArn: string; public readonly applicationName: string; @@ -92,6 +92,12 @@ export class ServerApplication extends ServerApplicationRef { this.applicationName = resource.ref; this.applicationArn = applicationName2Arn(this.applicationName); } + + public export(): ServerApplicationImportProps { + return { + applicationName: new cdk.Output(this, 'ApplicationName', { value: this.applicationName }).makeImportValue().toString() + }; + } } function applicationName2Arn(applicationName: string): string { diff --git a/packages/@aws-cdk/aws-codedeploy/lib/deployment-config.ts b/packages/@aws-cdk/aws-codedeploy/lib/deployment-config.ts index 20e85708926ce..c71421e84a2e8 100644 --- a/packages/@aws-cdk/aws-codedeploy/lib/deployment-config.ts +++ b/packages/@aws-cdk/aws-codedeploy/lib/deployment-config.ts @@ -11,15 +11,16 @@ import { CfnDeploymentConfig } from './codedeploy.generated'; export interface IServerDeploymentConfig { readonly deploymentConfigName: string; readonly deploymentConfigArn: string; + export(): ServerDeploymentConfigImportProps; } /** * Properties of a reference to a CodeDeploy EC2/on-premise Deployment Configuration. * - * @see ServerDeploymentConfigRef#import - * @see ServerDeploymentConfigRef#export + * @see ServerDeploymentConfig#import + * @see ServerDeploymentConfig#export */ -export interface ServerDeploymentConfigRefProps { +export interface ServerDeploymentConfigImportProps { /** * The physical, human-readable name of the custom CodeDeploy EC2/on-premise Deployment Configuration * that we are referencing. @@ -27,46 +28,20 @@ export interface ServerDeploymentConfigRefProps { 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 { +class ImportedServerDeploymentConfig extends cdk.Construct implements IServerDeploymentConfig { public readonly deploymentConfigName: string; public readonly deploymentConfigArn: string; - constructor(parent: cdk.Construct, id: string, props: ServerDeploymentConfigRefProps) { + constructor(parent: cdk.Construct, id: string, private readonly props: ServerDeploymentConfigImportProps) { super(parent, id); this.deploymentConfigName = props.deploymentConfigName; this.deploymentConfigArn = arnForDeploymentConfigName(this.deploymentConfigName); } + + public export() { + return this.props; + } } class DefaultServerDeploymentConfig implements IServerDeploymentConfig { @@ -77,6 +52,12 @@ class DefaultServerDeploymentConfig implements IServerDeploymentConfig { this.deploymentConfigName = deploymentConfigName; this.deploymentConfigArn = arnForDeploymentConfigName(this.deploymentConfigName); } + + public export(): ServerDeploymentConfigImportProps { + return { + deploymentConfigName: this.deploymentConfigName + }; + } } /** @@ -110,11 +91,24 @@ export interface ServerDeploymentConfigProps { /** * A custom Deployment Configuration for an EC2/on-premise Deployment Group. */ -export class ServerDeploymentConfig extends ServerDeploymentConfigRef { +export class ServerDeploymentConfig extends cdk.Construct implements IServerDeploymentConfig { 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'); + /** + * 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: ServerDeploymentConfigImportProps): IServerDeploymentConfig { + return new ImportedServerDeploymentConfig(parent, id, props); + } + public readonly deploymentConfigName: string; public readonly deploymentConfigArn: string; @@ -130,6 +124,14 @@ export class ServerDeploymentConfig extends ServerDeploymentConfigRef { this.deploymentConfigArn = arnForDeploymentConfigName(this.deploymentConfigName); } + public export(): ServerDeploymentConfigImportProps { + return { + deploymentConfigName: new cdk.Output(this, 'DeploymentConfigName', { + value: this.deploymentConfigName, + }).makeImportValue().toString(), + }; + } + private minimumHealthyHosts(props: ServerDeploymentConfigProps): CfnDeploymentConfig.MinimumHealthyHostsProperty { if (props.minHealthyHostCount === undefined && props.minHealthyHostPercentage === undefined) { diff --git a/packages/@aws-cdk/aws-codedeploy/lib/deployment-group.ts b/packages/@aws-cdk/aws-codedeploy/lib/deployment-group.ts index 95b3557ad70c7..8cd588b07bff6 100644 --- a/packages/@aws-cdk/aws-codedeploy/lib/deployment-group.ts +++ b/packages/@aws-cdk/aws-codedeploy/lib/deployment-group.ts @@ -6,23 +6,33 @@ import ec2 = require("@aws-cdk/aws-ec2"); import iam = require('@aws-cdk/aws-iam'); import s3 = require("@aws-cdk/aws-s3"); import cdk = require("@aws-cdk/cdk"); -import { ServerApplication, ServerApplicationRef } from "./application"; +import { IServerApplication, ServerApplication } from "./application"; import { CfnDeploymentGroup } from './codedeploy.generated'; import { IServerDeploymentConfig, ServerDeploymentConfig } from "./deployment-config"; import { CommonPipelineDeployActionProps, PipelineDeployAction } from "./pipeline-action"; +export interface IServerDeploymentGroup { + readonly application: IServerApplication; + readonly role?: iam.Role; + readonly deploymentGroupName: string; + readonly deploymentGroupArn: string; + readonly deploymentConfig: IServerDeploymentConfig; + readonly autoScalingGroups?: autoscaling.AutoScalingGroup[]; + export(): ServerDeploymentGroupImportProps; +} + /** * Properties of a reference to a CodeDeploy EC2/on-premise Deployment Group. * - * @see ServerDeploymentGroupRef#import - * @see ServerDeploymentGroupRef#export + * @see ServerDeploymentGroup#import + * @see IServerDeploymentGroup#export */ -export interface ServerDeploymentGroupRefProps { +export interface ServerDeploymentGroupImportProps { /** * The reference to the CodeDeploy EC2/on-premise Application * that this Deployment Group belongs to. */ - application: ServerApplicationRef; + application: IServerApplication; /** * The physical, human-readable name of the CodeDeploy EC2/on-premise Deployment Group @@ -48,21 +58,8 @@ export interface ServerDeploymentGroupRefProps { * 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; +export abstract class ServerDeploymentGroupBase extends cdk.Construct implements IServerDeploymentGroup { + public abstract readonly application: IServerApplication; public abstract readonly role?: iam.Role; public abstract readonly deploymentGroupName: string; public abstract readonly deploymentGroupArn: string; @@ -74,15 +71,7 @@ export abstract class ServerDeploymentGroupRef extends cdk.Construct { this.deploymentConfig = deploymentConfig || ServerDeploymentConfig.OneAtATime; } - public export(): ServerDeploymentGroupRefProps { - return { - application: this.application, - deploymentGroupName: new cdk.Output(this, 'DeploymentGroupName', { - value: this.deploymentGroupName - }).makeImportValue().toString(), - deploymentConfig: this.deploymentConfig, - }; - } + public abstract export(): ServerDeploymentGroupImportProps; /** * Convenience method for creating a new {@link PipelineDeployAction} @@ -103,14 +92,14 @@ export abstract class ServerDeploymentGroupRef extends cdk.Construct { } } -class ImportedServerDeploymentGroupRef extends ServerDeploymentGroupRef { - public readonly application: ServerApplicationRef; +class ImportedServerDeploymentGroup extends ServerDeploymentGroupBase { + public readonly application: IServerApplication; public readonly role?: iam.Role = undefined; public readonly deploymentGroupName: string; public readonly deploymentGroupArn: string; public readonly autoScalingGroups?: autoscaling.AutoScalingGroup[] = undefined; - constructor(parent: cdk.Construct, id: string, props: ServerDeploymentGroupRefProps) { + constructor(parent: cdk.Construct, id: string, private readonly props: ServerDeploymentGroupImportProps) { super(parent, id, props.deploymentConfig); this.application = props.application; @@ -118,6 +107,10 @@ class ImportedServerDeploymentGroupRef extends ServerDeploymentGroupRef { this.deploymentGroupArn = deploymentGroupName2Arn(props.application.applicationName, props.deploymentGroupName); } + + public export() { + return this.props; + } } /** @@ -190,7 +183,7 @@ 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; + application?: IServerApplication; /** * The service Role of this Deployment Group. @@ -281,15 +274,28 @@ export interface ServerDeploymentGroupProps { /** * A CodeDeploy Deployment Group that deploys to EC2/on-premise instances. */ -export class ServerDeploymentGroup extends ServerDeploymentGroupRef { - public readonly application: ServerApplicationRef; +export class ServerDeploymentGroup extends ServerDeploymentGroupBase { + /** + * 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: ServerDeploymentGroupImportProps): IServerDeploymentGroup { + return new ImportedServerDeploymentGroup(parent, id, props); + } + + public readonly application: IServerApplication; public readonly role?: iam.Role; public readonly deploymentGroupArn: string; public readonly deploymentGroupName: string; private readonly _autoScalingGroups: autoscaling.AutoScalingGroup[]; private readonly installAgent: boolean; - private readonly codeDeployBucket: s3.BucketRef; + private readonly codeDeployBucket: s3.IBucket; private readonly alarms: cloudwatch.Alarm[]; constructor(parent: cdk.Construct, id: string, props: ServerDeploymentGroupProps = {}) { @@ -304,8 +310,8 @@ export class ServerDeploymentGroup extends ServerDeploymentGroupRef { this._autoScalingGroups = props.autoScalingGroups || []; this.installAgent = props.installAgent === undefined ? true : props.installAgent; - const region = (new cdk.AwsRegion()).toString(); - this.codeDeployBucket = s3.BucketRef.import(this, 'CodeDeployBucket', { + const region = new cdk.AwsRegion().toString(); + this.codeDeployBucket = s3.Bucket.import(this, 'CodeDeployBucket', { bucketName: `aws-codedeploy-${region}`, }); for (const asg of this._autoScalingGroups) { @@ -341,6 +347,16 @@ export class ServerDeploymentGroup extends ServerDeploymentGroupRef { this.deploymentGroupName); } + public export(): ServerDeploymentGroupImportProps { + return { + application: this.application, + deploymentGroupName: new cdk.Output(this, 'DeploymentGroupName', { + value: this.deploymentGroupName + }).makeImportValue().toString(), + deploymentConfig: this.deploymentConfig, + }; + } + /** * Adds an additional auto-scaling group to this Deployment Group. * diff --git a/packages/@aws-cdk/aws-codedeploy/lib/pipeline-action.ts b/packages/@aws-cdk/aws-codedeploy/lib/pipeline-action.ts index 58985c522273d..2a840e575385a 100644 --- a/packages/@aws-cdk/aws-codedeploy/lib/pipeline-action.ts +++ b/packages/@aws-cdk/aws-codedeploy/lib/pipeline-action.ts @@ -1,12 +1,12 @@ import codepipeline = require('@aws-cdk/aws-codepipeline-api'); import iam = require('@aws-cdk/aws-iam'); import cdk = require('@aws-cdk/cdk'); -import { ServerDeploymentGroupRef } from './deployment-group'; +import { IServerDeploymentGroup } from './deployment-group'; /** * Common properties for creating a {@link PipelineDeployAction}, * either directly, through its constructor, - * or through {@link ServerDeploymentGroupRef#addToPipeline}. + * or through {@link IServerDeploymentGroup#addToPipeline}. */ export interface CommonPipelineDeployActionProps extends codepipeline.CommonActionProps { /** @@ -25,7 +25,7 @@ export interface PipelineDeployActionProps extends CommonPipelineDeployActionPro /** * The CodeDeploy Deployment Group to deploy to. */ - deploymentGroup: ServerDeploymentGroupRef; + deploymentGroup: IServerDeploymentGroup; } export class PipelineDeployAction extends codepipeline.DeployAction { diff --git a/packages/@aws-cdk/aws-codedeploy/test/test.deployment-config.ts b/packages/@aws-cdk/aws-codedeploy/test/test.deployment-config.ts index b3cd26b8c205d..eea90cf28f523 100644 --- a/packages/@aws-cdk/aws-codedeploy/test/test.deployment-config.ts +++ b/packages/@aws-cdk/aws-codedeploy/test/test.deployment-config.ts @@ -68,7 +68,7 @@ export = { 'can be imported'(test: Test) { const stack = new cdk.Stack(); - const deploymentConfig = codedeploy.ServerDeploymentConfigRef.import(stack, 'MyDC', { + const deploymentConfig = codedeploy.ServerDeploymentConfig.import(stack, 'MyDC', { deploymentConfigName: 'MyDC', }); diff --git a/packages/@aws-cdk/aws-codedeploy/test/test.deployment-group.ts b/packages/@aws-cdk/aws-codedeploy/test/test.deployment-group.ts index 3e8d47bfc0798..4b470209cc461 100644 --- a/packages/@aws-cdk/aws-codedeploy/test/test.deployment-group.ts +++ b/packages/@aws-cdk/aws-codedeploy/test/test.deployment-group.ts @@ -31,10 +31,10 @@ export = { 'can be imported'(test: Test) { const stack = new cdk.Stack(); - const application = codedeploy.ServerApplicationRef.import(stack, 'MyApp', { + const application = codedeploy.ServerApplication.import(stack, 'MyApp', { applicationName: 'MyApp', }); - const deploymentGroup = codedeploy.ServerDeploymentGroupRef.import(stack, 'MyDG', { + const deploymentGroup = codedeploy.ServerDeploymentGroup.import(stack, 'MyDG', { application, deploymentGroupName: 'MyDG', }); diff --git a/packages/@aws-cdk/aws-codepipeline/lib/manual-approval-action.ts b/packages/@aws-cdk/aws-codepipeline/lib/manual-approval-action.ts index 63089a872ed42..259fa080ae328 100644 --- a/packages/@aws-cdk/aws-codepipeline/lib/manual-approval-action.ts +++ b/packages/@aws-cdk/aws-codepipeline/lib/manual-approval-action.ts @@ -10,7 +10,7 @@ export interface ManualApprovalActionProps extends actions.CommonActionProps, /** * Optional SNS topic to send notifications to when an approval is pending. */ - notificationTopic?: sns.TopicRef; + notificationTopic?: sns.ITopic; /** * A list of email addresses to subscribe to notifications when this Action is pending approval. @@ -34,7 +34,7 @@ export class ManualApprovalAction extends actions.Action { * If no Topic was passed, but `notifyEmails` were provided, * a new Topic will be created. */ - public readonly notificationTopic?: sns.TopicRef; + public readonly notificationTopic?: sns.ITopic; constructor(parent: cdk.Construct, name: string, props: ManualApprovalActionProps) { super(parent, name, { diff --git a/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts b/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts index 4baa3aff60dd7..db8688b22bffe 100644 --- a/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts +++ b/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts @@ -12,7 +12,7 @@ export interface PipelineProps { * The S3 bucket used by this Pipeline to store artifacts. * If not specified, a new S3 bucket will be created. */ - artifactBucket?: s3.BucketRef; + artifactBucket?: s3.IBucket; /** * Indicates whether to rerun the AWS CodePipeline pipeline after you update it. @@ -79,7 +79,7 @@ export class Pipeline extends cdk.Construct implements cpapi.IPipeline { /** * Bucket used to store output artifacts */ - public readonly artifactBucket: s3.BucketRef; + public readonly artifactBucket: s3.IBucket; private readonly stages = new Array(); private eventsRole?: iam.Role; @@ -314,7 +314,7 @@ export class Pipeline extends cdk.Construct implements cpapi.IPipeline { replicationBucketName = crossRegionScaffoldStack.replicationBucketName; } - const replicationBucket = s3.BucketRef.import(this, 'CrossRegionCodePipelineReplicationBucket-' + action.region, { + const replicationBucket = s3.Bucket.import(this, 'CrossRegionCodePipelineReplicationBucket-' + action.region, { bucketName: replicationBucketName, }); replicationBucket.grantReadWrite(this.role); diff --git a/packages/@aws-cdk/aws-ec2/lib/connections.ts b/packages/@aws-cdk/aws-ec2/lib/connections.ts index cd416a4c7ee1e..ff8810d3ba7da 100644 --- a/packages/@aws-cdk/aws-ec2/lib/connections.ts +++ b/packages/@aws-cdk/aws-ec2/lib/connections.ts @@ -1,4 +1,4 @@ -import { SecurityGroupRef } from "./security-group"; +import { ISecurityGroup } from "./security-group"; import { AnyIPv4, IPortRange, ISecurityGroupRule } from "./security-group-rule"; /** @@ -40,7 +40,7 @@ export interface ConnectionsProps { * * @default No security groups */ - securityGroups?: SecurityGroupRef[]; + securityGroups?: ISecurityGroup[]; /** * Default port range for initiating connections to and from this object @@ -75,7 +75,7 @@ export class Connections implements IConnectable { * May be empty if this Connections object is not managing a SecurityGroup, * but simply representing a Connectable peer. */ - private readonly _securityGroups = new ReactiveList(); + private readonly _securityGroups = new ReactiveList(); /** * The rule that defines how to represent this peer in a security group @@ -96,14 +96,14 @@ export class Connections implements IConnectable { this.defaultPortRange = props.defaultPortRange; } - public get securityGroups(): SecurityGroupRef[] { + public get securityGroups(): ISecurityGroup[] { return this._securityGroups.asArray(); } /** * Add a security group to the list of security groups managed by this object */ - public addSecurityGroup(...securityGroups: SecurityGroupRef[]) { + public addSecurityGroup(...securityGroups: ISecurityGroup[]) { for (const securityGroup of securityGroups) { this._securityGroups.push(securityGroup); this._securityGroupRules.push(securityGroup); diff --git a/packages/@aws-cdk/aws-ec2/lib/security-group.ts b/packages/@aws-cdk/aws-ec2/lib/security-group.ts index 8c7f8479fee3f..001c3935b87f7 100644 --- a/packages/@aws-cdk/aws-ec2/lib/security-group.ts +++ b/packages/@aws-cdk/aws-ec2/lib/security-group.ts @@ -2,9 +2,16 @@ import { Construct, ITaggable, Output, TagManager, Tags, Token } from '@aws-cdk/ import { Connections, IConnectable } from './connections'; import { CfnSecurityGroup, CfnSecurityGroupEgress, CfnSecurityGroupIngress } from './ec2.generated'; import { IPortRange, ISecurityGroupRule } from './security-group-rule'; -import { VpcNetworkRef } from './vpc-ref'; +import { IVpcNetwork } from './vpc-ref'; -export interface SecurityGroupRefProps { +export interface ISecurityGroup extends ISecurityGroupRule, IConnectable { + readonly securityGroupId: string; + addIngressRule(peer: ISecurityGroupRule, connection: IPortRange, description?: string): void; + addEgressRule(peer: ISecurityGroupRule, connection: IPortRange, description?: string): void; + export(): SecurityGroupImportProps; +} + +export interface SecurityGroupImportProps { /** * ID of security group */ @@ -14,17 +21,10 @@ export interface SecurityGroupRefProps { /** * A SecurityGroup that is not created in this template */ -export abstract class SecurityGroupRef extends Construct implements ISecurityGroupRule, IConnectable { - /** - * Import an existing SecurityGroup - */ - public static import(parent: Construct, id: string, props: SecurityGroupRefProps): SecurityGroupRef { - return new ImportedSecurityGroup(parent, id, props); - } - +export abstract class SecurityGroupBase extends Construct implements ISecurityGroup { public abstract readonly securityGroupId: string; public readonly canInlineRule = false; - public readonly connections = new Connections({ securityGroups: [this] }); + public readonly connections: Connections = new Connections({ securityGroups: [this] }); /** * FIXME: Where to place this?? @@ -78,12 +78,7 @@ export abstract class SecurityGroupRef extends Construct implements ISecurityGro /** * Export this SecurityGroup for use in a different Stack */ - public export(): SecurityGroupRefProps { - return { - securityGroupId: new Output(this, 'SecurityGroupId', { value: this.securityGroupId }).makeImportValue().toString() - }; - } - + public abstract export(): SecurityGroupImportProps; } export interface SecurityGroupProps { @@ -114,7 +109,7 @@ export interface SecurityGroupProps { /** * The VPC in which to create the security group. */ - vpc: VpcNetworkRef; + vpc: IVpcNetwork; /** * Whether to allow all outbound traffic by default. @@ -131,11 +126,18 @@ export interface SecurityGroupProps { /** * Creates an Amazon EC2 security group within a VPC. * - * This class has an additional optimization over SecurityGroupRef that it can also create + * This class has an additional optimization over imported security groups that it can also create * inline ingress and egress rule (which saves on the total number of resources inside * the template). */ -export class SecurityGroup extends SecurityGroupRef implements ITaggable { +export class SecurityGroup extends SecurityGroupBase implements ITaggable { + /** + * Import an existing SecurityGroup + */ + public static import(parent: Construct, id: string, props: SecurityGroupImportProps): ISecurityGroup { + return new ImportedSecurityGroup(parent, id, props); + } + /** * An attribute that represents the security group name. */ @@ -186,6 +188,15 @@ export class SecurityGroup extends SecurityGroupRef implements ITaggable { this.addDefaultEgressRule(); } + /** + * Export this SecurityGroup for use in a different Stack + */ + public export(): SecurityGroupImportProps { + return { + securityGroupId: new Output(this, 'SecurityGroupId', { value: this.securityGroupId }).makeImportValue().toString() + }; + } + public addIngressRule(peer: ISecurityGroupRule, connection: IPortRange, description?: string) { if (!peer.canInlineRule || !connection.canInlineRule) { super.addIngressRule(peer, connection, description); @@ -378,14 +389,18 @@ export interface ConnectionRule { /** * A SecurityGroup that hasn't been created here */ -class ImportedSecurityGroup extends SecurityGroupRef { +class ImportedSecurityGroup extends SecurityGroupBase { public readonly securityGroupId: string; - constructor(parent: Construct, name: string, props: SecurityGroupRefProps) { + constructor(parent: Construct, name: string, private readonly props: SecurityGroupImportProps) { super(parent, name); this.securityGroupId = props.securityGroupId; } + + public export() { + return this.props; + } } /** diff --git a/packages/@aws-cdk/aws-ec2/lib/util.ts b/packages/@aws-cdk/aws-ec2/lib/util.ts index 430f383dce70a..a646aa8051470 100644 --- a/packages/@aws-cdk/aws-ec2/lib/util.ts +++ b/packages/@aws-cdk/aws-ec2/lib/util.ts @@ -1,5 +1,6 @@ import cdk = require('@aws-cdk/cdk'); -import { SubnetType, VpcSubnetRef } from "./vpc-ref"; +import { VpcSubnet } from './vpc'; +import { IVpcSubnet, SubnetType } from "./vpc-ref"; /** * Turn an arbitrary string into one that can be used as a CloudFormation identifier by stripping special characters @@ -24,7 +25,7 @@ export const DEFAULT_SUBNET_NAME = { * * All subnet names look like NAME <> "Subnet" <> INDEX */ -export function subnetName(subnet: VpcSubnetRef) { +export function subnetName(subnet: IVpcSubnet) { return subnet.id.replace(/Subnet\d+$/, ''); } @@ -47,7 +48,7 @@ export class ExportSubnetGroup { constructor( parent: cdk.Construct, exportName: string, - private readonly subnets: VpcSubnetRef[], + private readonly subnets: IVpcSubnet[], private readonly type: SubnetType, private readonly azs: number) { @@ -116,10 +117,10 @@ export class ImportSubnetGroup { this.names = this.normalizeNames(names, DEFAULT_SUBNET_NAME[type], nameField); } - public import(parent: cdk.Construct): VpcSubnetRef[] { + public import(parent: cdk.Construct): IVpcSubnet[] { return range(this.subnetIds.length).map(i => { const k = Math.floor(i / this.availabilityZones.length); - return VpcSubnetRef.import(parent, subnetId(this.names[k], i), { + return VpcSubnet.import(parent, subnetId(this.names[k], i), { availabilityZone: this.pickAZ(i), subnetId: this.subnetIds[i] }); diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc-network-provider.ts b/packages/@aws-cdk/aws-ec2/lib/vpc-network-provider.ts index 4312daa66bebb..29e8b42977f71 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc-network-provider.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc-network-provider.ts @@ -1,6 +1,6 @@ import cdk = require('@aws-cdk/cdk'); import cxapi = require('@aws-cdk/cx-api'); -import { VpcNetworkRefProps } from './vpc-ref'; +import { VpcNetworkImportProps } from './vpc-ref'; /** * Properties for looking up an existing VPC. @@ -66,7 +66,7 @@ export class VpcNetworkProvider { /** * Return the VPC import props matching the filter */ - public get vpcProps(): VpcNetworkRefProps { + public get vpcProps(): VpcNetworkImportProps { const ret: cxapi.VpcContextResponse = this.provider.getValue(DUMMY_VPC_PROPS); return ret; } diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc-ref.ts b/packages/@aws-cdk/aws-ec2/lib/vpc-ref.ts index 233754b08d879..3d0ce4dc6530b 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc-ref.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc-ref.ts @@ -1,6 +1,89 @@ -import { Construct, IDependable, Output } from "@aws-cdk/cdk"; -import { ExportSubnetGroup, ImportSubnetGroup, subnetName } from './util'; -import { VpcNetworkProvider, VpcNetworkProviderProps } from './vpc-network-provider'; +import { Construct, IDependable } from "@aws-cdk/cdk"; +import { subnetName } from './util'; + +export interface IVpcSubnet extends IDependable { + /** + * Logical ID of the subnet. + */ + readonly id: string; + + /** + * Construct path of this subnet. + */ + readonly path: string; + + /** + * The Availability Zone the subnet is located in + */ + readonly availabilityZone: string; + + /** + * The subnetId for this particular subnet + */ + readonly subnetId: string; + + /** + * Exports this subnet to another stack. + */ + export(): VpcSubnetImportProps; +} + +export interface IVpcNetwork extends IDependable { + /** + * Identifier for this VPC + */ + readonly vpcId: string; + + /** + * List of public subnets in this VPC + */ + readonly publicSubnets: IVpcSubnet[]; + + /** + * List of private subnets in this VPC + */ + readonly privateSubnets: IVpcSubnet[]; + + /** + * List of isolated subnets in this VPC + */ + readonly isolatedSubnets: IVpcSubnet[]; + + /** + * AZs for this VPC + */ + readonly availabilityZones: string[]; + + /** + * Take a dependency on internet connectivity having been added to this VPC + * + * Take a dependency on this if your constructs need an Internet Gateway + * added to the VPC before they can be constructed. + * + * This method is for construct authors; application builders should not + * need to call this. + */ + internetDependency(): IDependable; + + /** + * Return the subnets appropriate for the placement strategy + */ + subnets(placement?: VpcPlacementStrategy): IVpcSubnet[]; + + /** + * Return whether the given subnet is one of this VPC's public subnets. + * + * The subnet must literally be one of the subnet object obtained from + * this VPC. A subnet that merely represents the same subnet will + * never return true. + */ + isPublicSubnet(subnet: IVpcSubnet): boolean; + + /** + * Exports this VPC so it can be consumed by another stack. + */ + export(): VpcNetworkImportProps; +} /** * The type of Subnet @@ -74,20 +157,7 @@ export interface VpcPlacementStrategy { /** * A new or imported VPC */ -export abstract class VpcNetworkRef extends Construct implements IDependable { - /** - * Import an exported VPC - */ - public static import(parent: Construct, name: string, props: VpcNetworkRefProps): VpcNetworkRef { - return new ImportedVpcNetwork(parent, name, props); - } - - /** - * Import an existing VPC from context - */ - public static importFromContext(parent: Construct, name: string, props: VpcNetworkProviderProps): VpcNetworkRef { - return VpcNetworkRef.import(parent, name, new VpcNetworkProvider(parent, props).vpcProps); - } +export abstract class VpcNetworkBase extends Construct implements IVpcNetwork { /** * Identifier for this VPC @@ -97,17 +167,17 @@ export abstract class VpcNetworkRef extends Construct implements IDependable { /** * List of public subnets in this VPC */ - public abstract readonly publicSubnets: VpcSubnetRef[]; + public abstract readonly publicSubnets: IVpcSubnet[]; /** * List of private subnets in this VPC */ - public abstract readonly privateSubnets: VpcSubnetRef[]; + public abstract readonly privateSubnets: IVpcSubnet[]; /** * List of isolated subnets in this VPC */ - public abstract readonly isolatedSubnets: VpcSubnetRef[]; + public abstract readonly isolatedSubnets: IVpcSubnet[]; /** * AZs for this VPC @@ -122,12 +192,12 @@ export abstract class VpcNetworkRef extends Construct implements IDependable { /** * Dependencies for internet connectivity */ - protected readonly internetDependencies = new Array(); + public readonly internetDependencies = new Array(); /** * Return the subnets appropriate for the placement strategy */ - public subnets(placement: VpcPlacementStrategy = {}): VpcSubnetRef[] { + public subnets(placement: VpcPlacementStrategy = {}): IVpcSubnet[] { if (placement.subnetsToUse !== undefined && placement.subnetName !== undefined) { throw new Error('At most one of subnetsToUse and subnetName can be supplied'); } @@ -155,22 +225,7 @@ export abstract class VpcNetworkRef extends Construct implements IDependable { /** * Export this VPC from the stack */ - public export(): VpcNetworkRefProps { - const pub = new ExportSubnetGroup(this, 'PublicSubnetIDs', this.publicSubnets, SubnetType.Public, this.availabilityZones.length); - const priv = new ExportSubnetGroup(this, 'PrivateSubnetIDs', this.privateSubnets, SubnetType.Private, this.availabilityZones.length); - const iso = new ExportSubnetGroup(this, 'IsolatedSubnetIDs', this.isolatedSubnets, SubnetType.Isolated, this.availabilityZones.length); - - return { - vpcId: new Output(this, 'VpcId', { value: this.vpcId }).makeImportValue().toString(), - availabilityZones: this.availabilityZones, - publicSubnetIds: pub.ids, - publicSubnetNames: pub.names, - privateSubnetIds: priv.ids, - privateSubnetNames: priv.names, - isolatedSubnetIds: iso.ids, - isolatedSubnetNames: iso.names, - }; - } + public abstract export(): VpcNetworkImportProps; /** * Return whether the given subnet is one of this VPC's public subnets. @@ -179,7 +234,7 @@ export abstract class VpcNetworkRef extends Construct implements IDependable { * this VPC. A subnet that merely represents the same subnet will * never return true. */ - public isPublicSubnet(subnet: VpcSubnetRef) { + public isPublicSubnet(subnet: IVpcSubnet) { return this.publicSubnets.indexOf(subnet) > -1; } @@ -197,57 +252,10 @@ export abstract class VpcNetworkRef extends Construct implements IDependable { } } -/** - * An imported VpcNetwork - */ -class ImportedVpcNetwork extends VpcNetworkRef { - /** - * Identifier for this VPC - */ - public readonly vpcId: string; - - /** - * List of public subnets in this VPC - */ - public readonly publicSubnets: VpcSubnetRef[]; - - /** - * List of private subnets in this VPC - */ - public readonly privateSubnets: VpcSubnetRef[]; - - /** - * List of isolated subnets in this VPC - */ - public readonly isolatedSubnets: VpcSubnetRef[]; - - /** - * AZs for this VPC - */ - public readonly availabilityZones: string[]; - - constructor(parent: Construct, name: string, props: VpcNetworkRefProps) { - super(parent, name); - - this.vpcId = props.vpcId; - this.availabilityZones = props.availabilityZones; - - // tslint:disable:max-line-length - const pub = new ImportSubnetGroup(props.publicSubnetIds, props.publicSubnetNames, SubnetType.Public, this.availabilityZones, 'publicSubnetIds', 'publicSubnetNames'); - const priv = new ImportSubnetGroup(props.privateSubnetIds, props.privateSubnetNames, SubnetType.Private, this.availabilityZones, 'privateSubnetIds', 'privateSubnetNames'); - const iso = new ImportSubnetGroup(props.isolatedSubnetIds, props.isolatedSubnetNames, SubnetType.Isolated, this.availabilityZones, 'isolatedSubnetIds', 'isolatedSubnetNames'); - // tslint:enable:max-line-length - - this.publicSubnets = pub.import(this); - this.privateSubnets = priv.import(this); - this.isolatedSubnets = iso.import(this); - } -} - /** * Properties that reference an external VpcNetwork */ -export interface VpcNetworkRefProps { +export interface VpcNetworkImportProps { /** * VPC's identifier */ @@ -301,53 +309,7 @@ export interface VpcNetworkRefProps { isolatedSubnetNames?: string[]; } -/** - * A new or imported VPC Subnet - */ -export abstract class VpcSubnetRef extends Construct implements IDependable { - public static import(parent: Construct, name: string, props: VpcSubnetRefProps): VpcSubnetRef { - return new ImportedVpcSubnet(parent, name, props); - } - - /** - * The Availability Zone the subnet is located in - */ - public abstract readonly availabilityZone: string; - - /** - * The subnetId for this particular subnet - */ - public abstract readonly subnetId: string; - - /** - * Parts of this VPC subnet - */ - public readonly dependencyElements: IDependable[] = []; -} - -/** - * Subnet of an imported VPC - */ -class ImportedVpcSubnet extends VpcSubnetRef { - /** - * The Availability Zone the subnet is located in - */ - public readonly availabilityZone: string; - - /** - * The subnetId for this particular subnet - */ - public readonly subnetId: string; - - constructor(parent: Construct, name: string, props: VpcSubnetRefProps) { - super(parent, name); - - this.availabilityZone = props.availabilityZone; - this.subnetId = props.subnetId; - } -} - -export interface VpcSubnetRefProps { +export interface VpcSubnetImportProps { /** * The Availability Zone the subnet is located in */ diff --git a/packages/@aws-cdk/aws-ec2/lib/vpc.ts b/packages/@aws-cdk/aws-ec2/lib/vpc.ts index 04a9a97882316..080c0ae8bb922 100644 --- a/packages/@aws-cdk/aws-ec2/lib/vpc.ts +++ b/packages/@aws-cdk/aws-ec2/lib/vpc.ts @@ -2,9 +2,9 @@ import cdk = require('@aws-cdk/cdk'); import { CfnEIP, CfnInternetGateway, CfnNatGateway, CfnRoute } from './ec2.generated'; import { CfnRouteTable, CfnSubnet, CfnSubnetRouteTableAssociation, CfnVPC, CfnVPCGatewayAttachment } from './ec2.generated'; import { NetworkBuilder } from './network-util'; -import { DEFAULT_SUBNET_NAME, subnetId } from './util'; -import { SubnetType, VpcNetworkRef, VpcPlacementStrategy, VpcSubnetRef } from './vpc-ref'; - +import { DEFAULT_SUBNET_NAME, ExportSubnetGroup, ImportSubnetGroup, subnetId } from './util'; +import { VpcNetworkProvider, VpcNetworkProviderProps } from './vpc-network-provider'; +import { IVpcNetwork, IVpcSubnet, SubnetType, VpcNetworkBase, VpcNetworkImportProps, VpcPlacementStrategy, VpcSubnetImportProps } from './vpc-ref'; /** * Name tag constant */ @@ -184,7 +184,13 @@ export interface SubnetConfiguration { * * } */ -export class VpcNetwork extends VpcNetworkRef implements cdk.ITaggable { +export class VpcNetwork extends VpcNetworkBase implements cdk.ITaggable { + /** + * @returns The IPv4 CidrBlock as returned by the VPC + */ + public get cidr(): string { + return this.resource.getAtt("CidrBlock").toString(); + } /** * The default CIDR range used when creating VPCs. @@ -209,6 +215,20 @@ export class VpcNetwork extends VpcNetworkRef implements cdk.ITaggable { } ]; + /** + * Import an exported VPC + */ + public static import(parent: cdk.Construct, name: string, props: VpcNetworkImportProps): IVpcNetwork { + return new ImportedVpcNetwork(parent, name, props); + } + + /** + * Import an existing VPC from context + */ + public static importFromContext(parent: cdk.Construct, name: string, props: VpcNetworkProviderProps): IVpcNetwork { + return VpcNetwork.import(parent, name, new VpcNetworkProvider(parent, props).vpcProps); + } + /** * Identifier for this VPC */ @@ -217,17 +237,17 @@ export class VpcNetwork extends VpcNetworkRef implements cdk.ITaggable { /** * List of public subnets in this VPC */ - public readonly publicSubnets: VpcSubnetRef[] = []; + public readonly publicSubnets: IVpcSubnet[] = []; /** * List of private subnets in this VPC */ - public readonly privateSubnets: VpcSubnetRef[] = []; + public readonly privateSubnets: IVpcSubnet[] = []; /** * List of isolated subnets in this VPC */ - public readonly isolatedSubnets: VpcSubnetRef[] = []; + public readonly isolatedSubnets: IVpcSubnet[] = []; /** * AZs for this VPC @@ -340,10 +360,23 @@ export class VpcNetwork extends VpcNetworkRef implements cdk.ITaggable { } /** - * @returns The IPv4 CidrBlock as returned by the VPC + * Export this VPC from the stack */ - public get cidr(): string { - return this.resource.getAtt("CidrBlock").toString(); + public export(): VpcNetworkImportProps { + const pub = new ExportSubnetGroup(this, 'PublicSubnetIDs', this.publicSubnets, SubnetType.Public, this.availabilityZones.length); + const priv = new ExportSubnetGroup(this, 'PrivateSubnetIDs', this.privateSubnets, SubnetType.Private, this.availabilityZones.length); + const iso = new ExportSubnetGroup(this, 'IsolatedSubnetIDs', this.isolatedSubnets, SubnetType.Isolated, this.availabilityZones.length); + + return { + vpcId: new cdk.Output(this, 'VpcId', { value: this.vpcId }).makeImportValue().toString(), + availabilityZones: this.availabilityZones, + publicSubnetIds: pub.ids, + publicSubnetNames: pub.names, + privateSubnetIds: priv.ids, + privateSubnetNames: priv.names, + isolatedSubnetIds: iso.ids, + isolatedSubnetNames: iso.names, + }; } private createNatGateways(gateways?: number, placement?: VpcPlacementStrategy): void { @@ -485,7 +518,10 @@ export interface VpcSubnetProps { /** * Represents a new VPC subnet resource */ -export class VpcSubnet extends VpcSubnetRef implements cdk.ITaggable { +export class VpcSubnet extends cdk.Construct implements IVpcSubnet, cdk.ITaggable, cdk.IDependable { + public static import(parent: cdk.Construct, name: string, props: VpcSubnetImportProps): IVpcSubnet { + return new ImportedVpcSubnet(parent, name, props); + } /** * The Availability Zone the subnet is located in @@ -502,6 +538,11 @@ export class VpcSubnet extends VpcSubnetRef implements cdk.ITaggable { */ public readonly tags: cdk.TagManager; + /** + * Parts of this VPC subnet + */ + public readonly dependencyElements: cdk.IDependable[] = []; + /** * The routeTableId attached to this subnet. */ @@ -536,6 +577,13 @@ export class VpcSubnet extends VpcSubnetRef implements cdk.ITaggable { this.dependencyElements.push(subnet, table, routeAssoc); } + public export(): VpcSubnetImportProps { + return { + availabilityZone: new cdk.Output(this, 'AvailabilityZone', { value: this.availabilityZone }).makeImportValue().toString(), + subnetId: new cdk.Output(this, 'VpcSubnetId', { value: this.subnetId }).makeImportValue().toString(), + }; + } + protected addDefaultRouteToNAT(natGatewayId: string) { new CfnRoute(this, `DefaultRoute`, { routeTableId: this.routeTableId, @@ -615,3 +663,49 @@ export class VpcPrivateSubnet extends VpcSubnet { function ifUndefined(value: T | undefined, defaultValue: T): T { return value !== undefined ? value : defaultValue; } + +export class ImportedVpcNetwork extends VpcNetworkBase { + public readonly vpcId: string; + public readonly publicSubnets: IVpcSubnet[]; + public readonly privateSubnets: IVpcSubnet[]; + public readonly isolatedSubnets: IVpcSubnet[]; + public readonly availabilityZones: string[]; + + constructor(parent: cdk.Construct, id: string, private readonly props: VpcNetworkImportProps) { + super(parent, id); + + this.vpcId = props.vpcId; + this.availabilityZones = props.availabilityZones; + + // tslint:disable:max-line-length + const pub = new ImportSubnetGroup(props.publicSubnetIds, props.publicSubnetNames, SubnetType.Public, this.availabilityZones, 'publicSubnetIds', 'publicSubnetNames'); + const priv = new ImportSubnetGroup(props.privateSubnetIds, props.privateSubnetNames, SubnetType.Private, this.availabilityZones, 'privateSubnetIds', 'privateSubnetNames'); + const iso = new ImportSubnetGroup(props.isolatedSubnetIds, props.isolatedSubnetNames, SubnetType.Isolated, this.availabilityZones, 'isolatedSubnetIds', 'isolatedSubnetNames'); + // tslint:enable:max-line-length + + this.publicSubnets = pub.import(this); + this.privateSubnets = priv.import(this); + this.isolatedSubnets = iso.import(this); + } + + public export() { + return this.props; + } +} + +export class ImportedVpcSubnet extends cdk.Construct implements IVpcSubnet { + public readonly availabilityZone: string; + public readonly subnetId: string; + public readonly dependencyElements = new Array(); + + constructor(parent: cdk.Construct, id: string, private readonly props: VpcSubnetImportProps) { + super(parent, id); + + this.subnetId = props.subnetId; + this.availabilityZone = props.availabilityZone; + } + + public export() { + return this.props; + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ec2/test/example.share-vpcs.lit.ts b/packages/@aws-cdk/aws-ec2/test/example.share-vpcs.lit.ts index 6a6f4e997193c..c48f53f38fcd9 100644 --- a/packages/@aws-cdk/aws-ec2/test/example.share-vpcs.lit.ts +++ b/packages/@aws-cdk/aws-ec2/test/example.share-vpcs.lit.ts @@ -4,7 +4,7 @@ import ec2 = require("../lib"); const app = new cdk.App(); interface ConstructThatTakesAVpcProps { - vpc: ec2.VpcNetworkRef; + vpc: ec2.IVpcNetwork; } class ConstructThatTakesAVpc extends cdk.Construct { @@ -15,7 +15,7 @@ class ConstructThatTakesAVpc extends cdk.Construct { /// !show class Stack1 extends cdk.Stack { - public readonly vpcProps: ec2.VpcNetworkRefProps; + public readonly vpcProps: ec2.VpcNetworkImportProps; constructor(parent: cdk.App, id: string, props?: cdk.StackProps) { super(parent, id, props); @@ -28,7 +28,7 @@ class Stack1 extends cdk.Stack { } interface Stack2Props extends cdk.StackProps { - vpcProps: ec2.VpcNetworkRefProps; + vpcProps: ec2.VpcNetworkImportProps; } class Stack2 extends cdk.Stack { @@ -36,7 +36,7 @@ class Stack2 extends cdk.Stack { super(parent, id, props); // Import the VPC from a set of properties - const vpc = ec2.VpcNetworkRef.import(this, 'VPC', props.vpcProps); + const vpc = ec2.VpcNetwork.import(this, 'VPC', props.vpcProps); new ConstructThatTakesAVpc(this, 'Construct', { vpc diff --git a/packages/@aws-cdk/aws-ec2/test/integ.import-default-vpc.lit.ts b/packages/@aws-cdk/aws-ec2/test/integ.import-default-vpc.lit.ts index 2a9fb8921c65f..19fcff0cb4d04 100644 --- a/packages/@aws-cdk/aws-ec2/test/integ.import-default-vpc.lit.ts +++ b/packages/@aws-cdk/aws-ec2/test/integ.import-default-vpc.lit.ts @@ -5,7 +5,7 @@ const app = new cdk.App(); const stack = new cdk.Stack(app, 'aws-cdk-ec2-import'); /// !show -const vpc = ec2.VpcNetworkRef.importFromContext(stack, 'VPC', { +const vpc = ec2.VpcNetwork.importFromContext(stack, 'VPC', { // This imports the default VPC but you can also // specify a 'vpcName' or 'tags'. isDefault: true diff --git a/packages/@aws-cdk/aws-ec2/test/test.connections.ts b/packages/@aws-cdk/aws-ec2/test/test.connections.ts index bcdaf8c1627bf..9cc0482c1f9f2 100644 --- a/packages/@aws-cdk/aws-ec2/test/test.connections.ts +++ b/packages/@aws-cdk/aws-ec2/test/test.connections.ts @@ -6,7 +6,6 @@ import { Connections, IConnectable, SecurityGroup, - SecurityGroupRef, TcpAllPorts, TcpPort, VpcNetwork @@ -38,7 +37,7 @@ export = { const sg1 = new SecurityGroup(stack, 'SomeSecurityGroup', { vpc, allowAllOutbound: false }); const somethingConnectable = new SomethingConnectable(new Connections({ securityGroups: [sg1] })); - const securityGroup = SecurityGroupRef.import(stack, 'ImportedSG', { securityGroupId: 'sg-12345' }); + const securityGroup = SecurityGroup.import(stack, 'ImportedSG', { securityGroupId: 'sg-12345' }); // WHEN somethingConnectable.connections.allowTo(securityGroup, new TcpAllPorts(), 'Connect there'); diff --git a/packages/@aws-cdk/aws-ec2/test/test.vpc.ts b/packages/@aws-cdk/aws-ec2/test/test.vpc.ts index 4c730a03ccb02..f4cab6224ea79 100644 --- a/packages/@aws-cdk/aws-ec2/test/test.vpc.ts +++ b/packages/@aws-cdk/aws-ec2/test/test.vpc.ts @@ -1,7 +1,7 @@ import { countResources, expect, haveResource, haveResourceLike, isSuperObject } from '@aws-cdk/assert'; import { AvailabilityZoneProvider, Construct, resolve, Stack, Tags } from '@aws-cdk/cdk'; import { Test } from 'nodeunit'; -import { DefaultInstanceTenancy, SubnetType, VpcNetwork, VpcNetworkRef } from '../lib'; +import { DefaultInstanceTenancy, IVpcNetwork, SubnetType, VpcNetwork } from '../lib'; export = { "When creating a VPC": { @@ -531,7 +531,7 @@ function getTestStack(): Stack { /** * Do a complete import/export test, return the imported VPC */ -function doImportExportTest(constructFn: (parent: Construct) => VpcNetwork): VpcNetworkRef { +function doImportExportTest(constructFn: (parent: Construct) => VpcNetwork): IVpcNetwork { // GIVEN const stack1 = getTestStack(); const stack2 = getTestStack(); diff --git a/packages/@aws-cdk/aws-ecr/lib/pipeline-action.ts b/packages/@aws-cdk/aws-ecr/lib/pipeline-action.ts index 7d5af0917560e..ec0fa6db438f9 100644 --- a/packages/@aws-cdk/aws-ecr/lib/pipeline-action.ts +++ b/packages/@aws-cdk/aws-ecr/lib/pipeline-action.ts @@ -6,7 +6,7 @@ import { IRepository } from './repository-ref'; /** * Common properties for the {@link PipelineSourceAction CodePipeline source Action}, * whether creating it directly, - * or through the {@link RepositoryRef#addToPipeline} method. + * or through the {@link IRepository#addToPipeline} method. */ export interface CommonPipelineSourceActionProps extends codepipeline.CommonActionProps { /** diff --git a/packages/@aws-cdk/aws-ecr/lib/repository-ref.ts b/packages/@aws-cdk/aws-ecr/lib/repository-ref.ts index 4b758330cc6b8..3c73b055a06e6 100644 --- a/packages/@aws-cdk/aws-ecr/lib/repository-ref.ts +++ b/packages/@aws-cdk/aws-ecr/lib/repository-ref.ts @@ -75,9 +75,14 @@ export interface IRepository { * @param imageTag Only trigger on the specific image tag */ onImagePushed(name: string, target?: events.IEventRuleTarget, imageTag?: string): events.EventRule; + + /** + * Export this repository from the stack + */ + export(): RepositoryImportProps; } -export interface ImportRepositoryProps { +export interface RepositoryImportProps { /** * The ARN of the repository to import. * @@ -109,7 +114,7 @@ export abstract class RepositoryBase extends cdk.Construct implements IRepositor /** * Import a repository */ - public static import(parent: cdk.Construct, id: string, props: ImportRepositoryProps): IRepository { + public static import(parent: cdk.Construct, id: string, props: RepositoryImportProps): IRepository { return new ImportedRepository(parent, id, props); } @@ -166,12 +171,7 @@ export abstract class RepositoryBase extends cdk.Construct implements IRepositor /** * Export this repository from the stack */ - public export(): ImportRepositoryProps { - return { - repositoryArn: new cdk.Output(this, 'RepositoryArn', { value: this.repositoryArn }).makeImportValue().toString(), - repositoryName: new cdk.Output(this, 'RepositoryName', { value: this.repositoryName }).makeImportValue().toString() - }; - } + public abstract export(): RepositoryImportProps; public addToPipeline(stage: codepipeline.IStage, name: string, props: CommonPipelineSourceActionProps = {}): PipelineSourceAction { @@ -254,7 +254,7 @@ class ImportedRepository extends RepositoryBase { public readonly repositoryName: string; public readonly repositoryArn: string; - constructor(parent: cdk.Construct, id: string, props: ImportRepositoryProps) { + constructor(parent: cdk.Construct, id: string, private readonly props: RepositoryImportProps) { super(parent, id); if (props.repositoryArn) { @@ -282,6 +282,10 @@ class ImportedRepository extends RepositoryBase { } } + public export(): RepositoryImportProps { + return this.props; + } + public addToResourcePolicy(_statement: iam.PolicyStatement) { // FIXME: Add annotation about policy we dropped on the floor } diff --git a/packages/@aws-cdk/aws-ecr/lib/repository.ts b/packages/@aws-cdk/aws-ecr/lib/repository.ts index ee624946368d5..1d74accc18173 100644 --- a/packages/@aws-cdk/aws-ecr/lib/repository.ts +++ b/packages/@aws-cdk/aws-ecr/lib/repository.ts @@ -2,7 +2,7 @@ import iam = require('@aws-cdk/aws-iam'); import cdk = require('@aws-cdk/cdk'); import { CfnRepository } from './ecr.generated'; import { CountType, LifecycleRule, TagStatus } from './lifecycle'; -import { RepositoryBase } from "./repository-ref"; +import { RepositoryBase, RepositoryImportProps } from "./repository-ref"; export interface RepositoryProps { /** @@ -71,6 +71,16 @@ export class Repository extends RepositoryBase { this.repositoryArn = resource.repositoryArn; } + /** + * Export this repository from the stack + */ + public export(): RepositoryImportProps { + return { + repositoryArn: new cdk.Output(this, 'RepositoryArn', { value: this.repositoryArn }).makeImportValue().toString(), + repositoryName: new cdk.Output(this, 'RepositoryName', { value: this.repositoryName }).makeImportValue().toString() + }; + } + public addToResourcePolicy(statement: iam.PolicyStatement) { if (this.policyDocument === undefined) { this.policyDocument = new iam.PolicyDocument(); diff --git a/packages/@aws-cdk/aws-ecr/test/test.repository.ts b/packages/@aws-cdk/aws-ecr/test/test.repository.ts index a9b58c486b04c..e3bfa4ffcc657 100644 --- a/packages/@aws-cdk/aws-ecr/test/test.repository.ts +++ b/packages/@aws-cdk/aws-ecr/test/test.repository.ts @@ -179,9 +179,12 @@ export = { repositoryArn: 'arn:aws:ecr:us-east-1:585695036304:repository/foo/bar/foo/fooo' }); + const exportImport = repo2.export(); + // THEN test.deepEqual(cdk.resolve(repo2.repositoryArn), 'arn:aws:ecr:us-east-1:585695036304:repository/foo/bar/foo/fooo'); test.deepEqual(cdk.resolve(repo2.repositoryName), 'foo/bar/foo/fooo'); + test.deepEqual(cdk.resolve(exportImport), { repositoryArn: 'arn:aws:ecr:us-east-1:585695036304:repository/foo/bar/foo/fooo' }); test.done(); }, diff --git a/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts b/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts index abd1ae07fcbdb..de987d2f1decf 100644 --- a/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts +++ b/packages/@aws-cdk/aws-ecs/lib/base/base-service.ts @@ -183,7 +183,7 @@ export abstract class BaseService extends cdk.Construct * Set up AWSVPC networking for this construct */ // tslint:disable-next-line:max-line-length - protected configureAwsVpcNetworking(vpc: ec2.VpcNetworkRef, assignPublicIp?: boolean, vpcPlacement?: ec2.VpcPlacementStrategy, securityGroup?: ec2.SecurityGroupRef) { + protected configureAwsVpcNetworking(vpc: ec2.IVpcNetwork, assignPublicIp?: boolean, vpcPlacement?: ec2.VpcPlacementStrategy, securityGroup?: ec2.ISecurityGroup) { if (vpcPlacement === undefined) { vpcPlacement = { subnetsToUse: assignPublicIp ? ec2.SubnetType.Public : ec2.SubnetType.Private }; } diff --git a/packages/@aws-cdk/aws-ecs/lib/cluster.ts b/packages/@aws-cdk/aws-ecs/lib/cluster.ts index faa7288f26c05..db8ade9548d70 100644 --- a/packages/@aws-cdk/aws-ecs/lib/cluster.ts +++ b/packages/@aws-cdk/aws-ecs/lib/cluster.ts @@ -20,7 +20,7 @@ export interface ClusterProps { /** * The VPC where your ECS instances will be running or your ENIs will be deployed */ - vpc: ec2.VpcNetworkRef; + vpc: ec2.IVpcNetwork; } /** @@ -30,7 +30,7 @@ export class Cluster extends cdk.Construct implements ICluster { /** * Import an existing cluster */ - public static import(parent: cdk.Construct, name: string, props: ImportedClusterProps): ICluster { + public static import(parent: cdk.Construct, name: string, props: ClusterImportProps): ICluster { return new ImportedCluster(parent, name, props); } @@ -42,7 +42,7 @@ export class Cluster extends cdk.Construct implements ICluster { /** * The VPC this cluster was created in. */ - public readonly vpc: ec2.VpcNetworkRef; + public readonly vpc: ec2.IVpcNetwork; /** * The ARN of this cluster @@ -144,7 +144,7 @@ export class Cluster extends cdk.Construct implements ICluster { /** * Export the Cluster */ - public export(): ImportedClusterProps { + public export(): ClusterImportProps { return { clusterName: new cdk.Output(this, 'ClusterName', { value: this.clusterName }).makeImportValue().toString(), vpc: this.vpc.export(), @@ -217,7 +217,7 @@ export interface ICluster { /** * VPC that the cluster instances are running in */ - readonly vpc: ec2.VpcNetworkRef; + readonly vpc: ec2.IVpcNetwork; /** * Connections manager of the cluster instances @@ -228,12 +228,17 @@ export interface ICluster { * Whether the cluster has EC2 capacity associated with it */ readonly hasEc2Capacity: boolean; + + /** + * Export the Cluster + */ + export(): ClusterImportProps; } /** * Properties to import an ECS cluster */ -export interface ImportedClusterProps { +export interface ClusterImportProps { /** * Name of the cluster */ @@ -242,12 +247,12 @@ export interface ImportedClusterProps { /** * VPC that the cluster instances are running in */ - vpc: ec2.VpcNetworkRefProps; + vpc: ec2.VpcNetworkImportProps; /** * Security group of the cluster instances */ - securityGroups: ec2.SecurityGroupRefProps[]; + securityGroups: ec2.SecurityGroupImportProps[]; /** * Whether the given cluster has EC2 capacity @@ -269,7 +274,7 @@ class ImportedCluster extends cdk.Construct implements ICluster { /** * VPC that the cluster instances are running in */ - public readonly vpc: ec2.VpcNetworkRef; + public readonly vpc: ec2.IVpcNetwork; /** * Security group of the cluster instances @@ -281,18 +286,22 @@ class ImportedCluster extends cdk.Construct implements ICluster { */ public readonly hasEc2Capacity: boolean; - constructor(parent: cdk.Construct, name: string, props: ImportedClusterProps) { + constructor(parent: cdk.Construct, name: string, private readonly props: ClusterImportProps) { super(parent, name); this.clusterName = props.clusterName; - this.vpc = ec2.VpcNetworkRef.import(this, "vpc", props.vpc); + this.vpc = ec2.VpcNetwork.import(this, "vpc", props.vpc); this.hasEc2Capacity = props.hasEc2Capacity !== false; let i = 1; for (const sgProps of props.securityGroups) { - this.connections.addSecurityGroup(ec2.SecurityGroupRef.import(this, `SecurityGroup${i}`, sgProps)); + this.connections.addSecurityGroup(ec2.SecurityGroup.import(this, `SecurityGroup${i}`, sgProps)); i++; } } + + public export() { + return this.props; + } } /** diff --git a/packages/@aws-cdk/aws-ecs/lib/ec2/ec2-service.ts b/packages/@aws-cdk/aws-ecs/lib/ec2/ec2-service.ts index d28def8fcaf5f..de8bbac1be357 100644 --- a/packages/@aws-cdk/aws-ecs/lib/ec2/ec2-service.ts +++ b/packages/@aws-cdk/aws-ecs/lib/ec2/ec2-service.ts @@ -38,7 +38,7 @@ export interface Ec2ServiceProps extends BaseServiceProps { * * @default A new security group is created */ - securityGroup?: ec2.SecurityGroupRef; + securityGroup?: ec2.ISecurityGroup; /** * Whether to start services on distinct instances diff --git a/packages/@aws-cdk/aws-ecs/lib/fargate/fargate-service.ts b/packages/@aws-cdk/aws-ecs/lib/fargate/fargate-service.ts index c3caf6ef09971..409c360d0a49d 100644 --- a/packages/@aws-cdk/aws-ecs/lib/fargate/fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs/lib/fargate/fargate-service.ts @@ -38,7 +38,7 @@ export interface FargateServiceProps extends BaseServiceProps { * * @default A new security group is created */ - securityGroup?: ec2.SecurityGroupRef; + securityGroup?: ec2.ISecurityGroup; /** * Fargate platform version to run this service on diff --git a/packages/@aws-cdk/aws-ecs/lib/load-balanced-fargate-service-applet.ts b/packages/@aws-cdk/aws-ecs/lib/load-balanced-fargate-service-applet.ts index 4fe86ab5e1d45..af5937804d9d4 100644 --- a/packages/@aws-cdk/aws-ecs/lib/load-balanced-fargate-service-applet.ts +++ b/packages/@aws-cdk/aws-ecs/lib/load-balanced-fargate-service-applet.ts @@ -1,4 +1,4 @@ -import { CertificateRef } from '@aws-cdk/aws-certificatemanager'; +import { Certificate } from '@aws-cdk/aws-certificatemanager'; import { VpcNetwork } from '@aws-cdk/aws-ec2'; import { HostedZoneProvider } from '@aws-cdk/aws-route53'; import cdk = require('@aws-cdk/cdk'); @@ -114,7 +114,7 @@ export class LoadBalancedFargateServiceApplet extends cdk.Stack { } let certificate; if (props.certificate) { - certificate = CertificateRef.import(this, 'Cert', { certificateArn: props.certificate }); + certificate = Certificate.import(this, 'Cert', { certificateArn: props.certificate }); } // Instantiate Fargate Service with just cluster and image diff --git a/packages/@aws-cdk/aws-ecs/lib/load-balanced-fargate-service.ts b/packages/@aws-cdk/aws-ecs/lib/load-balanced-fargate-service.ts index 1336d79b1b3e0..722829eac58f7 100644 --- a/packages/@aws-cdk/aws-ecs/lib/load-balanced-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs/lib/load-balanced-fargate-service.ts @@ -1,6 +1,6 @@ -import { CertificateRef } from '@aws-cdk/aws-certificatemanager'; +import { ICertificate } from '@aws-cdk/aws-certificatemanager'; import elbv2 = require('@aws-cdk/aws-elasticloadbalancingv2'); -import { AliasRecord, HostedZoneRef } from '@aws-cdk/aws-route53'; +import { AliasRecord, IHostedZone } from '@aws-cdk/aws-route53'; import cdk = require('@aws-cdk/cdk'); import { ICluster } from './cluster'; import { IContainerImage } from './container-image'; @@ -95,13 +95,13 @@ export interface LoadBalancedFargateServiceProps { /** * Route53 hosted zone for the domain, e.g. "example.com." */ - domainZone?: HostedZoneRef; + domainZone?: IHostedZone; /** * Certificate Manager certificate to associate with the load balancer. * Setting this option will set the load balancer port to 443. */ - certificate?: CertificateRef; + certificate?: ICertificate; /** * Whether to create an AWS log driver * @@ -179,7 +179,8 @@ export class LoadBalancedFargateService extends cdk.Construct { throw new Error('A Route53 hosted domain zone name is required to configure the specified domain name'); } - new AliasRecord(props.domainZone, "DNS", { + new AliasRecord(this, "DNS", { + zone: props.domainZone, recordName: props.domainName, target: lb }); diff --git a/packages/@aws-cdk/aws-ecs/lib/log-drivers/aws-log-driver.ts b/packages/@aws-cdk/aws-ecs/lib/log-drivers/aws-log-driver.ts index 0a5a445d7e5c0..781938b45b4ed 100644 --- a/packages/@aws-cdk/aws-ecs/lib/log-drivers/aws-log-driver.ts +++ b/packages/@aws-cdk/aws-ecs/lib/log-drivers/aws-log-driver.ts @@ -25,7 +25,7 @@ export interface AwsLogDriverProps { * * @default A log group is automatically created */ - logGroup?: logs.LogGroupRef; + logGroup?: logs.ILogGroup; /** * This option defines a multiline start pattern in Python strftime format. @@ -53,7 +53,7 @@ export class AwsLogDriver extends LogDriver { /** * The log group that the logs will be sent to */ - public readonly logGroup: logs.LogGroupRef; + public readonly logGroup: logs.ILogGroup; constructor(parent: cdk.Construct, id: string, private readonly props: AwsLogDriverProps) { super(parent, id); diff --git a/packages/@aws-cdk/aws-ecs/test/test.l3s.ts b/packages/@aws-cdk/aws-ecs/test/test.l3s.ts index a8386d462b652..df6d3957837a8 100644 --- a/packages/@aws-cdk/aws-ecs/test/test.l3s.ts +++ b/packages/@aws-cdk/aws-ecs/test/test.l3s.ts @@ -1,5 +1,5 @@ import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert'; -import { CertificateRef } from '@aws-cdk/aws-certificatemanager'; +import { Certificate } from '@aws-cdk/aws-certificatemanager'; import ec2 = require('@aws-cdk/aws-ec2'); import { PublicHostedZone } from '@aws-cdk/aws-route53'; import cdk = require('@aws-cdk/cdk'); @@ -120,7 +120,7 @@ export = { image: ecs.ContainerImage.fromDockerHub('test'), domainName: 'api.example.com', domainZone: zone, - certificate: CertificateRef.import(stack, 'Cert', { certificateArn: 'helloworld' }) + certificate: Certificate.import(stack, 'Cert', { certificateArn: 'helloworld' }) }); // THEN - stack contains a load balancer and a service diff --git a/packages/@aws-cdk/aws-elasticloadbalancing/lib/load-balancer.ts b/packages/@aws-cdk/aws-elasticloadbalancing/lib/load-balancer.ts index 72573fc92697c..186d524ac6c99 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancing/lib/load-balancer.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancing/lib/load-balancer.ts @@ -1,6 +1,7 @@ import codedeploy = require('@aws-cdk/aws-codedeploy-api'); -import { AnyIPv4, Connections, IConnectable, IPortRange, SecurityGroup, SecurityGroupRef, - TcpPort, VpcNetworkRef, VpcSubnetRef } from '@aws-cdk/aws-ec2'; +import { + AnyIPv4, Connections, IConnectable, IPortRange, ISecurityGroup, + IVpcNetwork, IVpcSubnet, SecurityGroup, TcpPort } from '@aws-cdk/aws-ec2'; import cdk = require('@aws-cdk/cdk'); import { CfnLoadBalancer } from './elasticloadbalancing.generated'; @@ -11,7 +12,7 @@ export interface LoadBalancerProps { /** * VPC network of the fleet instances */ - vpc: VpcNetworkRef; + vpc: IVpcNetwork; /** * Whether this is an internet-facing Load Balancer @@ -211,7 +212,7 @@ export class LoadBalancer extends cdk.Construct implements IConnectable, codedep this.connections = new Connections({ securityGroups: [this.securityGroup] }); // Depending on whether the ELB has public or internal IPs, pick the right backend subnets - const subnets: VpcSubnetRef[] = props.internetFacing ? props.vpc.publicSubnets : props.vpc.privateSubnets; + const subnets: IVpcSubnet[] = props.internetFacing ? props.vpc.publicSubnets : props.vpc.privateSubnets; this.elb = new CfnLoadBalancer(this, 'Resource', { securityGroups: [ this.securityGroup.securityGroupId ], @@ -344,7 +345,7 @@ export class LoadBalancer extends cdk.Construct implements IConnectable, codedep export class ListenerPort implements IConnectable { public readonly connections: Connections; - constructor(securityGroup: SecurityGroupRef, defaultPortRange: IPortRange) { + constructor(securityGroup: ISecurityGroup, defaultPortRange: IPortRange) { this.connections = new Connections({ securityGroups: [securityGroup] , defaultPortRange }); } } diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts index 4d080c9277ac4..7257af6e3e4da 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener.ts @@ -79,7 +79,7 @@ export class ApplicationListener extends BaseListener implements IApplicationLis /** * Import an existing listener */ - public static import(parent: cdk.Construct, id: string, props: ApplicationListenerRefProps): IApplicationListener { + public static import(parent: cdk.Construct, id: string, props: ApplicationListenerImportProps): IApplicationListener { return new ImportedApplicationListener(parent, id, props); } @@ -238,7 +238,7 @@ export class ApplicationListener extends BaseListener implements IApplicationLis /** * Export this listener */ - public export(): ApplicationListenerRefProps { + public export(): ApplicationListenerImportProps { return { listenerArn: new cdk.Output(this, 'ListenerArn', { value: this.listenerArn }).makeImportValue().toString(), securityGroupId: this.connections.securityGroups[0]!.export().securityGroupId, @@ -296,12 +296,17 @@ export interface IApplicationListener extends ec2.IConnectable, cdk.IDependable * Don't call this directly. It is called by ApplicationTargetGroup. */ registerConnectable(connectable: ec2.IConnectable, portRange: ec2.IPortRange): void; + + /** + * Export this listener + */ + export(): ApplicationListenerImportProps; } /** * Properties to reference an existing listener */ -export interface ApplicationListenerRefProps { +export interface ApplicationListenerImportProps { /** * ARN of the listener */ @@ -327,7 +332,7 @@ class ImportedApplicationListener extends cdk.Construct implements IApplicationL */ public readonly listenerArn: string; - constructor(parent: cdk.Construct, id: string, props: ApplicationListenerRefProps) { + constructor(parent: cdk.Construct, id: string, private readonly props: ApplicationListenerImportProps) { super(parent, id); this.listenerArn = props.listenerArn; @@ -335,11 +340,15 @@ class ImportedApplicationListener extends cdk.Construct implements IApplicationL const defaultPortRange = props.defaultPort !== undefined ? new ec2.TcpPortFromAttribute(props.defaultPort) : undefined; this.connections = new ec2.Connections({ - securityGroups: [ec2.SecurityGroupRef.import(this, 'SecurityGroup', { securityGroupId: props.securityGroupId })], + securityGroups: [ec2.SecurityGroup.import(this, 'SecurityGroup', { securityGroupId: props.securityGroupId })], defaultPortRange, }); } + public export() { + return this.props; + } + /** * Add one or more certificates to this listener. */ diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-load-balancer.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-load-balancer.ts index 8fe575d0bcc9e..f3d1076ac023f 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-load-balancer.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-load-balancer.ts @@ -16,7 +16,7 @@ export interface ApplicationLoadBalancerProps extends BaseLoadBalancerProps { * * @default A security group is created */ - securityGroup?: ec2.SecurityGroupRef; + securityGroup?: ec2.ISecurityGroup; /** * The type of IP addresses to use @@ -49,12 +49,12 @@ export class ApplicationLoadBalancer extends BaseLoadBalancer implements IApplic /** * Import an existing Application Load Balancer */ - public static import(parent: cdk.Construct, id: string, props: ApplicationLoadBalancerRefProps): IApplicationLoadBalancer { + public static import(parent: cdk.Construct, id: string, props: ApplicationLoadBalancerImportProps): IApplicationLoadBalancer { return new ImportedApplicationLoadBalancer(parent, id, props); } public readonly connections: ec2.Connections; - private readonly securityGroup: ec2.SecurityGroupRef; + private readonly securityGroup: ec2.ISecurityGroup; constructor(parent: cdk.Construct, id: string, props: ApplicationLoadBalancerProps) { super(parent, id, props, { @@ -77,7 +77,7 @@ export class ApplicationLoadBalancer extends BaseLoadBalancer implements IApplic /** * Enable access logging for this load balancer */ - public logAccessLogs(bucket: s3.BucketRef, prefix?: string) { + public logAccessLogs(bucket: s3.IBucket, prefix?: string) { this.setAttribute('access_logs.s3.enabled', 'true'); this.setAttribute('access_logs.s3.bucket', bucket.bucketName.toString()); this.setAttribute('access_logs.s3.prefix', prefix); @@ -110,7 +110,7 @@ export class ApplicationLoadBalancer extends BaseLoadBalancer implements IApplic /** * Export this load balancer */ - public export(): ApplicationLoadBalancerRefProps { + public export(): ApplicationLoadBalancerImportProps { return { loadBalancerArn: new cdk.Output(this, 'LoadBalancerArn', { value: this.loadBalancerArn }).makeImportValue().toString(), securityGroupId: this.securityGroup.export().securityGroupId, @@ -485,18 +485,23 @@ export interface IApplicationLoadBalancer extends ec2.IConnectable { /** * The VPC this load balancer has been created in (if available) */ - readonly vpc?: ec2.VpcNetworkRef; + readonly vpc?: ec2.IVpcNetwork; /** * Add a new listener to this load balancer */ addListener(id: string, props: BaseApplicationListenerProps): ApplicationListener; + + /** + * Export this load balancer + */ + export(): ApplicationLoadBalancerImportProps; } /** * Properties to reference an existing load balancer */ -export interface ApplicationLoadBalancerRefProps { +export interface ApplicationLoadBalancerImportProps { /** * ARN of the load balancer */ @@ -534,7 +539,7 @@ const ELBV2_ACCOUNTS: {[region: string]: string } = { /** * An ApplicationLoadBalancer that has been defined elsewhere */ -class ImportedApplicationLoadBalancer extends cdk.Construct implements IApplicationLoadBalancer, ec2.IConnectable { +class ImportedApplicationLoadBalancer extends cdk.Construct implements IApplicationLoadBalancer { /** * Manage connections for this load balancer */ @@ -550,17 +555,21 @@ class ImportedApplicationLoadBalancer extends cdk.Construct implements IApplicat * * Always undefined. */ - public readonly vpc?: ec2.VpcNetworkRef; + public readonly vpc?: ec2.IVpcNetwork; - constructor(parent: cdk.Construct, id: string, props: ApplicationLoadBalancerRefProps) { + constructor(parent: cdk.Construct, id: string, private readonly props: ApplicationLoadBalancerImportProps) { super(parent, id); this.loadBalancerArn = props.loadBalancerArn; this.connections = new ec2.Connections({ - securityGroups: [ec2.SecurityGroupRef.import(this, 'SecurityGroup', { securityGroupId: props.securityGroupId })] + securityGroups: [ec2.SecurityGroup.import(this, 'SecurityGroup', { securityGroupId: props.securityGroupId })] }); } + public export() { + return this.props; + } + public addListener(id: string, props: BaseApplicationListenerProps): ApplicationListener { return new ApplicationListener(this, id, { loadBalancer: this, diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts index d579fab83d5a6..d3786805de5db 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-target-group.ts @@ -1,10 +1,10 @@ import cloudwatch = require('@aws-cdk/aws-cloudwatch'); import ec2 = require('@aws-cdk/aws-ec2'); import cdk = require('@aws-cdk/cdk'); -import { BaseTargetGroup, BaseTargetGroupProps, ITargetGroup, loadBalancerNameFromListenerArn, - LoadBalancerTargetProps, TargetGroupRefProps } from '../shared/base-target-group'; +import { BaseTargetGroupProps, ITargetGroup, loadBalancerNameFromListenerArn, LoadBalancerTargetProps, + TargetGroupBase, TargetGroupImportProps } from '../shared/base-target-group'; import { ApplicationProtocol } from '../shared/enums'; -import { BaseImportedTargetGroup } from '../shared/imported'; +import { ImportedTargetGroupBase } from '../shared/imported'; import { determineProtocolAndPort, LazyDependable } from '../shared/util'; import { IApplicationListener } from './application-listener'; import { HttpCodeTarget } from './application-load-balancer'; @@ -62,11 +62,11 @@ export interface ApplicationTargetGroupProps extends BaseTargetGroupProps { /** * Define an Application Target Group */ -export class ApplicationTargetGroup extends BaseTargetGroup { +export class ApplicationTargetGroup extends TargetGroupBase { /** * Import an existing target group */ - public static import(parent: cdk.Construct, id: string, props: TargetGroupRefProps): IApplicationTargetGroup { + public static import(parent: cdk.Construct, id: string, props: TargetGroupImportProps): IApplicationTargetGroup { return new ImportedApplicationTargetGroup(parent, id, props); } @@ -330,7 +330,7 @@ export interface IApplicationTargetGroup extends ITargetGroup { /** * An imported application target group */ -class ImportedApplicationTargetGroup extends BaseImportedTargetGroup implements IApplicationTargetGroup { +class ImportedApplicationTargetGroup extends ImportedTargetGroupBase implements IApplicationTargetGroup { public registerListener(_listener: IApplicationListener, _dependable?: cdk.IDependable) { // Nothing to do, we know nothing of our members } diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-listener.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-listener.ts index cb3ef4787cf99..e6c5ecba109aa 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-listener.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-listener.ts @@ -39,7 +39,7 @@ export class NetworkListener extends BaseListener implements INetworkListener { /** * Import an existing listener */ - public static import(parent: cdk.Construct, id: string, props: NetworkListenerRefProps): INetworkListener { + public static import(parent: cdk.Construct, id: string, props: NetworkListenerImportProps): INetworkListener { return new ImportedNetworkListener(parent, id, props); } @@ -103,7 +103,7 @@ export class NetworkListener extends BaseListener implements INetworkListener { /** * Export this listener */ - public export(): NetworkListenerRefProps { + public export(): NetworkListenerImportProps { return { listenerArn: new cdk.Output(this, 'ListenerArn', { value: this.listenerArn }).makeImportValue().toString() }; @@ -119,12 +119,17 @@ export interface INetworkListener extends cdk.IDependable { * ARN of the listener */ readonly listenerArn: string; + + /** + * Export this listener + */ + export(): NetworkListenerImportProps; } /** * Properties to reference an existing listener */ -export interface NetworkListenerRefProps { +export interface NetworkListenerImportProps { /** * ARN of the listener */ @@ -142,11 +147,15 @@ class ImportedNetworkListener extends cdk.Construct implements INetworkListener */ public readonly listenerArn: string; - constructor(parent: cdk.Construct, id: string, props: NetworkListenerRefProps) { + constructor(parent: cdk.Construct, id: string, private readonly props: NetworkListenerImportProps) { super(parent, id); this.listenerArn = props.listenerArn; } + + public export() { + return this.props; + } } /** diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-load-balancer.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-load-balancer.ts index 17ff56bd4af91..8979ae96939f3 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-load-balancer.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-load-balancer.ts @@ -20,7 +20,7 @@ export interface NetworkLoadBalancerProps extends BaseLoadBalancerProps { * Define a new network load balancer */ export class NetworkLoadBalancer extends BaseLoadBalancer implements INetworkLoadBalancer { - public static import(parent: cdk.Construct, id: string, props: NetworkLoadBalancerRefProps): INetworkLoadBalancer { + public static import(parent: cdk.Construct, id: string, props: NetworkLoadBalancerImportProps): INetworkLoadBalancer { return new ImportedNetworkLoadBalancer(parent, id, props); } @@ -47,7 +47,7 @@ export class NetworkLoadBalancer extends BaseLoadBalancer implements INetworkLoa /** * Export this load balancer */ - public export(): NetworkLoadBalancerRefProps { + public export(): NetworkLoadBalancerImportProps { return { loadBalancerArn: new cdk.Output(this, 'LoadBalancerArn', { value: this.loadBalancerArn }).makeImportValue().toString() }; @@ -196,7 +196,7 @@ export interface INetworkLoadBalancer { /** * The VPC this load balancer has been created in (if available) */ - readonly vpc?: ec2.VpcNetworkRef; + readonly vpc?: ec2.IVpcNetwork; /** * Add a listener to this load balancer @@ -204,12 +204,17 @@ export interface INetworkLoadBalancer { * @returns The newly created listener */ addListener(id: string, props: BaseNetworkListenerProps): NetworkListener; + + /** + * Export this load balancer + */ + export(): NetworkLoadBalancerImportProps; } /** * Properties to reference an existing load balancer */ -export interface NetworkLoadBalancerRefProps { +export interface NetworkLoadBalancerImportProps { /** * ARN of the load balancer */ @@ -230,14 +235,18 @@ class ImportedNetworkLoadBalancer extends cdk.Construct implements INetworkLoadB * * Always undefined. */ - public readonly vpc?: ec2.VpcNetworkRef; + public readonly vpc?: ec2.IVpcNetwork; - constructor(parent: cdk.Construct, id: string, props: NetworkLoadBalancerRefProps) { + constructor(parent: cdk.Construct, id: string, private readonly props: NetworkLoadBalancerImportProps) { super(parent, id); this.loadBalancerArn = props.loadBalancerArn; } + public export() { + return this.props; + } + /** * Add a listener to this load balancer * diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-target-group.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-target-group.ts index 4f9dfd2251591..44ef15726bbd6 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-target-group.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/nlb/network-target-group.ts @@ -1,8 +1,8 @@ import cdk = require('@aws-cdk/cdk'); -import { BaseTargetGroup, BaseTargetGroupProps, ITargetGroup, loadBalancerNameFromListenerArn, - LoadBalancerTargetProps, TargetGroupRefProps } from '../shared/base-target-group'; +import { BaseTargetGroupProps, ITargetGroup, loadBalancerNameFromListenerArn, LoadBalancerTargetProps, + TargetGroupBase, TargetGroupImportProps } from '../shared/base-target-group'; import { Protocol } from '../shared/enums'; -import { BaseImportedTargetGroup } from '../shared/imported'; +import { ImportedTargetGroupBase } from '../shared/imported'; import { LazyDependable } from '../shared/util'; import { INetworkListener } from './network-listener'; @@ -35,11 +35,11 @@ export interface NetworkTargetGroupProps extends BaseTargetGroupProps { /** * Define a Network Target Group */ -export class NetworkTargetGroup extends BaseTargetGroup { +export class NetworkTargetGroup extends TargetGroupBase { /** * Import an existing listener */ - public static import(parent: cdk.Construct, id: string, props: TargetGroupRefProps): INetworkTargetGroup { + public static import(parent: cdk.Construct, id: string, props: TargetGroupImportProps): INetworkTargetGroup { return new ImportedNetworkTargetGroup(parent, id, props); } @@ -107,7 +107,7 @@ export interface INetworkTargetGroup extends ITargetGroup { /** * An imported network target group */ -class ImportedNetworkTargetGroup extends BaseImportedTargetGroup implements INetworkTargetGroup { +class ImportedNetworkTargetGroup extends ImportedTargetGroupBase implements INetworkTargetGroup { public registerListener(_listener: INetworkListener) { // Nothing to do, we know nothing of our members } diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-load-balancer.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-load-balancer.ts index e36b003896456..6d2fdc138bd85 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-load-balancer.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-load-balancer.ts @@ -18,7 +18,7 @@ export interface BaseLoadBalancerProps { /** * The VPC network to place the load balancer in */ - vpc: ec2.VpcNetworkRef; + vpc: ec2.IVpcNetwork; /** * Whether the load balancer has an internet-routable address @@ -86,7 +86,7 @@ export abstract class BaseLoadBalancer extends cdk.Construct implements route53. * * If the Load Balancer was imported, the VPC is not available. */ - public readonly vpc?: ec2.VpcNetworkRef; + public readonly vpc?: ec2.IVpcNetwork; /** * Attributes set on this load balancer diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts index 0a50e3dfe13ee..5dc46928649ff 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts @@ -23,7 +23,7 @@ export interface BaseTargetGroupProps { /** * The virtual private cloud (VPC). */ - vpc: ec2.VpcNetworkRef; + vpc: ec2.IVpcNetwork; /** * The amount of time for Elastic Load Balancing to wait before deregistering a target. @@ -131,7 +131,7 @@ export interface HealthCheck { /** * Define the target of a load balancer */ -export abstract class BaseTargetGroup extends cdk.Construct implements ITargetGroup, codedeploy.ILoadBalancer { +export abstract class TargetGroupBase extends cdk.Construct implements ITargetGroup, codedeploy.ILoadBalancer { /** * The ARN of the target group */ @@ -261,7 +261,7 @@ export abstract class BaseTargetGroup extends cdk.Construct implements ITargetGr /** * Export this target group */ - public export(): TargetGroupRefProps { + public export(): TargetGroupImportProps { return { targetGroupArn: new cdk.Output(this, 'TargetGroupArn', { value: this.targetGroupArn }).makeImportValue().toString(), defaultPort: new cdk.Output(this, 'Port', { value: this.defaultPort }).makeImportValue().toString(), @@ -307,7 +307,7 @@ export abstract class BaseTargetGroup extends cdk.Construct implements ITargetGr /** * Properties to reference an existing target group */ -export interface TargetGroupRefProps { +export interface TargetGroupImportProps { /** * ARN of the target group */ @@ -342,6 +342,12 @@ export interface ITargetGroup { * Return an object to depend on the listeners added to this target group */ loadBalancerDependency(): cdk.IDependable; + + /** + * Export this target group + */ + export(): TargetGroupImportProps; + } /** diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/imported.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/imported.ts index fe989ed60a789..4449f667785c4 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/imported.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/imported.ts @@ -1,10 +1,10 @@ import cdk = require('@aws-cdk/cdk'); -import { TargetGroupRefProps } from './base-target-group'; +import { ITargetGroup, TargetGroupImportProps } from './base-target-group'; /** - * Base class for existing target groups + * Base internal class for existing target groups */ -export class BaseImportedTargetGroup extends cdk.Construct { +export abstract class ImportedTargetGroupBase extends cdk.Construct implements ITargetGroup { /** * ARN of the target group */ @@ -15,10 +15,19 @@ export class BaseImportedTargetGroup extends cdk.Construct { */ public readonly loadBalancerArns: string; - constructor(parent: cdk.Construct, id: string, props: TargetGroupRefProps) { + constructor(parent: cdk.Construct, id: string, private readonly props: TargetGroupImportProps) { super(parent, id); this.targetGroupArn = props.targetGroupArn; this.loadBalancerArns = props.loadBalancerArns || new cdk.AwsNoValue().toString(); } + + /** + * Return an object to depend on the listeners added to this target group + */ + public abstract loadBalancerDependency(): cdk.IDependable; + + public export() { + return this.props; + } } diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb-alias-target.ts b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb-alias-target.ts index 1226af9be4d55..abde2b0edd6a4 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb-alias-target.ts +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2/test/integ.alb-alias-target.ts @@ -19,6 +19,7 @@ const lb = new elbv2.ApplicationLoadBalancer(stack, 'LB', { const zone = new route53.PublicHostedZone(stack, 'HostedZone', { zoneName: 'test.public' }); new route53.AliasRecord(zone, 'Alias', { + zone, recordName: '_foo', target: lb }); diff --git a/packages/@aws-cdk/aws-events/lib/rule-ref.ts b/packages/@aws-cdk/aws-events/lib/rule-ref.ts index 2a6b50b6b6fb8..4bc2ebcb27398 100644 --- a/packages/@aws-cdk/aws-events/lib/rule-ref.ts +++ b/packages/@aws-cdk/aws-events/lib/rule-ref.ts @@ -1,6 +1,4 @@ -import { Construct, Output } from '@aws-cdk/cdk'; - -export interface EventRuleRefProps { +export interface EventRuleImportProps { /** * The value of the event rule Amazon Resource Name (ARN), such as * arn:aws:events:us-east-2:123456789012:rule/example. @@ -8,37 +6,15 @@ export interface EventRuleRefProps { eventRuleArn: string; } -export abstract class EventRuleRef extends Construct { - - /** - * Imports a rule by ARN into this stack. - */ - public static import(parent: Construct, name: string, props: EventRuleRefProps): EventRuleRef { - return new ImportedEventRule(parent, name, props); - } - +export interface IEventRule { /** * The value of the event rule Amazon Resource Name (ARN), such as * arn:aws:events:us-east-2:123456789012:rule/example. */ - public abstract readonly ruleArn: string; + readonly ruleArn: string; /** * Exports this rule resource from this stack and returns an import token. */ - public export(): EventRuleRefProps { - return { - eventRuleArn: new Output(this, 'RuleArn', { value: this.ruleArn }).makeImportValue().toString() - }; - } -} - -class ImportedEventRule extends EventRuleRef { - public readonly ruleArn: string; - - constructor(parent: Construct, name: string, props: EventRuleRefProps) { - super(parent, name); - - this.ruleArn = props.eventRuleArn; - } + export(): EventRuleImportProps; } diff --git a/packages/@aws-cdk/aws-events/lib/rule.ts b/packages/@aws-cdk/aws-events/lib/rule.ts index 3a2eaf5a0f3a5..85a989fcf27c3 100644 --- a/packages/@aws-cdk/aws-events/lib/rule.ts +++ b/packages/@aws-cdk/aws-events/lib/rule.ts @@ -1,8 +1,8 @@ -import { Construct, Token } from '@aws-cdk/cdk'; +import { Construct, Output, Token } from '@aws-cdk/cdk'; import { EventPattern } from './event-pattern'; import { CfnRule } from './events.generated'; import { TargetInputTemplate } from './input-options'; -import { EventRuleRef } from './rule-ref'; +import { EventRuleImportProps, IEventRule } from './rule-ref'; import { IEventRuleTarget } from './target'; import { mergeEventPattern } from './util'; @@ -63,7 +63,14 @@ export interface EventRuleProps { /** * Defines a CloudWatch Event Rule in this stack. */ -export class EventRule extends EventRuleRef { +export class EventRule extends Construct implements IEventRule { + /** + * Imports a rule by ARN into this stack. + */ + public static import(parent: Construct, name: string, props: EventRuleImportProps): IEventRule { + return new ImportedEventRule(parent, name, props); + } + public readonly ruleArn: string; private readonly targets = new Array(); @@ -92,6 +99,15 @@ export class EventRule extends EventRuleRef { } } + /** + * Exports this rule resource from this stack and returns an import token. + */ + public export(): EventRuleImportProps { + return { + eventRuleArn: new Output(this, 'RuleArn', { value: this.ruleArn }).makeImportValue().toString() + }; + } + /** * Adds a target to the rule. The abstract class RuleTarget can be extended to define new * targets. @@ -219,3 +235,17 @@ export class EventRule extends EventRuleRef { return out; } } + +class ImportedEventRule extends Construct implements IEventRule { + public readonly ruleArn: string; + + constructor(parent: Construct, id: string, private readonly props: EventRuleImportProps) { + super(parent, id); + + this.ruleArn = props.eventRuleArn; + } + + public export() { + return this.props; + } +} diff --git a/packages/@aws-cdk/aws-events/test/test.rule.ts b/packages/@aws-cdk/aws-events/test/test.rule.ts index 72743367c59d0..dd638cd64e548 100644 --- a/packages/@aws-cdk/aws-events/test/test.rule.ts +++ b/packages/@aws-cdk/aws-events/test/test.rule.ts @@ -1,6 +1,6 @@ import { expect, haveResource } from '@aws-cdk/assert'; import cdk = require('@aws-cdk/cdk'); -import { resolve } from '@aws-cdk/cdk'; +import { resolve, Stack } from '@aws-cdk/cdk'; import { Test } from 'nodeunit'; import { IEventRuleTarget } from '../lib'; import { EventRule } from '../lib/rule'; @@ -331,6 +331,25 @@ export = { test.deepEqual(resolve(receivedRuleArn), resolve(rule.ruleArn)); test.deepEqual(receivedRuleId, rule.uniqueId); + test.done(); + }, + + 'import/export rule'(test: Test) { + // GIVEN + const stack = new Stack(); + const myRule = new EventRule(stack, 'MyRule'); + + // WHEN + const exportedRule = myRule.export(); + + const importedRule = EventRule.import(stack, 'ImportedRule', { + eventRuleArn: 'arn:of:rule' + }); + + // THEN + test.deepEqual(cdk.resolve(exportedRule), { eventRuleArn: { 'Fn::ImportValue': 'MyRuleRuleArnDB13ADB1' } }); + test.deepEqual(importedRule.ruleArn, 'arn:of:rule'); + test.done(); } }; diff --git a/packages/@aws-cdk/aws-kinesis/lib/stream.ts b/packages/@aws-cdk/aws-kinesis/lib/stream.ts index a7261a929c0bf..01d272cf24cb4 100644 --- a/packages/@aws-cdk/aws-kinesis/lib/stream.ts +++ b/packages/@aws-cdk/aws-kinesis/lib/stream.ts @@ -4,12 +4,61 @@ import logs = require('@aws-cdk/aws-logs'); import cdk = require('@aws-cdk/cdk'); import { CfnStream } from './kinesis.generated'; +export interface IStream extends logs.ILogSubscriptionDestination { + /** + * The ARN of the stream. + */ + readonly streamArn: string; + + /** + * The name of the stream + */ + readonly streamName: string; + + /** + * Optional KMS encryption key associated with this stream. + */ + readonly encryptionKey?: kms.IEncryptionKey; + + /** + * Exports this stream from the stack. + */ + export(): StreamImportProps; + + /** + * Grant read permissions for this stream and its contents to an IAM + * principal (Role/Group/User). + * + * If an encryption key is used, permission to ues the key to decrypt the + * contents of the stream will also be granted. + */ + grantRead(identity?: iam.IPrincipal): void; + + /** + * Grant write permissions for this stream and its contents to an IAM + * principal (Role/Group/User). + * + * If an encryption key is used, permission to ues the key to encrypt the + * contents of the stream will also be granted. + */ + grantWrite(identity?: iam.IPrincipal): void; + + /** + * Grants read/write permissions for this stream and its contents to an IAM + * principal (Role/Group/User). + * + * If an encryption key is used, permission to use the key for + * encrypt/decrypt will also be granted. + */ + grantReadWrite(identity?: iam.IPrincipal): void; +} + /** * A reference to a stream. The easiest way to instantiate is to call * `stream.export()`. Then, the consumer can use `Stream.import(this, ref)` and * get a `Stream`. */ -export interface StreamRefProps { +export interface StreamImportProps { /** * The ARN of the stream. */ @@ -18,7 +67,7 @@ export interface StreamRefProps { /** * The KMS key securing the contents of the stream if encryption is enabled. */ - encryptionKey?: kms.EncryptionKeyRefProps; + encryptionKey?: kms.EncryptionKeyImportProps; } /** @@ -30,27 +79,15 @@ export interface StreamRefProps { * * Or imported from an existing stream: * - * StreamRef.import(this, 'MyImportedStream', { streamArn: ... }); + * Stream.import(this, 'MyImportedStream', { streamArn: ... }); * * You can also export a stream and import it into another stack: * * const ref = myStream.export(); - * StreamRef.import(this, 'MyImportedStream', ref); + * Stream.import(this, 'MyImportedStream', ref); * */ -export abstract class StreamRef extends cdk.Construct implements logs.ILogSubscriptionDestination { - /** - * Creates a Stream construct that represents an external stream. - * - * @param parent The parent creating construct (usually `this`). - * @param name The construct's name. - * @param ref A StreamRefProps object. Can be obtained from a call to - * `stream.export()`. - */ - public static import(parent: cdk.Construct, name: string, props: StreamRefProps): StreamRef { - return new ImportedStreamRef(parent, name, props); - } - +export abstract class StreamBase extends cdk.Construct implements IStream { /** * The ARN of the stream. */ @@ -64,22 +101,14 @@ export abstract class StreamRef extends cdk.Construct implements logs.ILogSubscr /** * Optional KMS encryption key associated with this stream. */ - public abstract readonly encryptionKey?: kms.EncryptionKeyRef; + public abstract readonly encryptionKey?: kms.IEncryptionKey; /** * The role that can be used by CloudWatch logs to write to this stream */ private cloudWatchLogsRole?: iam.Role; - /** - * Exports this stream from the stack. - */ - public export(): StreamRefProps { - return { - streamArn: new cdk.Output(this, 'StreamArn', { value: this.streamArn }).makeImportValue().toString(), - encryptionKey: this.encryptionKey ? this.encryptionKey.export() : undefined, - }; - } + public abstract export(): StreamImportProps; /** * Grant write permissions for this stream and its contents to an IAM @@ -165,7 +194,7 @@ export abstract class StreamRef extends cdk.Construct implements logs.ILogSubscr ); } - public logSubscriptionDestination(sourceLogGroup: logs.LogGroupRef): logs.LogSubscriptionDestination { + public logSubscriptionDestination(sourceLogGroup: logs.ILogGroup): logs.LogSubscriptionDestination { // Following example from https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/SubscriptionFilters.html#DestinationKinesisExample if (!this.cloudWatchLogsRole) { // Create a role to be assumed by CWL that can write to this stream and pass itself. @@ -178,7 +207,7 @@ export abstract class StreamRef extends cdk.Construct implements logs.ILogSubscr // We've now made it possible for CloudWatch events to write to us. In case the LogGroup is in a // different account, we must add a Destination in between as well. - const sourceStack = cdk.Stack.find(sourceLogGroup); + const sourceStack = cdk.Stack.find(sourceLogGroup as any); const thisStack = cdk.Stack.find(this); // Case considered: if both accounts are undefined, we can't make any assumptions. Better @@ -195,8 +224,9 @@ export abstract class StreamRef extends cdk.Construct implements logs.ILogSubscr /** * Generate a CloudWatch Logs Destination and return the properties in the form o a subscription destination */ - private crossAccountLogSubscriptionDestination(sourceLogGroup: logs.LogGroupRef): logs.LogSubscriptionDestination { - const sourceStack = cdk.Stack.find(sourceLogGroup); + private crossAccountLogSubscriptionDestination(sourceLogGroup: logs.ILogGroup): logs.LogSubscriptionDestination { + const sourceLogGroupConstruct: cdk.Construct = sourceLogGroup as any; + const sourceStack = cdk.Stack.find(sourceLogGroupConstruct); const thisStack = cdk.Stack.find(this); if (!sourceStack.env.account || !thisStack.env.account) { @@ -205,7 +235,7 @@ export abstract class StreamRef extends cdk.Construct implements logs.ILogSubscr // Take some effort to construct a unique ID for the destination that is unique to the // combination of (stream, loggroup). - const uniqueId = new cdk.HashedAddressingScheme().allocateAddress([sourceLogGroup.path.replace('/', ''), sourceStack.env.account!]); + const uniqueId = new cdk.HashedAddressingScheme().allocateAddress([sourceLogGroupConstruct.path.replace('/', ''), sourceStack.env.account!]); // The destination lives in the target account const dest = new logs.CrossAccountDestination(this, `CWLDestination${uniqueId}`, { @@ -272,16 +302,28 @@ export interface StreamProps { * @default If encryption is set to "Kms" and this property is undefined, a * new KMS key will be created and associated with this stream. */ - encryptionKey?: kms.EncryptionKeyRef; + encryptionKey?: kms.IEncryptionKey; } /** * A Kinesis stream. Can be encrypted with a KMS key. */ -export class Stream extends StreamRef { +export class Stream extends StreamBase { + /** + * Creates a Stream construct that represents an external stream. + * + * @param parent The parent creating construct (usually `this`). + * @param name The construct's name. + * @param ref A `StreamAttributes` object. Can be obtained from a call to + * `stream.export()`. + */ + public static import(parent: cdk.Construct, name: string, props: StreamImportProps): IStream { + return new ImportedStream(parent, name, props); + } + public readonly streamArn: string; public readonly streamName: string; - public readonly encryptionKey?: kms.EncryptionKeyRef; + public readonly encryptionKey?: kms.IEncryptionKey; private readonly stream: CfnStream; @@ -309,13 +351,23 @@ export class Stream extends StreamRef { if (props.streamName) { this.addMetadata('aws:cdk:hasPhysicalName', props.streamName); } } + /** + * Exports this stream from the stack. + */ + public export(): StreamImportProps { + return { + streamArn: new cdk.Output(this, 'StreamArn', { value: this.streamArn }).makeImportValue().toString(), + encryptionKey: this.encryptionKey ? this.encryptionKey.export() : undefined, + }; + } + /** * Set up key properties and return the Stream encryption property from the * user's configuration. */ private parseEncryption(props: StreamProps): { streamEncryption?: CfnStream.StreamEncryptionProperty, - encryptionKey?: kms.EncryptionKeyRef + encryptionKey?: kms.IEncryptionKey } { // default to unencrypted. @@ -362,12 +414,12 @@ export enum StreamEncryption { Kms = 'KMS', } -class ImportedStreamRef extends StreamRef { +class ImportedStream extends StreamBase { public readonly streamArn: string; public readonly streamName: string; - public readonly encryptionKey?: kms.EncryptionKeyRef; + public readonly encryptionKey?: kms.IEncryptionKey; - constructor(parent: cdk.Construct, name: string, props: StreamRefProps) { + constructor(parent: cdk.Construct, name: string, private readonly props: StreamImportProps) { super(parent, name); this.streamArn = props.streamArn; @@ -376,9 +428,13 @@ class ImportedStreamRef extends StreamRef { this.streamName = cdk.ArnUtils.parse(props.streamArn).resourceName!; if (props.encryptionKey) { - this.encryptionKey = kms.EncryptionKeyRef.import(parent, 'Key', props.encryptionKey); + this.encryptionKey = kms.EncryptionKey.import(parent, 'Key', props.encryptionKey); } else { this.encryptionKey = undefined; } } + + public export() { + return this.props; + } } diff --git a/packages/@aws-cdk/aws-kms/lib/alias.ts b/packages/@aws-cdk/aws-kms/lib/alias.ts index 9f05844243d13..dcb810b32de2c 100644 --- a/packages/@aws-cdk/aws-kms/lib/alias.ts +++ b/packages/@aws-cdk/aws-kms/lib/alias.ts @@ -1,5 +1,5 @@ import { Construct } from '@aws-cdk/cdk'; -import { EncryptionKeyRef } from './key'; +import { IEncryptionKey } from './key'; import { CfnAlias } from './kms.generated'; const REQUIRED_ALIAS_PREFIX = 'alias/'; @@ -18,7 +18,7 @@ export interface EncryptionKeyAliasProps { * globally unique identifier or Amazon Resource Name (ARN). You can't * specify another alias. */ - key: EncryptionKeyRef; + key: IEncryptionKey; } /** diff --git a/packages/@aws-cdk/aws-kms/lib/key.ts b/packages/@aws-cdk/aws-kms/lib/key.ts index 999b69ce7e10d..5bd50a5d531a5 100644 --- a/packages/@aws-cdk/aws-kms/lib/key.ts +++ b/packages/@aws-cdk/aws-kms/lib/key.ts @@ -3,36 +3,41 @@ import { Construct, DeletionPolicy, Output, resolve } from '@aws-cdk/cdk'; import { EncryptionKeyAlias } from './alias'; import { CfnKey } from './kms.generated'; -export interface EncryptionKeyRefProps { +export interface IEncryptionKey { /** - * The ARN of the external KMS key. + * The ARN of the key. */ - keyArn: string; + readonly keyArn: string; + + /** + * Defines a new alias for the key. + */ + addAlias(alias: string): EncryptionKeyAlias; + + /** + * Adds a statement to the KMS key resource policy. + * @param statement The policy statement to add + * @param allowNoOp If this is set to `false` and there is no policy + * defined (i.e. external key), the operation will fail. Otherwise, it will + * no-op. + */ + addToResourcePolicy(statement: PolicyStatement, allowNoOp?: boolean): void; + + /** + * Exports this key from the current stack. + * @returns a key ref which can be used in a call to `EncryptionKey.import(ref)`. + */ + export(): EncryptionKeyImportProps; } -export abstract class EncryptionKeyRef extends Construct { +export interface EncryptionKeyImportProps { /** - * Defines an imported encryption key. - * - * `ref` can be obtained either via a call to `key.export()` or using - * literals. - * - * For example: - * - * const keyRefProps = key.export(); - * const keyRef1 = EncryptionKeyRef.import(this, 'MyImportedKey1', keyRefProps); - * const keyRef2 = EncryptionKeyRef.import(this, 'MyImportedKey2', { - * keyArn: new KeyArn('arn:aws:kms:...') - * }); - * - * @param parent The parent construct. - * @param name The name of the construct. - * @param props The key reference. + * The ARN of the external KMS key. */ - public static import(parent: Construct, name: string, props: EncryptionKeyRefProps): EncryptionKeyRef { - return new EncryptionKeyRefImport(parent, name, props); - } + keyArn: string; +} +export abstract class EncryptionKeyBase extends Construct { /** * The ARN of the key. */ @@ -69,15 +74,7 @@ export abstract class EncryptionKeyRef extends Construct { this.policy.addStatement(statement); } - /** - * Exports this key from the current stack. - * @returns a key ref which can be used in a call to `EncryptionKey.import(ref)`. - */ - public export(): EncryptionKeyRefProps { - return { - keyArn: new Output(this, 'KeyArn', { value: this.keyArn }).makeImportValue().toString() - }; - } + public abstract export(): EncryptionKeyImportProps; } /** @@ -114,7 +111,29 @@ export interface EncryptionKeyProps { /** * Defines a KMS key. */ -export class EncryptionKey extends EncryptionKeyRef { +export class EncryptionKey extends EncryptionKeyBase { + /** + * Defines an imported encryption key. + * + * `ref` can be obtained either via a call to `key.export()` or using + * literals. + * + * For example: + * + * const keyAttr = key.export(); + * const keyRef1 = EncryptionKey.import(this, 'MyImportedKey1', keyAttr); + * const keyRef2 = EncryptionKey.import(this, 'MyImportedKey2', { + * keyArn: new KeyArn('arn:aws:kms:...') + * }); + * + * @param parent The parent construct. + * @param name The name of the construct. + * @param props The key reference. + */ + public static import(parent: Construct, name: string, props: EncryptionKeyImportProps): IEncryptionKey { + return new ImportedEncryptionKey(parent, name, props); + } + public readonly keyArn: string; protected readonly policy?: PolicyDocument; @@ -139,6 +158,16 @@ export class EncryptionKey extends EncryptionKeyRef { resource.options.deletionPolicy = DeletionPolicy.Retain; } + /** + * Exports this key from the current stack. + * @returns a key ref which can be used in a call to `EncryptionKey.import(ref)`. + */ + public export(): EncryptionKeyImportProps { + return { + keyArn: new Output(this, 'KeyArn', { value: this.keyArn }).makeImportValue().toString() + }; + } + /** * Let users from this account admin this key. * @link https://aws.amazon.com/premiumsupport/knowledge-center/update-key-policy-future/ @@ -166,13 +195,17 @@ export class EncryptionKey extends EncryptionKeyRef { } } -class EncryptionKeyRefImport extends EncryptionKeyRef { +class ImportedEncryptionKey extends EncryptionKeyBase { public readonly keyArn: string; protected readonly policy = undefined; // no policy associated with an imported key - constructor(parent: Construct, name: string, props: EncryptionKeyRefProps) { + constructor(parent: Construct, name: string, private readonly props: EncryptionKeyImportProps) { super(parent, name); this.keyArn = props.keyArn; } + + public export() { + return this.props; + } } diff --git a/packages/@aws-cdk/aws-lambda-event-sources/lib/s3.ts b/packages/@aws-cdk/aws-lambda-event-sources/lib/s3.ts index 5682f91fc9bf9..49e4fe8e9d4a9 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/lib/s3.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/lib/s3.ts @@ -24,7 +24,7 @@ export class S3EventSource implements lambda.IEventSource { } - public bind(target: lambda.FunctionRef) { + public bind(target: lambda.FunctionBase) { const filters = this.props.filters || []; for (const event of this.props.events) { this.bucket.onEvent(event, target, ...filters); diff --git a/packages/@aws-cdk/aws-lambda-event-sources/lib/sns.ts b/packages/@aws-cdk/aws-lambda-event-sources/lib/sns.ts index 093bfd8a37d76..f4f690f00dd7d 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/lib/sns.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/lib/sns.ts @@ -5,10 +5,10 @@ import sns = require('@aws-cdk/aws-sns'); * Use an Amazon SNS topic as an event source for AWS Lambda. */ export class SnsEventSource implements lambda.IEventSource { - constructor(readonly topic: sns.TopicRef) { + constructor(readonly topic: sns.ITopic) { } - public bind(target: lambda.FunctionRef) { + public bind(target: lambda.FunctionBase) { this.topic.subscribeLambda(target); } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda-event-sources/lib/sqs.ts b/packages/@aws-cdk/aws-lambda-event-sources/lib/sqs.ts index 3cb3273ae6146..faf7576047f68 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/lib/sqs.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/lib/sqs.ts @@ -18,13 +18,13 @@ export interface SqsEventSourceProps { * Use an Amazon SQS queue as an event source for AWS Lambda. */ export class SqsEventSource implements lambda.IEventSource { - constructor(readonly queue: sqs.QueueRef, private readonly props: SqsEventSourceProps = { }) { + constructor(readonly queue: sqs.IQueue, private readonly props: SqsEventSourceProps = { }) { if (this.props.batchSize !== undefined && (this.props.batchSize < 1 || this.props.batchSize > 10)) { throw new Error(`Maximum batch size must be between 1 and 10 inclusive (given ${this.props.batchSize})`); } } - public bind(target: lambda.FunctionRef) { + public bind(target: lambda.FunctionBase) { new lambda.EventSourceMapping(target, `SqsEventSource:${this.queue.uniqueId}`, { target, batchSize: this.props.batchSize, diff --git a/packages/@aws-cdk/aws-lambda/lib/alias.ts b/packages/@aws-cdk/aws-lambda/lib/alias.ts index 3170a95bc2f4b..a1d728b3b87c3 100644 --- a/packages/@aws-cdk/aws-lambda/lib/alias.ts +++ b/packages/@aws-cdk/aws-lambda/lib/alias.ts @@ -1,7 +1,7 @@ import iam = require('@aws-cdk/aws-iam'); import cdk = require('@aws-cdk/cdk'); -import { FunctionRef } from './lambda-ref'; -import { FunctionVersion } from './lambda-version'; +import { FunctionBase, FunctionImportProps, IFunction } from './lambda-ref'; +import { Version } from './lambda-version'; import { CfnAlias } from './lambda.generated'; import { Permission } from './permission'; @@ -21,7 +21,7 @@ export interface AliasProps { * * Use lambda.addVersion() to obtain a new lambda version to refer to. */ - version: FunctionVersion; + version: Version; /** * Name of this alias @@ -51,7 +51,7 @@ export interface AliasProps { /** * A new alias to a particular version of a Lambda function. */ -export class Alias extends FunctionRef { +export class Alias extends FunctionBase { /** * ARN of this alias * @@ -78,10 +78,10 @@ export class Alias extends FunctionRef { /** * The actual Lambda function object that this Alias is pointing to */ - private readonly underlyingLambda: FunctionRef; + private readonly underlyingLambda: IFunction; - constructor(parent: cdk.Construct, name: string, props: AliasProps) { - super(parent, name); + constructor(parent: cdk.Construct, id: string, props: AliasProps) { + super(parent, id); this.underlyingLambda = props.version.lambda; @@ -99,6 +99,12 @@ export class Alias extends FunctionRef { this.functionArn = alias.aliasArn; } + public export(): FunctionImportProps { + return { + functionArn: new cdk.Output(this, 'AliasArn', { value: this.functionArn }).makeImportValue().toString() + }; + } + public addPermission(name: string, permission: Permission) { // Forward addPermission() to the underlying Lambda object this.underlyingLambda.addPermission(name, permission); @@ -148,7 +154,7 @@ export interface VersionWeight { /** * The version to route traffic to */ - readonly version: FunctionVersion; + readonly version: Version; /** * How much weight to assign to this version (0..1) diff --git a/packages/@aws-cdk/aws-lambda/lib/code.ts b/packages/@aws-cdk/aws-lambda/lib/code.ts index 2c7f35f8af84c..ebbd34940d0c3 100644 --- a/packages/@aws-cdk/aws-lambda/lib/code.ts +++ b/packages/@aws-cdk/aws-lambda/lib/code.ts @@ -11,7 +11,7 @@ export abstract class Code { * @param key The object key * @param objectVersion Optional S3 object version */ - public static bucket(bucket: s3.BucketRef, key: string, objectVersion?: string) { + public static bucket(bucket: s3.IBucket, key: string, objectVersion?: string) { return new S3Code(bucket, key, objectVersion); } @@ -71,7 +71,7 @@ export abstract class Code { export class S3Code extends Code { private bucketName: string; - constructor(bucket: s3.BucketRef, private key: string, private objectVersion?: string) { + constructor(bucket: s3.IBucket, private key: string, private objectVersion?: string) { super(); if (!bucket.bucketName) { diff --git a/packages/@aws-cdk/aws-lambda/lib/event-source-mapping.ts b/packages/@aws-cdk/aws-lambda/lib/event-source-mapping.ts index 481658dda5853..784777c1218f7 100644 --- a/packages/@aws-cdk/aws-lambda/lib/event-source-mapping.ts +++ b/packages/@aws-cdk/aws-lambda/lib/event-source-mapping.ts @@ -1,5 +1,5 @@ import cdk = require('@aws-cdk/cdk'); -import { FunctionRef } from './lambda-ref'; +import { IFunction } from './lambda-ref'; import { CfnEventSourceMapping } from './lambda.generated'; export interface EventSourceMappingProps { @@ -12,7 +12,7 @@ export interface EventSourceMappingProps { /** * The target AWS Lambda function. */ - target: FunctionRef; + target: IFunction; /** * The largest number of records that AWS Lambda will retrieve from your event diff --git a/packages/@aws-cdk/aws-lambda/lib/event-source.ts b/packages/@aws-cdk/aws-lambda/lib/event-source.ts index 76aa56311e05e..10b0937a6cfca 100644 --- a/packages/@aws-cdk/aws-lambda/lib/event-source.ts +++ b/packages/@aws-cdk/aws-lambda/lib/event-source.ts @@ -1,4 +1,4 @@ -import { FunctionRef } from './lambda-ref'; +import { FunctionBase } from './lambda-ref'; /** * An abstract class which represents an AWS Lambda event source. @@ -9,5 +9,5 @@ export interface IEventSource { * function. * @param target That lambda function to bind to. */ - bind(target: FunctionRef): void; + bind(target: FunctionBase): void; } diff --git a/packages/@aws-cdk/aws-lambda/lib/lambda-ref.ts b/packages/@aws-cdk/aws-lambda/lib/lambda-ref.ts index 2971dc26c76d8..5f4f1f7d621a8 100644 --- a/packages/@aws-cdk/aws-lambda/lib/lambda-ref.ts +++ b/packages/@aws-cdk/aws-lambda/lib/lambda-ref.ts @@ -12,121 +12,129 @@ import { CfnPermission } from './lambda.generated'; import { Permission } from './permission'; import { CommonPipelineInvokeActionProps, PipelineInvokeAction } from './pipeline-action'; -/** - * Represents a Lambda function defined outside of this stack. - */ -export interface FunctionRefProps { +export interface IFunction extends events.IEventRuleTarget, logs.ILogSubscriptionDestination, + s3n.IBucketNotificationDestination, ec2.IConnectable, stepfunctions.IStepFunctionsTaskResource { + /** - * The ARN of the Lambda function. - * - * Format: arn::lambda:::function: + * Logical ID of this Function. */ - functionArn: string; + readonly id: string; /** - * The IAM execution role associated with this function. - * - * If the role is not specified, any role-related operations will no-op. + * The name of the function. */ - role?: iam.Role; + readonly functionName: string; /** - * Id of the securityGroup for this Lambda, if in a VPC. - * - * This needs to be given in order to support allowing connections - * to this Lambda. + * The ARN fo the function. */ - securityGroupId?: string; -} + readonly functionArn: string; -export abstract class FunctionRef extends cdk.Construct - implements events.IEventRuleTarget, logs.ILogSubscriptionDestination, s3n.IBucketNotificationDestination, - ec2.IConnectable, stepfunctions.IStepFunctionsTaskResource { + /** + * The IAM role associated with this function. + */ + readonly role?: iam.Role; /** - * Creates a Lambda function object which represents a function not defined - * within this stack. + * Whether or not this Lambda function was bound to a VPC * - * Lambda.import(this, 'MyImportedFunction', { lambdaArn: new LambdaArn('arn:aws:...') }); + * If this is is `false`, trying to access the `connections` object will fail. + */ + readonly isBoundToVpc: boolean; + + /** + * Adds a permission to the Lambda resource policy. + * @param id The id Æ’or the permission construct + */ + addPermission(id: string, permission: Permission): void; + + /** + * Convenience method for creating a new {@link PipelineInvokeAction}, + * and adding it to the given Stage. * - * @param parent The parent construct - * @param name The name of the lambda construct - * @param ref A reference to a Lambda function. Can be created manually (see - * example above) or obtained through a call to `lambda.export()`. + * @param stage the Pipeline Stage to add the new Action to + * @param name the name of the newly created Action + * @param props the properties of the new Action + * @returns the newly created {@link PipelineInvokeAction} */ - public static import(parent: cdk.Construct, name: string, ref: FunctionRefProps): FunctionRef { - return new LambdaRefImport(parent, name, ref); - } + addToPipeline(stage: codepipeline.IStage, name: string, props?: CommonPipelineInvokeActionProps): PipelineInvokeAction; + + addToRolePolicy(statement: iam.PolicyStatement): void; + + /** + * Grant the given identity permissions to invoke this Lambda + */ + grantInvoke(identity?: iam.IPrincipal): void; /** * Return the given named metric for this Lambda */ - public static metricAll(metricName: string, props?: cloudwatch.MetricCustomization): cloudwatch.Metric { - return new cloudwatch.Metric({ - namespace: 'AWS/Lambda', - metricName, - ...props - }); - } + metric(metricName: string, props?: cloudwatch.MetricCustomization): cloudwatch.Metric; + /** - * Metric for the number of Errors executing all Lambdas + * Metric for the Errors executing this Lambda * * @default sum over 5 minutes */ - public static metricAllErrors(props?: cloudwatch.MetricCustomization): cloudwatch.Metric { - return FunctionRef.metricAll('Errors', { statistic: 'sum', ...props }); - } + metricErrors(props?: cloudwatch.MetricCustomization): cloudwatch.Metric; /** - * Metric for the Duration executing all Lambdas + * Metric for the Duration of this Lambda * * @default average over 5 minutes */ - public static metricAllDuration(props?: cloudwatch.MetricCustomization): cloudwatch.Metric { - return FunctionRef.metricAll('Duration', props); - } + metricDuration(props?: cloudwatch.MetricCustomization): cloudwatch.Metric; /** - * Metric for the number of invocations of all Lambdas + * Metric for the number of invocations of this Lambda * * @default sum over 5 minutes */ - public static metricAllInvocations(props?: cloudwatch.MetricCustomization): cloudwatch.Metric { - return FunctionRef.metricAll('Invocations', { statistic: 'sum', ...props }); - } + metricInvocations(props?: cloudwatch.MetricCustomization): cloudwatch.Metric; /** - * Metric for the number of throttled invocations of all Lambdas + * Metric for the number of throttled invocations of this Lambda * * @default sum over 5 minutes */ - public static metricAllThrottles(props?: cloudwatch.MetricCustomization): cloudwatch.Metric { - return FunctionRef.metricAll('Throttles', { statistic: 'sum', ...props }); - } + metricThrottles(props?: cloudwatch.MetricCustomization): cloudwatch.Metric; /** - * Metric for the number of concurrent executions across all Lambdas + * Export this Function (without the role) + */ + export(): FunctionImportProps; + + addEventSource(source: IEventSource): void; +} + +/** + * Represents a Lambda function defined outside of this stack. + */ +export interface FunctionImportProps { + /** + * The ARN of the Lambda function. * - * @default max over 5 minutes - */ - public static metricAllConcurrentExecutions(props?: cloudwatch.MetricCustomization): cloudwatch.Metric { - // Mini-FAQ: why max? This metric is a gauge that is emitted every - // minute, so either max or avg or a percentile make sense (but sum - // doesn't). Max is more sensitive to spiky load changes which is - // probably what you're interested in if you're looking at this metric - // (Load spikes may lead to concurrent execution errors that would - // otherwise not be visible in the avg) - return FunctionRef.metricAll('ConcurrentExecutions', { statistic: 'max', ...props }); - } + * Format: arn::lambda:::function: + */ + functionArn: string; /** - * Metric for the number of unreserved concurrent executions across all Lambdas + * The IAM execution role associated with this function. * - * @default max over 5 minutes + * If the role is not specified, any role-related operations will no-op. */ - public static metricAllUnreservedConcurrentExecutions(props?: cloudwatch.MetricCustomization): cloudwatch.Metric { - return FunctionRef.metricAll('UnreservedConcurrentExecutions', { statistic: 'max', ...props }); - } + role?: iam.Role; + + /** + * Id of the securityGroup for this Lambda, if in a VPC. + * + * This needs to be given in order to support allowing connections + * to this Lambda. + */ + securityGroupId?: string; +} + +export abstract class FunctionBase extends cdk.Construct implements IFunction { /** * The name of the function. @@ -311,7 +319,7 @@ export abstract class FunctionRef extends cdk.Construct return this.metric('Throttles', { statistic: 'sum', ...props }); } - public logSubscriptionDestination(sourceLogGroup: logs.LogGroupRef): logs.LogSubscriptionDestination { + public logSubscriptionDestination(sourceLogGroup: logs.ILogGroup): logs.LogSubscriptionDestination { const arn = sourceLogGroup.logGroupArn; if (this.logSubscriptionDestinationPolicyAddedFor.indexOf(arn) === -1) { @@ -331,14 +339,7 @@ export abstract class FunctionRef extends cdk.Construct /** * Export this Function (without the role) */ - public export(): FunctionRefProps { - return { - functionArn: new cdk.Output(this, 'FunctionArn', { value: this.functionArn }).makeImportValue().toString(), - securityGroupId: this._connections && this._connections.securityGroups[0] - ? new cdk.Output(this, 'SecurityGroupId', { value: this._connections.securityGroups[0].securityGroupId }).makeImportValue().toString() - : undefined - }; - } + public abstract export(): FunctionImportProps; /** * Allows this Lambda to be used as a destination for bucket notifications. @@ -413,44 +414,3 @@ export abstract class FunctionRef extends cdk.Construct 'Supported: AccountPrincipal, ServicePrincipal'); } } - -class LambdaRefImport extends FunctionRef { - public readonly functionName: string; - public readonly functionArn: string; - public readonly role?: iam.Role; - - protected readonly canCreatePermissions = false; - - constructor(parent: cdk.Construct, name: string, props: FunctionRefProps) { - super(parent, name); - - this.functionArn = props.functionArn; - this.functionName = this.extractNameFromArn(props.functionArn); - this.role = props.role; - - if (props.securityGroupId) { - this._connections = new ec2.Connections({ - securityGroups: [ec2.SecurityGroupRef.import(this, 'SecurityGroup', { - securityGroupId: props.securityGroupId - })] - }); - } - } - - /** - * Given an opaque (token) ARN, returns a CloudFormation expression that extracts the function - * name from the ARN. - * - * Function ARNs look like this: - * - * arn:aws:lambda:region:account-id:function:function-name - * - * ..which means that in order to extract the `function-name` component from the ARN, we can - * split the ARN using ":" and select the component in index 6. - * - * @returns `FnSelect(6, FnSplit(':', arn))` - */ - private extractNameFromArn(arn: string) { - return cdk.Fn.select(6, cdk.Fn.split(':', arn)).toString(); - } -} diff --git a/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts b/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts index d2e058e3d7729..652f91442e77d 100644 --- a/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts +++ b/packages/@aws-cdk/aws-lambda/lib/lambda-version.ts @@ -1,11 +1,11 @@ import { Construct } from '@aws-cdk/cdk'; -import { FunctionRef } from './lambda-ref'; +import { IFunction } from './lambda-ref'; import { CfnVersion } from './lambda.generated'; /** * Properties for a new Lambda version */ -export interface FunctionVersionProps { +export interface VersionProps { /** * SHA256 of the version of the Lambda source code * @@ -25,7 +25,7 @@ export interface FunctionVersionProps { /** * Function to get the value of */ - lambda: FunctionRef; + lambda: IFunction; } /** @@ -44,7 +44,7 @@ export interface FunctionVersionProps { * the right deployment, specify the `codeSha256` property while * creating the `Version. */ -export class FunctionVersion extends Construct { +export class Version extends Construct { /** * The most recently deployed version of this function. */ @@ -53,10 +53,10 @@ export class FunctionVersion extends Construct { /** * Lambda object this version is associated with */ - public readonly lambda: FunctionRef; + public readonly lambda: IFunction; - constructor(parent: Construct, name: string, props: FunctionVersionProps) { - super(parent, name); + constructor(parent: Construct, id: string, props: VersionProps) { + super(parent, id); const version = new CfnVersion(this, 'Resource', { codeSha256: props.codeSha256, diff --git a/packages/@aws-cdk/aws-lambda/lib/lambda.ts b/packages/@aws-cdk/aws-lambda/lib/lambda.ts index d2ec71d12d4b2..34e52e03b09be 100644 --- a/packages/@aws-cdk/aws-lambda/lib/lambda.ts +++ b/packages/@aws-cdk/aws-lambda/lib/lambda.ts @@ -1,10 +1,11 @@ +import cloudwatch = require('@aws-cdk/aws-cloudwatch'); import ec2 = require('@aws-cdk/aws-ec2'); import iam = require('@aws-cdk/aws-iam'); import sqs = require('@aws-cdk/aws-sqs'); import cdk = require('@aws-cdk/cdk'); import { Code } from './code'; -import { FunctionRef } from './lambda-ref'; -import { FunctionVersion } from './lambda-version'; +import { FunctionBase, FunctionImportProps, IFunction } from './lambda-ref'; +import { Version } from './lambda-version'; import { CfnFunction } from './lambda.generated'; import { Runtime } from './runtime'; @@ -117,7 +118,7 @@ export interface FunctionProps { * * Specify this if the Lambda function needs to access resources in a VPC. */ - vpc?: ec2.VpcNetworkRef; + vpc?: ec2.IVpcNetwork; /** * Where to place the network interfaces within the VPC. @@ -138,7 +139,7 @@ export interface FunctionProps { * not specified, a dedicated security group will be created for this * function. */ - securityGroup?: ec2.SecurityGroupRef; + securityGroup?: ec2.ISecurityGroup; /** * Whether to allow the Lambda to send all network traffic @@ -163,7 +164,7 @@ export interface FunctionProps { * * @default SQS queue with 14 day retention period if `deadLetterQueueEnabled` is `true` */ - deadLetterQueue?: sqs.QueueRef; + deadLetterQueue?: sqs.IQueue; /** * Enable AWS X-Ray Tracing for Lambda Function. @@ -184,7 +185,92 @@ export interface FunctionProps { * This construct does not yet reproduce all features from the underlying resource * library. */ -export class Function extends FunctionRef { +export class Function extends FunctionBase { + /** + * Creates a Lambda function object which represents a function not defined + * within this stack. + * + * Lambda.import(this, 'MyImportedFunction', { lambdaArn: new LambdaArn('arn:aws:...') }); + * + * @param parent The parent construct + * @param id The name of the lambda construct + * @param attrs A reference to a Lambda function. Can be created manually (see + * example above) or obtained through a call to `lambda.export()`. + */ + public static import(parent: cdk.Construct, id: string, attrs: FunctionImportProps): IFunction { + return new ImportedFunction(parent, id, attrs); + } + + /** + * Return the given named metric for this Lambda + */ + public static metricAll(metricName: string, props?: cloudwatch.MetricCustomization): cloudwatch.Metric { + return new cloudwatch.Metric({ + namespace: 'AWS/Lambda', + metricName, + ...props + }); + } + /** + * Metric for the number of Errors executing all Lambdas + * + * @default sum over 5 minutes + */ + public static metricAllErrors(props?: cloudwatch.MetricCustomization): cloudwatch.Metric { + return this.metricAll('Errors', { statistic: 'sum', ...props }); + } + + /** + * Metric for the Duration executing all Lambdas + * + * @default average over 5 minutes + */ + public static metricAllDuration(props?: cloudwatch.MetricCustomization): cloudwatch.Metric { + return this.metricAll('Duration', props); + } + + /** + * Metric for the number of invocations of all Lambdas + * + * @default sum over 5 minutes + */ + public static metricAllInvocations(props?: cloudwatch.MetricCustomization): cloudwatch.Metric { + return this.metricAll('Invocations', { statistic: 'sum', ...props }); + } + + /** + * Metric for the number of throttled invocations of all Lambdas + * + * @default sum over 5 minutes + */ + public static metricAllThrottles(props?: cloudwatch.MetricCustomization): cloudwatch.Metric { + return this.metricAll('Throttles', { statistic: 'sum', ...props }); + } + + /** + * Metric for the number of concurrent executions across all Lambdas + * + * @default max over 5 minutes + */ + public static metricAllConcurrentExecutions(props?: cloudwatch.MetricCustomization): cloudwatch.Metric { + // Mini-FAQ: why max? This metric is a gauge that is emitted every + // minute, so either max or avg or a percentile make sense (but sum + // doesn't). Max is more sensitive to spiky load changes which is + // probably what you're interested in if you're looking at this metric + // (Load spikes may lead to concurrent execution errors that would + // otherwise not be visible in the avg) + return this.metricAll('ConcurrentExecutions', { statistic: 'max', ...props }); + } + + /** + * Metric for the number of unreserved concurrent executions across all Lambdas + * + * @default max over 5 minutes + */ + public static metricAllUnreservedConcurrentExecutions(props?: cloudwatch.MetricCustomization): cloudwatch.Metric { + return this.metricAll('UnreservedConcurrentExecutions', { statistic: 'max', ...props }); + } + /** * Name of this function */ @@ -217,8 +303,8 @@ export class Function extends FunctionRef { */ private readonly environment?: { [key: string]: any }; - constructor(parent: cdk.Construct, name: string, props: FunctionProps) { - super(parent, name); + constructor(parent: cdk.Construct, id: string, props: FunctionProps) { + super(parent, id); this.environment = props.environment || { }; @@ -267,6 +353,18 @@ export class Function extends FunctionRef { props.code.bind(this); } + /** + * Export this Function (without the role) + */ + public export(): FunctionImportProps { + return { + functionArn: new cdk.Output(this, 'FunctionArn', { value: this.functionArn }).makeImportValue().toString(), + securityGroupId: this._connections && this._connections.securityGroups[0] + ? new cdk.Output(this, 'SecurityGroupId', { value: this._connections.securityGroups[0].securityGroupId }).makeImportValue().toString() + : undefined + }; + } + /** * Adds an environment variable to this Lambda function. * If this is a ref to a Lambda function, this operation results in a no-op. @@ -297,8 +395,8 @@ export class Function extends FunctionRef { * @param description A description for this version. * @returns A new Version object. */ - public addVersion(name: string, codeSha256?: string, description?: string): FunctionVersion { - return new FunctionVersion(this, 'Version' + name, { + public addVersion(name: string, codeSha256?: string, description?: string): Version { + return new Version(this, 'Version' + name, { lambda: this, codeSha256, description, @@ -390,5 +488,49 @@ export class Function extends FunctionRef { mode: Tracing[props.tracing] }; } +} + +export class ImportedFunction extends FunctionBase { + public readonly functionName: string; + public readonly functionArn: string; + public readonly role?: iam.Role; + + protected readonly canCreatePermissions = false; + + constructor(parent: cdk.Construct, id: string, private readonly props: FunctionImportProps) { + super(parent, id); + + this.functionArn = props.functionArn; + this.functionName = extractNameFromArn(props.functionArn); + this.role = props.role; + + if (props.securityGroupId) { + this._connections = new ec2.Connections({ + securityGroups: [ + ec2.SecurityGroup.import(this, 'SecurityGroup', { securityGroupId: props.securityGroupId }) + ] + }); + } + } + public export() { + return this.props; + } } + +/** + * Given an opaque (token) ARN, returns a CloudFormation expression that extracts the function + * name from the ARN. + * + * Function ARNs look like this: + * + * arn:aws:lambda:region:account-id:function:function-name + * + * ..which means that in order to extract the `function-name` component from the ARN, we can + * split the ARN using ":" and select the component in index 6. + * + * @returns `FnSelect(6, FnSplit(':', arn))` + */ +function extractNameFromArn(arn: string) { + return cdk.Fn.select(6, cdk.Fn.split(':', arn)); +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda/lib/pipeline-action.ts b/packages/@aws-cdk/aws-lambda/lib/pipeline-action.ts index a5a930c355ed4..256c7c0d8f4d6 100644 --- a/packages/@aws-cdk/aws-lambda/lib/pipeline-action.ts +++ b/packages/@aws-cdk/aws-lambda/lib/pipeline-action.ts @@ -1,12 +1,12 @@ import codepipeline = require('@aws-cdk/aws-codepipeline-api'); import iam = require('@aws-cdk/aws-iam'); import cdk = require('@aws-cdk/cdk'); -import { FunctionRef } from './lambda-ref'; +import { IFunction } from './lambda-ref'; /** * Common properties for creating a {@link PipelineInvokeAction} - * either directly, through its constructor, - * or through {@link FunctionRef#addToPipeline}. + * or through {@link IFunction#addToPipeline}. */ export interface CommonPipelineInvokeActionProps extends codepipeline.CommonActionProps { // because of @see links @@ -72,7 +72,7 @@ export interface PipelineInvokeActionProps extends CommonPipelineInvokeActionPro /** * The lambda function to invoke. */ - lambda: FunctionRef; + lambda: IFunction; } /** diff --git a/packages/@aws-cdk/aws-lambda/lib/singleton-lambda.ts b/packages/@aws-cdk/aws-lambda/lib/singleton-lambda.ts index 026dc3b5676b3..8f5abe4b9eb7e 100644 --- a/packages/@aws-cdk/aws-lambda/lib/singleton-lambda.ts +++ b/packages/@aws-cdk/aws-lambda/lib/singleton-lambda.ts @@ -1,7 +1,7 @@ import iam = require('@aws-cdk/aws-iam'); import cdk = require('@aws-cdk/cdk'); import { Function as LambdaFunction, FunctionProps } from './lambda'; -import { FunctionRef } from './lambda-ref'; +import { FunctionBase, FunctionImportProps, IFunction } from './lambda-ref'; import { Permission } from './permission'; /** @@ -34,12 +34,12 @@ export interface SingletonFunctionProps extends FunctionProps { * The lambda is identified using the value of 'uuid'. Run 'uuidgen' * for every SingletonLambda you create. */ -export class SingletonFunction extends FunctionRef { +export class SingletonFunction extends FunctionBase { public readonly functionName: string; public readonly functionArn: string; public readonly role?: iam.Role | undefined; protected readonly canCreatePermissions: boolean; - private lambdaFunction: FunctionRef; + private lambdaFunction: IFunction; constructor(parent: cdk.Construct, name: string, props: SingletonFunctionProps) { super(parent, name); @@ -53,17 +53,21 @@ export class SingletonFunction extends FunctionRef { this.canCreatePermissions = true; // Doesn't matter, addPermission is overriden anyway } + public export(): FunctionImportProps { + return this.lambdaFunction.export(); + } + public addPermission(name: string, permission: Permission) { return this.lambdaFunction.addPermission(name, permission); } - private ensureLambda(props: SingletonFunctionProps): FunctionRef { + private ensureLambda(props: SingletonFunctionProps): IFunction { const constructName = (props.lambdaPurpose || 'SingletonLambda') + slugify(props.uuid); const stack = cdk.Stack.find(this); const existing = stack.tryFindChild(constructName); if (existing) { // Just assume this is true - return existing as FunctionRef; + return existing as FunctionBase; } return new LambdaFunction(stack, constructName, props); diff --git a/packages/@aws-cdk/aws-lambda/test/test.lambda.ts b/packages/@aws-cdk/aws-lambda/test/test.lambda.ts index ebcca95f660e6..38c6a81a4c21e 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.lambda.ts +++ b/packages/@aws-cdk/aws-lambda/test/test.lambda.ts @@ -234,7 +234,7 @@ export = { }, 'import/export': { - 'lambda.export() can be used to add Outputs to the stack and returns a LambdaRef object'(test: Test) { + 'lambda.export() can be used to add Outputs to the stack and returns an IFunction object'(test: Test) { // GIVEN const stack1 = new cdk.Stack(); const stack2 = new cdk.Stack(); @@ -242,7 +242,7 @@ export = { // WHEN const props = fn.export(); - const imported = lambda.FunctionRef.import(stack2, 'Imported', props); + const imported = lambda.Function.import(stack2, 'Imported', props); // Can call addPermission() but it won't do anything imported.addPermission('Hello', { @@ -1076,7 +1076,7 @@ export = { let bindTarget; class EventSourceMock implements lambda.IEventSource { - public bind(target: lambda.FunctionRef) { + public bind(target: lambda.IFunction) { bindTarget = target; } } diff --git a/packages/@aws-cdk/aws-lambda/test/test.vpc-lambda.ts b/packages/@aws-cdk/aws-lambda/test/test.vpc-lambda.ts index cebff1fcf4272..46ba08766c520 100644 --- a/packages/@aws-cdk/aws-lambda/test/test.vpc-lambda.ts +++ b/packages/@aws-cdk/aws-lambda/test/test.vpc-lambda.ts @@ -81,7 +81,7 @@ export = { const somethingConnectable = new SomethingConnectable(new ec2.Connections({ securityGroups: [securityGroup] })); // WHEN - const importedLambda = lambda.FunctionRef.import(stack2, 'Lambda', this.lambda.export()); + const importedLambda = lambda.Function.import(stack2, 'Lambda', this.lambda.export()); importedLambda.connections.allowTo(somethingConnectable, new ec2.TcpAllPorts(), 'Lambda can call connectable'); // THEN: SomeSecurityGroup accepts connections from Lambda diff --git a/packages/@aws-cdk/aws-logs/lib/cross-account-destination.ts b/packages/@aws-cdk/aws-logs/lib/cross-account-destination.ts index 46e4adbf5dfd8..230775ab598a3 100644 --- a/packages/@aws-cdk/aws-logs/lib/cross-account-destination.ts +++ b/packages/@aws-cdk/aws-logs/lib/cross-account-destination.ts @@ -1,6 +1,6 @@ import iam = require('@aws-cdk/aws-iam'); import cdk = require('@aws-cdk/cdk'); -import { LogGroupRef } from './log-group'; +import { ILogGroup } from './log-group'; import { CfnDestination } from './logs.generated'; import { ILogSubscriptionDestination, LogSubscriptionDestination } from './subscription-filter'; @@ -78,7 +78,7 @@ export class CrossAccountDestination extends cdk.Construct implements ILogSubscr this.policyDocument.addStatement(statement); } - public logSubscriptionDestination(_sourceLogGroup: LogGroupRef): LogSubscriptionDestination { + public logSubscriptionDestination(_sourceLogGroup: ILogGroup): LogSubscriptionDestination { return { arn: this.destinationArn }; } diff --git a/packages/@aws-cdk/aws-logs/lib/log-group.ts b/packages/@aws-cdk/aws-logs/lib/log-group.ts index bf27df4338963..29999317512dc 100644 --- a/packages/@aws-cdk/aws-logs/lib/log-group.ts +++ b/packages/@aws-cdk/aws-logs/lib/log-group.ts @@ -7,24 +7,87 @@ import { MetricFilter } from './metric-filter'; import { FilterPattern, IFilterPattern } from './pattern'; import { ILogSubscriptionDestination, SubscriptionFilter } from './subscription-filter'; +export interface ILogGroup { + /** + * The ARN of this log group + */ + readonly logGroupArn: string; + + /** + * The name of this log group + */ + readonly logGroupName: string; + + /** + * Create a new Log Stream for this Log Group + * + * @param parent Parent construct + * @param id Unique identifier for the construct in its parent + * @param props Properties for creating the LogStream + */ + newStream(parent: cdk.Construct, id: string, props?: NewLogStreamProps): LogStream; + + /** + * Create a new Subscription Filter on this Log Group + * + * @param parent Parent construct + * @param id Unique identifier for the construct in its parent + * @param props Properties for creating the SubscriptionFilter + */ + newSubscriptionFilter(parent: cdk.Construct, id: string, props: NewSubscriptionFilterProps): SubscriptionFilter; + + /** + * Create a new Metric Filter on this Log Group + * + * @param parent Parent construct + * @param id Unique identifier for the construct in its parent + * @param props Properties for creating the MetricFilter + */ + newMetricFilter(parent: cdk.Construct, id: string, props: NewMetricFilterProps): MetricFilter; + + /** + * Export this LogGroup + */ + export(): LogGroupImportProps; + + /** + * Extract a metric from structured log events in the LogGroup + * + * Creates a MetricFilter on this LogGroup that will extract the value + * of the indicated JSON field in all records where it occurs. + * + * The metric will be available in CloudWatch Metrics under the + * indicated namespace and name. + * + * @param jsonField JSON field to extract (example: '$.myfield') + * @param metricNamespace Namespace to emit the metric under + * @param metricName Name to emit the metric under + * @returns A Metric object representing the extracted metric + */ + extractMetric(jsonField: string, metricNamespace: string, metricName: string): cloudwatch.Metric; + + /** + * Give permissions to write to create and write to streams in this log group + */ + grantWrite(principal?: iam.IPrincipal): void; + + /** + * Give the indicated permissions on this log group and all streams + */ + grant(principal?: iam.IPrincipal, ...actions: string[]): void; +} + /** * Properties for importing a LogGroup */ -export interface LogGroupRefProps { +export interface LogGroupImportProps { logGroupArn: string; } /** * An CloudWatch Log Group */ -export abstract class LogGroupRef extends cdk.Construct { - /** - * Import an existing LogGroup - */ - public static import(parent: cdk.Construct, id: string, props: LogGroupRefProps): LogGroupRef { - return new ImportedLogGroup(parent, id, props); - } - +export abstract class LogGroupBase extends cdk.Construct implements ILogGroup { /** * The ARN of this log group */ @@ -77,14 +140,7 @@ export abstract class LogGroupRef extends cdk.Construct { }); } - /** - * Export this LogGroup - */ - public export(): LogGroupRefProps { - return { - logGroupArn: new cdk.Output(this, 'LogGroupArn', { value: this.logGroupArn }).makeImportValue().toString() - }; - } + public abstract export(): LogGroupImportProps; /** * Extract a metric from structured log events in the LogGroup @@ -169,7 +225,14 @@ export interface LogGroupProps { /** * Define a CloudWatch Log Group */ -export class LogGroup extends LogGroupRef { +export class LogGroup extends LogGroupBase { + /** + * Import an existing LogGroup + */ + public static import(parent: cdk.Construct, id: string, props: LogGroupImportProps): ILogGroup { + return new ImportedLogGroup(parent, id, props); + } + /** * The ARN of this log group */ @@ -203,12 +266,21 @@ export class LogGroup extends LogGroupRef { this.logGroupArn = resource.logGroupArn; this.logGroupName = resource.logGroupName; } + + /** + * Export this LogGroup + */ + public export(): LogGroupImportProps { + return { + logGroupArn: new cdk.Output(this, 'LogGroupArn', { value: this.logGroupArn }).makeImportValue().toString() + }; + } } /** * An imported CloudWatch Log Group */ -class ImportedLogGroup extends LogGroupRef { +class ImportedLogGroup extends LogGroupBase { /** * The ARN of this log group */ @@ -219,12 +291,19 @@ class ImportedLogGroup extends LogGroupRef { */ public readonly logGroupName: string; - constructor(parent: cdk.Construct, id: string, props: LogGroupRefProps) { + constructor(parent: cdk.Construct, id: string, private readonly props: LogGroupImportProps) { super(parent, id); this.logGroupArn = props.logGroupArn; this.logGroupName = cdk.ArnUtils.resourceNameComponent(props.logGroupArn, ':'); } + + /** + * Export this LogGroup + */ + public export() { + return this.props; + } } /** diff --git a/packages/@aws-cdk/aws-logs/lib/log-stream.ts b/packages/@aws-cdk/aws-logs/lib/log-stream.ts index 6387bad4e9e45..33d6b36688192 100644 --- a/packages/@aws-cdk/aws-logs/lib/log-stream.ts +++ b/packages/@aws-cdk/aws-logs/lib/log-stream.ts @@ -1,38 +1,24 @@ import cdk = require('@aws-cdk/cdk'); -import { LogGroupRef } from './log-group'; +import { ILogGroup } from './log-group'; import { CfnLogStream } from './logs.generated'; -/** - * Properties for importing a LogStream - */ -export interface LogStreamRefProps { - logStreamName: string; -} - -/** - * A Log Stream in a Log Group - */ -export abstract class LogStreamRef extends cdk.Construct { - /** - * Import an existing LogGroup - */ - public static import(parent: cdk.Construct, id: string, props: LogStreamRefProps): LogStreamRef { - return new ImportedLogStream(parent, id, props); - } - +export interface ILogStream { /** * The name of this log stream */ - public abstract readonly logStreamName: string; + readonly logStreamName: string; /** * Export this LogStream */ - public export(): LogStreamRefProps { - return { - logStreamName: new cdk.Output(this, 'LogStreamName', { value: this.logStreamName }).makeImportValue().toString() - }; - } + export(): LogStreamImportProps; +} + +/** + * Properties for importing a LogStream + */ +export interface LogStreamImportProps { + logStreamName: string; } /** @@ -42,7 +28,7 @@ export interface LogStreamProps { /** * The log group to create a log stream for. */ - logGroup: LogGroupRef; + logGroup: ILogGroup; /** * The name of the log stream to create. @@ -70,7 +56,14 @@ export interface LogStreamProps { /** * Define a Log Stream in a Log Group */ -export class LogStream extends LogStreamRef { +export class LogStream extends cdk.Construct implements ILogStream { + /** + * Import an existing LogGroup + */ + public static import(parent: cdk.Construct, id: string, props: LogStreamImportProps): ILogStream { + return new ImportedLogStream(parent, id, props); + } + /** * The name of this log stream */ @@ -90,20 +83,33 @@ export class LogStream extends LogStreamRef { this.logStreamName = resource.logStreamName; } + + /** + * Export this LogStream + */ + public export(): LogStreamImportProps { + return { + logStreamName: new cdk.Output(this, 'LogStreamName', { value: this.logStreamName }).makeImportValue().toString() + }; + } } /** * An imported LogStream */ -class ImportedLogStream extends LogStreamRef { +class ImportedLogStream extends cdk.Construct implements ILogStream { /** * The name of this log stream */ public readonly logStreamName: string; - constructor(parent: cdk.Construct, id: string, props: LogStreamRefProps) { + constructor(parent: cdk.Construct, id: string, private readonly props: LogStreamImportProps) { super(parent, id); this.logStreamName = props.logStreamName; } + + public export() { + return this.props; + } } diff --git a/packages/@aws-cdk/aws-logs/lib/metric-filter.ts b/packages/@aws-cdk/aws-logs/lib/metric-filter.ts index 9e3881df94b54..797273e241613 100644 --- a/packages/@aws-cdk/aws-logs/lib/metric-filter.ts +++ b/packages/@aws-cdk/aws-logs/lib/metric-filter.ts @@ -1,5 +1,5 @@ import cdk = require('@aws-cdk/cdk'); -import { LogGroupRef } from './log-group'; +import { ILogGroup } from './log-group'; import { CfnMetricFilter } from './logs.generated'; import { IFilterPattern } from './pattern'; @@ -10,7 +10,7 @@ export interface MetricFilterProps { /** * The log group to create the filter on. */ - logGroup: LogGroupRef; + logGroup: ILogGroup; /** * Pattern to search for log events. diff --git a/packages/@aws-cdk/aws-logs/lib/subscription-filter.ts b/packages/@aws-cdk/aws-logs/lib/subscription-filter.ts index c5f7850807ce0..e85ee7986076c 100644 --- a/packages/@aws-cdk/aws-logs/lib/subscription-filter.ts +++ b/packages/@aws-cdk/aws-logs/lib/subscription-filter.ts @@ -1,6 +1,6 @@ import iam = require('@aws-cdk/aws-iam'); import cdk = require('@aws-cdk/cdk'); -import { LogGroupRef } from './log-group'; +import { ILogGroup } from './log-group'; import { CfnSubscriptionFilter } from './logs.generated'; import { IFilterPattern } from './pattern'; @@ -18,7 +18,7 @@ export interface ILogSubscriptionDestination { * The destination may reconfigure its own permissions in response to this * function call. */ - logSubscriptionDestination(sourceLogGroup: LogGroupRef): LogSubscriptionDestination; + logSubscriptionDestination(sourceLogGroup: ILogGroup): LogSubscriptionDestination; } /** @@ -45,7 +45,7 @@ export interface SubscriptionFilterProps { /** * The log group to create the subscription on. */ - logGroup: LogGroupRef; + logGroup: ILogGroup; /** * The destination to send the filtered events to. diff --git a/packages/@aws-cdk/aws-logs/test/test.loggroup.ts b/packages/@aws-cdk/aws-logs/test/test.loggroup.ts index bbfb3c88970b7..f23d3b16f8002 100644 --- a/packages/@aws-cdk/aws-logs/test/test.loggroup.ts +++ b/packages/@aws-cdk/aws-logs/test/test.loggroup.ts @@ -2,7 +2,7 @@ import { expect, haveResource, matchTemplate } from '@aws-cdk/assert'; import iam = require('@aws-cdk/aws-iam'); import { Stack } from '@aws-cdk/cdk'; import { Test } from 'nodeunit'; -import { LogGroup, LogGroupRef } from '../lib'; +import { LogGroup } from '../lib'; export = { 'fixed retention'(test: Test) { @@ -86,7 +86,7 @@ export = { const stack2 = new Stack(); // WHEN - const imported = LogGroupRef.import(stack2, 'Import', lg.export()); + const imported = LogGroup.import(stack2, 'Import', lg.export()); imported.newStream(stack2, 'MakeMeAStream'); // THEN diff --git a/packages/@aws-cdk/aws-logs/test/test.subscriptionfilter.ts b/packages/@aws-cdk/aws-logs/test/test.subscriptionfilter.ts index 2eea9d0b37ba6..6002b3681d452 100644 --- a/packages/@aws-cdk/aws-logs/test/test.subscriptionfilter.ts +++ b/packages/@aws-cdk/aws-logs/test/test.subscriptionfilter.ts @@ -1,7 +1,7 @@ import { expect, haveResource } from '@aws-cdk/assert'; import { Stack } from '@aws-cdk/cdk'; import { Test } from 'nodeunit'; -import { FilterPattern, ILogSubscriptionDestination, LogGroup, LogGroupRef, SubscriptionFilter } from '../lib'; +import { FilterPattern, ILogGroup, ILogSubscriptionDestination, LogGroup, SubscriptionFilter } from '../lib'; export = { 'trivial instantiation'(test: Test) { @@ -28,7 +28,7 @@ export = { }; class FakeDestination implements ILogSubscriptionDestination { - public logSubscriptionDestination(_sourceLogGroup: LogGroupRef) { + public logSubscriptionDestination(_sourceLogGroup: ILogGroup) { return { arn: 'arn:bogus', }; diff --git a/packages/@aws-cdk/aws-quickstarts/lib/database.ts b/packages/@aws-cdk/aws-quickstarts/lib/database.ts index 7ef5ef5a04e46..03c7c8e4aa788 100644 --- a/packages/@aws-cdk/aws-quickstarts/lib/database.ts +++ b/packages/@aws-cdk/aws-quickstarts/lib/database.ts @@ -10,7 +10,7 @@ export interface SqlServerProps { masterUsername: string; masterPassword: string; allocatedStorage?: number; - vpc: ec2.VpcNetworkRef; + vpc: ec2.IVpcNetwork; } /** diff --git a/packages/@aws-cdk/aws-quickstarts/lib/rdgw.ts b/packages/@aws-cdk/aws-quickstarts/lib/rdgw.ts index e1832d83fb9b5..0855618af1117 100644 --- a/packages/@aws-cdk/aws-quickstarts/lib/rdgw.ts +++ b/packages/@aws-cdk/aws-quickstarts/lib/rdgw.ts @@ -4,7 +4,7 @@ import cdk = require('@aws-cdk/cdk'); export interface RemoteDesktopGatewayProps { rdgwCIDR: string; - vpc: ec2.VpcNetworkRef; + vpc: ec2.IVpcNetwork; keyPairName: string; adminPassword: string; @@ -47,7 +47,7 @@ export class RemoteDesktopGateway extends cdk.Construct implements ec2.IConnecta parameters: params }); - const securityGroup = ec2.SecurityGroupRef.import(this, 'SecurityGroup', { + const securityGroup = ec2.SecurityGroup.import(this, 'SecurityGroup', { securityGroupId: nestedStack.getAtt('Outputs.RemoteDesktopGatewaySGID').toString() }); diff --git a/packages/@aws-cdk/aws-rds/lib/cluster-parameter-group-ref.ts b/packages/@aws-cdk/aws-rds/lib/cluster-parameter-group-ref.ts deleted file mode 100644 index 5d6cc27131c50..0000000000000 --- a/packages/@aws-cdk/aws-rds/lib/cluster-parameter-group-ref.ts +++ /dev/null @@ -1,46 +0,0 @@ -import cdk = require('@aws-cdk/cdk'); - -/** - * A cluster parameter group - */ -export abstract class ClusterParameterGroupRef extends cdk.Construct { - /** - * Import a parameter group - */ - public static import(parent: cdk.Construct, id: string, props: ClusterParameterGroupRefProps): ClusterParameterGroupRef { - return new ImportedClusterParameterGroup(parent, id, props); - } - - /** - * Name of this parameter group - */ - public abstract readonly parameterGroupName: string; - - /** - * Export this parameter group - */ - public export(): ClusterParameterGroupRefProps { - return { - parameterGroupName: new cdk.Output(this, 'ParameterGroupName', { value: this.parameterGroupName }).makeImportValue().toString() - }; - } -} - -/** - * Properties to reference a cluster parameter group - */ -export interface ClusterParameterGroupRefProps { - parameterGroupName: string; -} - -/** - * An imported cluster parameter group - */ -class ImportedClusterParameterGroup extends ClusterParameterGroupRef { - public readonly parameterGroupName: string; - - constructor(parent: cdk.Construct, id: string, props: ClusterParameterGroupRefProps) { - super(parent, id); - this.parameterGroupName = props.parameterGroupName; - } -} diff --git a/packages/@aws-cdk/aws-rds/lib/cluster-parameter-group.ts b/packages/@aws-cdk/aws-rds/lib/cluster-parameter-group.ts index 0b59400fc5c5c..d5b35b3553beb 100644 --- a/packages/@aws-cdk/aws-rds/lib/cluster-parameter-group.ts +++ b/packages/@aws-cdk/aws-rds/lib/cluster-parameter-group.ts @@ -1,8 +1,29 @@ import cdk = require('@aws-cdk/cdk'); -import { ClusterParameterGroupRef } from './cluster-parameter-group-ref'; import { Parameters } from './props'; import { CfnDBClusterParameterGroup } from './rds.generated'; +/** + * A cluster parameter group + */ +export interface IClusterParameterGroup { + /** + * Name of this parameter group + */ + readonly parameterGroupName: string; + + /** + * Export this parameter group + */ + export(): ClusterParameterGroupImportProps; +} + +/** + * Properties to reference a cluster parameter group + */ +export interface ClusterParameterGroupImportProps { + parameterGroupName: string; +} + /** * Properties for a cluster parameter group */ @@ -26,7 +47,14 @@ export interface ClusterParameterGroupProps { /** * Defina a cluster parameter group */ -export class ClusterParameterGroup extends ClusterParameterGroupRef { +export class ClusterParameterGroup extends cdk.Construct implements IClusterParameterGroup { + /** + * Import a parameter group + */ + public static import(parent: cdk.Construct, id: string, props: ClusterParameterGroupImportProps): IClusterParameterGroup { + return new ImportedClusterParameterGroup(parent, id, props); + } + public readonly parameterGroupName: string; private readonly parameters: Parameters = {}; @@ -46,6 +74,15 @@ export class ClusterParameterGroup extends ClusterParameterGroupRef { this.parameterGroupName = resource.ref; } + /** + * Export this parameter group + */ + public export(): ClusterParameterGroupImportProps { + return { + parameterGroupName: new cdk.Output(this, 'ParameterGroupName', { value: this.parameterGroupName }).makeImportValue().toString() + }; + } + /** * Set a single parameter in this parameter group */ @@ -75,3 +112,19 @@ export class ClusterParameterGroup extends ClusterParameterGroupRef { return []; } } + +/** + * An imported cluster parameter group + */ +class ImportedClusterParameterGroup extends cdk.Construct implements IClusterParameterGroup { + public readonly parameterGroupName: string; + + constructor(parent: cdk.Construct, id: string, private readonly props: ClusterParameterGroupImportProps) { + super(parent, id); + this.parameterGroupName = props.parameterGroupName; + } + + public export() { + return this.props; + } +} diff --git a/packages/@aws-cdk/aws-rds/lib/cluster-ref.ts b/packages/@aws-cdk/aws-rds/lib/cluster-ref.ts index 5f7d6409a87ee..4e4c8a4766c39 100644 --- a/packages/@aws-cdk/aws-rds/lib/cluster-ref.ts +++ b/packages/@aws-cdk/aws-rds/lib/cluster-ref.ts @@ -1,74 +1,49 @@ import ec2 = require('@aws-cdk/aws-ec2'); -import cdk = require('@aws-cdk/cdk'); /** * Create a clustered database with a given number of instances. */ -export abstract class DatabaseClusterRef extends cdk.Construct implements ec2.IConnectable { - /** - * Import an existing DatabaseCluster from properties - */ - public static import(parent: cdk.Construct, name: string, props: DatabaseClusterRefProps): DatabaseClusterRef { - return new ImportedDatabaseCluster(parent, name, props); - } - - /** - * Access to the network connections - */ - public abstract readonly connections: ec2.Connections; - +export interface IDatabaseCluster extends ec2.IConnectable { /** * Identifier of the cluster */ - public abstract readonly clusterIdentifier: string; + readonly clusterIdentifier: string; /** * Identifiers of the replicas */ - public abstract readonly instanceIdentifiers: string[] = []; + readonly instanceIdentifiers: string[]; /** * The endpoint to use for read/write operations */ - public abstract readonly clusterEndpoint: Endpoint; + readonly clusterEndpoint: Endpoint; /** * Endpoint to use for load-balanced read-only operations. */ - public abstract readonly readerEndpoint: Endpoint; + readonly readerEndpoint: Endpoint; /** * Endpoints which address each individual replica. */ - public abstract readonly instanceEndpoints: Endpoint[] = []; + readonly instanceEndpoints: Endpoint[]; /** * The security group for this database cluster */ - protected abstract readonly securityGroupId: string; + readonly securityGroupId: string; /** * Export a Database Cluster for importing in another stack */ - public export(): DatabaseClusterRefProps { - // tslint:disable:max-line-length - return { - port: new cdk.Output(this, 'Port', { value: this.clusterEndpoint.port, }).makeImportValue().toString(), - securityGroupId: new cdk.Output(this, 'SecurityGroupId', { value: this.securityGroupId, }).makeImportValue().toString(), - clusterIdentifier: new cdk.Output(this, 'ClusterIdentifier', { value: this.clusterIdentifier, }).makeImportValue().toString(), - instanceIdentifiers: new cdk.StringListOutput(this, 'InstanceIdentifiers', { values: this.instanceIdentifiers }).makeImportValues().map(x => x.toString()), - clusterEndpointAddress: new cdk.Output(this, 'ClusterEndpointAddress', { value: this.clusterEndpoint.hostname, }).makeImportValue().toString(), - readerEndpointAddress: new cdk.Output(this, 'ReaderEndpointAddress', { value: this.readerEndpoint.hostname, }).makeImportValue().toString(), - instanceEndpointAddresses: new cdk.StringListOutput(this, 'InstanceEndpointAddresses', { values: this.instanceEndpoints.map(e => e.hostname) }).makeImportValues().map(x => x.toString()), - }; - // tslint:enable:max-line-length - } + export(): DatabaseClusterImportProps; } /** * Properties that describe an existing cluster instance */ -export interface DatabaseClusterRefProps { +export interface DatabaseClusterImportProps { /** * The database port */ @@ -106,66 +81,6 @@ export interface DatabaseClusterRefProps { instanceEndpointAddresses: string[]; } -/** - * An imported Database Cluster - */ -class ImportedDatabaseCluster extends DatabaseClusterRef { - /** - * Default port to connect to this database - */ - public readonly defaultPortRange: ec2.IPortRange; - - /** - * Access to the network connections - */ - public readonly connections: ec2.Connections; - - /** - * Identifier of the cluster - */ - public readonly clusterIdentifier: string; - - /** - * Identifiers of the replicas - */ - public readonly instanceIdentifiers: string[] = []; - - /** - * The endpoint to use for read/write operations - */ - public readonly clusterEndpoint: Endpoint; - - /** - * Endpoint to use for load-balanced read-only operations. - */ - public readonly readerEndpoint: Endpoint; - - /** - * Endpoints which address each individual replica. - */ - public readonly instanceEndpoints: Endpoint[] = []; - - /** - * Security group identifier of this database - */ - protected readonly securityGroupId: string; - - constructor(parent: cdk.Construct, name: string, props: DatabaseClusterRefProps) { - super(parent, name); - - this.securityGroupId = props.securityGroupId; - this.defaultPortRange = new ec2.TcpPortFromAttribute(props.port); - this.connections = new ec2.Connections({ - securityGroups: [ec2.SecurityGroupRef.import(this, 'SecurityGroup', props)], - defaultPortRange: this.defaultPortRange - }); - this.clusterIdentifier = props.clusterIdentifier; - this.clusterEndpoint = new Endpoint(props.clusterEndpointAddress, props.port); - this.readerEndpoint = new Endpoint(props.readerEndpointAddress, props.port); - this.instanceEndpoints = props.instanceEndpointAddresses.map(a => new Endpoint(a, props.port)); - } -} - /** * Connection endpoint of a database cluster or instance * diff --git a/packages/@aws-cdk/aws-rds/lib/cluster.ts b/packages/@aws-cdk/aws-rds/lib/cluster.ts index 7d2d357ee096d..0b92b2be67362 100644 --- a/packages/@aws-cdk/aws-rds/lib/cluster.ts +++ b/packages/@aws-cdk/aws-rds/lib/cluster.ts @@ -1,7 +1,7 @@ import ec2 = require('@aws-cdk/aws-ec2'); import cdk = require('@aws-cdk/cdk'); -import { ClusterParameterGroupRef } from './cluster-parameter-group-ref'; -import { DatabaseClusterRef, Endpoint } from './cluster-ref'; +import { IClusterParameterGroup } from './cluster-parameter-group'; +import { DatabaseClusterImportProps, Endpoint, IDatabaseCluster } from './cluster-ref'; import { BackupProps, DatabaseClusterEngine, InstanceProps, Login } from './props'; import { CfnDBCluster, CfnDBInstance, CfnDBSubnetGroup } from './rds.generated'; @@ -87,13 +87,20 @@ export interface DatabaseClusterProps { * * @default No parameter group */ - parameterGroup?: ClusterParameterGroupRef; + parameterGroup?: IClusterParameterGroup; } /** * Create a clustered database with a given number of instances. */ -export class DatabaseCluster extends DatabaseClusterRef { +export class DatabaseCluster extends cdk.Construct implements IDatabaseCluster { + /** + * Import an existing DatabaseCluster from properties + */ + public static import(parent: cdk.Construct, name: string, props: DatabaseClusterImportProps): IDatabaseCluster { + return new ImportedDatabaseCluster(parent, name, props); + } + /** * Identifier of the cluster */ @@ -127,7 +134,7 @@ export class DatabaseCluster extends DatabaseClusterRef { /** * Security group identifier of this database */ - protected readonly securityGroupId: string; + public readonly securityGroupId: string; constructor(parent: cdk.Construct, name: string, props: DatabaseClusterProps) { super(parent, name); @@ -215,6 +222,23 @@ export class DatabaseCluster extends DatabaseClusterRef { const defaultPortRange = new ec2.TcpPortFromAttribute(this.clusterEndpoint.port); this.connections = new ec2.Connections({ securityGroups: [securityGroup], defaultPortRange }); } + + /** + * Export a Database Cluster for importing in another stack + */ + public export(): DatabaseClusterImportProps { + // tslint:disable:max-line-length + return { + port: new cdk.Output(this, 'Port', { value: this.clusterEndpoint.port, }).makeImportValue().toString(), + securityGroupId: new cdk.Output(this, 'SecurityGroupId', { value: this.securityGroupId, }).makeImportValue().toString(), + clusterIdentifier: new cdk.Output(this, 'ClusterIdentifier', { value: this.clusterIdentifier, }).makeImportValue().toString(), + instanceIdentifiers: new cdk.StringListOutput(this, 'InstanceIdentifiers', { values: this.instanceIdentifiers }).makeImportValues().map(x => x.toString()), + clusterEndpointAddress: new cdk.Output(this, 'ClusterEndpointAddress', { value: this.clusterEndpoint.hostname, }).makeImportValue().toString(), + readerEndpointAddress: new cdk.Output(this, 'ReaderEndpointAddress', { value: this.readerEndpoint.hostname, }).makeImportValue().toString(), + instanceEndpointAddresses: new cdk.StringListOutput(this, 'InstanceEndpointAddresses', { values: this.instanceEndpoints.map(e => e.hostname) }).makeImportValues().map(x => x.toString()), + }; + // tslint:enable:max-line-length + } } /** @@ -223,3 +247,67 @@ export class DatabaseCluster extends DatabaseClusterRef { function databaseInstanceType(instanceType: ec2.InstanceType) { return 'db.' + instanceType.toString(); } + +/** + * An imported Database Cluster + */ +class ImportedDatabaseCluster extends cdk.Construct implements IDatabaseCluster { + /** + * Default port to connect to this database + */ + public readonly defaultPortRange: ec2.IPortRange; + + /** + * Access to the network connections + */ + public readonly connections: ec2.Connections; + + /** + * Identifier of the cluster + */ + public readonly clusterIdentifier: string; + + /** + * Identifiers of the replicas + */ + public readonly instanceIdentifiers: string[] = []; + + /** + * The endpoint to use for read/write operations + */ + public readonly clusterEndpoint: Endpoint; + + /** + * Endpoint to use for load-balanced read-only operations. + */ + public readonly readerEndpoint: Endpoint; + + /** + * Endpoints which address each individual replica. + */ + public readonly instanceEndpoints: Endpoint[] = []; + + /** + * Security group identifier of this database + */ + public readonly securityGroupId: string; + + constructor(parent: cdk.Construct, name: string, private readonly props: DatabaseClusterImportProps) { + super(parent, name); + + this.securityGroupId = props.securityGroupId; + this.defaultPortRange = new ec2.TcpPortFromAttribute(props.port); + this.connections = new ec2.Connections({ + securityGroups: [ec2.SecurityGroup.import(this, 'SecurityGroup', props)], + defaultPortRange: this.defaultPortRange + }); + this.clusterIdentifier = props.clusterIdentifier; + this.clusterEndpoint = new Endpoint(props.clusterEndpointAddress, props.port); + this.readerEndpoint = new Endpoint(props.readerEndpointAddress, props.port); + this.instanceEndpoints = props.instanceEndpointAddresses.map(a => new Endpoint(a, props.port)); + } + + public export() { + return this.props; + } +} diff --git a/packages/@aws-cdk/aws-rds/lib/index.ts b/packages/@aws-cdk/aws-rds/lib/index.ts index abd9739d1f8f1..4a0f2ed04ee88 100644 --- a/packages/@aws-cdk/aws-rds/lib/index.ts +++ b/packages/@aws-cdk/aws-rds/lib/index.ts @@ -3,7 +3,6 @@ export * from './cluster-ref'; export * from './instance'; export * from './props'; export * from './cluster-parameter-group'; -export * from './cluster-parameter-group-ref'; // AWS::RDS CloudFormation Resources: export * from './rds.generated'; diff --git a/packages/@aws-cdk/aws-rds/lib/props.ts b/packages/@aws-cdk/aws-rds/lib/props.ts index 16a6fb0460a22..f36afe4521cc6 100644 --- a/packages/@aws-cdk/aws-rds/lib/props.ts +++ b/packages/@aws-cdk/aws-rds/lib/props.ts @@ -24,7 +24,7 @@ export interface InstanceProps { * * Must be at least 2 subnets in two different AZs. */ - vpc: ec2.VpcNetworkRef; + vpc: ec2.IVpcNetwork; /** * Where to place the instances within the VPC diff --git a/packages/@aws-cdk/aws-rds/test/test.cluster.ts b/packages/@aws-cdk/aws-rds/test/test.cluster.ts index afd49e94d6da3..fad6e775c460a 100644 --- a/packages/@aws-cdk/aws-rds/test/test.cluster.ts +++ b/packages/@aws-cdk/aws-rds/test/test.cluster.ts @@ -2,7 +2,7 @@ import { expect, haveResource } from '@aws-cdk/assert'; import ec2 = require('@aws-cdk/aws-ec2'); import cdk = require('@aws-cdk/cdk'); import { Test } from 'nodeunit'; -import { ClusterParameterGroup, DatabaseCluster, DatabaseClusterEngine, DatabaseClusterRef } from '../lib'; +import { ClusterParameterGroup, DatabaseCluster, DatabaseClusterEngine } from '../lib'; export = { 'check that instantiation works'(test: Test) { @@ -52,7 +52,7 @@ export = { }); // WHEN - DatabaseClusterRef.import(stack2, 'Database', cluster.export()); + DatabaseCluster.import(stack2, 'Database', cluster.export()); // THEN: No error diff --git a/packages/@aws-cdk/aws-route53/README.md b/packages/@aws-cdk/aws-route53/README.md index 2501ba578e22e..6476432160805 100644 --- a/packages/@aws-cdk/aws-route53/README.md +++ b/packages/@aws-cdk/aws-route53/README.md @@ -49,7 +49,7 @@ new route53.TXTRecord(zone, 'TXTRecord', { If you know the ID and Name of a Hosted Zone, you can import it directly: ```ts -const zone = HostedZoneRef.import(this, 'MyZone', { +const zone = HostedZone.import(this, 'MyZone', { zoneName: 'example.com', hostedZoneId: 'ZOJJZC49E0EPZ', }); diff --git a/packages/@aws-cdk/aws-route53/lib/hosted-zone-provider.ts b/packages/@aws-cdk/aws-route53/lib/hosted-zone-provider.ts index fc3d01bf88e2f..cb54ebe820ebf 100644 --- a/packages/@aws-cdk/aws-route53/lib/hosted-zone-provider.ts +++ b/packages/@aws-cdk/aws-route53/lib/hosted-zone-provider.ts @@ -1,6 +1,7 @@ import cdk = require('@aws-cdk/cdk'); import cxapi = require('@aws-cdk/cx-api'); -import { HostedZoneRef, HostedZoneRefProps } from './hosted-zone-ref'; +import { HostedZone } from './hosted-zone'; +import { HostedZoneImportProps, IHostedZone } from './hosted-zone-ref'; /** * Zone properties for looking up the Hosted Zone @@ -37,15 +38,15 @@ export class HostedZoneProvider { } /** - * This method calls `findHostedZone` and returns the imported `HostedZoneRef` + * This method calls `findHostedZone` and returns the imported hosted zone */ - public findAndImport(parent: cdk.Construct, id: string): HostedZoneRef { - return HostedZoneRef.import(parent, id, this.findHostedZone()); + public findAndImport(parent: cdk.Construct, id: string): IHostedZone { + return HostedZone.import(parent, id, this.findHostedZone()); } /** * Return the hosted zone meeting the filter */ - public findHostedZone(): HostedZoneRefProps { + public findHostedZone(): HostedZoneImportProps { const zone = this.provider.getValue(DEFAULT_HOSTED_ZONE) as HostedZoneContextResponse; // CDK handles the '.' at the end, so remove it here if (zone.Name.endsWith('.')) { diff --git a/packages/@aws-cdk/aws-route53/lib/hosted-zone-ref.ts b/packages/@aws-cdk/aws-route53/lib/hosted-zone-ref.ts index 4810d5572c3ec..25602d6132c05 100644 --- a/packages/@aws-cdk/aws-route53/lib/hosted-zone-ref.ts +++ b/packages/@aws-cdk/aws-route53/lib/hosted-zone-ref.ts @@ -1,38 +1,27 @@ -import { Construct, Output } from "@aws-cdk/cdk"; - /** * Imported or created hosted zone */ -export abstract class HostedZoneRef extends Construct { - public static import(parent: Construct, name: string, props: HostedZoneRefProps): HostedZoneRef { - return new ImportedHostedZone(parent, name, props); - } - +export interface IHostedZone { /** * ID of this hosted zone */ - public abstract readonly hostedZoneId: string; + readonly hostedZoneId: string; /** * FQDN of this hosted zone */ - public abstract readonly zoneName: string; + readonly zoneName: string; /** * Export the hosted zone */ - public export(): HostedZoneRefProps { - return { - hostedZoneId: new Output(this, 'HostedZoneId', { value: this.hostedZoneId }).makeImportValue().toString(), - zoneName: this.zoneName, - }; - } + export(): HostedZoneImportProps; } /** * Reference to a hosted zone */ -export interface HostedZoneRefProps { +export interface HostedZoneImportProps { /** * Identifier of the hosted zone */ @@ -43,19 +32,3 @@ export interface HostedZoneRefProps { */ zoneName: string; } - -/** - * Imported hosted zone - */ -export class ImportedHostedZone extends HostedZoneRef { - public readonly hostedZoneId: string; - - public readonly zoneName: string; - - constructor(parent: Construct, name: string, props: HostedZoneRefProps) { - super(parent, name); - - this.hostedZoneId = props.hostedZoneId; - this.zoneName = props.zoneName; - } -} diff --git a/packages/@aws-cdk/aws-route53/lib/hosted-zone.ts b/packages/@aws-cdk/aws-route53/lib/hosted-zone.ts index 4769734048bc1..d0c6579d9d907 100644 --- a/packages/@aws-cdk/aws-route53/lib/hosted-zone.ts +++ b/packages/@aws-cdk/aws-route53/lib/hosted-zone.ts @@ -1,6 +1,6 @@ import ec2 = require('@aws-cdk/aws-ec2'); import cdk = require('@aws-cdk/cdk'); -import { HostedZoneRef } from './hosted-zone-ref'; +import { HostedZoneImportProps, IHostedZone } from './hosted-zone-ref'; import { CfnHostedZone, HostedZoneNameServers } from './route53.generated'; import { validateZoneName } from './util'; @@ -28,10 +28,26 @@ export interface PublicHostedZoneProps { queryLogsLogGroupArn?: string; } +export abstract class HostedZone extends cdk.Construct implements IHostedZone { + public static import(parent: cdk.Construct, name: string, props: HostedZoneImportProps): IHostedZone { + return new ImportedHostedZone(parent, name, props); + } + + public abstract readonly hostedZoneId: string; + public abstract readonly zoneName: string; + + public export(): HostedZoneImportProps { + return { + hostedZoneId: new cdk.Output(this, 'HostedZoneId', { value: this.hostedZoneId }).makeImportValue().toString(), + zoneName: this.zoneName, + }; + } +} + /** * Create a Route53 public hosted zone. */ -export class PublicHostedZone extends HostedZoneRef { +export class PublicHostedZone extends HostedZone { /** * Identifier of this hosted zone */ @@ -69,7 +85,7 @@ export interface PrivateHostedZoneProps extends PublicHostedZoneProps { /** * One VPC that you want to associate with this hosted zone. */ - vpc: ec2.VpcNetworkRef; + vpc: ec2.IVpcNetwork; } /** @@ -78,7 +94,7 @@ export interface PrivateHostedZoneProps extends PublicHostedZoneProps { * Note that `enableDnsHostnames` and `enableDnsSupport` must have been enabled * for the VPC you're configuring for private hosted zones. */ -export class PrivateHostedZone extends HostedZoneRef { +export class PrivateHostedZone extends HostedZone { /** * Identifier of this hosted zone */ @@ -115,12 +131,12 @@ export class PrivateHostedZone extends HostedZoneRef { * * @param vpc the other VPC to add. */ - public addVpc(vpc: ec2.VpcNetworkRef) { + public addVpc(vpc: ec2.IVpcNetwork) { this.vpcs.push(toVpcProperty(vpc)); } } -function toVpcProperty(vpc: ec2.VpcNetworkRef): CfnHostedZone.VPCProperty { +function toVpcProperty(vpc: ec2.IVpcNetwork): CfnHostedZone.VPCProperty { return { vpcId: vpc.vpcId, vpcRegion: new cdk.AwsRegion() }; } @@ -131,3 +147,23 @@ function determineHostedZoneProps(props: PublicHostedZoneProps) { return { name, hostedZoneConfig, queryLoggingConfig }; } + +/** + * Imported hosted zone + */ +class ImportedHostedZone extends cdk.Construct implements IHostedZone { + public readonly hostedZoneId: string; + + public readonly zoneName: string; + + constructor(parent: cdk.Construct, name: string, private readonly props: HostedZoneImportProps) { + super(parent, name); + + this.hostedZoneId = props.hostedZoneId; + this.zoneName = props.zoneName; + } + + public export() { + return this.props; + } +} diff --git a/packages/@aws-cdk/aws-route53/lib/records/_util.ts b/packages/@aws-cdk/aws-route53/lib/records/_util.ts index 53747dece7848..b51a2f89620a8 100644 --- a/packages/@aws-cdk/aws-route53/lib/records/_util.ts +++ b/packages/@aws-cdk/aws-route53/lib/records/_util.ts @@ -1,4 +1,4 @@ -import { HostedZoneRef } from '../hosted-zone-ref'; +import { IHostedZone } from '../hosted-zone-ref'; /** * Route53 requires the record names are specified as fully qualified names, but this @@ -15,7 +15,7 @@ import { HostedZoneRef } from '../hosted-zone-ref'; *
  • Otherwise, append +.+, +zoneName+ and a trailing +.+
  • * */ -export function determineFullyQualifiedDomainName(providedName: string, hostedZone: HostedZoneRef): string { +export function determineFullyQualifiedDomainName(providedName: string, hostedZone: IHostedZone): string { if (providedName.endsWith('.')) { return providedName; } diff --git a/packages/@aws-cdk/aws-route53/lib/records/alias.ts b/packages/@aws-cdk/aws-route53/lib/records/alias.ts index 57ea706f43338..d861e8bd6caa0 100644 --- a/packages/@aws-cdk/aws-route53/lib/records/alias.ts +++ b/packages/@aws-cdk/aws-route53/lib/records/alias.ts @@ -1,5 +1,5 @@ import { Construct } from '@aws-cdk/cdk'; -import { HostedZoneRef } from '../hosted-zone-ref'; +import { IHostedZone } from '../hosted-zone-ref'; import { CfnRecordSet } from '../route53.generated'; import { determineFullyQualifiedDomainName } from './_util'; @@ -30,6 +30,10 @@ export interface AliasRecordTargetProps { } export interface AliasRecordProps { + /** + * The zone in which this alias should be defined. + */ + zone: IHostedZone; /** * Name for the record. This can be the FQDN for the record (foo.example.com) or * a subdomain of the parent hosted zone (foo, with example.com as the hosted zone). @@ -45,12 +49,12 @@ export interface AliasRecordProps { * A Route53 alias record */ export class AliasRecord extends Construct { - constructor(parent: HostedZoneRef, id: string, props: AliasRecordProps) { + constructor(parent: Construct, id: string, props: AliasRecordProps) { super(parent, id); new CfnRecordSet(this, 'Resource', { - hostedZoneId: parent.hostedZoneId, - name: determineFullyQualifiedDomainName(props.recordName, parent), + hostedZoneId: props.zone.hostedZoneId, + name: determineFullyQualifiedDomainName(props.recordName, props.zone), type: 'A', // ipv4 aliasTarget: props.target.asAliasRecordTarget() }); diff --git a/packages/@aws-cdk/aws-route53/lib/records/txt.ts b/packages/@aws-cdk/aws-route53/lib/records/txt.ts index 7c7c058d4ba73..731b94e3d883a 100644 --- a/packages/@aws-cdk/aws-route53/lib/records/txt.ts +++ b/packages/@aws-cdk/aws-route53/lib/records/txt.ts @@ -1,9 +1,10 @@ import { Construct } from '@aws-cdk/cdk'; -import { HostedZoneRef } from '../hosted-zone-ref'; +import { IHostedZone } from '../hosted-zone-ref'; import { CfnRecordSet } from '../route53.generated'; import { determineFullyQualifiedDomainName } from './_util'; export interface TXTRecordProps { + zone: IHostedZone; recordName: string; recordValue: string; /** @default 1800 seconds */ @@ -14,7 +15,7 @@ export interface TXTRecordProps { * A DNS TXT record */ export class TXTRecord extends Construct { - constructor(parent: HostedZoneRef, name: string, props: TXTRecordProps) { + constructor(parent: Construct, name: string, props: TXTRecordProps) { super(parent, name); // JSON.stringify conveniently wraps strings in " and escapes ". @@ -22,8 +23,8 @@ export class TXTRecord extends Construct { const ttl = props.ttl === undefined ? 1800 : props.ttl; new CfnRecordSet(this, 'Resource', { - hostedZoneId: parent.hostedZoneId, - name: determineFullyQualifiedDomainName(props.recordName, parent), + hostedZoneId: props.zone.hostedZoneId, + name: determineFullyQualifiedDomainName(props.recordName, props.zone), type: 'TXT', resourceRecords: [recordValue], ttl: ttl.toString() diff --git a/packages/@aws-cdk/aws-route53/lib/records/zone-delegation.ts b/packages/@aws-cdk/aws-route53/lib/records/zone-delegation.ts index df7fbcacf7e5b..2b634634005e9 100644 --- a/packages/@aws-cdk/aws-route53/lib/records/zone-delegation.ts +++ b/packages/@aws-cdk/aws-route53/lib/records/zone-delegation.ts @@ -1,9 +1,13 @@ import { Construct } from '@aws-cdk/cdk'; -import { HostedZoneRef } from '../hosted-zone-ref'; +import { IHostedZone } from '../hosted-zone-ref'; import { CfnRecordSet } from '../route53.generated'; import { determineFullyQualifiedDomainName } from './_util'; export interface ZoneDelegationRecordProps { + /** + * The zone in which this delegate is defined. + */ + zone: IHostedZone; /** * The name of the zone that delegation is made to. */ @@ -33,14 +37,14 @@ export interface ZoneDelegationRecordProps { * A record to delegate further lookups to a different set of name servers */ export class ZoneDelegationRecord extends Construct { - constructor(parent: HostedZoneRef, name: string, props: ZoneDelegationRecordProps) { + constructor(parent: Construct, name: string, props: ZoneDelegationRecordProps) { super(parent, name); const ttl = props.ttl === undefined ? 172_800 : props.ttl; new CfnRecordSet(this, 'Resource', { - hostedZoneId: parent.hostedZoneId, - name: determineFullyQualifiedDomainName(props.delegatedZoneName, parent), + hostedZoneId: props.zone.hostedZoneId, + name: determineFullyQualifiedDomainName(props.delegatedZoneName, props.zone), type: 'NS', ttl: ttl.toString(), comment: props.comment, diff --git a/packages/@aws-cdk/aws-route53/test/integ.route53.ts b/packages/@aws-cdk/aws-route53/test/integ.route53.ts index dd20866e2fb9a..f276d80e26aaa 100644 --- a/packages/@aws-cdk/aws-route53/test/integ.route53.ts +++ b/packages/@aws-cdk/aws-route53/test/integ.route53.ts @@ -17,6 +17,7 @@ const publicZone = new PublicHostedZone(stack, 'PublicZone', { }); new TXTRecord(privateZone, 'TXT', { + zone: privateZone, recordName: '_foo', recordValue: 'Bar!', ttl: 60 diff --git a/packages/@aws-cdk/aws-route53/test/test.alias-record.ts b/packages/@aws-cdk/aws-route53/test/test.alias-record.ts index f0eeeffa7bb38..e5344bdd50b87 100644 --- a/packages/@aws-cdk/aws-route53/test/test.alias-record.ts +++ b/packages/@aws-cdk/aws-route53/test/test.alias-record.ts @@ -20,6 +20,7 @@ export = { // WHEN new AliasRecord(zone, 'Alias', { + zone, recordName: '_foo', target }); diff --git a/packages/@aws-cdk/aws-route53/test/test.hosted-zone-provider.ts b/packages/@aws-cdk/aws-route53/test/test.hosted-zone-provider.ts index a26f57fe36449..202710d47b9ad 100644 --- a/packages/@aws-cdk/aws-route53/test/test.hosted-zone-provider.ts +++ b/packages/@aws-cdk/aws-route53/test/test.hosted-zone-provider.ts @@ -1,6 +1,6 @@ import cdk = require('@aws-cdk/cdk'); import { Test } from 'nodeunit'; -import { HostedZoneProvider, HostedZoneRef, HostedZoneRefProps } from '../lib'; +import { HostedZone, HostedZoneImportProps, HostedZoneProvider } from '../lib'; export = { 'Hosted Zone Provider': { @@ -24,12 +24,12 @@ export = { stack.setContext(key, fakeZone); - const cdkZoneProps: HostedZoneRefProps = { + const cdkZoneProps: HostedZoneImportProps = { hostedZoneId: fakeZone.Id, zoneName: 'example.com', }; - const cdkZone = HostedZoneRef.import(stack, 'MyZone', cdkZoneProps); + const cdkZone = HostedZone.import(stack, 'MyZone', cdkZoneProps); // WHEN const provider = new HostedZoneProvider(stack, filter); diff --git a/packages/@aws-cdk/aws-route53/test/test.route53.ts b/packages/@aws-cdk/aws-route53/test/test.route53.ts index e82d01b0e4dc5..7cb0c53c9c687 100644 --- a/packages/@aws-cdk/aws-route53/test/test.route53.ts +++ b/packages/@aws-cdk/aws-route53/test/test.route53.ts @@ -2,7 +2,7 @@ import { beASupersetOfTemplate, exactlyMatchTemplate, expect, haveResource } fro import ec2 = require('@aws-cdk/aws-ec2'); import cdk = require('@aws-cdk/cdk'); import { Test } from 'nodeunit'; -import { HostedZoneRef, PrivateHostedZone, PublicHostedZone, TXTRecord } from '../lib'; +import { HostedZone, PrivateHostedZone, PublicHostedZone, TXTRecord } from '../lib'; export = { 'default properties': { @@ -78,8 +78,9 @@ export = { }); const zoneRef = zone.export(); - const importedZone = HostedZoneRef.import(stack2, 'Imported', zoneRef); - new TXTRecord(importedZone, 'Record', { + const importedZone = HostedZone.import(stack2, 'Imported', zoneRef); + new TXTRecord(importedZone as any, 'Record', { + zone: importedZone, recordName: 'lookHere', recordValue: 'SeeThere' }); diff --git a/packages/@aws-cdk/aws-route53/test/test.txt-record.ts b/packages/@aws-cdk/aws-route53/test/test.txt-record.ts index fd05091176d4b..54b2dc4418d82 100644 --- a/packages/@aws-cdk/aws-route53/test/test.txt-record.ts +++ b/packages/@aws-cdk/aws-route53/test/test.txt-record.ts @@ -8,7 +8,7 @@ export = { TXT(test: Test) { const app = new TestApp(); const zone = new PublicHostedZone(app.stack, 'HostedZone', { zoneName: 'test.public' }); - new TXTRecord(zone, 'TXT', { recordName: '_foo', recordValue: 'Bar!' }); + new TXTRecord(zone, 'TXT', { zone, recordName: '_foo', recordValue: 'Bar!' }); expect(app.synthesizeTemplate()).to(exactlyMatchTemplate({ Resources: { HostedZoneDB99F866: { diff --git a/packages/@aws-cdk/aws-route53/test/test.zone-delegation-record.ts b/packages/@aws-cdk/aws-route53/test/test.zone-delegation-record.ts index 9d49513cbd418..37c437a655f4a 100644 --- a/packages/@aws-cdk/aws-route53/test/test.zone-delegation-record.ts +++ b/packages/@aws-cdk/aws-route53/test/test.zone-delegation-record.ts @@ -9,6 +9,7 @@ export = { const app = new TestApp(); const zone = new PublicHostedZone(app.stack, 'HostedZone', { zoneName: 'test.public' }); new ZoneDelegationRecord(zone, 'NS', { + zone, delegatedZoneName: 'foo', nameServers: ['ns-1777.awsdns-30.co.uk'] }); diff --git a/packages/@aws-cdk/aws-s3-deployment/lib/bucket-deployment.ts b/packages/@aws-cdk/aws-s3-deployment/lib/bucket-deployment.ts index a438af1a8b682..2862c450b9cb5 100644 --- a/packages/@aws-cdk/aws-s3-deployment/lib/bucket-deployment.ts +++ b/packages/@aws-cdk/aws-s3-deployment/lib/bucket-deployment.ts @@ -16,7 +16,7 @@ export interface BucketDeploymentProps { /** * The S3 bucket to sync the contents of the zip file to. */ - destinationBucket: s3.BucketRef; + destinationBucket: s3.IBucket; /** * Key prefix in the destination bucket. diff --git a/packages/@aws-cdk/aws-s3-deployment/lib/source.ts b/packages/@aws-cdk/aws-s3-deployment/lib/source.ts index 9df095c59722f..61507865c4840 100644 --- a/packages/@aws-cdk/aws-s3-deployment/lib/source.ts +++ b/packages/@aws-cdk/aws-s3-deployment/lib/source.ts @@ -7,7 +7,7 @@ export interface SourceProps { /** * The source bucket to deploy from. */ - bucket: s3.BucketRef; + bucket: s3.IBucket; /** * An S3 object key in the source bucket that points to a zip file. @@ -42,7 +42,7 @@ export class Source { * @param bucket The S3 Bucket * @param zipObjectKey The S3 object key of the zip file with contents */ - public static bucket(bucket: s3.BucketRef, zipObjectKey: string): ISource { + public static bucket(bucket: s3.IBucket, zipObjectKey: string): ISource { return { bind: () => ({ bucket, zipObjectKey }) }; diff --git a/packages/@aws-cdk/aws-s3/lib/bucket-policy.ts b/packages/@aws-cdk/aws-s3/lib/bucket-policy.ts index 3e6e3a7273601..1f9a21a283c33 100644 --- a/packages/@aws-cdk/aws-s3/lib/bucket-policy.ts +++ b/packages/@aws-cdk/aws-s3/lib/bucket-policy.ts @@ -1,13 +1,13 @@ import { PolicyDocument } from '@aws-cdk/aws-iam'; import { Construct } from '@aws-cdk/cdk'; -import { BucketRef } from './bucket'; +import { IBucket } from './bucket'; import { CfnBucketPolicy } from './s3.generated'; export interface BucketPolicyProps { /** * The Amazon S3 bucket that the policy applies to. */ - bucket: BucketRef; + bucket: IBucket; } /** diff --git a/packages/@aws-cdk/aws-s3/lib/bucket.ts b/packages/@aws-cdk/aws-s3/lib/bucket.ts index c289052722672..efba50fde88fc 100644 --- a/packages/@aws-cdk/aws-s3/lib/bucket.ts +++ b/packages/@aws-cdk/aws-s3/lib/bucket.ts @@ -11,12 +11,174 @@ import { LifecycleRule } from './rule'; import { CfnBucket } from './s3.generated'; import { parseBucketArn, parseBucketName } from './util'; +export interface IBucket { + /** + * The ARN of the bucket. + */ + readonly bucketArn: string; + + /** + * The name of the bucket. + */ + readonly bucketName: string; + + /** + * The domain of the bucket. + */ + readonly domainName: string; + + /** + * Optional KMS encryption key associated with this bucket. + */ + readonly encryptionKey?: kms.IEncryptionKey; + + /** + * The https:// URL of this bucket. + * @example https://s3.us-west-1.amazonaws.com/onlybucket + * Similar to calling `urlForObject` with no object key. + */ + readonly bucketUrl: string; + + /** + * The resource policy assoicated with this bucket. + * + * If `autoCreatePolicy` is true, a `BucketPolicy` will be created upon the + * first call to addToResourcePolicy(s). + */ + policy?: BucketPolicy; + + /** + * Exports this bucket from the stack. + */ + export(): BucketImportProps; + + /** + * Convenience method for creating a new {@link PipelineSourceAction}, + * and adding it to the given Stage. + * + * @param stage the Pipeline Stage to add the new Action to + * @param name the name of the newly created Action + * @param props the properties of the new Action + * @returns the newly created {@link PipelineSourceAction} + */ + addToPipeline(stage: actions.IStage, name: string, props: CommonPipelineSourceActionProps): PipelineSourceAction; + + /** + * Adds a statement to the resource policy for a principal (i.e. + * account/role/service) to perform actions on this bucket and/or it's + * contents. Use `bucketArn` and `arnForObjects(keys)` to obtain ARNs for + * this bucket or objects. + */ + addToResourcePolicy(permission: iam.PolicyStatement): void; + + /** + * The https URL of an S3 object. For example: + * @example https://s3.us-west-1.amazonaws.com/onlybucket + * @example https://s3.us-west-1.amazonaws.com/bucket/key + * @example https://s3.cn-north-1.amazonaws.com.cn/china-bucket/mykey + * @param key The S3 key of the object. If not specified, the URL of the + * bucket is returned. + * @returns an ObjectS3Url token + */ + urlForObject(key?: string): string; + + /** + * Returns an ARN that represents all objects within the bucket that match + * the key pattern specified. To represent all keys, specify ``"*"``. + * + * If you specify multiple components for keyPattern, they will be concatenated:: + * + * arnForObjects('home/', team, '/', user, '/*') + * + */ + arnForObjects(...keyPattern: string[]): string; + + /** + * Grant read permissions for this bucket and it's contents to an IAM + * principal (Role/Group/User). + * + * If encryption is used, permission to use the key to decrypt the contents + * of the bucket will also be granted to the same principal. + * + * @param identity The principal + * @param objectsKeyPattern Restrict the permission to a certain key pattern (default '*') + */ + grantRead(identity?: iam.IPrincipal, objectsKeyPattern?: any): void; + + /** + * Grant write permissions to this bucket to an IAM principal. + * + * If encryption is used, permission to use the key to encrypt the contents + * of written files will also be granted to the same principal. + * + * @param identity The principal + * @param objectsKeyPattern Restrict the permission to a certain key pattern (default '*') + */ + grantWrite(identity?: iam.IPrincipal, objectsKeyPattern?: any): void; + + /** + * Grants s3:PutObject* and s3:Abort* permissions for this bucket to an IAM principal. + * + * If encryption is used, permission to use the key to encrypt the contents + * of written files will also be granted to the same principal. + * @param identity The principal + * @param objectsKeyPattern Restrict the permission to a certain key pattern (default '*') + */ + grantPut(identity?: iam.IPrincipal, objectsKeyPattern?: any): void; + + /** + * Grants s3:DeleteObject* permission to an IAM pricipal for objects + * in this bucket. + * + * @param identity The principal + * @param objectsKeyPattern Restrict the permission to a certain key pattern (default '*') + */ + grantDelete(identity?: iam.IPrincipal, objectsKeyPattern?: any): void; + + /** + * Grants read/write permissions for this bucket and it's contents to an IAM + * principal (Role/Group/User). + * + * If an encryption key is used, permission to use the key for + * encrypt/decrypt will also be granted. + * + * @param identity The principal + * @param objectsKeyPattern Restrict the permission to a certain key pattern (default '*') + */ + grantReadWrite(identity?: iam.IPrincipal, objectsKeyPattern?: any): void; + + /** + * Allows unrestricted access to objects from this bucket. + * + * IMPORTANT: This permission allows anyone to perform actions on S3 objects + * in this bucket, which is useful for when you configure your bucket as a + * website and want everyone to be able to read objects in the bucket without + * needing to authenticate. + * + * Without arguments, this method will grant read ("s3:GetObject") access to + * all objects ("*") in the bucket. + * + * The method returns the `iam.PolicyStatement` object, which can then be modified + * as needed. For example, you can add a condition that will restrict access only + * to an IPv4 range like this: + * + * const statement = bucket.grantPublicAccess(); + * statement.addCondition('IpAddress', { "aws:SourceIp": "54.240.143.0/24" }); + * + * + * @param keyPrefix the prefix of S3 object keys (e.g. `home/*`). Default is "*". + * @param allowedActions the set of S3 actions to allow. Default is "s3:GetObject". + * @returns The `iam.PolicyStatement` object, which can be used to apply e.g. conditions. + */ + grantPublicAccess(keyPrefix?: string, ...allowedActions: string[]): iam.PolicyStatement; +} + /** * A reference to a bucket. The easiest way to instantiate is to call * `bucket.export()`. Then, the consumer can use `Bucket.import(this, ref)` and * get a `Bucket`. */ -export interface BucketRefProps { +export interface BucketImportProps { /** * The ARN fo the bucket. At least one of bucketArn or bucketName must be * defined in order to initialize a bucket ref. @@ -48,27 +210,15 @@ export interface BucketRefProps { * * Or imported from an existing bucket: * - * BucketRef.import(this, 'MyImportedBucket', { bucketArn: ... }); + * Bucket.import(this, 'MyImportedBucket', { bucketArn: ... }); * * You can also export a bucket and import it into another stack: * * const ref = myBucket.export(); - * BucketRef.import(this, 'MyImportedBucket', ref); + * Bucket.import(this, 'MyImportedBucket', ref); * */ -export abstract class BucketRef extends cdk.Construct { - /** - * Creates a Bucket construct that represents an external bucket. - * - * @param parent The parent creating construct (usually `this`). - * @param name The construct's name. - * @param ref A BucketRefProps object. Can be obtained from a call to - * `bucket.export()`. - */ - public static import(parent: cdk.Construct, name: string, props: BucketRefProps): BucketRef { - return new ImportedBucketRef(parent, name, props); - } - +export abstract class BucketBase extends cdk.Construct implements IBucket { /** * The ARN of the bucket. */ @@ -87,7 +237,7 @@ export abstract class BucketRef extends cdk.Construct { /** * Optional KMS encryption key associated with this bucket. */ - public abstract readonly encryptionKey?: kms.EncryptionKeyRef; + public abstract readonly encryptionKey?: kms.IEncryptionKey; /** * The resource policy assoicated with this bucket. @@ -95,7 +245,7 @@ export abstract class BucketRef extends cdk.Construct { * If `autoCreatePolicy` is true, a `BucketPolicy` will be created upon the * first call to addToResourcePolicy(s). */ - protected abstract policy?: BucketPolicy; + public abstract policy?: BucketPolicy; /** * Indicates if a bucket resource policy should automatically created upon @@ -106,13 +256,7 @@ export abstract class BucketRef extends cdk.Construct { /** * Exports this bucket from the stack. */ - public export(): BucketRefProps { - return { - bucketArn: new cdk.Output(this, 'BucketArn', { value: this.bucketArn }).makeImportValue().toString(), - bucketName: new cdk.Output(this, 'BucketName', { value: this.bucketName }).makeImportValue().toString(), - bucketDomainName: new cdk.Output(this, 'DomainName', { value: this.domainName }).makeImportValue().toString(), - }; - } + public abstract export(): BucketImportProps; /** * Convenience method for creating a new {@link PipelineSourceAction}, @@ -355,7 +499,7 @@ export interface BucketProps { * @default If encryption is set to "Kms" and this property is undefined, a * new KMS key will be created and associated with this bucket. */ - encryptionKey?: kms.EncryptionKeyRef; + encryptionKey?: kms.IEncryptionKey; /** * Physical name of this bucket. @@ -410,13 +554,25 @@ export interface BucketProps { * This bucket does not yet have all features that exposed by the underlying * BucketResource. */ -export class Bucket extends BucketRef { +export class Bucket extends BucketBase { + /** + * Creates a Bucket construct that represents an external bucket. + * + * @param parent The parent creating construct (usually `this`). + * @param id The construct's name. + * @param attrs A `BucketAttributes` object. Can be obtained from a call to + * `bucket.export()` or manually created. + */ + public static import(parent: cdk.Construct, id: string, attrs: BucketImportProps): IBucket { + return new ImportedBucket(parent, id, attrs); + } + public readonly bucketArn: string; public readonly bucketName: string; public readonly domainName: string; public readonly dualstackDomainName: string; - public readonly encryptionKey?: kms.EncryptionKeyRef; - protected policy?: BucketPolicy; + public readonly encryptionKey?: kms.IEncryptionKey; + public policy?: BucketPolicy; protected autoCreatePolicy = true; private readonly lifecycleRules: LifecycleRule[] = []; private readonly versioned?: boolean; @@ -456,6 +612,17 @@ export class Bucket extends BucketRef { } } + /** + * Exports this bucket from the stack. + */ + public export(): BucketImportProps { + return { + bucketArn: new cdk.Output(this, 'BucketArn', { value: this.bucketArn }).makeImportValue().toString(), + bucketName: new cdk.Output(this, 'BucketName', { value: this.bucketName }).makeImportValue().toString(), + bucketDomainName: new cdk.Output(this, 'DomainName', { value: this.domainName }).makeImportValue().toString(), + }; + } + /** * Add a lifecycle rule to the bucket * @@ -524,7 +691,7 @@ export class Bucket extends BucketRef { */ private parseEncryption(props: BucketProps): { bucketEncryption?: CfnBucket.BucketEncryptionProperty, - encryptionKey?: kms.EncryptionKeyRef + encryptionKey?: kms.IEncryptionKey } { // default to unencrypted. @@ -784,16 +951,16 @@ export interface NotificationKeyFilter { suffix?: string; } -class ImportedBucketRef extends BucketRef { +class ImportedBucket extends BucketBase { public readonly bucketArn: string; public readonly bucketName: string; public readonly domainName: string; public readonly encryptionKey?: kms.EncryptionKey; - protected policy?: BucketPolicy; + public policy?: BucketPolicy; protected autoCreatePolicy: boolean; - constructor(parent: cdk.Construct, name: string, props: BucketRefProps) { + constructor(parent: cdk.Construct, name: string, private readonly props: BucketImportProps) { super(parent, name); const bucketName = parseBucketName(props); @@ -808,6 +975,13 @@ class ImportedBucketRef extends BucketRef { this.policy = undefined; } + /** + * Exports this bucket from the stack. + */ + public export() { + return this.props; + } + private generateDomainName() { return `${this.bucketName}.s3.amazonaws.com`; } diff --git a/packages/@aws-cdk/aws-s3/lib/notifications-resource/notifications-resource.ts b/packages/@aws-cdk/aws-s3/lib/notifications-resource/notifications-resource.ts index 10ae2819085e2..4e824f7447920 100644 --- a/packages/@aws-cdk/aws-s3/lib/notifications-resource/notifications-resource.ts +++ b/packages/@aws-cdk/aws-s3/lib/notifications-resource/notifications-resource.ts @@ -7,7 +7,7 @@ interface NotificationsProps { /** * The bucket to manage notifications for. * - * This cannot be a `BucketRef` because the bucket maintains the 1:1 + * This cannot be an `IBucket` because the bucket maintains the 1:1 * relationship with this resource. */ bucket: Bucket; diff --git a/packages/@aws-cdk/aws-s3/lib/pipeline-action.ts b/packages/@aws-cdk/aws-s3/lib/pipeline-action.ts index a4f03b9c79be5..43aa1a94a836c 100644 --- a/packages/@aws-cdk/aws-s3/lib/pipeline-action.ts +++ b/packages/@aws-cdk/aws-s3/lib/pipeline-action.ts @@ -1,11 +1,11 @@ import codepipeline = require('@aws-cdk/aws-codepipeline-api'); import cdk = require('@aws-cdk/cdk'); -import { BucketRef } from './bucket'; +import { IBucket } from './bucket'; /** * Common properties for creating {@link PipelineSourceAction} - * either directly, through its constructor, - * or through {@link BucketRef#addToPipeline}. + * or through {@link IBucket#addToPipeline}. */ export interface CommonPipelineSourceActionProps extends codepipeline.CommonActionProps { /** @@ -40,7 +40,7 @@ export interface PipelineSourceActionProps extends CommonPipelineSourceActionPro /** * The Amazon S3 bucket that stores the source code */ - bucket: BucketRef; + bucket: IBucket; } /** diff --git a/packages/@aws-cdk/aws-s3/lib/util.ts b/packages/@aws-cdk/aws-s3/lib/util.ts index d75fc4008fd91..a6c9861829a15 100644 --- a/packages/@aws-cdk/aws-s3/lib/util.ts +++ b/packages/@aws-cdk/aws-s3/lib/util.ts @@ -1,7 +1,7 @@ import cdk = require('@aws-cdk/cdk'); -import { BucketRefProps } from './bucket'; +import { BucketImportProps } from './bucket'; -export function parseBucketArn(props: BucketRefProps): string { +export function parseBucketArn(props: BucketImportProps): string { // if we have an explicit bucket ARN, use it. if (props.bucketArn) { @@ -22,7 +22,7 @@ export function parseBucketArn(props: BucketRefProps): string { throw new Error('Cannot determine bucket ARN. At least `bucketArn` or `bucketName` is needed'); } -export function parseBucketName(props: BucketRefProps): string | undefined { +export function parseBucketName(props: BucketImportProps): string | undefined { // if we have an explicit bucket name, use it. if (props.bucketName) { diff --git a/packages/@aws-cdk/aws-s3/test/demo.import-export.ts b/packages/@aws-cdk/aws-s3/test/demo.import-export.ts index e30ce772effcd..e05b9dc41eeda 100644 --- a/packages/@aws-cdk/aws-s3/test/demo.import-export.ts +++ b/packages/@aws-cdk/aws-s3/test/demo.import-export.ts @@ -3,11 +3,11 @@ import cdk = require('@aws-cdk/cdk'); import s3 = require('../lib'); // Define a stack with an S3 bucket and export it using `bucket.export()`. -// bucket.export returns a `BucketRef` object which can later be used in +// bucket.export returns an `IBucket` object which can later be used in // `Bucket.import`. class Producer extends cdk.Stack { - public readonly myBucketRef: s3.BucketRefProps; + public readonly myBucketRef: s3.BucketImportProps; constructor(parent: cdk.App, name: string) { super(parent, name); @@ -18,7 +18,7 @@ class Producer extends cdk.Stack { } interface ConsumerConstructProps { - bucket: s3.BucketRef; + bucket: s3.IBucket; } class ConsumerConstruct extends cdk.Construct { @@ -29,13 +29,13 @@ class ConsumerConstruct extends cdk.Construct { } } -// Define a stack that requires a BucketRef as an input and uses `Bucket.import` +// Define a stack that requires an IBucket as an input and uses `Bucket.import` // to create a `Bucket` object that represents this external bucket. Grant a // user principal created within this consuming stack read/write permissions to // this bucket and contents. interface ConsumerProps { - userBucketRef: s3.BucketRefProps; + userBucketRef: s3.BucketImportProps; } class Consumer extends cdk.Stack { diff --git a/packages/@aws-cdk/aws-sns/lib/policy.ts b/packages/@aws-cdk/aws-sns/lib/policy.ts index c1be7dfdfe7b9..07c2767d49ff4 100644 --- a/packages/@aws-cdk/aws-sns/lib/policy.ts +++ b/packages/@aws-cdk/aws-sns/lib/policy.ts @@ -1,13 +1,13 @@ import { PolicyDocument } from '@aws-cdk/aws-iam'; import { Construct, IDependable } from '@aws-cdk/cdk'; import { CfnTopicPolicy } from './sns.generated'; -import { TopicRef } from './topic-ref'; +import { ITopic } from './topic-ref'; export interface TopicPolicyProps { /** * The set of topics this policy applies to. */ - topics: TopicRef[]; + topics: ITopic[]; } /** @@ -24,8 +24,8 @@ export class TopicPolicy extends Construct implements IDependable { */ public readonly dependencyElements = new Array(); - constructor(parent: Construct, name: string, props: TopicPolicyProps) { - super(parent, name); + constructor(parent: Construct, id: string, props: TopicPolicyProps) { + super(parent, id); const resource = new CfnTopicPolicy(this, 'Resource', { policyDocument: this.document, diff --git a/packages/@aws-cdk/aws-sns/lib/subscription.ts b/packages/@aws-cdk/aws-sns/lib/subscription.ts index 7202191f13af7..6a6d5d2d3b192 100644 --- a/packages/@aws-cdk/aws-sns/lib/subscription.ts +++ b/packages/@aws-cdk/aws-sns/lib/subscription.ts @@ -1,6 +1,6 @@ import { Construct } from '@aws-cdk/cdk'; import { CfnSubscription } from './sns.generated'; -import { TopicRef } from './topic-ref'; +import { ITopic } from './topic-ref'; /** * Properties for creating a new subscription @@ -21,18 +21,18 @@ export interface SubscriptionProps { /** * The topic to subscribe to. */ - topic: TopicRef; + topic: ITopic; } /** * A new subscription. * - * Prefer to use the `TopicRef.subscribeXxx()` methods to creating instances of + * Prefer to use the `ITopic.subscribeXxx()` methods to creating instances of * this class. */ export class Subscription extends Construct { - constructor(parent: Construct, name: string, props: SubscriptionProps) { - super(parent, name); + constructor(parent: Construct, id: string, props: SubscriptionProps) { + super(parent, id); new CfnSubscription(this, 'Resource', { endpoint: props.endpoint, diff --git a/packages/@aws-cdk/aws-sns/lib/topic-ref.ts b/packages/@aws-cdk/aws-sns/lib/topic-ref.ts index 0074358b691e1..c8cd0f83875a4 100644 --- a/packages/@aws-cdk/aws-sns/lib/topic-ref.ts +++ b/packages/@aws-cdk/aws-sns/lib/topic-ref.ts @@ -9,23 +9,117 @@ import cdk = require('@aws-cdk/cdk'); import { TopicPolicy } from './policy'; import { Subscription, SubscriptionProtocol } from './subscription'; -/** - * Either a new or imported Topic - */ -export abstract class TopicRef extends cdk.Construct - implements - events.IEventRuleTarget, - cloudwatch.IAlarmAction, - s3n.IBucketNotificationDestination, - autoscaling_api.ILifecycleHookTarget { +export interface ITopic extends + events.IEventRuleTarget, + cloudwatch.IAlarmAction, + s3n.IBucketNotificationDestination, + autoscaling_api.ILifecycleHookTarget { + + readonly topicArn: string; + + readonly topicName: string; /** - * Import a Topic defined elsewhere + * Export this Topic */ - public static import(parent: cdk.Construct, name: string, props: TopicRefProps): TopicRef { - return new ImportedTopic(parent, name, props); - } + export(): TopicImportProps; + + /** + * Subscribe some endpoint to this topic + */ + subscribe(name: string, endpoint: string, protocol: SubscriptionProtocol): Subscription; + + /** + * Defines a subscription from this SNS topic to an SQS queue. + * + * The queue resource policy will be updated to allow this SNS topic to send + * messages to the queue. + * + * @param name The subscription name + * @param queue The target queue + */ + subscribeQueue(queue: sqs.IQueue): Subscription; + + /** + * Defines a subscription from this SNS Topic to a Lambda function. + * + * The Lambda's resource policy will be updated to allow this topic to + * invoke the function. + * + * @param name A name for the subscription + * @param lambdaFunction The Lambda function to invoke + */ + subscribeLambda(lambdaFunction: lambda.IFunction): Subscription; + + /** + * Defines a subscription from this SNS topic to an email address. + * + * @param name A name for the subscription + * @param emailAddress The email address to use. + * @param jsonFormat True if the email content should be in JSON format (default is false). + */ + subscribeEmail(name: string, emailAddress: string, options?: EmailSubscriptionOptions): Subscription; + + /** + * Defines a subscription from this SNS topic to an http:// or https:// URL. + * + * @param name A name for the subscription + * @param url The URL to invoke + */ + subscribeUrl(name: string, url: string): Subscription; + + /** + * Adds a statement to the IAM resource policy associated with this topic. + * + * If this topic was created in this stack (`new Topic`), a topic policy + * will be automatically created upon the first call to `addToPolicy`. If + * the topic is improted (`Topic.import`), then this is a no-op. + */ + addToResourcePolicy(statement: iam.PolicyStatement): void; + + /** + * Grant topic publishing permissions to the given identity + */ + grantPublish(identity?: iam.IPrincipal): void; + + /** + * Construct a Metric object for the current topic for the given metric + */ + metric(metricName: string, props?: cloudwatch.MetricCustomization): cloudwatch.Metric; + + /** + * Metric for the size of messages published through this topic + * + * @default average over 5 minutes + */ + metricPublishSize(props?: cloudwatch.MetricCustomization): cloudwatch.Metric; + /** + * Metric for the number of messages published through this topic + * + * @default sum over 5 minutes + */ + metricNumberOfMessagesPublished(props?: cloudwatch.MetricCustomization): cloudwatch.Metric; + + /** + * Metric for the number of messages that failed to publish through this topic + * + * @default sum over 5 minutes + */ + metricNumberOfMessagesFailed(props?: cloudwatch.MetricCustomization): cloudwatch.Metric; + + /** + * Metric for the number of messages that were successfully delivered through this topic + * + * @default sum over 5 minutes + */ + metricNumberOfMessagesDelivered(props?: cloudwatch.MetricCustomization): cloudwatch.Metric; +} + +/** + * Either a new or imported Topic + */ +export abstract class TopicBase extends cdk.Construct implements ITopic { public abstract readonly topicArn: string; public abstract readonly topicName: string; @@ -51,18 +145,13 @@ export abstract class TopicRef extends cdk.Construct /** * Export this Topic */ - public export(): TopicRefProps { - return { - topicArn: new cdk.Output(this, 'TopicArn', { value: this.topicArn }).makeImportValue().toString(), - topicName: new cdk.Output(this, 'TopicName', { value: this.topicName }).makeImportValue().toString(), - }; - } + public abstract export(): TopicImportProps; /** * Subscribe some endpoint to this topic */ - public subscribe(name: string, endpoint: string, protocol: SubscriptionProtocol) { - new Subscription(this, name, { + public subscribe(name: string, endpoint: string, protocol: SubscriptionProtocol): Subscription { + return new Subscription(this, name, { topic: this, endpoint, protocol @@ -75,12 +164,10 @@ export abstract class TopicRef extends cdk.Construct * The queue resource policy will be updated to allow this SNS topic to send * messages to the queue. * - * TODO: change to QueueRef. - * * @param name The subscription name * @param queue The target queue */ - public subscribeQueue(queue: sqs.QueueRef) { + public subscribeQueue(queue: sqs.IQueue): Subscription { const subscriptionName = queue.id + 'Subscription'; if (this.tryFindChild(subscriptionName)) { throw new Error(`A subscription between the topic ${this.id} and the queue ${queue.id} already exists`); @@ -114,7 +201,7 @@ export abstract class TopicRef extends cdk.Construct * @param name A name for the subscription * @param lambdaFunction The Lambda function to invoke */ - public subscribeLambda(lambdaFunction: lambda.FunctionRef) { + public subscribeLambda(lambdaFunction: lambda.IFunction): Subscription { const subscriptionName = lambdaFunction.id + 'Subscription'; if (this.tryFindChild(subscriptionName)) { @@ -142,7 +229,7 @@ export abstract class TopicRef extends cdk.Construct * @param emailAddress The email address to use. * @param jsonFormat True if the email content should be in JSON format (default is false). */ - public subscribeEmail(name: string, emailAddress: string, options?: EmailSubscriptionOptions) { + public subscribeEmail(name: string, emailAddress: string, options?: EmailSubscriptionOptions): Subscription { const protocol = (options && options.json ? SubscriptionProtocol.EmailJson : SubscriptionProtocol.Email); return new Subscription(this, name, { @@ -158,7 +245,7 @@ export abstract class TopicRef extends cdk.Construct * @param name A name for the subscription * @param url The URL to invoke */ - public subscribeUrl(name: string, url: string) { + public subscribeUrl(name: string, url: string): Subscription { if (!url.startsWith('http://') && !url.startsWith('https://')) { throw new Error('URL must start with either http:// or https://'); } @@ -317,26 +404,10 @@ export abstract class TopicRef extends cdk.Construct } } -/** - * An imported topic - */ -class ImportedTopic extends TopicRef { - public readonly topicArn: string; - public readonly topicName: string; - - protected autoCreatePolicy: boolean = false; - - constructor(parent: cdk.Construct, name: string, props: TopicRefProps) { - super(parent, name); - this.topicArn = props.topicArn; - this.topicName = props.topicName; - } -} - /** * Reference to an external topic. */ -export interface TopicRefProps { +export interface TopicImportProps { topicArn: string; topicName: string; } diff --git a/packages/@aws-cdk/aws-sns/lib/topic.ts b/packages/@aws-cdk/aws-sns/lib/topic.ts index 476a2446c6c7d..3c51e8717ef74 100644 --- a/packages/@aws-cdk/aws-sns/lib/topic.ts +++ b/packages/@aws-cdk/aws-sns/lib/topic.ts @@ -1,6 +1,6 @@ -import { Construct, } from '@aws-cdk/cdk'; +import { Construct, Output } from '@aws-cdk/cdk'; import { CfnTopic } from './sns.generated'; -import { TopicRef } from './topic-ref'; +import { ITopic, TopicBase, TopicImportProps } from './topic-ref'; /** * Properties for a new SNS topic @@ -28,7 +28,14 @@ export interface TopicProps { /** * A new SNS topic */ -export class Topic extends TopicRef { +export class Topic extends TopicBase { + /** + * Import a Topic defined elsewhere + */ + public static import(parent: Construct, name: string, props: TopicImportProps): ITopic { + return new ImportedTopic(parent, name, props); + } + public readonly topicArn: string; public readonly topicName: string; @@ -45,4 +52,34 @@ export class Topic extends TopicRef { this.topicArn = resource.ref; this.topicName = resource.topicName; } + + /** + * Export this Topic + */ + public export(): TopicImportProps { + return { + topicArn: new Output(this, 'TopicArn', { value: this.topicArn }).makeImportValue().toString(), + topicName: new Output(this, 'TopicName', { value: this.topicName }).makeImportValue().toString(), + }; + } +} + +/** + * An imported topic + */ +class ImportedTopic extends TopicBase { + public readonly topicArn: string; + public readonly topicName: string; + + protected autoCreatePolicy: boolean = false; + + constructor(parent: Construct, id: string, private readonly props: TopicImportProps) { + super(parent, id); + this.topicArn = props.topicArn; + this.topicName = props.topicName; + } + + public export(): TopicImportProps { + return this.props; + } } diff --git a/packages/@aws-cdk/aws-sns/test/test.sns.ts b/packages/@aws-cdk/aws-sns/test/test.sns.ts index 8a59d503cb0bd..9ca00798b18ad 100644 --- a/packages/@aws-cdk/aws-sns/test/test.sns.ts +++ b/packages/@aws-cdk/aws-sns/test/test.sns.ts @@ -677,7 +677,7 @@ export = { // WHEN const ref = topic.export(); - const imported = sns.TopicRef.import(stack2, 'Imported', ref); + const imported = sns.Topic.import(stack2, 'Imported', ref); imported.subscribeQueue(queue); // THEN diff --git a/packages/@aws-cdk/aws-sqs/lib/policy.ts b/packages/@aws-cdk/aws-sqs/lib/policy.ts index e0d7eec007c4d..ba8a69b821a66 100644 --- a/packages/@aws-cdk/aws-sqs/lib/policy.ts +++ b/packages/@aws-cdk/aws-sqs/lib/policy.ts @@ -1,13 +1,13 @@ import { PolicyDocument } from '@aws-cdk/aws-iam'; import { Construct, IDependable } from '@aws-cdk/cdk'; -import { QueueRef } from './queue-ref'; +import { IQueue } from './queue-ref'; import { CfnQueuePolicy } from './sqs.generated'; export interface QueuePolicyProps { /** * The set of queues this policy applies to. */ - queues: QueueRef[]; + queues: IQueue[]; } /** diff --git a/packages/@aws-cdk/aws-sqs/lib/queue-ref.ts b/packages/@aws-cdk/aws-sqs/lib/queue-ref.ts index 7ee4148c3a93c..84287c71f1dc6 100644 --- a/packages/@aws-cdk/aws-sqs/lib/queue-ref.ts +++ b/packages/@aws-cdk/aws-sqs/lib/queue-ref.ts @@ -5,16 +5,105 @@ import s3n = require('@aws-cdk/aws-s3-notifications'); import cdk = require('@aws-cdk/cdk'); import { QueuePolicy } from './policy'; +export interface IQueue extends s3n.IBucketNotificationDestination, autoscaling_api.ILifecycleHookTarget { + /** + * Local logical ID. + */ + readonly id: string; + + /** + * Unique logical ID. + */ + readonly uniqueId: string; + + /** + * The ARN of this queue + */ + readonly queueArn: string; + + /** + * The URL of this queue + */ + readonly queueUrl: string; + + /** + * If this queue is server-side encrypted, this is the KMS encryption key. + */ + readonly encryptionMasterKey?: kms.IEncryptionKey; + + /** + * Export a queue + */ + export(): QueueImportProps; + + /** + * Adds a statement to the IAM resource policy associated with this queue. + * + * If this queue was created in this stack (`new Queue`), a queue policy + * will be automatically created upon the first call to `addToPolicy`. If + * the queue is improted (`Queue.import`), then this is a no-op. + */ + addToResourcePolicy(statement: iam.PolicyStatement): void; + + /** + * Grant permissions to consume messages from a queue + * + * This will grant the following permissions: + * + * - sqs:ChangeMessageVisibility + * - sqs:ChangeMessageVisibilityBatch + * - sqs:DeleteMessage + * - sqs:ReceiveMessage + * - sqs:DeleteMessageBatch + * - sqs:GetQueueAttributes + * - sqs:GetQueueUrl + * + * @param identity Principal to grant consume rights to + */ + grantConsumeMessages(identity?: iam.IPrincipal): void; + + /** + * Grant access to send messages to a queue to the given identity. + * + * This will grant the following permissions: + * + * - sqs:SendMessage + * - sqs:SendMessageBatch + * - sqs:GetQueueAttributes + * - sqs:GetQueueUrl + * + * @param identity Principal to grant send rights to + */ + grantSendMessages(identity?: iam.IPrincipal): void; + + /** + * Grant an IAM principal permissions to purge all messages from the queue. + * + * This will grant the following permissions: + * + * - sqs:PurgeQueue + * - sqs:GetQueueAttributes + * - sqs:GetQueueUrl + * + * @param identity Principal to grant send rights to + * @param queueActions additional queue actions to allow + */ + grantPurge(identity?: iam.IPrincipal): void; + + /** + * Grant the actions defined in queueActions to the identity Principal given + * on this SQS queue resource. + * + * @param identity Principal to grant right to + * @param queueActions The actions to grant + */ + grant(identity?: iam.IPrincipal, ...queueActions: string[]): void; +} + /** * Reference to a new or existing Amazon SQS queue */ -export abstract class QueueRef extends cdk.Construct implements s3n.IBucketNotificationDestination, autoscaling_api.ILifecycleHookTarget { - /** - * Import an existing queue - */ - public static import(parent: cdk.Construct, name: string, props: QueueRefProps): QueueRef { - return new ImportedQueue(parent, name, props); - } +export abstract class QueueBase extends cdk.Construct implements IQueue { /** * The ARN of this queue @@ -29,7 +118,7 @@ export abstract class QueueRef extends cdk.Construct implements s3n.IBucketNotif /** * If this queue is server-side encrypted, this is the KMS encryption key. */ - public abstract readonly encryptionMasterKey?: kms.EncryptionKeyRef; + public abstract readonly encryptionMasterKey?: kms.IEncryptionKey; /** * Controls automatic creation of policy objects. @@ -48,15 +137,7 @@ export abstract class QueueRef extends cdk.Construct implements s3n.IBucketNotif /** * Export a queue */ - public export(): QueueRefProps { - return { - queueArn: new cdk.Output(this, 'QueueArn', { value: this.queueArn }).makeImportValue().toString(), - queueUrl: new cdk.Output(this, 'QueueUrl', { value: this.queueUrl }).makeImportValue().toString(), - keyArn: this.encryptionMasterKey - ? new cdk.Output(this, 'KeyArn', { value: this.encryptionMasterKey.keyArn }).makeImportValue().toString() - : undefined - }; - } + public abstract export(): QueueImportProps; /** * Adds a statement to the IAM resource policy associated with this queue. @@ -206,7 +287,7 @@ export abstract class QueueRef extends cdk.Construct implements s3n.IBucketNotif /** * Reference to a queue */ -export interface QueueRefProps { +export interface QueueImportProps { /** * The ARN of the queue. */ @@ -217,31 +298,14 @@ export interface QueueRefProps { */ queueUrl: string; + /** + * The name of the queue. + * @default if queue name is not specified, the name will be derived from the queue ARN + */ + queueName?: string; + /** * KMS encryption key, if this queue is server-side encrypted by a KMS key. */ keyArn?: string; } - -/** - * A queue that has been imported - */ -class ImportedQueue extends QueueRef { - public readonly queueArn: string; - public readonly queueUrl: string; - public readonly encryptionMasterKey?: kms.EncryptionKeyRef; - - protected readonly autoCreatePolicy = false; - - constructor(parent: cdk.Construct, name: string, props: QueueRefProps) { - super(parent, name); - this.queueArn = props.queueArn; - this.queueUrl = props.queueUrl; - - if (props.keyArn) { - this.encryptionMasterKey = kms.EncryptionKey.import(this, 'Key', { - keyArn: props.keyArn - }); - } - } -} diff --git a/packages/@aws-cdk/aws-sqs/lib/queue.ts b/packages/@aws-cdk/aws-sqs/lib/queue.ts index f6b633a3ab1fe..e066040fc3efd 100644 --- a/packages/@aws-cdk/aws-sqs/lib/queue.ts +++ b/packages/@aws-cdk/aws-sqs/lib/queue.ts @@ -1,6 +1,6 @@ import kms = require('@aws-cdk/aws-kms'); import cdk = require('@aws-cdk/cdk'); -import { QueueRef } from './queue-ref'; +import { IQueue, QueueBase, QueueImportProps } from './queue-ref'; import { CfnQueue } from './sqs.generated'; import { validateProps } from './validate-props'; @@ -103,7 +103,7 @@ export interface QueueProps { * * @default If encryption is set to KMS and not specified, a key will be created. */ - encryptionMasterKey?: kms.EncryptionKeyRef; + encryptionMasterKey?: kms.IEncryptionKey; /** * The length of time that Amazon SQS reuses a data key before calling KMS again. @@ -146,7 +146,7 @@ export interface DeadLetterQueue { /** * The dead-letter queue to which Amazon SQS moves messages after the value of maxReceiveCount is exceeded. */ - queue: QueueRef; + queue: IQueue; /** * The number of times a message can be unsuccesfully dequeued before being moved to the dead-letter queue. @@ -179,7 +179,14 @@ export enum QueueEncryption { /** * A new Amazon SQS queue */ -export class Queue extends QueueRef { +export class Queue extends QueueBase { + /** + * Import an existing queue + */ + public static import(parent: cdk.Construct, name: string, props: QueueImportProps): IQueue { + return new ImportedQueue(parent, name, props); + } + /** * The ARN of this queue */ @@ -198,7 +205,7 @@ export class Queue extends QueueRef { /** * If this queue is encrypted, this is the KMS key. */ - public readonly encryptionMasterKey?: kms.EncryptionKeyRef; + public readonly encryptionMasterKey?: kms.IEncryptionKey; protected readonly autoCreatePolicy = true; @@ -232,7 +239,7 @@ export class Queue extends QueueRef { this.queueName = queue.queueName; this.queueUrl = queue.ref; - function _determineEncryptionProps(this: Queue): { encryptionProps: EncryptionProps, encryptionMasterKey?: kms.EncryptionKeyRef } { + function _determineEncryptionProps(this: Queue): { encryptionProps: EncryptionProps, encryptionMasterKey?: kms.IEncryptionKey } { let encryption = props.encryption || QueueEncryption.Unencrypted; if (encryption !== QueueEncryption.Kms && props.encryptionMasterKey) { @@ -275,6 +282,19 @@ export class Queue extends QueueRef { } } + /** + * Export a queue + */ + public export(): QueueImportProps { + return { + queueArn: new cdk.Output(this, 'QueueArn', { value: this.queueArn }).makeImportValue().toString(), + queueUrl: new cdk.Output(this, 'QueueUrl', { value: this.queueUrl }).makeImportValue().toString(), + keyArn: this.encryptionMasterKey + ? new cdk.Output(this, 'KeyArn', { value: this.encryptionMasterKey.keyArn }).makeImportValue().toString() + : undefined + }; + } + /** * Look at the props, see if the FIFO props agree, and return the correct subset of props */ @@ -314,3 +334,33 @@ interface EncryptionProps { readonly kmsMasterKeyId?: string; readonly kmsDataKeyReusePeriodSeconds?: number; } + +/** + * A queue that has been imported + */ +class ImportedQueue extends QueueBase { + public readonly queueArn: string; + public readonly queueUrl: string; + public readonly encryptionMasterKey?: kms.IEncryptionKey; + + protected readonly autoCreatePolicy = false; + + constructor(parent: cdk.Construct, name: string, private readonly props: QueueImportProps) { + super(parent, name); + this.queueArn = props.queueArn; + this.queueUrl = props.queueUrl; + + if (props.keyArn) { + this.encryptionMasterKey = kms.EncryptionKey.import(this, 'Key', { + keyArn: props.keyArn + }); + } + } + + /** + * Export a queue + */ + public export() { + return this.props; + } +} diff --git a/packages/@aws-cdk/aws-sqs/test/test.sqs.ts b/packages/@aws-cdk/aws-sqs/test/test.sqs.ts index d6481db432925..37e9faff6a5ff 100644 --- a/packages/@aws-cdk/aws-sqs/test/test.sqs.ts +++ b/packages/@aws-cdk/aws-sqs/test/test.sqs.ts @@ -98,11 +98,11 @@ export = { // WHEN const ref = queue.export(); - const imports = sqs.QueueRef.import(stack, 'Imported', ref); + const imports = sqs.Queue.import(stack, 'Imported', ref); // THEN - // "import" returns a a QueueRef bound to `Fn::ImportValue`s. + // "import" returns an IQueue bound to `Fn::ImportValue`s. test.deepEqual(resolve(imports.queueArn), { 'Fn::ImportValue': 'QueueQueueArn8CF496D5' }); test.deepEqual(resolve(imports.queueUrl), { 'Fn::ImportValue': 'QueueQueueUrlC30FF916' }); diff --git a/packages/@aws-cdk/aws-stepfunctions/lib/state-machine.ts b/packages/@aws-cdk/aws-stepfunctions/lib/state-machine.ts index 1368bc599f37a..ea016a18217f6 100644 --- a/packages/@aws-cdk/aws-stepfunctions/lib/state-machine.ts +++ b/packages/@aws-cdk/aws-stepfunctions/lib/state-machine.ts @@ -44,7 +44,7 @@ export class StateMachine extends cdk.Construct implements IStateMachine { /** * Import a state machine */ - public static import(parent: cdk.Construct, id: string, props: ImportedStateMachineProps): IStateMachine { + public static import(parent: cdk.Construct, id: string, props: StateMachineImportProps): IStateMachine { return new ImportedStateMachine(parent, id, props); } @@ -192,7 +192,7 @@ export class StateMachine extends cdk.Construct implements IStateMachine { /** * Export this state machine */ - public export(): ImportedStateMachineProps { + public export(): StateMachineImportProps { return { stateMachineArn: new cdk.Output(this, 'StateMachineArn', { value: this.stateMachineArn }).makeImportValue().toString(), }; @@ -207,12 +207,17 @@ export interface IStateMachine { * The ARN of the state machine */ readonly stateMachineArn: string; + + /** + * Export this state machine + */ + export(): StateMachineImportProps; } /** * Properties for an imported state machine */ -export interface ImportedStateMachineProps { +export interface StateMachineImportProps { /** * The ARN of the state machine */ @@ -221,8 +226,12 @@ export interface ImportedStateMachineProps { class ImportedStateMachine extends cdk.Construct implements IStateMachine { public readonly stateMachineArn: string; - constructor(parent: cdk.Construct, id: string, props: ImportedStateMachineProps) { + constructor(parent: cdk.Construct, id: string, private readonly props: StateMachineImportProps) { super(parent, id); this.stateMachineArn = props.stateMachineArn; } + + public export() { + return this.props; + } } \ No newline at end of file