Skip to content
Open
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

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,7 @@
"DeploymentConfiguration": {
"LifecycleHooks": [
{
"HookDetails": "{\"stringKey\":\"stringValue\",\"intKey\":1,\"boolKey\":true,\"listKey\":[\"stringValue1\",\"stringValue2\"]}",
"HookTargetArn": {
"Fn::GetAtt": [
"LambdaHookBF1BC8B4",
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,12 @@ const service = new ecs.FargateService(stack, 'Service', {

service.addLifecycleHook(new ecs.DeploymentLifecycleLambdaTarget(lambdaHook, 'PreScaleUp', {
lifecycleStages: [ecs.DeploymentLifecycleStage.PRE_SCALE_UP],
hookDetails: {
stringKey: 'stringValue',
intKey: 1,
boolKey: true,
listKey: ['stringValue1', 'stringValue2'],
},
}));

const target = service.loadBalancerTarget({
Expand Down
1 change: 1 addition & 0 deletions packages/aws-cdk-lib/aws-ecs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2200,6 +2200,7 @@ const service = new ecs.FargateService(this, 'Service', {

service.addLifecycleHook(new ecs.DeploymentLifecycleLambdaTarget(lambdaHook, 'PreScaleHook', {
lifecycleStages: [ecs.DeploymentLifecycleStage.PRE_SCALE_UP],
hookDetails: {'stringKey':'stringValue', 'intKey':1, 'boolKey':true, "list": ["abc",1,true]},
}));

const target = service.loadBalancerTarget({
Expand Down
1 change: 1 addition & 0 deletions packages/aws-cdk-lib/aws-ecs/lib/base/base-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -879,6 +879,7 @@ export abstract class BaseService extends Resource
hookTargetArn: config.targetArn,
roleArn: config.role!.roleArn,
lifecycleStages: config.lifecycleStages.map(stage => stage.toString()),
hookDetails: config.hookDetails,
};
});
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { IConstruct } from 'constructs';
import * as iam from '../../aws-iam';
import * as lambda from '../../aws-lambda';
import { Fn, ValidationError } from '../../core';

/**
* Deployment lifecycle stages where hooks can be executed
Expand Down Expand Up @@ -55,6 +56,12 @@ export interface DeploymentLifecycleHookTargetConfig {
* The lifecycle stages when this hook should be executed
*/
readonly lifecycleStages: DeploymentLifecycleStage[];

/**
* Use this field to specify custom parameters that Amazon ECS will pass to your hook target invocations (such as a Lambda function).
* @default - No custom parameters will be passed
*/
readonly hookDetails?: string;
}

/**
Expand All @@ -65,7 +72,6 @@ export interface IDeploymentLifecycleHookTarget {
* Bind this target to a deployment lifecycle hook
*
* @param scope The construct scope
* @param id A unique identifier for this binding
*/
bind(scope: IConstruct): DeploymentLifecycleHookTargetConfig;
}
Expand All @@ -84,6 +90,18 @@ export interface DeploymentLifecycleLambdaTargetProps {
* The lifecycle stages when this hook should be executed
*/
readonly lifecycleStages: DeploymentLifecycleStage[];

/**
* Use this field to specify custom parameters that Amazon ECS will pass to your hook target invocations (such as a Lambda function).
*
* This field accepts JSON objects only
*
* @example
* {environment:"production",timeout:300};
*
* @default - No custom parameters will be passed
*/
readonly hookDetails?: { [key: string]: any };
}

/**
Expand Down Expand Up @@ -118,10 +136,16 @@ export class DeploymentLifecycleLambdaTarget implements IDeploymentLifecycleHook
this.handler.grantInvoke(this._role);
}

// Reject arrays
if (Array.isArray(this.props.hookDetails)) {
throw new ValidationError('hookDetails must be a JSON object, got: array', scope);
}

return {
targetArn: this.handler.functionArn,
role: this._role,
lifecycleStages: this.props.lifecycleStages,
hookDetails: this.props.hookDetails ? Fn.toJsonString(this.props.hookDetails) : undefined,
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -282,4 +282,59 @@ describe('DeploymentLifecycleHookTarget', () => {
service.addLifecycleHook(hookTarget);
}).toThrow(/Deployment lifecycle hooks requires the ECS deployment controller/);
});

describe('hookDetails validation', () => {
test('validates valid JSON object hookDetails', () => {
// GIVEN
const service = new ecs.FargateService(stack, 'FargateService', {
cluster,
taskDefinition,
});

// WHEN
const hookTarget = new ecs.DeploymentLifecycleLambdaTarget(lambdaFunction, 'PreScaleUpHook', {
lifecycleStages: [ecs.DeploymentLifecycleStage.PRE_SCALE_UP],
hookDetails: { environment: 'production', timeout: 300 },
});
service.addLifecycleHook(hookTarget);

// THEN
Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', {
DeploymentConfiguration: {
LifecycleHooks: [
{
LifecycleStages: ['PRE_SCALE_UP'],
HookTargetArn: {
'Fn::GetAtt': [
Match.stringLikeRegexp('TestFunction'),
'Arn',
],
},
HookDetails: '{\"environment\":\"production\",\"timeout\":300}',
},
],
},
});
});

test('throws error for JSON array hookDetails', () => {
// GIVEN
const service = new ecs.FargateService(stack, 'FargateService', {
cluster,
taskDefinition,
});

// WHEN
const hookTarget = new ecs.DeploymentLifecycleLambdaTarget(lambdaFunction, 'PreScaleUpHook', {
lifecycleStages: [ecs.DeploymentLifecycleStage.PRE_SCALE_UP],
hookDetails: ['param1', 'param2', 1, true],
});
service.addLifecycleHook(hookTarget);

// GIVEN & WHEN & THEN
expect(() => {
Template.fromStack(stack);
}).toThrow(/hookDetails must be a JSON object, got: array/);
});
});
});
Loading