'AWS Codepipeline Multiple Output Artifacts
Still fairly new to AWS Codepipeline and I am trying to pass an output artifact out into the next stage of my build. In this particular case, I want to do two artifacts for the builds phase which is the only part I am focusing on right now. I have included my codepipeline code for reference:
resource "aws_codepipeline" "cp_plan_pipeline" {
name = "${local.name_prefix_H}-${var.cp_name}"
role_arn = aws_iam_role.cp_service_role.arn
artifact_store {
type = var.cp_artifact_type
location = module.S3.bucket_name
}
stage {
name = "Clone"
action {
name = "Source"
category = "Source"
owner = "AWS"
provider = "CodeCommit"
input_artifacts = []
version = "1"
output_artifacts = ["CodeWorkspace"]
configuration = {
RepositoryName = var.cp_repo_name
BranchName = var.cp_branch_name
PollForSourceChanges = var.cp_poll_sources
OutputArtifactFormat = var.cp_ouput_format
}
run_order = "1"
}
}
stage {
name = "Plan"
action {
name = "Terraform-Plan"
category = "Build"
owner = "AWS"
provider = "CodeBuild"
version = "1"
input_artifacts = ["CodeWorkspace"]
output_artifacts = ["CodeSource","TerraformPlanFile"]
configuration = {
ProjectName = var.cp_plan_project_name
EnvironmentVariables = jsonencode([
{
name = "PIPELINE_EXECUTION_ID"
value = "#{codepipeline.PipelineExecutionId}"
type = "PLAINTEXT"
}
])
}
}
}
stage {
name = "Test"
action {
name = "Testing"
category = "Test"
owner = "AWS"
provider = "CodeBuild"
input_artifacts = ["CodeSource"]
output_artifacts = ["TestOutput"]
version = "1"
configuration = {
ProjectName = var.cp_test_project_name
EnvironmentVariables = jsonencode([
{
name = "PIPELINE_EXECUTION_ID"
value = "#{codepipeline.PipelineExecutionId}"
type = "PLAINTEXT"
}
])
}
}
}
stage {
name = "Manual-Approval"
action {
run_order = 1
name = "AWS-Admin-Approval"
category = "Approval"
owner = "AWS"
provider = "Manual"
version = "1"
input_artifacts = []
output_artifacts = []
configuration = {
CustomData = "Please verify the terraform plan output on the Plan stage and only approve this step if you see expected changes!"
}
}
}
stage {
name = "Deploy"
action {
run_order = 1
name = "Terraform-Apply"
category = "Build"
owner = "AWS"
provider = "CodeBuild"
input_artifacts = ["TerraformPlanFile"]
output_artifacts = []
version = "1"
configuration = {
ProjectName = var.cp_apply_project_name
PrimarySource = "CodeWorkspace"
EnvironmentVariables = jsonencode([
{
name = "PIPELINE_EXECUTION_ID"
value = "#{codepipeline.PipelineExecutionId}"
type = "PLAINTEXT"
}
])
}
}
}
}
So the pipeline works fine as far as the deployment of the pipeline goes. My buildspec works great up until the point where I get to the artifact stage of the buildspec where i get the following error: Phase context status code: CLIENT_ERROR Message: no definition for secondary artifact CodeSource in buildspec My issue is the buildspec and trying to output the second source so i can upload it for the second phase. Please note some parts of the buildspec such as variables have been scrubbed. Buildspec below:
version: 0.2
env:
variables:
TF_VERSION: "1.0.7"
PY_VERSION: "3.9.6"
GIT_VERSION: "2.9.5"
PACKER_VERSION: "1.7.8"
JQ_VERSION: "1.6"
TFLINT_VERSION: "0.34.0"
PERMISSION_SETS_DIR: "CodeSource"
phases:
install:
commands:
# iNSTALL/UPDATE SSH CLIENT
- echo UPDATING SSH CLIENT
- "which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )"
# iNSTALL JQ JSON PARSER
- curl -s -qL -o jq https://github.com/stedolan/jq/releases/download/jq-${JQ_VERSION}/jq-linux64
- chmod +x ./jq
- cp jq /usr/bin
# INSTALL TERRAFORM
- echo STARTING TERRAFORM INSTALLATION
- curl -s -qL -o terraform.zip https://releases.hashicorp.com/terraform/${TF_VERSION}/terraform_${TF_VERSION}_linux_amd64.zip
- unzip terraform -d /usr/bin/
- "chmod +x /usr/bin/terraform"
- "/usr/bin/terraform --version"
# INSTALL Packer
- echo STARTING PACKER INSTALLATION
- curl -s -qL -o packer.zip https://releases.hashicorp.com/packer/${PACKER_VERSION}/packer_${PACKER_VERSION}_linux_amd64.zip
- unzip packer -d /usr/bin/
- "chmod +x /usr/bin/packer"
- "/usr/bin/packer --version"
# INSTALL PYTHON
- echo "STARTING PYTHON INSTALLATION"
- "curl -s -qL -o python.tgz https://www.python.org/ftp/python/${PY_VERSION}/Python-${PY_VERSION}.tgz"
- "tar xf python.tgz -C /usr/bin/"
- "python --version"
- python -m pip install -U pip
# ADD PYTHON MODULES
- echo "INSTALL PYTHON MODULES"
- pip install git-remote-codecommit
pre_build:
commands:
# Adds a private SSH key to allow us to clone or npm install Git repositories
- rootpath=$(pwd)
- eval $(ssh-agent -s)
- mkdir -p ~/.ssh
# Configure SSH Key
- echo "$ssh_key" > ~/.ssh/cc_rsa
- cd ~/.ssh/
- cat cc_rsa
- |
echo "Multiline command"
cat > ~/.ssh/config <<EOL
Host idt-codecommit
Hostname git-codecommit.us-east-1.amazonaws.com
User ${cc_user}
IdentityFile ~/.ssh/cc_rsa
EOL
- cat ~/.ssh/config
# Configure SSH Permissions
- echo +++++++++CONFIG SSH+++++++++
- chmod 700 ~/.ssh
- chmod 600 ~/.ssh/config
- chmod 600 ~/.ssh/cc_rsa
- ssh-keyscan -t rsa1,rsa,dsa git-codecommit.us-east-1.amazonaws.com >> ~/.ssh/known_hosts
# Clone directories
- echo +++++++++CLONE DIRECTORIES+++++++++
- mkdir -p ${CODEBUILD_SRC_DIR}/configurations/${PERMISSION_SETS_DIR}
- cd ${CODEBUILD_SRC_DIR}/configurations/${PERMISSION_SETS_DIR}
- git clone codecommit://sourcerepo local_primary_repo
- git clone -b development ssh://sourcerepo2/v1/repos/sourcerepo2
# GET AWS ACCOUNT VARIABLES
- aws_region=$AWS_DEFAULT_REGION
- awsaccountnumber=$(aws sts get-caller-identity --query "Account")
- awsaccountname=$(aws iam list-account-aliases | jq -r '.AccountAliases | .[]')
- |
if [[ "$awsaccountname" == *"prod"* ]]; then
appenv="prod"
else
if [[ "$awsaccountname" == *"test"* ]]; then
appenv="test"
else
if [[ "$awsaccountname" == *"dev"* ]]; then
appenv="dev"
else
if [[ "$awsaccountname" == *"sbx"* ]]; then
appenv="sbx"
else
appenv="other"
fi
fi
fi
fi
build:
on-failure: ABORT
commands:
# Import S3 Folder Location Variable
- cd ${CODEBUILD_SRC_DIR}/configurations/${PERMISSION_SETS_DIR}/local_primary_repo
- CODEBUILD_GIT_BRANCH=`git symbolic-ref HEAD --short 2>/dev/null`
# CHECK TERRAFORM CODE
- cd ${CODEBUILD_SRC_DIR}/configurations/${PERMISSION_SETS_DIR}/local_primary_repo
- echo "yes" | terraform init
- terraform validate > ${bucketconfig}-tfvalidateexport.txt
- terraform validate
- terraform plan -out=tfplan_commitid_${CODEBUILD_RESOLVED_SOURCE_VERSION}_pipelineid_${PIPELINE_EXECUTION_ID}
- cp ${bucketconfig}-tfvalidateexport.txt ${CODEBUILD_SRC_DIR}/
- cp tfplan_commitid_${CODEBUILD_RESOLVED_SOURCE_VERSION}_pipelineid_${PIPELINE_EXECUTION_ID} ${CODEBUILD_SRC_DIR}/
post_build:
commands:
- echo "Terraform plan completed on `date`"
artifacts:
files:
- tfplan_commitid_${CODEBUILD_RESOLVED_SOURCE_VERSION}_pipelineid_${PIPELINE_EXECUTION_ID}
name: TerraformPlanFile
secondary-artifacts:
artifact_1:
files:
- '**/*'
name: CodeSource
base-directory: ${CODEBUILD_SRC_DIR}/configurations/${PERMISSION_SETS_DIR}
Links or advice of what i am doing wrong would be very helpful. Thank you!!
Solution 1:[1]
First of I wanted to thank Antonio González for his post. It was exactly what I needed for the solution. I would like to recap the solution here for any other folks looking for an answer to the same issue. I have a working understanding that will help beginners. When Outputting multiple artifacts you have to use the secondary artifacts: action within the phase of the artifacts. See the example below as you follow along:
artifacts:
base-directory: ${CODEBUILD_SRC_DIR}/
files:
- '**/*'
secondary-artifacts:
ARTIFACT1:
base-directory: DIRECTORY_FOR_ARTIFACT_1/
files:
- FILES_YOU_LOOKING_TO_OUTPUT
name: ARTIFACT_1_NAME_ANYTHING_YOU_WANT
ARTIFACT2:
base-directory: DIRECTORY_FOR_ARTIFACT_2/
files:
- FILES_YOU_LOOKING_TO_OUTPUT
name: ARTIFACT_2_NAME_ANYTHING_YOU_WANT
So this is the basic setup for multiple artifacts, if you wanted to do another artifact you would do a third. Now the key to this setup is mapping the secondary-artifacts headings to the outputs that you defined in your codepipeline output. Recall my pipeline build phase:
stage { name = "Plan"
action {
name = "Terraform-Plan"
category = "Build"
owner = "AWS"
provider = "CodeBuild"
version = "1"
input_artifacts = ["CodeWorkspace"]
output_artifacts = ["CodeSource","TerraformPlanFile"]
The output artifacts MUST be associated with the secondary-artifacts heading as shown below:
secondary-artifacts:
TerraformPlanFile:
base-directory: ${CODEBUILD_SRC_DIR}/
files:
- tfplan_commitid_${CODEBUILD_RESOLVED_SOURCE_VERSION}_pipelineid_${PIPELINE_EXECUTION_ID}
name: TerraformPlanFile
CodeSource:
base-directory: ${CODEBUILD_SRC_DIR}/configurations/${PERMISSION_SETS_DIR}/
files:
- '**/*'
name: CodeSource
Notice how the secondary artifact heading matches the output_artifacts. By ensuring that those heading match with the headings you ensure that the files passed are outputted correctly.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |