Skip to content

Commit

Permalink
feat(layers): add support for publishing v2 layer (#1558)
Browse files Browse the repository at this point in the history
Co-authored-by: Heitor Lessa <lessa@amazon.com>
  • Loading branch information
rubenfonseca and heitorlessa committed Oct 14, 2022
1 parent b0bc888 commit bbc1c14
Show file tree
Hide file tree
Showing 15 changed files with 489 additions and 164 deletions.
79 changes: 76 additions & 3 deletions .github/workflows/publish_v2_layer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,84 @@ on:
inputs:
latest_published_version:
description: "Latest PyPi published version to rebuild latest docs for, e.g. v1.22.0"
default: "v2.0.0"
required: true
# workflow_run:
# workflows: ["Publish to PyPi"]
# types:
# - completed

jobs:
dummy:
build-layer:
runs-on: ubuntu-latest
if: ${{ (github.event.workflow_run.conclusion == 'success') || (github.event_name == 'workflow_dispatch') }}
defaults:
run:
working-directory: ./layer
steps:
- name: Hello world
run: echo "hello world"
- name: checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Install poetry
run: pipx install poetry
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: "16.12"
- name: Setup python
uses: actions/setup-python@v4
with:
python-version: "3.9"
cache: "pip"
- name: Resolve and install project dependencies
# CDK spawns system python when compiling stack
# therefore it ignores both activated virtual env and cached interpreter by GH
run: |
poetry export --format requirements.txt --output requirements.txt
pip install -r requirements.txt
- name: Set 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"
- 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)
- name: Set up Docker Buildx
id: builder
uses: docker/setup-buildx-action@dc7b9719a96d48369863986a06765841d7ea23f6 # v2.0.0
- name: install cdk and deps
run: |
npm install -g aws-cdk@2.44.0
cdk --version
- name: CDK build
run: cdk synth --context version="$RELEASE_TAG_VERSION" -o cdk.out
- name: zip output
run: zip -r cdk.out.zip cdk.out
- name: Archive CDK artifacts
uses: actions/upload-artifact@v3
with:
name: cdk-layer-artefact
path: layer/cdk.out.zip

deploy-beta:
needs:
- build-layer
uses: ./.github/workflows/reusable_deploy_v2_layer_stack.yml
secrets: inherit
with:
stage: "BETA"
artefact-name: "cdk-layer-artefact"
environment: "layer-beta"

# deploy-prod:
# needs:
# - deploy-beta
# uses: ./.github/workflows/reusable_deploy_layer_stack.yml
# secrets: inherit
# with:
# stage: "PROD"
# artefact-name: "cdk-layer-artefact"
# environment: "layer-prod"
102 changes: 102 additions & 0 deletions .github/workflows/reusable_deploy_v2_layer_stack.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
name: Deploy CDK Layer v2 stack

permissions:
id-token: write
contents: read

env:
CDK_VERSION: 2.44.0

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
environment:
description: "GitHub Environment to use for encrypted secrets"
required: true
type: string

jobs:
deploy-cdk-stack:
runs-on: ubuntu-latest
environment: ${{ inputs.environment }}
defaults:
run:
working-directory: ./layer
strategy:
fail-fast: false
matrix:
region:
[
"af-south-1",
"eu-central-1",
"us-east-1",
"us-east-2",
"us-west-1",
"us-west-2",
"ap-east-1",
"ap-south-1",
"ap-northeast-1",
"ap-northeast-2",
"ap-southeast-1",
"ap-southeast-2",
"ca-central-1",
"eu-west-1",
"eu-west-2",
"eu-west-3",
"eu-south-1",
"eu-north-1",
"sa-east-1",
"ap-southeast-3",
"ap-northeast-3",
"me-south-1",
]
steps:
- name: checkout
uses: actions/checkout@v3
- name: Install poetry
run: pipx install poetry
- name: aws credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-region: ${{ matrix.region }}
role-to-assume: ${{ secrets.AWS_LAYERS_ROLE_ARN }}
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: "16.12"
- name: Setup python
uses: actions/setup-python@v4
with:
python-version: "3.9"
cache: "pip"
- name: Resolve and install project dependencies
# CDK spawns system python when compiling stack
# therefore it ignores both activated virtual env and cached interpreter by GH
run: |
poetry export --format requirements.txt --output requirements.txt
pip install -r requirements.txt
- name: install cdk and deps
run: |
npm install -g "aws-cdk@$CDK_VERSION"
cdk --version
- name: install deps
run: poetry install
- name: Download artifact
uses: actions/download-artifact@v3
with:
name: ${{ inputs.artefact-name }}
path: layer
- 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
- name: CDK Deploy Canary
run: cdk deploy --app cdk.out --context region=${{ matrix.region}} --parameters DeployStage="${{ inputs.stage }}" 'CanaryStack' --require-approval never --verbose
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ target:

