Skip to content

Commit

Permalink
feat(event-targets): workaround for CDK issue: aws/aws-cdk#17002
Browse files Browse the repository at this point in the history
workaround for CDK issue: aws/aws-cdk#17002
  • Loading branch information
despock committed May 5, 2022
1 parent 00ab578 commit f0dc530
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 0 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ module.exports = {
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/no-empty-interface': 'off',
'@typescript-eslint/no-var-requires': 'off',
'@typescript-eslint/no-unused-vars': 'off',
'no-empty': 'off'
}
}
2 changes: 2 additions & 0 deletions src/lib/common/construct.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export class CommonConstruct extends Construct {
eksManager: aws.EksManager
elasticacheManager: aws.ElastiCacheManager
eventManager: aws.EventManager
eventTargetManager: aws.EventTargetManager
iamManager: aws.IamManager
kmsManager: aws.KmsManager
lambdaManager: aws.LambdaManager
Expand Down Expand Up @@ -67,6 +68,7 @@ export class CommonConstruct extends Construct {
this.eksManager = new aws.EksManager()
this.elasticacheManager = new aws.ElastiCacheManager()
this.eventManager = new aws.EventManager()
this.eventTargetManager = new aws.EventTargetManager()
this.iamManager = new aws.IamManager()
this.kmsManager = new aws.KmsManager()
this.lambdaManager = new aws.LambdaManager()
Expand Down
84 changes: 84 additions & 0 deletions src/lib/manager/aws/event-target-manager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import * as cdk from 'aws-cdk-lib'
import * as events from 'aws-cdk-lib/aws-events'
import * as targets from 'aws-cdk-lib/aws-events-targets'
import * as logs from 'aws-cdk-lib/aws-logs'
import * as common from '../../common'

/**
* @stability stable
* @category cdk-utils.event-taeget-manager
* @subcategory Construct
* @classdesc Provides operations on AWS EventBridge Targets.
* - A new instance of this class is injected into {@link common.CommonConstruct} constructor.
* - If a custom construct extends {@link common.CommonConstruct}, an instance is available within the context.
* @example
* import * as common from '@gradientedge/cdk-utils'
*
* class CustomConstruct extends common.common.CommonConstruct {
* constructor(parent: cdk.Construct, id: string, props: common.CommonStackProps) {
* super(parent, id, props)
* this.props = props
* this.eventTargetManager.createCloudWatchLogGroupNoPolicy('MyLogGrouptarget', this, myLogGroup)
* }
* }
*
* @see [CDK EventBridge Target Module]{@link https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_events_targets-readme.html}
*/
export class EventTargetManager {
/**
* @summary Method to create a cloud watch log group target without a policy.
* - This method is created as a workaround for cdk issue - https://github.com/aws/aws-cdk/issues/17002
* @param {string} id scoped id of the resource
* @param {common.CommonConstruct} scope scope in which this resource is defined
* @param {logs.ILogGroup} logGroup the log group
* @param {LogGroupNoPolicyProps} props the log group target properties
*/
public createCloudWatchLogGroupNoPolicy(
id: string,
scope: common.CommonConstruct,
logGroup: logs.ILogGroup,
props?: LogGroupNoPolicyProps
) {
return new CloudWatchLogGroupNoPolicy(logGroup, props)
}
}

/**
* Customize the CloudWatch LogGroup Event Target
*/
export interface LogGroupNoPolicyProps extends targets.TargetBaseProps {
/**
* The event to send to the CloudWatch LogGroup
*
* This will be the event logged into the CloudWatch LogGroup
*
* @default - the entire EventBridge event
*/
readonly event?: events.RuleTargetInput
}

/**
* Use an AWS CloudWatch LogGroup as an event rule target, but don't apply a policy.
*/
export class CloudWatchLogGroupNoPolicy implements events.IRuleTarget {
constructor(private readonly logGroup: logs.ILogGroup, private readonly props: LogGroupNoPolicyProps = {}) {}

/**
* Returns a RuleTarget that can be used to log an event into a CloudWatch LogGroup
*/
public bind(_rule: events.IRule, _id?: string): events.RuleTargetConfig {
const logGroupStack = cdk.Stack.of(this.logGroup)

return {
...targets.bindBaseTargetConfig(this.props),
arn: logGroupStack.formatArn({
service: 'logs',
resource: 'log-group',
arnFormat: cdk.ArnFormat.COLON_RESOURCE_NAME,
resourceName: this.logGroup.logGroupName,
}),
input: this.props.event,
targetResource: this.logGroup,
}
}
}
1 change: 1 addition & 0 deletions src/lib/manager/aws/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export * from './ecs-manager'
export * from './eks-manager'
export * from './elasticache-manager'
export * from './event-manager'
export * from './event-target-manager'
export * from './iam-manager'
export * from './kms-manager'
export * from './lambda-manager'
Expand Down
78 changes: 78 additions & 0 deletions src/test/manager/event-target-manager.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import * as cdk from 'aws-cdk-lib'
import { Template } from 'aws-cdk-lib/assertions'
import { Construct } from 'constructs'
import * as common from '../../lib/common'
import * as types from '../../lib/types'

interface TestStackProps extends types.CommonStackProps {
testLogGroup: any
}

const testStackProps = {
env: {
account: '123456789',
region: 'eu-west-1',
},
name: 'test-common-stack',
domainName: 'gradientedge.io',
region: 'eu-west-1',
stackName: 'test',
stage: 'test',
extraContexts: ['src/test/common/cdkConfig/logs.json'],
stageContextPath: 'src/test/common/cdkEnv',
}

class TestCommonStack extends common.CommonStack {
declare props: TestStackProps

constructor(parent: cdk.App, name: string, props: cdk.StackProps) {
super(parent, name, props)

this.construct = new TestCommonConstruct(this, testStackProps.name, this.props)
}

protected determineConstructProps(props: cdk.StackProps) {
return {
...super.determineConstructProps(props),
...{
testLogGroup: this.node.tryGetContext('testLogGroup'),
},
}
}
}

class TestCommonConstruct extends common.CommonConstruct {
declare props: TestStackProps

constructor(parent: Construct, name: string, props: TestStackProps) {
super(parent, name, props)
const testLogGroup = this.logManager.createLogGroup('test-log-group', this, this.props.testLogGroup)
this.eventTargetManager.createCloudWatchLogGroupNoPolicy('test-log-group-target', this, testLogGroup)
}
}

const app = new cdk.App({ context: testStackProps })
const commonStack = new TestCommonStack(app, 'test-common-stack', testStackProps)
const template = Template.fromStack(commonStack)

describe('TestEventTargetConstruct', () => {
test('synthesises as expected', () => {
/* test if number of resources are correctly synthesised */
template.resourceCountIs('AWS::Logs::LogGroup', 1)
template.resourceCountIs('AWS::Logs::ResourcePolicy', 0)
})
})

describe('TestEventTargetConstruct', () => {
test('outputs as expected', () => {
template.hasOutput('testLogGroupLogGroupArn', {})
})
})

describe('TestEventTargetConstruct', () => {
test('provisions new log group target as expected', () => {
template.hasResourceProperties('AWS::Logs::LogGroup', {
LogGroupName: 'test-lg-test',
})
})
})

0 comments on commit f0dc530

Please sign in to comment.