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 8e8f4f73eb82c..db8209eccc379 100644 --- a/packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts +++ b/packages/@aws-cdk/aws-autoscaling/lib/auto-scaling-group.ts @@ -5,7 +5,10 @@ import elbv2 = require('@aws-cdk/aws-elasticloadbalancingv2'); import iam = require('@aws-cdk/aws-iam'); import sns = require('@aws-cdk/aws-sns'); -import { CfnAutoScalingRollingUpdate, Construct, Duration, Fn, IResource, Lazy, Resource, Stack, Tag, Token, withResolved } from '@aws-cdk/core'; +import { + CfnAutoScalingRollingUpdate, Construct, Duration, Fn, IResource, Lazy, PhysicalName, Resource, Stack, + Tag, Token, withResolved +} from '@aws-cdk/core'; import { CfnAutoScalingGroup, CfnAutoScalingGroupProps, CfnLaunchConfiguration } from './autoscaling.generated'; import { BasicLifecycleHookProps, LifecycleHook } from './lifecycle-hook'; import { BasicScheduledActionProps, ScheduledAction } from './scheduled-action'; @@ -414,6 +417,7 @@ export class AutoScalingGroup extends AutoScalingGroupBase implements this.node.applyAspect(new Tag(NAME_TAG, this.node.path)); this.role = props.role || new iam.Role(this, 'InstanceRole', { + roleName: PhysicalName.GENERATE_IF_NEEDED, assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com') }); @@ -1091,4 +1095,4 @@ function stringifyNumber(x: number) { } else { return `${x}`; } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/codecommit/source-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/codecommit/source-action.ts index f8ce21d23f95d..f4f6da6574c62 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/codecommit/source-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/codecommit/source-action.ts @@ -68,6 +68,7 @@ export class CodeCommitSourceAction extends Action { super({ ...props, + resource: props.repository, category: codepipeline.ActionCategory.SOURCE, provider: 'CodeCommit', artifactBounds: sourceArtifactBounds(), diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/codedeploy/server-deploy-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/codedeploy/server-deploy-action.ts index 11925ece7a6cd..c77bc5f90597a 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/codedeploy/server-deploy-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/codedeploy/server-deploy-action.ts @@ -26,6 +26,7 @@ export class CodeDeployServerDeployAction extends Action { constructor(props: CodeDeployServerDeployActionProps) { super({ ...props, + resource: props.deploymentGroup, category: codepipeline.ActionCategory.DEPLOY, provider: 'CodeDeploy', artifactBounds: deployArtifactBounds(), diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/ecr/source-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/ecr/source-action.ts index 63d5cea9ea831..072c44f5dc2e3 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/ecr/source-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/ecr/source-action.ts @@ -41,6 +41,7 @@ export class EcrSourceAction extends Action { constructor(props: EcrSourceActionProps) { super({ ...props, + resource: props.repository, category: codepipeline.ActionCategory.SOURCE, provider: 'ECR', artifactBounds: sourceArtifactBounds(), diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/lambda/invoke-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/lambda/invoke-action.ts index 40441253a4bc7..36c46b69b33aa 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/lambda/invoke-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/lambda/invoke-action.ts @@ -60,6 +60,7 @@ export class LambdaInvokeAction extends Action { constructor(props: LambdaInvokeActionProps) { super({ ...props, + resource: props.lambda, category: codepipeline.ActionCategory.INVOKE, provider: 'Lambda', artifactBounds: { diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/s3/deploy-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/s3/deploy-action.ts index 60521a3d362be..49dd36d229b19 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/s3/deploy-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/s3/deploy-action.ts @@ -40,6 +40,7 @@ export class S3DeployAction extends Action { constructor(props: S3DeployActionProps) { super({ ...props, + resource: props.bucket, category: codepipeline.ActionCategory.DEPLOY, provider: 'S3', artifactBounds: deployArtifactBounds(), diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/s3/source-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/s3/source-action.ts index af54ed6e084e7..fc5f4013bcbd8 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/s3/source-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/s3/source-action.ts @@ -74,6 +74,7 @@ export class S3SourceAction extends Action { constructor(props: S3SourceActionProps) { super({ ...props, + resource: props.bucket, category: codepipeline.ActionCategory.SOURCE, provider: 'S3', artifactBounds: sourceArtifactBounds(), diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.cfn-template-from-repo.lit.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.cfn-template-from-repo.lit.expected.json index ce1f5d554bd45..961e28feed8c7 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.cfn-template-from-repo.lit.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.cfn-template-from-repo.lit.expected.json @@ -393,7 +393,10 @@ "ArtifactStore": { "EncryptionKey": { "Id": { - "Ref": "PipelineArtifactsBucketEncryptionKey01D58D69" + "Fn::GetAtt": [ + "PipelineArtifactsBucketEncryptionKey01D58D69", + "Arn" + ] }, "Type": "KMS" }, diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-deployed-through-codepipeline.lit.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-deployed-through-codepipeline.lit.expected.json index a9cd3292bc0df..a7708e2fb66d8 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-deployed-through-codepipeline.lit.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-deployed-through-codepipeline.lit.expected.json @@ -518,7 +518,10 @@ "ArtifactStore": { "EncryptionKey": { "Id": { - "Ref": "PipelineArtifactsBucketEncryptionKey01D58D69" + "Fn::GetAtt": [ + "PipelineArtifactsBucketEncryptionKey01D58D69", + "Arn" + ] }, "Type": "KMS" }, diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-pipeline.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-pipeline.expected.json index d1e562e2204e0..9448dd957a9b6 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-pipeline.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.lambda-pipeline.expected.json @@ -296,7 +296,10 @@ "ArtifactStore": { "EncryptionKey": { "Id": { - "Ref": "PipelineArtifactsBucketEncryptionKey01D58D69" + "Fn::GetAtt": [ + "PipelineArtifactsBucketEncryptionKey01D58D69", + "Arn" + ] }, "Type": "KMS" }, diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-alexa-deploy.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-alexa-deploy.expected.json index 4f6d52c4c1829..d743dde53d584 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-alexa-deploy.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-alexa-deploy.expected.json @@ -295,7 +295,10 @@ "ArtifactStore": { "EncryptionKey": { "Id": { - "Ref": "PipelineArtifactsBucketEncryptionKey01D58D69" + "Fn::GetAtt": [ + "PipelineArtifactsBucketEncryptionKey01D58D69", + "Arn" + ] }, "Type": "KMS" }, diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn.expected.json index 44990099303a5..3776591db7866 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-cfn.expected.json @@ -381,7 +381,10 @@ "ArtifactStore": { "EncryptionKey": { "Id": { - "Ref": "PipelineArtifactsBucketEncryptionKey01D58D69" + "Fn::GetAtt": [ + "PipelineArtifactsBucketEncryptionKey01D58D69", + "Arn" + ] }, "Type": "KMS" }, diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-commit-build.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-commit-build.expected.json index c18c56d5f9e4f..d0e69fc6f9ec2 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-commit-build.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-commit-build.expected.json @@ -593,7 +593,10 @@ "ArtifactStore": { "EncryptionKey": { "Id": { - "Ref": "PipelineArtifactsBucketEncryptionKey01D58D69" + "Fn::GetAtt": [ + "PipelineArtifactsBucketEncryptionKey01D58D69", + "Arn" + ] }, "Type": "KMS" }, diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-commit.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-commit.expected.json index 5c53fa46db4ef..12b5964daed96 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-commit.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-code-commit.expected.json @@ -367,7 +367,10 @@ "ArtifactStore": { "EncryptionKey": { "Id": { - "Ref": "PipelineArtifactsBucketEncryptionKey01D58D69" + "Fn::GetAtt": [ + "PipelineArtifactsBucketEncryptionKey01D58D69", + "Arn" + ] }, "Type": "KMS" }, diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-events.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-events.expected.json index 8ab452d92da02..7d7a6b3fa036d 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-events.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-events.expected.json @@ -330,7 +330,10 @@ "ArtifactStore": { "EncryptionKey": { "Id": { - "Ref": "MyPipelineArtifactsBucketEncryptionKey8BF0A7F3" + "Fn::GetAtt": [ + "MyPipelineArtifactsBucketEncryptionKey8BF0A7F3", + "Arn" + ] }, "Type": "KMS" }, diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-s3-deploy.expected.json b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-s3-deploy.expected.json index 59590ad989c44..f3affd79bafd8 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-s3-deploy.expected.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/integ.pipeline-s3-deploy.expected.json @@ -332,7 +332,10 @@ "ArtifactStore": { "EncryptionKey": { "Id": { - "Ref": "PipelineArtifactsBucketEncryptionKey01D58D69" + "Fn::GetAtt": [ + "PipelineArtifactsBucketEncryptionKey01D58D69", + "Arn" + ] }, "Type": "KMS" }, diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/test.pipeline.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/test.pipeline.ts index b006aea4800e2..a09f31665a46e 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/test.pipeline.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/test.pipeline.ts @@ -789,7 +789,18 @@ export = { "Type": "S3", "Location": "replicationstackeplicationbucket2464cd5c33b386483b66", "EncryptionKey": { - "Id": "alias/replicationstacktencryptionalias043cb2f8ceac9da9c07c", + "Id": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition", + }, + ":kms:us-west-1:123456789012:alias/ionstacktencryptionalias043cb2f8ceac9da9c07c", + ], + ], + }, "Type": "KMS" }, }, diff --git a/packages/@aws-cdk/aws-codepipeline/lib/cross-region-support-stack.ts b/packages/@aws-cdk/aws-codepipeline/lib/cross-region-support-stack.ts index 3bea50df80aff..1f9c07477755f 100644 --- a/packages/@aws-cdk/aws-codepipeline/lib/cross-region-support-stack.ts +++ b/packages/@aws-cdk/aws-codepipeline/lib/cross-region-support-stack.ts @@ -2,6 +2,32 @@ import kms = require('@aws-cdk/aws-kms'); import s3 = require('@aws-cdk/aws-s3'); import cdk = require('@aws-cdk/core'); +const REQUIRED_ALIAS_PREFIX = 'alias/'; + +/** + * A class needed to work around CodePipeline's extremely small (100 characters) + * limit for the name/ARN of the key in the ArtifactStore. + * Limits the length of the alias' auto-generated name to 50 characters. + */ +class AliasWithShorterGeneratedName extends kms.Alias { + protected generatePhysicalName(): string { + let baseName = super.generatePhysicalName(); + if (baseName.startsWith(REQUIRED_ALIAS_PREFIX)) { + // remove the prefix, because we're taking the last characters of the name below + baseName = baseName.substring(REQUIRED_ALIAS_PREFIX.length); + } + const maxLength = 50 - REQUIRED_ALIAS_PREFIX.length; + // take the last characters, as they include the hash, + // and so have a higher chance of not colliding + return REQUIRED_ALIAS_PREFIX + lastNCharacters(baseName, maxLength); + } +} + +function lastNCharacters(str: string, n: number) { + const startIndex = Math.max(str.length - n, 0); + return str.substring(startIndex); +} + export class CrossRegionSupportConstruct extends cdk.Construct { public readonly replicationBucket: s3.IBucket; @@ -9,7 +35,7 @@ export class CrossRegionSupportConstruct extends cdk.Construct { super(scope, id); const encryptionKey = new kms.Key(this, 'CrossRegionCodePipelineReplicationBucketEncryptionKey'); - const encryptionAlias = new kms.Alias(this, 'CrossRegionCodePipelineReplicationBucketEncryptionAlias', { + const encryptionAlias = new AliasWithShorterGeneratedName(this, 'CrossRegionCodePipelineReplicationBucketEncryptionAlias', { targetKey: encryptionKey, aliasName: cdk.PhysicalName.GENERATE_IF_NEEDED, removalPolicy: cdk.RemovalPolicy.RETAIN, diff --git a/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts b/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts index 50d584121697d..b7312764fba14 100644 --- a/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts +++ b/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts @@ -206,6 +206,7 @@ export class Pipeline extends PipelineBase { private readonly stages = new Array(); private readonly crossRegionBucketsPassed: boolean; private readonly _crossRegionSupport: { [region: string]: CrossRegionSupport } = {}; + private readonly _crossAccountSupport: { [account: string]: Stack } = {}; constructor(scope: Construct, id: string, props: PipelineProps = {}) { super(scope, id, { @@ -379,7 +380,11 @@ export class Pipeline extends PipelineBase { const actionResourceStack = Stack.of(actionResource); if (pipelineStack.region !== actionResourceStack.region) { actionRegion = actionResourceStack.region; - otherStack = actionResourceStack; + // if the resource is from a different stack in another region but the same account, + // use that stack as home for the cross-region support resources + if (pipelineStack.account === actionResourceStack.account) { + otherStack = actionResourceStack; + } } } else { actionRegion = action.actionProperties.region; @@ -570,9 +575,12 @@ export class Pipeline extends PipelineBase { if (action.actionProperties.resource) { const resourceStack = Stack.of(action.actionProperties.resource); // check if resource is from a different account - return pipelineStack.account === resourceStack.account - ? undefined - : resourceStack; + if (pipelineStack.account === resourceStack.account) { + return undefined; + } else { + this._crossAccountSupport[resourceStack.account] = resourceStack; + return resourceStack; + } } if (!action.actionProperties.account) { @@ -593,17 +601,21 @@ export class Pipeline extends PipelineBase { return undefined; } - const stackId = `cross-account-support-stack-${targetAccount}`; - const app = this.requireApp(); - let targetAccountStack = app.node.tryFindChild(stackId) as Stack; + let targetAccountStack: Stack | undefined = this._crossAccountSupport[targetAccount]; if (!targetAccountStack) { - targetAccountStack = new Stack(app, stackId, { - stackName: `${pipelineStack.stackName}-support-${targetAccount}`, - env: { - account: targetAccount, - region: action.actionProperties.region ? action.actionProperties.region : pipelineStack.region, - }, - }); + const stackId = `cross-account-support-stack-${targetAccount}`; + const app = this.requireApp(); + targetAccountStack = app.node.tryFindChild(stackId) as Stack; + if (!targetAccountStack) { + targetAccountStack = new Stack(app, stackId, { + stackName: `${pipelineStack.stackName}-support-${targetAccount}`, + env: { + account: targetAccount, + region: action.actionProperties.region ? action.actionProperties.region : pipelineStack.region, + }, + }); + } + this._crossAccountSupport[targetAccount] = targetAccountStack; } return targetAccountStack; } @@ -752,7 +764,7 @@ export class Pipeline extends PipelineBase { if (bucketKey) { encryptionKey = { type: 'KMS', - id: bucketKey.keyId, + id: bucketKey.keyArn, }; } diff --git a/packages/@aws-cdk/aws-codepipeline/test/test.pipeline.ts b/packages/@aws-cdk/aws-codepipeline/test/test.pipeline.ts index c7e21f0ba25a8..3c09883230cf0 100644 --- a/packages/@aws-cdk/aws-codepipeline/test/test.pipeline.ts +++ b/packages/@aws-cdk/aws-codepipeline/test/test.pipeline.ts @@ -116,7 +116,18 @@ export = { "Type": "S3", "EncryptionKey": { "Type": "KMS", - "Id": "alias/my-replication-alias", + "Id": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition", + }, + ":kms:us-west-1:123456789012:alias/my-replication-alias", + ], + ], + }, }, }, }, @@ -163,7 +174,7 @@ export = { test.done(); }, - "generates ArtifactStores with the alias' name as the KeyID"(test: Test) { + "generates ArtifactStores with the alias' ARN as the KeyID"(test: Test) { const app = new cdk.App(); const replicationRegion = 'us-west-1'; @@ -200,7 +211,18 @@ export = { "Type": "S3", "EncryptionKey": { "Type": "KMS", - "Id": "alias/mystack-support-us-west-1tencryptionalias9b344b2b8e6825cb1f7d", + "Id": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition", + }, + ":kms:us-west-1:123456789012:alias/s-west-1tencryptionalias9b344b2b8e6825cb1f7d", + ], + ], + }, }, }, }, @@ -262,7 +284,7 @@ export = { "Location": "my-us-west-1-replication-bucket", "EncryptionKey": { "Type": "KMS", - "Id": "1234-5678-9012", + "Id": "arn:aws:kms:us-west-1:123456789012:key/1234-5678-9012", }, }, }, diff --git a/packages/@aws-cdk/aws-events-targets/test/codepipeline/integ.pipeline-event-target.expected.json b/packages/@aws-cdk/aws-events-targets/test/codepipeline/integ.pipeline-event-target.expected.json index fe5590840de9e..b7a1d5ca1de84 100644 --- a/packages/@aws-cdk/aws-events-targets/test/codepipeline/integ.pipeline-event-target.expected.json +++ b/packages/@aws-cdk/aws-events-targets/test/codepipeline/integ.pipeline-event-target.expected.json @@ -282,7 +282,10 @@ "ArtifactStore": { "EncryptionKey": { "Id": { - "Ref": "pipelinePipeline22F2A91DArtifactsBucketEncryptionKey87C796D2" + "Fn::GetAtt": [ + "pipelinePipeline22F2A91DArtifactsBucketEncryptionKey87C796D2", + "Arn" + ] }, "Type": "KMS" }, diff --git a/packages/@aws-cdk/aws-events/lib/rule.ts b/packages/@aws-cdk/aws-events/lib/rule.ts index f85882f6db0ea..52bcfe83f8c91 100644 --- a/packages/@aws-cdk/aws-events/lib/rule.ts +++ b/packages/@aws-cdk/aws-events/lib/rule.ts @@ -107,7 +107,7 @@ export class Rule extends Resource implements IRule { description: this.description, state: props.enabled == null ? 'ENABLED' : (props.enabled ? 'ENABLED' : 'DISABLED'), scheduleExpression: Lazy.stringValue({ produce: () => this.scheduleExpression }), - eventPattern: Lazy.anyValue({ produce: () => this.renderEventPattern() }), + eventPattern: Lazy.anyValue({ produce: () => this._renderEventPattern() }), targets: Lazy.anyValue({ produce: () => this.renderTargets() }), }); @@ -229,7 +229,29 @@ export class Rule extends Resource implements IRule { // The actual rule lives in the target stack. // Other than the account, it's identical to this one - new Rule(targetStack, `${this.node.uniqueId}-${id}`, { + + // eventPattern is mutable through addEventPattern(), so we need to lazy evaluate it + // but only Tokens can be lazy in the framework, so make a subclass instead + const self = this; + class CopyRule extends Rule { + public _renderEventPattern(): any { + return self._renderEventPattern(); + } + + // we need to override validate(), as it uses the + // value of the eventPattern field, + // which might be empty in the case of the copied rule + // (as the patterns in the original might be added through addEventPattern(), + // not passed through the constructor). + // Anyway, even if the original rule is invalid, + // we would get duplicate errors if we didn't override this, + // which is probably a bad idea in and of itself + protected validate(): string[] { + return []; + } + } + + new CopyRule(targetStack, `${this.node.uniqueId}-${id}`, { targets: [target], eventPattern: this.eventPattern, schedule: this.scheduleExpression ? Schedule.expression(this.scheduleExpression) : undefined, @@ -297,23 +319,12 @@ export class Rule extends Resource implements IRule { mergeEventPattern(this.eventPattern, eventPattern); } - protected validate() { - if (Object.keys(this.eventPattern).length === 0 && !this.scheduleExpression) { - return [ `Either 'eventPattern' or 'schedule' must be defined` ]; - } - - return [ ]; - } - - private renderTargets() { - if (this.targets.length === 0) { - return undefined; - } - - return this.targets; - } - - private renderEventPattern() { + /** + * Not private only to be overrideen in CopyRule. + * + * @internal + */ + public _renderEventPattern(): any { const eventPattern = this.eventPattern; if (Object.keys(eventPattern).length === 0) { @@ -332,4 +343,20 @@ export class Rule extends Resource implements IRule { return out; } + + protected validate() { + if (Object.keys(this.eventPattern).length === 0 && !this.scheduleExpression) { + return [ `Either 'eventPattern' or 'schedule' must be defined` ]; + } + + return [ ]; + } + + private renderTargets() { + if (this.targets.length === 0) { + return undefined; + } + + return this.targets; + } } diff --git a/packages/@aws-cdk/aws-events/test/test.rule.ts b/packages/@aws-cdk/aws-events/test/test.rule.ts index a2dc94afd5187..c92b38bd509c0 100644 --- a/packages/@aws-cdk/aws-events/test/test.rule.ts +++ b/packages/@aws-cdk/aws-events/test/test.rule.ts @@ -597,7 +597,7 @@ export = { test.done(); }, - 'generates an event bus target in the source rule, and a separate rule with an identical target in the target stack'(test: Test) { + 'generates the correct rules in the source and target stacks when eventPattern is passed in the constructor'(test: Test) { const app = new cdk.App(); const sourceAccount = '123456789012'; @@ -688,6 +688,51 @@ export = { test.done(); }, + + 'generates the correct rule in the target stack when addEventPattern in the source rule is used'(test: Test) { + const app = new cdk.App(); + + const sourceAccount = '123456789012'; + const sourceStack = new cdk.Stack(app, 'SourceStack', { + env: { + account: sourceAccount, + region: 'us-west-2', + }, + }); + const rule = new Rule(sourceStack, 'Rule'); + + const targetAccount = '234567890123'; + const targetStack = new cdk.Stack(app, 'TargetStack', { + env: { + account: targetAccount, + region: 'us-west-2', + }, + }); + const resource = new cdk.Construct(targetStack, 'Resource1'); + + rule.addTarget(new SomeTarget('T', resource)); + + rule.addEventPattern({ + source: ['some-event'], + }); + + expect(targetStack).to(haveResourceLike('AWS::Events::Rule', { + "EventPattern": { + "source": [ + "some-event", + ], + }, + "State": "ENABLED", + "Targets": [ + { + "Id": "T", + "Arn": "ARN1", + }, + ], + })); + + test.done(); + }, }, }; diff --git a/packages/decdk/test/__snapshots__/synth.test.js.snap b/packages/decdk/test/__snapshots__/synth.test.js.snap index 17ba586b28fdf..038b710553bf3 100644 --- a/packages/decdk/test/__snapshots__/synth.test.js.snap +++ b/packages/decdk/test/__snapshots__/synth.test.js.snap @@ -2097,7 +2097,10 @@ Object { "ArtifactStore": Object { "EncryptionKey": Object { "Id": Object { - "Ref": "PipelineArtifactsBucketEncryptionKey01D58D69", + "Fn::GetAtt": Array [ + "PipelineArtifactsBucketEncryptionKey01D58D69", + "Arn", + ], }, "Type": "KMS", },