How can I reference an existing codebuild project in codepipeline via CDK? - amazon-web-services

I am using AWS CDK to deploy codepipeline and codebuild. What I am current doing is to create codebuild in one cloudformation stack and reference the codebuild in the codepipeline in a different cf stack.
Below is my code, I create a codebuild action like:
const action = new actions.CodeBuildAction({
actionName: "MockEventBridge",
type: actions.CodeBuildActionType.BUILD,
input: input,
project: new codebuild.PipelineProject(this, name, {
projectName: mockName,
environment: {
computeType: codebuild.ComputeType.SMALL,
buildImage
privileged: true,
},
role,
buildSpec: codebuild.BuildSpec.fromSourceFilename(
"cicd/buildspec/mockEventbridge.yaml"
),
}),
runOrder: 1,
})
...
const stages = {
stageName, actions: [action]
}
once build the action, I use below code to build codepipeline.
new codepipeline.Pipeline(this, name, {
pipelineName: this.projectName,
role,
stages,
artifactBucket
});
The problem is that both the codebuild project and codepipeline are built into one stack. If I build the codebuild project in a separate cf stack, how can I reference this stack in codepipeline?
when look at the api reference https://docs.aws.amazon.com/cdk/api/v1/docs/#aws-cdk_aws-codepipeline.Pipeline.html, I can't find a way to reference the codebuild arn in codepipeline instance.

Use the codebuild.Project.fromProjectArn static method to import an external Project resource using its ARN. It returns an IProject, which is what your pipeline's actions.CodeBuildAction props expect.

You can use the export value to export the resource Codebuild created in another Stack.
The exported CodeBuild from the first Stack can be imported in the new Stack of CodePipeline.
You can see this page for more info https://lzygo1995.medium.com/how-to-export-and-import-stack-output-values-in-cdk-ff3e066ca6fc

Related

AWS CodePipeline CDK TypeScript

The install commands in the Build Step of the AWS CodePipeline do not update when there are changes made in the AWS CDK Code (TypeScript) and are pushed to the repository. The Buildspec section under the Build details of the project has the same configuration as when it was created.
Is there a way to fix it? We've made some changes to the BuildStep CDK but does not take effect on the AWS CodeBuild configuration details. I'm only new to AWS CodeBuild and CodePipeline. Any answer/suggestion would be a great help.
Sample Code
const pipeline = new CodePipeline(this, 'SamplePipeline', {
pipelineName: 'SamplePipeline',
synth: new CodeBuildStep('BuildSynthStep', {
input: source,
buildEnvironment: {
buildImage: codebuild.LinuxBuildImage.STANDARD_5_0
},
installCommands: [
'install_command_1',
'install_command_2',
...
'install_command_n'
],
commands: [
'command_2',
...
'command_n'
],
}
)
});
Artifact Provider: Amazon S3
The self-mutation of a CDK Pipeline is only applied, when you change something on an application stage (precisely CDK Stage) or other phases after the synth codebuild job.
If you have something running before, e.g. unit tests, then you won't get into the self-update job.
So, what are your options now?
Well, changes according to a pipeline itself are mostly done manually.
So you have to re-run a cdk deploy PipelineStack on your local machine with your changes committed to the source branch aside.

Adding the role to code build to access the ECR

I want to give the policy to codebuild to access the ecr repository for push.
However to what should I give the policy?
I can do this manually in amazon web console though,
it's quite not clear to me in cdk.
const buildProject = new codebuild.PipelineProject(this, 'buildproject', {
environment: {
buildImage:codebuild.LinuxBuildImage.STANDARD_4_0,
privileged:true,
},
buildSpec: codebuild.BuildSpec.fromSourceFilename("./buildspec.yml")
});
buildProject.addToRolePolicy(new iam.PolicyStatement({
resources: [what should be here?],
actions: ['ecr:GetAuthorizationToken'] }
));
Simply myRepository.grantPullPush(buildProject).
Reference: https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ecr.Repository.html#grantwbrpullwbrpushgrantee
This will abstract away the content of the policy.

Cloudformation template for CodePipeline

