Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(event-targets): Adding Event Target Manager construct #106

Merged
merged 1 commit into from
May 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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',
})
})
})