From 57026ea2c1bc101d8bb38eaf7ab68fccea38c34c Mon Sep 17 00:00:00 2001 From: Jonathan Goldwasser Date: Tue, 18 Jun 2019 17:10:38 +0200 Subject: [PATCH 1/6] feat(events): make target optional in `onXxx()` methods Make `target` optional in `OnEventOptions` so that it is no required when calling a `onXxx()` method. This allows to use "preconfigured" rules in other constructs. Closes #2913 --- packages/@aws-cdk/aws-events/lib/on-event-options.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/@aws-cdk/aws-events/lib/on-event-options.ts b/packages/@aws-cdk/aws-events/lib/on-event-options.ts index 047722cb35ab7..ff54919fcc8ba 100644 --- a/packages/@aws-cdk/aws-events/lib/on-event-options.ts +++ b/packages/@aws-cdk/aws-events/lib/on-event-options.ts @@ -7,11 +7,15 @@ import { IRuleTarget } from "./target"; export interface OnEventOptions { /** * The target to register for the event + * + * @default - No target is added to the rule. Use `addTarget()` to add a target. */ - readonly target: IRuleTarget; + readonly target?: IRuleTarget; /** * A description of the rule's purpose. + * + * @default - No description */ readonly description?: string; @@ -29,8 +33,10 @@ export interface OnEventOptions { * filtering. The filtering implied by what you pass here is added * on top of that filtering. * + * @default - No additional filtering based on an event pattern. + * * @see * http://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/CloudWatchEventsandEventPatterns.html */ readonly eventPattern?: EventPattern; -} \ No newline at end of file +} From 058031b3dc74af7ad9fbb4f7345db16b2805d587 Mon Sep 17 00:00:00 2001 From: Jonathan Goldwasser Date: Wed, 19 Jun 2019 11:01:56 +0200 Subject: [PATCH 2/6] add onEvent test in rds --- packages/@aws-cdk/aws-rds/lib/instance.ts | 2 +- .../@aws-cdk/aws-rds/test/test.instance.ts | 62 +++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-rds/lib/instance.ts b/packages/@aws-cdk/aws-rds/lib/instance.ts index 1205dfb8f2ee9..fc157f19a4065 100644 --- a/packages/@aws-cdk/aws-rds/lib/instance.ts +++ b/packages/@aws-cdk/aws-rds/lib/instance.ts @@ -116,7 +116,7 @@ export abstract class DatabaseInstanceBase extends Resource implements IDatabase * Defines a CloudWatch event rule which triggers for instance events. Use * `rule.addEventPattern(pattern)` to specify a filter. */ - public onEvent(id: string, options: events.OnEventOptions) { + public onEvent(id: string, options: events.OnEventOptions = {}) { const rule = new events.Rule(this, id, options); rule.addEventPattern({ source: ['aws.rds'], diff --git a/packages/@aws-cdk/aws-rds/test/test.instance.ts b/packages/@aws-cdk/aws-rds/test/test.instance.ts index eab88f7d721f8..48c5333bed3a3 100644 --- a/packages/@aws-cdk/aws-rds/test/test.instance.ts +++ b/packages/@aws-cdk/aws-rds/test/test.instance.ts @@ -316,6 +316,68 @@ export = { // WHEN instance.onEvent('InstanceEvent', { target: new targets.LambdaFunction(fn) }); + // THEN + expect(stack).to(haveResource('AWS::Events::Rule', { + EventPattern: { + source: [ + 'aws.rds' + ], + resources: [ + { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition' + }, + ':rds:', + { + Ref: 'AWS::Region' + }, + ':', + { + Ref: 'AWS::AccountId' + }, + ':db:', + { + Ref: 'InstanceC1063A87' + } + ] + ] + } + ] + }, + Targets: [ + { + Arn: { + 'Fn::GetAtt': [ + 'Function76856677', + 'Arn' + ], + }, + Id: 'Function' + } + ] + })); + + test.done(); + }, + + 'on event without target'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const instance = new rds.DatabaseInstance(stack, 'Instance', { + engine: rds.DatabaseInstanceEngine.Mysql, + instanceClass: new ec2.InstanceTypePair(ec2.InstanceClass.Burstable2, ec2.InstanceSize.Small), + masterUsername: 'admin', + vpc + }); + + // WHEN + instance.onEvent('InstanceEvent'); + // THEN expect(stack).to(haveResource('AWS::Events::Rule', { EventPattern: { From 7a4c3336f8b9488d46069bf63f97e6c757e2e736 Mon Sep 17 00:00:00 2001 From: Jonathan Goldwasser Date: Wed, 19 Jun 2019 11:13:58 +0200 Subject: [PATCH 3/6] make options optional everywhere --- packages/@aws-cdk/aws-cloudtrail/lib/index.ts | 2 +- packages/@aws-cdk/aws-codebuild/lib/project.ts | 10 +++++----- .../@aws-cdk/aws-codecommit/lib/repository.ts | 18 +++++++++--------- .../@aws-cdk/aws-codepipeline/lib/pipeline.ts | 4 ++-- packages/@aws-cdk/aws-config/lib/rule.ts | 6 +++--- packages/@aws-cdk/aws-ecr/lib/repository.ts | 4 ++-- packages/@aws-cdk/aws-s3/lib/bucket.ts | 6 +++--- 7 files changed, 25 insertions(+), 25 deletions(-) diff --git a/packages/@aws-cdk/aws-cloudtrail/lib/index.ts b/packages/@aws-cdk/aws-cloudtrail/lib/index.ts index 7ca64ae6d0ff7..c1c5345c45089 100644 --- a/packages/@aws-cdk/aws-cloudtrail/lib/index.ts +++ b/packages/@aws-cdk/aws-cloudtrail/lib/index.ts @@ -234,7 +234,7 @@ export class Trail extends Resource { * * Be sure to filter the event further down using an event pattern. */ - public onCloudTrailEvent(id: string, options: events.OnEventOptions): events.Rule { + public onCloudTrailEvent(id: string, options: events.OnEventOptions = {}): events.Rule { const rule = new events.Rule(this, id, options); rule.addTarget(options.target); rule.addEventPattern({ diff --git a/packages/@aws-cdk/aws-codebuild/lib/project.ts b/packages/@aws-cdk/aws-codebuild/lib/project.ts index 5ca69b746309a..df0b5731a4255 100644 --- a/packages/@aws-cdk/aws-codebuild/lib/project.ts +++ b/packages/@aws-cdk/aws-codebuild/lib/project.ts @@ -239,7 +239,7 @@ abstract class ProjectBase extends Resource implements IProject { * * @see https://docs.aws.amazon.com/codebuild/latest/userguide/sample-build-notifications.html */ - public onStateChange(id: string, options: events.OnEventOptions) { + public onStateChange(id: string, options: events.OnEventOptions = {}) { const rule = this.onEvent(id, options); rule.addEventPattern({ detailType: ['CodeBuild Build State Change'], @@ -253,7 +253,7 @@ abstract class ProjectBase extends Resource implements IProject { * * @see https://docs.aws.amazon.com/codebuild/latest/userguide/sample-build-notifications.html */ - public onPhaseChange(id: string, options: events.OnEventOptions) { + public onPhaseChange(id: string, options: events.OnEventOptions = {}) { const rule = this.onEvent(id, options); rule.addEventPattern({ detailType: ['CodeBuild Build Phase Change'], @@ -267,7 +267,7 @@ abstract class ProjectBase extends Resource implements IProject { * To access fields from the event in the event target input, * use the static fields on the `StateChangeEvent` class. */ - public onBuildStarted(id: string, options: events.OnEventOptions) { + public onBuildStarted(id: string, options: events.OnEventOptions = {}) { const rule = this.onStateChange(id, options); rule.addEventPattern({ detail: { @@ -283,7 +283,7 @@ abstract class ProjectBase extends Resource implements IProject { * To access fields from the event in the event target input, * use the static fields on the `StateChangeEvent` class. */ - public onBuildFailed(id: string, options: events.OnEventOptions) { + public onBuildFailed(id: string, options: events.OnEventOptions = {}) { const rule = this.onStateChange(id, options); rule.addEventPattern({ detail: { @@ -299,7 +299,7 @@ abstract class ProjectBase extends Resource implements IProject { * To access fields from the event in the event target input, * use the static fields on the `StateChangeEvent` class. */ - public onBuildSucceeded(id: string, options: events.OnEventOptions) { + public onBuildSucceeded(id: string, options: events.OnEventOptions = {}) { const rule = this.onStateChange(id, options); rule.addEventPattern({ detail: { diff --git a/packages/@aws-cdk/aws-codecommit/lib/repository.ts b/packages/@aws-cdk/aws-codecommit/lib/repository.ts index cbd32c91bb936..93281e104ada3 100644 --- a/packages/@aws-cdk/aws-codecommit/lib/repository.ts +++ b/packages/@aws-cdk/aws-codecommit/lib/repository.ts @@ -117,7 +117,7 @@ abstract class RepositoryBase extends Resource implements IRepository { * Defines a CloudWatch event rule which triggers for repository events. Use * `rule.addEventPattern(pattern)` to specify a filter. */ - public onEvent(id: string, options: events.OnEventOptions) { + public onEvent(id: string, options: events.OnEventOptions = {}) { const rule = new events.Rule(this, id, options); rule.addEventPattern({ source: [ 'aws.codecommit' ], @@ -131,7 +131,7 @@ abstract class RepositoryBase extends Resource implements IRepository { * Defines a CloudWatch event rule which triggers when a "CodeCommit * Repository State Change" event occurs. */ - public onStateChange(id: string, options: events.OnEventOptions) { + public onStateChange(id: string, options: events.OnEventOptions = {}) { const rule = this.onEvent(id, options); rule.addEventPattern({ detailType: [ 'CodeCommit Repository State Change' ], @@ -143,7 +143,7 @@ abstract class RepositoryBase extends Resource implements IRepository { * Defines a CloudWatch event rule which triggers when a reference is * created (i.e. a new branch/tag is created) to the repository. */ - public onReferenceCreated(id: string, options: events.OnEventOptions) { + public onReferenceCreated(id: string, options: events.OnEventOptions = {}) { const rule = this.onStateChange(id, options); rule.addEventPattern({ detail: { event: [ 'referenceCreated' ] } }); return rule; @@ -153,7 +153,7 @@ abstract class RepositoryBase extends Resource implements IRepository { * 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. */ - public onReferenceUpdated(id: string, options: events.OnEventOptions) { + public onReferenceUpdated(id: string, options: events.OnEventOptions = {}) { const rule = this.onStateChange(id, options); rule.addEventPattern({ detail: { event: [ 'referenceCreated', 'referenceUpdated' ] } }); return rule; @@ -163,7 +163,7 @@ abstract class RepositoryBase extends Resource implements IRepository { * Defines a CloudWatch event rule which triggers when a reference is * delete (i.e. a branch/tag is deleted) from the repository. */ - public onReferenceDeleted(id: string, options: events.OnEventOptions) { + public onReferenceDeleted(id: string, options: events.OnEventOptions = {}) { const rule = this.onStateChange(id, options); rule.addEventPattern({ detail: { event: [ 'referenceDeleted' ] } }); return rule; @@ -172,7 +172,7 @@ abstract class RepositoryBase extends Resource implements IRepository { /** * Defines a CloudWatch event rule which triggers when a pull request state is changed. */ - public onPullRequestStateChange(id: string, options: events.OnEventOptions) { + public onPullRequestStateChange(id: string, options: events.OnEventOptions = {}) { const rule = this.onEvent(id, options); rule.addEventPattern({ detailType: [ 'CodeCommit Pull Request State Change' ] }); return rule; @@ -181,7 +181,7 @@ abstract class RepositoryBase extends Resource implements IRepository { /** * Defines a CloudWatch event rule which triggers when a comment is made on a pull request. */ - public onCommentOnPullRequest(id: string, options: events.OnEventOptions) { + public onCommentOnPullRequest(id: string, options: events.OnEventOptions = {}) { const rule = this.onEvent(id, options); rule.addEventPattern({ detailType: [ 'CodeCommit Comment on Pull Request' ] }); return rule; @@ -190,7 +190,7 @@ abstract class RepositoryBase extends Resource implements IRepository { /** * Defines a CloudWatch event rule which triggers when a comment is made on a commit. */ - public onCommentOnCommit(id: string, options: events.OnEventOptions) { + public onCommentOnCommit(id: string, options: events.OnEventOptions = {}) { const rule = this.onEvent(id, options); rule.addEventPattern({ detailType: [ 'CodeCommit Comment on Commit' ] }); return rule; @@ -199,7 +199,7 @@ abstract class RepositoryBase extends Resource implements IRepository { /** * Defines a CloudWatch event rule which triggers when a commit is pushed to a branch. */ - public onCommit(id: string, options: OnCommitOptions) { + public onCommit(id: string, options: OnCommitOptions = {}) { const rule = this.onReferenceUpdated(id, options); if (options.branches) { rule.addEventPattern({ detail: { referenceName: options.branches }}); diff --git a/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts b/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts index 0a469927fb308..b28f95235119f 100644 --- a/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts +++ b/packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts @@ -114,7 +114,7 @@ abstract class PipelineBase extends Resource implements IPipeline { * @param id Identifier for this event handler. * @param options Additional options to pass to the event rule. */ - public onEvent(id: string, options: events.OnEventOptions): events.Rule { + public onEvent(id: string, options: events.OnEventOptions = {}): events.Rule { const rule = new events.Rule(this, id, options); rule.addTarget(options.target); rule.addEventPattern({ @@ -131,7 +131,7 @@ abstract class PipelineBase extends Resource implements IPipeline { * @param id Identifier for this event handler. * @param options Additional options to pass to the event rule. */ - public onStateChange(id: string, options: events.OnEventOptions): events.Rule { + public onStateChange(id: string, options: events.OnEventOptions = {}): events.Rule { const rule = this.onEvent(id, options); rule.addEventPattern({ detailType: [ 'CodePipeline Pipeline Execution State Change' ], diff --git a/packages/@aws-cdk/aws-config/lib/rule.ts b/packages/@aws-cdk/aws-config/lib/rule.ts index e41ea24a889a6..8b79ba8979095 100644 --- a/packages/@aws-cdk/aws-config/lib/rule.ts +++ b/packages/@aws-cdk/aws-config/lib/rule.ts @@ -65,7 +65,7 @@ abstract class RuleBase extends Resource implements IRule { * Defines a CloudWatch event rule which triggers for rule events. Use * `rule.addEventPattern(pattern)` to specify a filter. */ - public onEvent(id: string, options: events.OnEventOptions) { + public onEvent(id: string, options: events.OnEventOptions = {}) { const rule = new events.Rule(this, id, options); rule.addEventPattern({ source: ['aws.config'], @@ -80,7 +80,7 @@ abstract class RuleBase extends Resource implements IRule { /** * Defines a CloudWatch event rule which triggers for rule compliance events. */ - public onComplianceChange(id: string, options: events.OnEventOptions): events.Rule { + public onComplianceChange(id: string, options: events.OnEventOptions = {}): events.Rule { const rule = this.onEvent(id, options); rule.addEventPattern({ detailType: [ 'Config Rules Compliance Change' ], @@ -91,7 +91,7 @@ abstract class RuleBase extends Resource implements IRule { /** * Defines a CloudWatch event rule which triggers for rule re-evaluation status events. */ - public onReEvaluationStatus(id: string, options: events.OnEventOptions): events.Rule { + public onReEvaluationStatus(id: string, options: events.OnEventOptions = {}): events.Rule { const rule = this.onEvent(id, options); rule.addEventPattern({ detailType: [ 'Config Rules Re-evaluation Status' ], diff --git a/packages/@aws-cdk/aws-ecr/lib/repository.ts b/packages/@aws-cdk/aws-ecr/lib/repository.ts index 08739c8a0eb02..58efbb09ad361 100644 --- a/packages/@aws-cdk/aws-ecr/lib/repository.ts +++ b/packages/@aws-cdk/aws-ecr/lib/repository.ts @@ -133,7 +133,7 @@ export abstract class RepositoryBase extends Resource implements IRepository { * @param id The id of the rule * @param options Options for adding the rule */ - public onCloudTrailEvent(id: string, options: events.OnEventOptions): events.Rule { + public onCloudTrailEvent(id: string, options: events.OnEventOptions = {}): events.Rule { const rule = new events.Rule(this, id, options); rule.addTarget(options.target); rule.addEventPattern({ @@ -158,7 +158,7 @@ export abstract class RepositoryBase extends Resource implements IRepository { * @param id The id of the rule * @param options Options for adding the rule */ - public onCloudTrailImagePushed(id: string, options: OnCloudTrailImagePushedOptions): events.Rule { + public onCloudTrailImagePushed(id: string, options: OnCloudTrailImagePushedOptions = {}): events.Rule { const rule = this.onCloudTrailEvent(id, options); rule.addEventPattern({ detail: { diff --git a/packages/@aws-cdk/aws-s3/lib/bucket.ts b/packages/@aws-cdk/aws-s3/lib/bucket.ts index fa2d0dcfdc69b..79ad4318fe811 100644 --- a/packages/@aws-cdk/aws-s3/lib/bucket.ts +++ b/packages/@aws-cdk/aws-s3/lib/bucket.ts @@ -301,7 +301,7 @@ abstract class BucketBase extends Resource implements IBucket { * @param id The id of the rule * @param options Options for adding the rule */ - public onCloudTrailEvent(id: string, options: OnCloudTrailBucketEventOptions): events.Rule { + public onCloudTrailEvent(id: string, options: OnCloudTrailBucketEventOptions = {}): events.Rule { const rule = new events.Rule(this, id, options); rule.addTarget(options.target); rule.addEventPattern({ @@ -326,7 +326,7 @@ abstract class BucketBase extends Resource implements IBucket { * @param id The id of the rule * @param options Options for adding the rule */ - public onCloudTrailPutObject(id: string, options: OnCloudTrailBucketEventOptions): events.Rule { + public onCloudTrailPutObject(id: string, options: OnCloudTrailBucketEventOptions = {}): events.Rule { const rule = this.onCloudTrailEvent(id, options); rule.addEventPattern({ detail: { @@ -1399,4 +1399,4 @@ function mapOrUndefined(list: T[] | undefined, callback: (element: T) => U } return list.map(callback); -} \ No newline at end of file +} From 5b9607ede1364cb2c79be6a45529ba172cb3cbdb Mon Sep 17 00:00:00 2001 From: Jonathan Goldwasser Date: Wed, 19 Jun 2019 11:38:25 +0200 Subject: [PATCH 4/6] enforce with awslint --- tools/awslint/lib/linter.ts | 9 ++++++++- tools/awslint/lib/rules/cloudwatch-events.ts | 6 +++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/tools/awslint/lib/linter.ts b/tools/awslint/lib/linter.ts index 8ce53d42c1093..95cc7d125fa0c 100644 --- a/tools/awslint/lib/linter.ts +++ b/tools/awslint/lib/linter.ts @@ -172,6 +172,10 @@ export class Evaluation { return this.assert(a.toString() === e.toString() || (a.fqn && e.fqn && a.type!.extends(e.type!)), scope, ` ("${a}" not assignable to "${e}")`); } + public assertParameterOptional(actual: boolean, expected: boolean, scope: string) { + return this.assert(actual === expected, scope, ` (${scope} should be ${expected ? 'optional' : 'mandatory '})`); + } + public assertSignature(method: reflect.Callable, expectations: MethodSignatureExpectations) { const scope = method.parentType.fqn + '.' + method.name; if (expectations.returns && reflect.Method.isMethod(method)) { @@ -198,6 +202,9 @@ export class Evaluation { this.assertTypesEqual(method.system, actual.type, expect.type, pscope); } } + if (expect.optional !== undefined) { + this.assertParameterOptional(actual.optional, expect.optional, pscope); + } } } } @@ -315,4 +322,4 @@ function typeReferenceFrom(ts: reflect.TypeSystem, x: TypeSpecifier): reflect.Ty function isTypeReference(x: any): x is reflect.TypeReference { return x instanceof reflect.TypeReference; -} \ No newline at end of file +} diff --git a/tools/awslint/lib/rules/cloudwatch-events.ts b/tools/awslint/lib/rules/cloudwatch-events.ts index 57dcbbb52923a..63ed49578c3f2 100644 --- a/tools/awslint/lib/rules/cloudwatch-events.ts +++ b/tools/awslint/lib/rules/cloudwatch-events.ts @@ -48,13 +48,13 @@ eventsLinter.add({ eventsLinter.add({ code: 'events-method-signature', - message: `all 'onXxx()' methods should have the CloudWatch Events signature (id: string, options: events.OnEventOptions) => events.Rule`, + message: `all 'onXxx()' methods should have the CloudWatch Events signature (id: string, options: events.OnEventOptions = {}) => events.Rule`, eval: e => { for (const method of e.ctx.directEventMethods) { e.assertSignature(method, { parameters: [ { type: 'string' }, - { type: ON_EVENT_OPTIONS_FQN, subtypeAllowed: true }, + { type: ON_EVENT_OPTIONS_FQN, subtypeAllowed: true, optional: true }, ], returns: EVENT_RULE_FQN }); @@ -68,4 +68,4 @@ function isDirectEventMethod(m: reflect.Method) { function isCloudTrailEventMethod(m: reflect.Method) { return m.name.startsWith('onCloudTrail'); -} \ No newline at end of file +} From d0f361fef69d5245138c6001a7c57fec7d74b4ef Mon Sep 17 00:00:00 2001 From: Jonathan Goldwasser Date: Wed, 19 Jun 2019 11:39:59 +0200 Subject: [PATCH 5/6] whitespace --- tools/awslint/lib/linter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/awslint/lib/linter.ts b/tools/awslint/lib/linter.ts index 95cc7d125fa0c..4dedc791be35f 100644 --- a/tools/awslint/lib/linter.ts +++ b/tools/awslint/lib/linter.ts @@ -173,7 +173,7 @@ export class Evaluation { } public assertParameterOptional(actual: boolean, expected: boolean, scope: string) { - return this.assert(actual === expected, scope, ` (${scope} should be ${expected ? 'optional' : 'mandatory '})`); + return this.assert(actual === expected, scope, ` (${scope} should be ${expected ? 'optional' : 'mandatory'})`); } public assertSignature(method: reflect.Callable, expectations: MethodSignatureExpectations) { From 3c5e11e216e276227515bd9fc1da278a5205e5bf Mon Sep 17 00:00:00 2001 From: Jonathan Goldwasser Date: Wed, 19 Jun 2019 12:05:18 +0200 Subject: [PATCH 6/6] fix codebuild onEvent optional --- packages/@aws-cdk/aws-codebuild/lib/project.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-codebuild/lib/project.ts b/packages/@aws-cdk/aws-codebuild/lib/project.ts index df0b5731a4255..6a83b09440a73 100644 --- a/packages/@aws-cdk/aws-codebuild/lib/project.ts +++ b/packages/@aws-cdk/aws-codebuild/lib/project.ts @@ -202,7 +202,7 @@ abstract class ProjectBase extends Resource implements IProject { * * @see https://docs.aws.amazon.com/codebuild/latest/userguide/sample-build-notifications.html */ - public onEvent(id: string, options: events.OnEventOptions): events.Rule { + public onEvent(id: string, options: events.OnEventOptions = {}): events.Rule { const rule = new events.Rule(this, id, options); rule.addTarget(options.target); rule.addEventPattern({