Open markusl opened 3 years ago
Hey @markusl 👋🏻 I'm happy to help
I relabeled this to guidance until we can confirm this is broken functionality w/expected vs actual result reports. Let me try to reproduce this on my end and i'll update this with my results.
@ryparker any update on this?
@markusl The pre
and post
params are used for defining actions you wish to run before/after deploying the Stage
s associated with the Wave
.
_Param definitions from WaveOptions docs:_
pre: "Additional steps to run before any of the stages in the wave." post: "Additional steps to run after all of the stages in the wave."
Whenever you're initializing a Wave
you should also define a Stage
to associate with your Wave
using the wave.addStage()
method.
Wave
s will execute in this order:
pre
paramStage
sStage
spost
paramHere is an example where I define a wave with both pre
and post
props like you have above. However I also create a new Stage
that is used to define another stack with some resources.
const app = new App();
const stack = new Stack(app, "MyStack");
const pipeline = new CodePipeline(stack, "Pipeline", {
pipelineName: "MyPipeline",
selfMutation: false,
synth: new ShellStep('Synth', {
input: CodePipelineSource.gitHub('ryparker/aws-cdk-sample-pipeline', 'main'),
commands: [
'yarn install',
'yarn build'
],
primaryOutputDirectory: 'build/cloudformation',
}),
});
const wave = pipeline.addWave('CustomWave', {
pre: [new ManualApprovalStep('ManualApproval')],
post: [
new CodeBuildStep('CustomWaveAction', {
projectName: 'CustomWaveActionBuild',
commands: [
'echo Hello World'
],
})],
});
// New code: Adds a new Stage to be deployed by the Wave.
const lambdaStage = new Stage(stack, 'LambdaWaveStage');
const lambdaStack = new Stack(lambdaStage, 'lambdaWaveStack');
new Function(lambdaStack, 'MyFunction', {
code: Code.fromInline('console.log("hello world");'),
runtime: Runtime.NODEJS_14_X,
handler: 'index.handler',
});
wave.addStage(lambdaStage);
Full repro code available here
@ryparker yeah, that is clear. However, we just need to run a CodeBuild action and have a manual approval gate just before it.
With previous pipelines this was possible by adding a Stage to the pipeline, and the required actions to the stage. In https://github.com/aws/aws-cdk/issues/15945 @rix0rrr explained that Stage and Stage are not the same anymore and we need to use a Wave when we don't have a stack to deploy.
Now the problem is that the pre and post-actions within a Wave do not seem to work very intuitively. Any ideas on how to proceed with this?
@markusl I see what you're trying to implement. Unfortunately I don't believe the @aws-cdk/pipelines
project supports adding custom CodePipeline stages, other than using escape hatches (which can get ugly here). Perhaps @rix0rrr knows better and can comment.
Assuming i'm correct, i'd like to offer an alternative solution that uses the @aws-cdk/aws-codepipeline
package.
import { App, Stack, SecretValue } from "@aws-cdk/core";
import { Pipeline, Artifact } from '@aws-cdk/aws-codepipeline';
import { PipelineProject } from '@aws-cdk/aws-codebuild';
import { ShellScriptAction } from '@aws-cdk/pipelines';
import { ManualApprovalAction, GitHubSourceAction, CodeBuildAction } from '@aws-cdk/aws-codepipeline-actions';
import { PolicyStatement, Effect } from '@aws-cdk/aws-iam';
const app = new App();
const stack = new Stack(app, "AwsCodepipelinesStack");
const sourceArtifact = new Artifact('SourceCode');
new Pipeline(stack, 'Pipeline', {
pipelineName: 'Pipeline-Using-AwsCodepipelines',
stages: [
{
stageName: 'Source',
actions: [
new GitHubSourceAction({
actionName: 'GitHub',
oauthToken: SecretValue.secretsManager('github-token'),
owner: 'ryparker',
repo: 'aws-cdk-sample-pipeline',
branch: 'main',
output: sourceArtifact,
runOrder: 1,
}),
],
},
{
stageName: 'Deploy',
actions: [
new ShellScriptAction({
actionName: 'Deploy',
additionalArtifacts: [sourceArtifact],
commands: [
'yarn install',
'yarn run tsc',
'yarn run cdk synth',
'yarn run cdk deploy --all --require-approval never'
],
rolePolicyStatements: [
new PolicyStatement({
effect: Effect.ALLOW,
actions: ['*'],
resources: ['*'],
})
],
runOrder: 1,
})
]
},
{
stageName: 'Post-Deploy-Actions',
actions: [
new ManualApprovalAction({
actionName: 'Approve',
runOrder: 1,
}),
new CodeBuildAction({
actionName: 'CustomCodeBuildAction',
input: sourceArtifact,
project: new PipelineProject(stack, 'CustomProject'),
runOrder: 2,
}),
]
}
],
});
My example pipeline executes in the following order:
This pipeline implementation IMO is much easier to customize. Although it will require more code than the abstract @aws-cdk/pipelines
's CodePipeline
.
@ryparker I don't fully understand the limitation which is basically implemented here: https://github.com/aws/aws-cdk/blob/d499c85e4c09cc00b457ca7f2f4611a925ca8aeb/packages/%40aws-cdk/pipelines/lib/blueprint/stage-deployment.ts#L56-L60
What would be the problem of allowing adding Stages to the pipelines.CodePipeline
which do not contain any Stacks but only CodeBuild or other actions?
What would be the problem of allowing adding Stages to the pipelines.CodePipeline which do not contain any Stacks but only CodeBuild or other actions?
I don't have a great answer for this. Both CdkPipeline
and CodePipeline
from the @aws-cdk/pipelines
package reduce the required code to implement a simple self mutating CDK pipeline. Ideally it should be easy to add something like a pipeline stage that includes a manual approval step however at the moment this is not supported. We continue to add features and improvements to these constructs so they will evolve with time.
As a workaround it is possible to use the Pipeline
construct from @aws-cdk/aws-codepipeline
to build out custom stages as I did in the example pipeline above.
Support for adding pipeline stages to CodePipeline
would be a good feature request. We also appreciate any pull requests if you already have an idea of how this should be implemented.
Thanks for the reply, @ryparker. What you are proposing does not really sound like a workaround but a rewrite of the pipeline :)
The support for easily adding stages is already there, but for some reason, it is prevented by the code I linked before: https://github.com/aws/aws-cdk/blob/d499c85e4c09cc00b457ca7f2f4611a925ca8aeb/packages/%40aws-cdk/pipelines/lib/blueprint/stage-deployment.ts#L56-L60
None of the options seem very good to me:
The actual workaround we can use is adding two waves where the manual approval is in the first one, and the CodeBuild action is in the second one.
Is there any possibility you could look into this?
The actual workaround we can use is adding two waves where the manual approval is in the first one, and the CodeBuild action is in the second one.
👍🏻 Thanks for providing the workaround.
Is there any possibility you could look into this?
We can certainly give this a look once we have bandwidth. I've changed this issue back to a bug report, unassigned, and prioritized it as p1. p1 means it has been prioritized as important, although please keep in mind that we do have a large number of issues at the moment. It may be some time before we are able to solve this particular issue. We use +1s to help us prioritize our work, and as always we are happy to take contributions if anyone is interested to pick this up and submit a PR.
Classifying as p2 since there is a workaround
This issue has not received any attention in 1 year. If you want to keep this issue open, please leave a comment below and auto-close will be canceled.
Still an issue.
Hello, is there any update on this? In my case I have a Lambda invoke action that i need to run as a Pre step and also as a Post step, right before a Manual Approval step that deploys everything to our production account. The thing is when i add it as a Post step, it is always being added as the first step (as if it were a Pre step).
@markusl have you had something like that happen to you?
I have a similar issue, but not quite the same. I do have a stage that needs to be deployed, so I'm using addPost to add something else to the wave. However, I need to add more than one step in sequence, yet it generates a pipeline that runs the actions in parallel.
I'm also a bit confused about the addPost
method on the StageDeployment
class and another one on the Wave
class. One says deploy after Stacks and one after Stage.
I ended up reading this in FULL. As in trying to absorb everything and it did fill some gaps about running in parallel and in sequence and creating dependencies between steps to force the pipeline to go in sequence. It's easy to miss so I suggest read it ALL. Maybe it will help...
https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.pipelines-readme.html
Sharing easy workaround if you don't want to create multiple waves, use dummy stacks, or model the step dependencies yourself between post and pre...
Extend the CodePipeline from "aws-cdk-lib/pipelines" with your subclass name and override the doPipelineBuild to add the deps between post and pre steps.
class MyPipeline extends CodePipeline {
protected doBuildPipeline() {
// For all waves, add an explicit step dependency for the wave's post steps on the wave's pre steps
// to enforce ordering. This should probably be done implicitly by the CodePipeline class given the
// naming. Without this dependency when there are no stages between pre and post steps they
// run concurrently (no ordering).
this.waves.forEach(wave =>
wave.post.forEach(postStep =>
wave.pre.forEach(preStep => postStep.addStepDependency(preStep))));
super.doBuildPipeline();
}
}
Now any wave pre steps will all run before any post steps in that same wave. This behavior probably should be the default in general as it is unexpected behavior for steps in pre
to run concurrently with steps in post
when using a wave without stages / stacks. When a wave has a stage this ordering gets added for you.
It seems that the following code does not really add the
ManualApprovalStep
before the build action. What would be the proper way to do this with the new CDK Pipelines?Environment
Other
This is :bug: Bug Report