diff --git a/.ci/Jenkinsfile b/.ci/Jenkinsfile index d6de0b69..877aadaa 100644 --- a/.ci/Jenkinsfile +++ b/.ci/Jenkinsfile @@ -8,6 +8,8 @@ pipeline { REPO = 'apm-aws-lambda' BASE_DIR = "src/github.com/elastic/${env.REPO}" PIPELINE_LOG_LEVEL = 'INFO' + SUFFIX_ARN_FILE = 'arn-file.md' + ELASTIC_LAYER_NAME = 'apm-lambda-extension' } options { timeout(time: 1, unit: 'HOURS') @@ -77,8 +79,6 @@ pipeline { stage('Test') { steps { withGithubNotify(context: "Test-${GO_VERSION}-${PLATFORM}") { - deleteDir() - unstash 'source' withGoEnv(){ dir("${BASE_DIR}/apm-lambda-extension"){ goTestJUnit(options: '-v ./...', output: 'junit-report.xml') @@ -95,6 +95,75 @@ pipeline { } } } + stage('Release') { + options { skipDefaultCheckout() } + when { + tag pattern: 'v\\d+\\.\\d+\\.\\d+', comparator: 'REGEXP' + } + stages { + stage('BuildPublish') { + failFast false + matrix { + agent {label "${PLATFORM}"} + options { skipDefaultCheckout() } + axes { + axis { + name 'PLATFORM' + values 'arm', 'ubuntu-18 && immutable' + } + } + stages { + stage('Dist') { + steps { + withGithubNotify(context: "Dist-${PLATFORM}") { + deleteDir() + unstash 'source' + withGoEnv(){ + dir("${BASE_DIR}/apm-lambda-extension"){ + cmd(label: 'make dist', script: 'make dist') + } + } + } + } + } + stage('Publish') { + steps { + withGithubNotify(context: "Publish-${PLATFORM}") { + withGoEnv(){ + withAWSEnv(secret: 'secret/observability-team/ci/service-account/apm-aws-lambda', forceInstallation: true, version: '2.4.10') { + dir("${BASE_DIR}/apm-lambda-extension"){ + cmd(label: 'make publish-in-all-aws-regions', script: 'make publish-in-all-aws-regions') + stash(includes: "*${SUFFIX_ARN_FILE}", name: "arn-${isArm() ? 'arm' : 'amd'}") + stash(includes: "bin/${BRANCH_NAME}-*.zip", name: "dist-${isArm() ? 'arm' : 'amd'}") + } + } + } + } + } + post { + always { + archiveArtifacts(allowEmptyArchive: true, artifacts: "${BASE_DIR}/apm-lambda-extension/.regions") + } + } + } + } + } + } + stage('Release Notes') { + steps { + withGhEnv(forceInstallation: true, version: '2.4.0') { + dir("${BASE_DIR}/apm-lambda-extension"){ + unstash "arn-arm" + unstash "arn-amd" + unstash "dist-arm" + unstash "dist-amd" + cmd(label: 'make release-notes', script: 'make release-notes') + } + } + } + } + } + } } post { cleanup { diff --git a/.ci/create-arn-table.sh b/.ci/create-arn-table.sh new file mode 100755 index 00000000..65ccae60 --- /dev/null +++ b/.ci/create-arn-table.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -eo pipefail + +# +# Create the AWS ARN table given the below environment variables: +# +# - AWS_FOLDER - that's the location of the publish-layer-version output for each region +# - ARCHITECTURE - that's the supported architecture. +# - SUFFIX_ARN_FILE - that's the output file. +# + +{ + echo "### ARCH: ${ARCHITECTURE}" + echo '' + echo '|Region|Arch|ARN|' + echo '|------|----|---|' + for f in $(ls "${AWS_FOLDER}"); do + # TODO: identify what field to be used. + echo "|${f}|${ARCHITECTURE}|$(cat $AWS_FOLDER/${f} | jq -r .LayerVersionArn)|" + done + echo '' +} > ${ARCHITECTURE}-${SUFFIX_ARN_FILE} diff --git a/.gitignore b/.gitignore index 66fd13c9..de9071ac 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,7 @@ # Dependency directories (remove the comment below to include it) # vendor/ + +# AWS regions file +.regions +.aws/ diff --git a/apm-lambda-extension/DEVELOPMENT.md b/apm-lambda-extension/DEVELOPMENT.md index 95bd15d7..f2199203 100644 --- a/apm-lambda-extension/DEVELOPMENT.md +++ b/apm-lambda-extension/DEVELOPMENT.md @@ -1,15 +1,11 @@ ## Releasing -Releasing a version of the Lambda Extension is currently a three step manual process. - -1. Tag the Release -2. Create the Build Artifacts -3. Add a Release via the Github UI +### :robot: Automatically -### Tag the Release +Releasing a version of the Lambda Extension requires a tag release. -First, tag the release via your preferred tagging method. Tagging a release (v0.0.2) via the command line looks something like this. +Tag the release via your preferred tagging method. Tagging a release (v0.0.2) via the command line looks something like this. % git clone git@github.com:elastic/apm-aws-lambda.git # ... @@ -21,7 +17,20 @@ First, tag the release via your preferred tagging method. Tagging a release (v0 To github.com:elastic/apm-aws-lambda.git * [new tag] v0.0.2 -> v0.0.2 +This will trigger a build in the CI that will create the Build Artifacts +and a Release in the Github UI. + +### :thumbsdown: Manually + +Releasing a version of the Lambda Extension is currently a three step manual process. + +1. Tag the Release +2. Create the Build Artifacts +3. Add a Release via the Github UI + +### Tag the Release +See the above section regarding tagging a release. ### Create the Build Artifacts Next, create the build artifacts for the release. These are go binaries of the Lambda Extension, built for both Intel and ARM architectures. diff --git a/apm-lambda-extension/Makefile b/apm-lambda-extension/Makefile index ffe2e12a..7744b64b 100644 --- a/apm-lambda-extension/Makefile +++ b/apm-lambda-extension/Makefile @@ -1,31 +1,103 @@ -build: +SHELL = /bin/bash -eo pipefail + +AWS_FOLDER = .aws + ifndef GOARCH GOARCH=amd64 endif + +# Transform GOARCH into the architecture of the extension layer +ifeq ($(GOARCH),amd64) + ARCHITECTURE=x86_64 +else + ARCHITECTURE=arm64 +endif + +export AWS_FOLDER GOARCH ARCHITECTURE + +build: GOOS=linux go build -o bin/extensions/apm-lambda-extension main.go chmod +x bin/extensions/apm-lambda-extension -build-and-publish: -ifndef AWS_DEFAULT_REGION - $(error AWS_DEFAULT_REGION is undefined) -endif +build-and-publish: validate-layer-name validate-aws-default-region ifndef AWS_ACCESS_KEY_ID $(error AWS_ACCESS_KEY_ID is undefined) endif ifndef AWS_SECRET_ACCESS_KEY $(error AWS_SECRET_ACCESS_KEY is undefined) -endif -ifndef ELASTIC_LAYER_NAME - $(error ELASTIC_LAYER_NAME is undefined) endif GOARCH=${GOARCH} make build GOARCH=${GOARCH} make zip - aws lambda publish-layer-version --layer-name "${ELASTIC_LAYER_NAME}" --zip-file "fileb://./bin/extension.zip" + $(MAKE) publish zip: cd bin && rm -f extension.zip || true && zip -r extension.zip extensions && cp extension.zip ${GOARCH}.zip test: go test extension/*.go -v env: -ifndef GOARCH - export GOARCH=amd64 -endif env +dist: validate-branch-name build test zip + @cp ./bin/$(GOARCH).zip bin/$(BRANCH_NAME)-linux-$(GOARCH).zip + +# List all the AWS regions +get-all-aws-regions: + @aws \ + ec2 \ + describe-regions \ + --region us-east-1 \ + --output json \ + --no-cli-pager \ + | jq -r '.Regions[].RegionName' > .regions + +# Publish the given LAYER in all the AWS regions +publish-in-all-aws-regions: validate-layer-name get-all-aws-regions + @mkdir -p $(AWS_FOLDER) + @while read AWS_DEFAULT_REGION; do \ + echo "publish '$(ELASTIC_LAYER_NAME)' in $${AWS_DEFAULT_REGION}"; \ + AWS_DEFAULT_REGION="$${AWS_DEFAULT_REGION}" ELASTIC_LAYER_NAME=$(ELASTIC_LAYER_NAME) $(MAKE) publish > $(AWS_FOLDER)/$${AWS_DEFAULT_REGION}; \ + done <.regions + $(MAKE) create-arn-file + +# Publish the given LAYER in the given AWS region +publish: validate-layer-name validate-aws-default-region + @aws lambda \ + --output json \ + publish-layer-version \ + --layer-name "${ELASTIC_LAYER_NAME}" \ + --description "AWS Lambda Extension Layer for Elastic APM" \ + --license "Apache-2.0" \ + --compatible-architectures "$(ARCHITECTURE)" \ + --zip-file "fileb://./bin/extension.zip" + +# Generate the file with the ARN entries +create-arn-file: validate-suffix-arn-file + @../.ci/create-arn-table.sh + +release-notes: validate-branch-name validate-suffix-arn-file + @gh release list + cat *-$(SUFFIX_ARN_FILE) > $(SUFFIX_ARN_FILE) + @gh \ + release \ + create $(BRANCH_NAME) \ + --title '$(BRANCH_NAME)' \ + --generate-notes \ + --notes-file $(SUFFIX_ARN_FILE) \ + ./bin/$(BRANCH_NAME)*.zip + +validate-branch-name: +ifndef BRANCH_NAME + $(error BRANCH_NAME is undefined) +endif + +validate-suffix-arn-file: +ifndef SUFFIX_ARN_FILE + $(error SUFFIX_ARN_FILE is undefined) +endif + +validate-layer-name: +ifndef ELASTIC_LAYER_NAME + $(error ELASTIC_LAYER_NAME is undefined) +endif + +validate-aws-default-region: +ifndef AWS_DEFAULT_REGION + $(error AWS_DEFAULT_REGION is undefined) +endif