dev:
pip install --upgrade pip pre-commit poetry
poetry install --extras "pydantic"
poetry install --extras "all"
pre-commit install

dev-gitpod:
pip install --upgrade pip poetry
poetry install --extras "pydantic"
poetry install --extras "all"
pre-commit install

format:
Expand Down
5 changes: 4 additions & 1 deletion layer/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
app = cdk.App()

POWERTOOLS_VERSION: str = app.node.try_get_context("version")
SSM_PARAM_LAYER_ARN: str = "/layers/powertools-layer-arn"
SSM_PARAM_LAYER_ARN: str = "/layers/powertools-layer-v2-arn"
SSM_PARAM_LAYER_ARM64_ARN: str = "/layers/powertools-layer-v2-arm64-arn"

if not POWERTOOLS_VERSION:
raise ValueError(
Expand All @@ -21,13 +22,15 @@
"LayerStack",
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",
powertools_version=POWERTOOLS_VERSION,
ssm_paramter_layer_arn=SSM_PARAM_LAYER_ARN,
ssm_parameter_layer_arm64_arn=SSM_PARAM_LAYER_ARM64_ARN,
)

app.synth()
46 changes: 37 additions & 9 deletions layer/layer/canary/app.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import datetime
import json
import os
import platform
from importlib.metadata import version

import boto3
from pydantic import EmailStr

from aws_lambda_powertools import Logger, Metrics, Tracer
from aws_lambda_powertools.utilities.parser import BaseModel, envelopes, event_parser
from aws_lambda_powertools.utilities.typing import LambdaContext
from aws_lambda_powertools.utilities.validation import validator

logger = Logger(service="version-track")
tracer = Tracer()
tracer = Tracer() # this checks for aws-xray-sdk presence
metrics = Metrics(namespace="powertools-layer-canary", service="PowertoolsLayerCanary")

layer_arn = os.getenv("POWERTOOLS_LAYER_ARN")
Expand All @@ -17,6 +22,26 @@
event_bus_arn = os.getenv("VERSION_TRACKING_EVENT_BUS_ARN")


# Model to check parser imports correctly, tests for pydantic and email-validator
class OrderItem(BaseModel):
order_id: int
quantity: int
description: str
email: EmailStr


# Tests for jmespath presence
@event_parser(model=OrderItem, envelope=envelopes.EventBridgeEnvelope)
def envelope_handler(event: OrderItem, context: LambdaContext):
assert event.order_id != 1


# Tests for fastjsonschema presence
@validator(inbound_schema={}, envelope="detail")
def validator_handler(event, context: LambdaContext):
pass


def handler(event):
logger.info("Running checks")
check_envs()
Expand All @@ -42,9 +67,7 @@ def on_create(event):


def check_envs():
logger.info(
'Checking required envs ["POWERTOOLS_LAYER_ARN", "AWS_REGION", "STAGE"]'
)
logger.info('Checking required envs ["POWERTOOLS_LAYER_ARN", "AWS_REGION", "STAGE"]')
if not layer_arn:
raise ValueError("POWERTOOLS_LAYER_ARN is not set. Aborting...")
if not powertools_version:
Expand All @@ -66,20 +89,19 @@ def verify_powertools_version() -> None:
current_version = version("aws_lambda_powertools")
if powertools_version != current_version:
raise ValueError(
f'Expected powertoosl version is "{powertools_version}", but layer contains version "{current_version}"'
f'Expected Powertools version is "{powertools_version}", but layer contains version "{current_version}"'
)
logger.info(f"Current Powertools version is: {current_version}")
logger.info(f"Current Powertools version is: {current_version} [{_get_architecture()}]")


def send_notification():
"""
sends an event to version tracking event bridge
"""
if stage != "PROD":
logger.info(
"Not sending notification to event bus, because this is not the PROD stage"
)
logger.info("Not sending notification to event bus, because this is not the PROD stage")
return

event = {
"Time": datetime.datetime.now(),
"Source": "powertools.layer.canary",
Expand All @@ -90,6 +112,7 @@ def send_notification():
"version": powertools_version,
"region": os.environ["AWS_REGION"],
"layerArn": layer_arn,
"architecture": _get_architecture(),
}
),
}
Expand All @@ -102,3 +125,8 @@ def send_notification():
if resp["FailedEntryCount"] != 0:
logger.error(resp)
raise ValueError("Failed to send deployment notification to version tracking")


def _get_architecture() -> str:
"""Returns aarch64, x86_64"""
return platform.uname()[4]
Loading

0 comments on commit bbc1c14

Please sign in to comment.