Skip to content

Commit

Permalink
chore(integ-test-alpha): add log group retention days to integ test s…
Browse files Browse the repository at this point in the history
…tack (#29277)

### Issue # (if applicable)

Closes #29260

### Reason for this change

CloudWatch log groups created by the integ tests are set to never expire, so end up cluttering up your aws account and need manual cleanup.

### Description of changes

Added custom log group with log group retention

### Description of how you validated changes

All existing tests and new tests pass.

### Checklist
- [ ] My code adheres to the [CONTRIBUTING GUIDE](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and [DESIGN GUIDELINES](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md)

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
GavinZZ authored Mar 15, 2024
1 parent 3c1307e commit 9ec41ad
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 11 deletions.
22 changes: 22 additions & 0 deletions packages/@aws-cdk/integ-tests-alpha/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,28 @@ invoke.expect(ExpectedResult.objectLike({
}));
```

The above example will by default create a CloudWatch log group that's never
expired. If you want to configure it with custom log retention days, you need
to specify the `logRetention` property.

```ts
import * as logs from 'aws-cdk-lib/aws-logs';

declare const lambdaFunction: lambda.IFunction;
declare const app: App;

const stack = new Stack(app, 'cdk-integ-lambda-bundling');

const integ = new IntegTest(app, 'IntegTest', {
testCases: [stack],
});

const invoke = integ.assertions.invokeFunction({
functionName: lambdaFunction.functionName,
logRetention: logs.RetentionDays.ONE_WEEK,
});
```

#### Make an AWS API Call

In this example there is a StepFunctions state machine that is executed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as path from 'path';
import { Duration, CfnResource, AssetStaging, Stack, FileAssetPackaging, Token, Lazy, Reference } from 'aws-cdk-lib/core';
import { Construct } from 'constructs';
import { awsSdkToIamAction } from 'aws-cdk-lib/custom-resources/lib/helpers-internal';
import { RetentionDays } from 'aws-cdk-lib/aws-logs';

/**
* Properties for a lambda function provider
Expand All @@ -13,6 +14,13 @@ export interface LambdaFunctionProviderProps {
* @default index.handler
*/
readonly handler?: string;

/**
* How long, in days, the log contents will be retained.
*
* @default - no retention days specified
*/
readonly logRetention?: RetentionDays;
}

/**
Expand Down Expand Up @@ -75,18 +83,34 @@ class LambdaFunctionProvider extends Construct {
},
});

const functionProperties: any = {
Runtime: 'nodejs18.x',
Code: {
S3Bucket: asset.bucketName,
S3Key: asset.objectKey,
},
Timeout: Duration.minutes(2).toSeconds(),
Handler: props?.handler ?? 'index.handler',
Role: role.getAtt('Arn'),
};

if (props?.logRetention) {
const logGroup = new CfnResource(this, 'LogGroup', {
type: 'AWS::Logs::LogGroup',
properties: {
LogGroupName: `/aws/lambda/${id}`,
RetentionInDays: props.logRetention,
},
});

functionProperties.LoggingConfig = {
LogGroup: logGroup.ref,
};
}

const handler = new CfnResource(this, 'Handler', {
type: 'AWS::Lambda::Function',
properties: {
Runtime: 'nodejs18.x',
Code: {
S3Bucket: asset.bucketName,
S3Key: asset.objectKey,
},
Timeout: Duration.minutes(2).toSeconds(),
Handler: props?.handler ?? 'index.handler',
Role: role.getAtt('Arn'),
},
properties: functionProperties,
});

this.serviceToken = Token.asString(handler.getAtt('Arn'));
Expand Down Expand Up @@ -131,6 +155,7 @@ class SingletonFunction extends Construct {

return new LambdaFunctionProvider(Stack.of(this), constructName, {
handler: props.handler,
logRetention: props.logRetention,
});
}

Expand Down Expand Up @@ -204,6 +229,7 @@ export class AssertionsProvider extends Construct {
this.handler = new SingletonFunction(this, 'AssertionsProvider', {
handler: props?.handler,
uuid: props?.uuid ?? '1488541a-7b23-4664-81b6-9b4408076b81',
logRetention: props?.logRetention,
});

this.handlerRoleArn = this.handler.lambdaFunction.roleArn;
Expand Down
13 changes: 12 additions & 1 deletion packages/@aws-cdk/integ-tests-alpha/lib/assertions/sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { ApiCallBase, IApiCall } from './api-call-base';
import { ExpectedResult } from './common';
import { AssertionsProvider, SDK_RESOURCE_TYPE_PREFIX } from './providers';
import { WaiterStateMachine, WaiterStateMachineOptions } from './waiter-state-machine';
import { RetentionDays } from 'aws-cdk-lib/aws-logs';

/**
* Options to perform an AWS JavaScript V2 API call
Expand Down Expand Up @@ -75,7 +76,9 @@ export class AwsApiCall extends ApiCallBase {
constructor(scope: Construct, id: string, props: AwsApiCallProps) {
super(scope, id);

this.provider = new AssertionsProvider(this, 'SdkProvider');
this.provider = new AssertionsProvider(this, 'SdkProvider', {
logRetention: props.parameters?.RetentionDays,
});
this.provider.addPolicyStatementFromSdkCall(props.service, props.api);
this.name = `${props.service}${props.api}`;
this.api = props.api;
Expand Down Expand Up @@ -210,6 +213,13 @@ export interface LambdaInvokeFunctionProps {
*/
readonly logType?: LogType;

/**
* How long, in days, the log contents will be retained.
*
* @default - no retention days specified
*/
readonly logRetention?: RetentionDays;

/**
* Payload to send as part of the invoke
*
Expand All @@ -234,6 +244,7 @@ export class LambdaInvokeFunction extends AwsApiCall {
InvocationType: props.invocationType,
LogType: props.logType,
Payload: props.payload,
RetentionDays: props.logRetention,
},
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Template } from 'aws-cdk-lib/assertions';
import { Stack } from 'aws-cdk-lib';
import { AssertionsProvider } from '../../../lib/assertions';
import { RetentionDays } from 'aws-cdk-lib/aws-logs';

let stack: Stack;
beforeEach(() => {
Expand All @@ -20,6 +21,25 @@ describe('AssertionProvider', () => {
});
});

test('default', () => {
// WHEN
const provider = new AssertionsProvider(stack, 'AssertionProvider', {
logRetention: RetentionDays.ONE_WEEK,
});

// THEN
const template = Template.fromStack(stack);
template.resourceCountIs('AWS::Logs::LogGroup', 1);
expect(stack.resolve(provider.serviceToken)).toEqual({ 'Fn::GetAtt': ['SingletonFunction1488541a7b23466481b69b4408076b81HandlerCD40AE9F', 'Arn'] });
Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', {
Handler: 'index.handler',
Timeout: 120,
});
template.hasResourceProperties('AWS::Logs::LogGroup', {
RetentionInDays: 7,
});
});

describe('addPolicyStatementForSdkCall', () => {
test('default', () => {
// WHEN
Expand Down

0 comments on commit 9ec41ad

Please sign in to comment.