Skip to content

Commit

Permalink
feat(layer): publish SAR v2 via Github actions (#1585)
Browse files Browse the repository at this point in the history
Co-authored-by: Heitor Lessa <[email protected]>
  • Loading branch information
rubenfonseca and heitorlessa authored Oct 13, 2022
1 parent fd7c235 commit be64e4e
Show file tree
Hide file tree
Showing 7 changed files with 268 additions and 43 deletions.
30 changes: 26 additions & 4 deletions .github/workflows/publish_v2_layer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ on:
workflow_dispatch:
inputs:
latest_published_version:
description: "Latest PyPi published version to rebuild latest docs for, e.g. v1.22.0"
default: "v2.0.0"
description: "Latest PyPi published version to rebuild latest docs for, e.g. v2.0.0"
required: true
# workflow_run:
# workflows: ["Publish to PyPi"]
Expand All @@ -23,6 +22,8 @@ jobs:
defaults:
run:
working-directory: ./layer
outputs:
release-tag-version: ${{ steps.release-notes-tag.outputs.RELEASE_TAG_VERSION }}
steps:
- name: checkout
uses: actions/checkout@v3
Expand All @@ -46,11 +47,12 @@ jobs:
poetry export --format requirements.txt --output requirements.txt
pip install -r requirements.txt
- name: Set release notes tag
id: release-notes-tag
run: |
RELEASE_INPUT=${{ inputs.latest_published_version }}
LATEST_TAG=$(git describe --tag --abbrev=0)
RELEASE_TAG_VERSION=${RELEASE_INPUT:-$LATEST_TAG}
echo RELEASE_TAG_VERSION="${RELEASE_TAG_VERSION:1}" >> "$GITHUB_ENV"
echo RELEASE_TAG_VERSION="${RELEASE_TAG_VERSION:1}" >> "$GITHUB_OUTPUT"
- name: Set up QEMU
uses: docker/setup-qemu-action@8b122486cedac8393e77aa9734c3528886e4a1a8 # v2.0.0
# NOTE: we need QEMU to build Layer against a different architecture (e.g., ARM)
Expand All @@ -62,7 +64,7 @@ jobs:
npm install -g [email protected]
cdk --version
- name: CDK build
run: cdk synth --context version="$RELEASE_TAG_VERSION" -o cdk.out
run: cdk synth --context version="${{ steps.release-notes-tag.outputs.RELEASE_TAG_VERSION }}" -o cdk.out
- name: zip output
run: zip -r cdk.out.zip cdk.out
- name: Archive CDK artifacts
Expand Down Expand Up @@ -90,3 +92,23 @@ jobs:
# stage: "PROD"
# artefact-name: "cdk-layer-artefact"
# environment: "layer-prod"

deploy-sar-beta:
needs: build-layer
uses: ./.github/workflows/reusable_deploy_v2_sar.yml
secrets: inherit
with:
stage: "BETA"
artefact-name: "cdk-layer-artefact"
environment: "layer-beta"
package-version: ${{ needs.build-layer.outputs.release-tag-version }}

deploy-sar-prod:
needs: deploy-sar-beta
uses: ./.github/workflows/reusable_deploy_v2_sar.yml
secrets: inherit
with:
stage: "PROD"
artefact-name: "cdk-layer-artefact"
environment: "layer-prod"
package-version: ${{ needs.build-layer.outputs.release-tag-version }}
4 changes: 2 additions & 2 deletions .github/workflows/reusable_deploy_v2_layer_stack.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,6 @@ jobs:
- name: unzip artefact
run: unzip cdk.out.zip
- name: CDK Deploy Layer
run: cdk deploy --app cdk.out --context region=${{ matrix.region }} 'LayerStack' --require-approval never --verbose
run: cdk deploy --app cdk.out --context region=${{ matrix.region }} 'LayerV2Stack' --require-approval never --verbose
- name: CDK Deploy Canary
run: cdk deploy --app cdk.out --context region=${{ matrix.region}} --parameters DeployStage="${{ inputs.stage }}" 'CanaryStack' --require-approval never --verbose
run: cdk deploy --app cdk.out --context region=${{ matrix.region}} --parameters DeployStage="${{ inputs.stage }}" 'CanaryV2Stack' --require-approval never --verbose
139 changes: 139 additions & 0 deletions .github/workflows/reusable_deploy_v2_sar.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
name: Deploy V2 SAR

# SAR deployment process
#
# 1. This workflow starts after the layer artifact is produced on `publish_v2_layer`
# 2. We use the same layer artifact to ensure the SAR app is consistent with the published Lambda Layer
# 3. We publish the SAR for both x86_64 and arm64 (see `matrix` section)
# 4. We use `sam package` and `sam publish` to publish the SAR app
# 5. We remove the previous Canary stack (if present) and deploy a new one to test the SAR App. We retain the Canary in the account for debugging purposes
# 6. Finally the published SAR app is made public on the PROD environment

permissions:
id-token: write
contents: read

env:
NODE_VERSION: 16.12
AWS_REGION: eu-west-1
SAR_NAME: aws-lambda-powertools-python-layer-v2
TEST_STACK_NAME: serverlessrepo-v2-powertools-layer-test-stack

on:
workflow_call:
inputs:
stage:
description: "Deployment stage (BETA, PROD)"
required: true
type: string
artefact-name:
description: "CDK Layer Artefact name to download"
required: true
type: string
package-version:
description: "The version of the package to deploy"
required: true
type: string
environment:
description: "GitHub Environment to use for encrypted secrets"
required: true
type: string

jobs:
deploy-sar-app:
runs-on: ubuntu-latest
environment: ${{ inputs.environment }}
strategy:
matrix:
architecture: ["x86_64", "arm64"]
steps:
- name: Checkout
uses: actions/checkout@v3
- name: AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-region: ${{ env.AWS_REGION }}
role-to-assume: ${{ secrets.AWS_LAYERS_ROLE_ARN }}
- name: AWS credentials SAR role
uses: aws-actions/configure-aws-credentials@v1
id: aws-credentials-sar-role
with:
aws-access-key-id: ${{ env.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ env.AWS_SECRET_ACCESS_KEY }}
aws-session-token: ${{ env.AWS_SESSION_TOKEN }}
role-duration-seconds: 1200
aws-region: ${{ env.AWS_REGION }}
role-to-assume: ${{ secrets.AWS_SAR_V2_ROLE_ARN }}
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: ${{ env.NODE_VERSION }}
- name: Download artifact
uses: actions/download-artifact@v3
with:
name: ${{ inputs.artefact-name }}
- name: Unzip artefact
run: unzip cdk.out.zip
- name: Configure SAR name
run: |
if [[ "${{ inputs.stage }}" == "BETA" ]]; then
SAR_NAME="test-${SAR_NAME}"
fi
echo SAR_NAME="${SAR_NAME}" >> "$GITHUB_ENV"
- name: Adds arm64 suffix to SAR name
if: ${{ matrix.architecture == 'arm64' }}
run: echo SAR_NAME="${SAR_NAME}-arm64" >> "$GITHUB_ENV"
- name: Deploy SAR
run: |
# From the generated LayerStack cdk.out artifact, find the layer asset path for the correct architecture.
# We'll use this as the source directory of our SAR. This way we are re-using the same layer asset for our SAR.
asset=$(jq -jc '.Resources[] | select(.Properties.CompatibleArchitectures == ["${{ matrix.architecture }}"]) | .Metadata."aws:asset:path"' cdk.out/LayerV2Stack.template.json)
# fill in the SAR SAM template
sed -e "s|<VERSION>|${{ inputs.package-version }}|g" -e "s/<SAR_APP_NAME>/${{ env.SAR_NAME }}/g" -e "s|<LAYER_CONTENT_PATH>|./cdk.out/$asset|g" layer/sar/template.txt > template.yml
# SAR needs a README and a LICENSE, so just copy the ones from the repo
cp README.md LICENSE "./cdk.out/$asset/"
# Package the SAR to our SAR S3 bucket, and publish it
sam package --template-file template.yml --output-template-file packaged.yml --s3-bucket ${{ secrets.AWS_SAR_S3_BUCKET }}
sam publish --template packaged.yml --region "$AWS_REGION"
- name: Deploy BETA canary
if: ${{ inputs.stage == 'BETA' }}
run: |
if [[ "${{ matrix.architecture }}" == "arm64" ]]; then
TEST_STACK_NAME="${TEST_STACK_NAME}-arm64"
fi
echo "Check if stack does not exist"
stack_exists=$(aws cloudformation list-stacks --query "StackSummaries[?(StackName == '$TEST_STACK_NAME' && StackStatus == 'CREATE_COMPLETE')].{StackId:StackId, StackName:StackName, CreationTime:CreationTime, StackStatus:StackStatus}" --output text)
if [[ -n "$stack_exists" ]] ; then
echo "Found test deployment stack, removing..."
aws cloudformation delete-stack --stack-name "$TEST_STACK_NAME"
aws cloudformation wait stack-delete-complete --stack-name "$TEST_STACK_NAME"
fi
echo "Creating canary stack"
echo "Stack name: $TEST_STACK_NAME"
aws serverlessrepo create-cloud-formation-change-set --application-id arn:aws:serverlessrepo:${{ env.AWS_REGION }}:${{ steps.aws-credentials-sar-role.outputs.aws-account-id }}:applications/${{ env.SAR_NAME }} --stack-name "${TEST_STACK_NAME/serverlessrepo-/}" --capabilities CAPABILITY_NAMED_IAM
CHANGE_SET_ID=$(aws cloudformation list-change-sets --stack-name "$TEST_STACK_NAME" --query 'Summaries[*].ChangeSetId' --output text)
aws cloudformation wait change-set-create-complete --change-set-name "$CHANGE_SET_ID"
aws cloudformation execute-change-set --change-set-name "$CHANGE_SET_ID"
aws cloudformation wait stack-create-complete --stack-name "$TEST_STACK_NAME"
echo "Waiting until stack deployment completes..."
echo "Exit with error if stack is not in CREATE_COMPLETE"
stack_exists=$(aws cloudformation list-stacks --query "StackSummaries[?(StackName == '$TEST_STACK_NAME' && StackStatus == 'CREATE_COMPLETE')].{StackId:StackId, StackName:StackName, CreationTime:CreationTime, StackStatus:StackStatus}")
if [[ -z "$stack_exists" ]] ; then
echo "Could find successful deployment, exit error..."
exit 1
fi
echo "Deployment successful"
- name: Publish SAR
if: ${{ inputs.stage == 'PROD' }}
run: |
# wait until SAR registers the app, otherwise it fails to make it public
sleep 15
echo "Make SAR app public"
aws serverlessrepo put-application-policy --application-id arn:aws:serverlessrepo:${{ env.AWS_REGION }}:${{ steps.aws-credentials-sar-role.outputs.aws-account-id }}:applications/${{ env.SAR_NAME }} --statements Principals='*',Actions=Deploy
4 changes: 2 additions & 2 deletions layer/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@

LayerStack(
app,
"LayerStack",
"LayerV2Stack",
powertools_version=POWERTOOLS_VERSION,
ssm_paramter_layer_arn=SSM_PARAM_LAYER_ARN,
ssm_parameter_layer_arm64_arn=SSM_PARAM_LAYER_ARM64_ARN,
)

CanaryStack(
app,
"CanaryStack",
"CanaryV2Stack",
powertools_version=POWERTOOLS_VERSION,
ssm_paramter_layer_arn=SSM_PARAM_LAYER_ARN,
ssm_parameter_layer_arm64_arn=SSM_PARAM_LAYER_ARM64_ARN,
Expand Down
Loading

0 comments on commit be64e4e

Please sign in to comment.