I'm trying to replicate following CloudFormation template using AWS CDK:
- Name: UpdateDev
Actions:
- Name: DeployImage
InputArtifacts:
- Name: BuildOutput
ActionTypeId: {Category: Deploy, Owner: AWS, Version: 1, Provider: ECS}
RoleArn: !Sub arn:aws:iam::${account}:role/deploy-role
Configuration:
ClusterName: cluster-name
ServiceName: service-name
FileName: imagedefinitions.json
However, I'm not sure how I should construct ecs.BaseService to achieve the needed functionality. Is there a raw Cfn class that could be used for this?
None of these combinations worked that I tried to use:
new codepipeline_actions.EcsDeployAction({
actionName: 'Deploy',
imageFile: ...,
service: ecs.FargateService.fromFargateServiceArn(stack, `service`, 'xxxx'), // does not compile
}),
new codepipeline_actions.EcsDeployAction({
actionName: 'Deploy',
imageFile: ...,
service: {
stack,
cluster,
serviceName: name,
node: stack.node,
} as ecs.BaseService // does not synth
}),
pipeline.addStage({
stageName: 'UpdateDev',
actions: [
new codepipeline_actions.EcsDeployAction({
actionName: 'Deploy',
imageFile: ...,
service: 'service-name'
}),
]
});
This is a :rocket: Feature Request
Thanks for opening the issue @markusl . The problem you're running into is that ecs.FargateService.fromFargateServiceArn does not allow passing the cluster the service is part of, and that's needed information for the action to fill the ClusterName parameter (as you see in CFN).
If you know the cluster name, you can just implement the IAction interface directly:
import codepipeline = require('@aws-cdk/aws-codepipeline');
import events = require('@aws-cdk/aws-events');
import iam = require('@aws-cdk/aws-iam');
import { Construct } from '@aws-cdk/core';
export interface MyEcsDeployActionProps extends codepipeline.CommonAwsActionProps {
readonly input: codepipeline.Artifact;
readonly serviceName: string;
readonly clusterName: string
}
export class MyEcsDeployAction implements codepipeline.IAction {
public readonly actionProperties: codepipeline.ActionProperties;
private readonly props: MyEcsDeployActionProps;
constructor(props: MyEcsDeployActionProps) {
this.actionProperties = {
...props,
category: codepipeline.ActionCategory.DEPLOY,
provider: 'ECS',
artifactBounds: { minInputs: 1, maxInputs: 1, minOutputs: 0, maxOutputs: 0 },
inputs: [props.input],
};
this.props = props;
}
public bind(_scope: Construct, _stage: codepipeline.IStage, options: codepipeline.ActionBindOptions):
codepipeline.ActionConfig {
// you probably need all these permissions
options.role.addToPolicy(new iam.PolicyStatement({
actions: [
'ecs:DescribeServices',
'ecs:DescribeTaskDefinition',
'ecs:DescribeTasks',
'ecs:ListTasks',
'ecs:RegisterTaskDefinition',
'ecs:UpdateService',
],
resources: ['*']
}));
options.role.addToPolicy(new iam.PolicyStatement({
actions: ['iam:PassRole'],
resources: ['*'],
conditions: {
StringEqualsIfExists: {
'iam:PassedToService': [
'ec2.amazonaws.com',
'ecs-tasks.amazonaws.com',
],
}
}
}));
options.bucket.grantRead(options.role);
return {
configuration: {
ClusterName: this.props.clusterName,
ServiceName: this.props.serviceName,
// FileName is imagedefinitions.json by default
},
};
}
public onStateChange(name: string, target?: events.IRuleTarget, options?: events.RuleProps): events.Rule {
throw new Error("Method not implemented.");
}
}
And you use it like so:
pipeline.addStage({
stageName: 'UpdateDev',
actions: [
new MyEcsDeployAction({
actionName: 'Deploy',
serviceName: 'service-name',
clusterName: 'cluster-name',
input: buildOutput,
}),
],
});
Let me know if that helps!
Thanks,
Adam
@skinny85 thank you for quick response! We will use the provided workaround until this is natively supported in CDK.
Regards,
Markus
This is being worked on in https://github.com/aws/aws-cdk/pull/5939
Done in #6412 :)
Most helpful comment
This is being worked on in https://github.com/aws/aws-cdk/pull/5939