We have an aws setup where we have a test account and a production account.
Our code commit (java lambda's) is in our test account and we want to use CodePipeline to deploy code from here to our test account and production accounts.
I was wondering if anyone is aware of any ready made cloudformation (or cdk) templates that can perform this work?
Thanks
Damien
I have implemented that a few days ago using CDK, the idea is to create an IAM Role on the target environment and assume this role when running the codebuild(which runs as part of the code pipeline).
In my case, since the codebuild creates CDK stacks I gave an AdministratorAccess policy to this role.
Later, create new codebuild and attach permissions to codebuild project role.
// create the codebuild project used by the codepipeline
const codeBuildProject = new codebuild.PipelineProject(scope, `${props.environment}-${props.pipelineNamePrefix}-codebuild`, {
projectName: `${props.environment}-${props.pipelineNamePrefix}`,
buildSpec: codebuild.BuildSpec.fromSourceFilename('buildspec.yml'),
environment: {
buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2,
privileged: true,
environmentVariables: buildEnvVariables,
computeType: props.computeType
},
})
// attach permissions to codebuild project role
codeBuildProject.addToRolePolicy(new PolicyStatement({
effect: Effect.ALLOW,
resources: [props.deploymentRoleArn],
actions: ['sts:AssumeRole']
}));
Be aware that props.deploymentRoleArn is the ARN of the role you created on the target environment.
Then, create a new pipeline and add codeBuildProject to codepipelineActions.CodeBuildAction as project:
// create codepipeline to deploy cdk changes
const codePipeline = new codepipeline.Pipeline(scope, `${props.environment}-${props.pipelineNamePrefix}-codepipeline`, {
restartExecutionOnUpdate: false,
pipelineName: `${props.environment}-${props.pipelineNamePrefix}`,
stages: [
{
stageName: 'Source',
actions: [
new codepipelineActions.GitHubSourceAction({
branch: props.targetBranch,
oauthToken: gitHubToken,
owner: props.githubRepositoryOwner,
repo: props.githubRepositoryName,
actionName: 'get-sources',
output: pipelineSourceArtifact,
})]
},
{
stageName: 'Deploy',
actions: [
new codepipelineActions.CodeBuildAction({
actionName: 'deploy-cdk',
input: pipelineSourceArtifact,
type: codepipelineActions.CodeBuildActionType.BUILD,
project: codeBuildProject
}),
]
}
]
});
The relevant part from above code snippet is Deploy stage.The other stage is only required in case you want to get sources from github - More info here.
This is the full solution, in case you want to implement something else, Read more about code pipeline actions here.

How do I specify the CodeUri in my pipeline?

I'm doing a serverless app in lambda using CloudFormation.
In my CodeBuild project, I set it to zip up the output and place it in "myBucket\AWSServerless1.zip" and it does correctly.
Now I'm working on my CodePipeline, I reference the original CodeBuild project. However, now instead, it puts it in codepipeline-us-west-#####. That's fine. The issue is that the .zip file has a RANDOM name. CodePipeline ignores the name I gave it in the CodeBuild project.
In the serverless.template, I have to specify the CodeUri (which seems to be the CodeBuild project output for some odd reason). If I reference the AWSServerless1.zip, it works fine (but its not building to there, so its stale code)... but...
Since CodePipeline calling CodeBuild gives it a random name, how am I supposed to reference the ACTUAL BuildArtifact in the serverless.template?
I know this is very weird, I was stuck with this behavior of CodePipeline and then had to rewrite the buildspec to make CodePipeline work. CodePipeline makes it's own zip file even if you create your own zip through CodeBuild as well and that too with a unique name.
But there is one way out, Codepipeline will create one zip file but it will unzip it while giving the artifact to CodeDeploy. So you need not worry about its name. CodeDeploy will get the unzipped version of your code. CodePipeline keeps track of the name and it will always point to the newest one.
Suppose :
CodePipeline creates artifact : some-random-name.zip
some-random-name
|- deploy/lib/lambda-code
|- some-file.yaml
Whenever CodePipeline gives artifact to CodeDeploy, it will unzip it so you can anytime refer the code under some-random-name.zip
So in your case when you give CodeUri in the SAM template just give the folder name which is deploy where your lambda code is present.
Resources:
Hello:
Type: 'AWS::Serverless::Function'
Properties:
Handler: example.MyHandler
Runtime: java8
CodeUri: deploy
Description: ''
MemorySize: 512
Timeout: 15
Hope this helps.
I was facing the same error and I managed to work around it by doing the following:
1- On the build specification (buildspec.yml) add a sam package command (this generates a package.yml that will be used by cloudformation to deploy the lambda).
build:
commands:
- sam package
--template-file ../template.yaml
--output-template-file ../package.yml
--s3-bucket onnera-ci-cd-bucketcode here
2- Add the package.yml to output artifacts
artifacts:
files:
- DeviceProvisioning/package.yml
3- On the template.yaml that will be deployed reference directly the CodeUri (internally this will be resolved to the bucket with the output artificats from codebuild).
Resources:
DeviceProvisioningFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: DeviceProvisioningFunction/target/DeviceProvisioningFunction-1.0.jar
4- On the pipeline make the output of the build phase avaialble on deployment phase:
const buildOutput = [new codepipeline.Artifact()];
const buildAction = new codepipeline_actions.CodeBuildAction({
actionName: 'CodeBuild',
project: deviceProvisioning,
input: sourceOutput,
outputs: buildOutput,
});
5- Use the build output to specify the templatePath on the deploy action:
const deployAction = new codepipeline_actions.CloudFormationCreateUpdateStackAction({
extraInputs: buildAction.actionProperties.outputs,
actionName: "UpdateLambda",
stackName: "DeviceProvisioningStack",
adminPermissions: true,
templatePath: buildOutput[0].atPath("package.yml"),
cfnCapabilities: [CfnCapabilities.AUTO_EXPAND, CfnCapabilities.NAMED_IAM]
});
Make sure that the output artifacts from the build phase are available on the deploy phase.

How can my CodeBuild in a CodePipeline resolve resources created by the previous CloudFormation step?

I have setup my CodePipeline something like:
Source: Github
CodeBuild: Package SAM application (CloudFormation resources like DB)
Deploy CloudFormation: Does the create & execute changesets
CodeBuild: I want to run DB migrations for the DB created by CloudFormation ... but how do I get it ... CodeBuild does not support parameters from my Pipeline
Maybe I am creating my pipeline wrong?
The CloudFormation action can output stack parameters, but currently the CodeBuild action in CodePipeline can't accept both a code artifact and an artifact with CloudFormation outputs.
For now I'd call aws cloudformation describe-stacks from the CLI inside your build script to retrieve the DB information from your CloudFormation stacks.
Maybe in the step 3. You setup your cloudformation in this way:
1- create the database...Export as an output the name of the database
Outputs:
DataBaseName:
Description: "Name of the Database"
Value: !Ref DataBaseName
2- In the codebuild use the Boto3 and use the Describe Stacks and get the output (the name of the database and another information about it), now you could take advangate of Python in your codebuild and start the migration usign Boto3.
response = client.describe_stacks(
StackName='string',
NextToken='string'
)