Skip to content

patch: Update actions/checkout digest to 8e8c483 #137

patch: Update actions/checkout digest to 8e8c483

patch: Update actions/checkout digest to 8e8c483 #137

Workflow file for this run

---
# https://github.com/balena-os/balena-yocto-scripts/blob/master/.github/workflows/yocto-build-deploy.yml
# https://github.com/balena-os/balena-yocto-scripts/blob/master/automation/entry_scripts/balena-generate-ami.sh
name: Register balenaOS AWS/EC2 AMI
on:
pull_request:
branches:
- master
- main
workflow_dispatch:
permissions:
contents: read
id-token: write # AWS GitHub OIDC required: write
concurrency:
group: ${{ github.workflow }}-${{ github.event.number || github.ref }}
# cancel jobs in progress for updated PRs, but not merge or tag events
cancel-in-progress: ${{ github.event.action == 'synchronize' }}
env:
AWS_DEFAULT_REGION: ${{ vars.AWS_REGION || 'us-east-1' }}
AWS_IAM_ROLE: ${{ vars.AWS_IAM_ROLE }}
AWS_REGION: ${{ vars.AWS_REGION || 'us-east-1' }}
AWS_SECURITY_GROUP_ID: ${{ vars.AWS_SECURITY_GROUP_ID }}
AWS_SUBNET_IDS: ${{ vars.AWS_SUBNET_IDS }}
BALENA_TEST_ORG: ${{ vars.BALENA_TEST_ORG || 'belodetek' }}
VMIMPORT_S3_BUCKET: ${{ vars.VMIMPORT_S3_BUCKET }}
jobs:
import-vm:
defaults:
run:
shell: bash --noprofile --norc -eo pipefail -x {0}
runs-on: ubuntu-latest
timeout-minutes: 45
strategy:
fail-fast: false
matrix:
target:
- generic-amd64
- generic-aarch64
include:
- target: generic-amd64
# renovate: datasource=github-releases depName=balena-os/balena-generic
BALENA_OS_VERSION: v6.8.0
balena_app_name: ${{ vars.BALENA_APP_NAME_AMD64 || 'bh.cr/balena_os/cloud-config-amd64' }}
balena_app_commit: ${{ vars.BALENA_APP_COMMIT_AMD64 || '461031537d2655560b9bc29ea2e1405c' }}
development_mode: true
ec2_instance_type: c7a.medium
aws_ec2_metadata_v2: optional # IMDSv1
- target: generic-aarch64
# renovate: datasource=github-releases depName=balena-os/balena-generic
BALENA_OS_VERSION: v6.8.0
balena_app_name: ${{ vars.BALENA_APP_NAME_AARCH64 || 'bh.cr/balena_os/cloud-config-aarch64' }}
balena_app_commit: ${{ vars.BALENA_APP_COMMIT_AARCH64 || 'cfe1502b178daf06475c939e16473b9c' }}
development_mode: true
ec2_instance_type: m8g.medium
aws_ec2_metadata_v2: required # IMDSv2
steps:
# https://github.com/unfor19/install-aws-cli-action
- uses: unfor19/install-aws-cli-action@f5b46b7f32cf5e7ebd652656c5036bf83dd1e60c # v1
- uses: aws-actions/configure-aws-credentials@259eac73d3898af00550394d11116c4a94c9b1dc
with:
aws-region: ${{ vars.AWS_REGION || 'us-east-1' }}
role-session-name: github-${{ github.job }}-${{ github.run_id }}-${{ github.run_attempt }}
# balena-io/environments-bases: aws/balenacloud/ephemeral-tests/balena-tests-iam.yml
role-to-assume: ${{ vars.AWS_IAM_ROLE }}
mask-aws-account-id: false
- name: Set AWS/EC2/AMI image architecture string from balena device type
id: ami
run: |
if [[ '${{ matrix.target }}' =~ "amd64" ]]; then
echo 'arch=x86_64' >>"${GITHUB_OUTPUT}"
elif [[ '${{ matrix.target }}' =~ "aarch64" ]]; then
echo 'arch=arm64' >>"${GITHUB_OUTPUT}"
else
exit 1
fi
echo "name=balena-os-${{ matrix.BALENA_OS_VERSION }}-${{ matrix.target }}" \
| sed 's/+/-/g' >>"${GITHUB_OUTPUT}"
- name: Check if the AWS/EC2 AMI already exists for this version of balenaOS
id: check
env:
AMI_NAME: ${{ steps.ami.outputs.name }}
run: |
[ -z "$AMI_NAME" ] && exit 1
existing_image_id=$(aws ec2 describe-images --output text \
--filters "Name=name,Values=${AMI_NAME}" \
--query 'Images[*].[ImageId]')
if [ -n "$existing_image_id" ]; then
echo 'skip=true' >>"${GITHUB_OUTPUT}"
fi
# https://github.com/balena-io-examples/setup-balena-action
- uses: balena-io-examples/setup-balena-action@7bd1b61bd4165bac817cf0ba19ed53a25e8c66ca # v0.0.61
if: steps.check.outputs.skip != 'true'
env:
# renovate: datasource=github-releases depName=balena-io/balena-cli
BALENA_CLI_VERSION: v23.2.0
with:
cli-version: ${{ env.BALENA_CLI_VERSION }}
balena-token: ${{ secrets.BALENA_API_KEY }}
- uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
id: cache
if: steps.check.outputs.skip != 'true'
continue-on-error: true
with:
key: ${{ runner.os }}-balena-os-${{ matrix.target }}-image-${{ matrix.BALENA_OS_VERSION }}
path: balena.img
- name: download balena.img
id: download
if: steps.cache.outputs.cache-hit != 'true' && steps.check.outputs.skip != 'true'
run: |
balena os download ${{ matrix.target }} -o balena.img --version ${{ matrix.BALENA_OS_VERSION }}
- uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
if: always() && steps.download.outcome == 'success' && steps.check.outputs.skip != 'true'
with:
path: balena.img
key: ${{ runner.os }}-balena-os-${{ matrix.target }}-image-${{ matrix.BALENA_OS_VERSION }}
- uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
id: preloaded
if: steps.check.outputs.skip != 'true'
continue-on-error: true
with:
key: ${{ runner.os }}-balena-os-${{ matrix.target }}-preload-${{ matrix.BALENA_OS_VERSION }}-${{ matrix.balena_app_commit }}
path: balena.img
- name: Create temporary fleet to preload the public app
id: preload-fleet
if: steps.preloaded.outputs.cache-hit != 'true' && steps.check.outputs.skip != 'true'
run: |
user="$(balena whoami | grep USERNAME | awk '{print $2}')"
tmpfleet="tmpload-$(( RANDOM ))"
balena fleet create "${tmpfleet}" --type ${{ matrix.target }} --organization "${user}"
docker pull ${{ matrix.balena_app_name }}/${{ matrix.balena_app_commit }}
tmpush=$(mktemp -d)
pushd "${tmpush}"
cat <<EOF> Dockerfile
FROM ${{ matrix.balena_app_name }}/${{ matrix.balena_app_commit }}
EOF
balena push "${tmpfleet}"
popd
rm -rf "${tmpush}"
echo "name=${user}/${tmpfleet}" >>"${GITHUB_OUTPUT}"
- name: Pre-load cloud-config app to handle cloud provider metadata interfaces
id: preload
if: steps.preloaded.outputs.cache-hit != 'true' && steps.check.outputs.skip != 'true'
env:
PRELOAD_FLEET: ${{ steps.preload-fleet.outputs.name }}
run: |
balena preload --debug --pin-device-to-release balena.img \
--fleet "${PRELOAD_FLEET}" \
--commit current
- uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
if: always() && steps.preload.outcome == 'success' && steps.check.outputs.skip != 'true'
with:
path: balena.img
key: ${{ runner.os }}-balena-os-${{ matrix.target }}-preload-${{ matrix.BALENA_OS_VERSION }}-${{ matrix.balena_app_commit }}
- name: Copy balenaOS image to AWS/S3 for import
id: s3
if: steps.check.outputs.skip != 'true'
env:
VMIMPORT_S3_BUCKET: ${{ env.VMIMPORT_S3_BUCKET }}
run: |
s3_key="balena-${RANDOM}.tmp"
s3_url="s3://${VMIMPORT_S3_BUCKET}/preloaded-images/${s3_key}"
aws s3 cp --no-progress balena.img "${s3_url}"
echo "key=${s3_key}" >>"${GITHUB_OUTPUT}"
echo "url=${s3_url}" >>"${GITHUB_OUTPUT}"
- name: Create AWS/EC2 EBS snapshot from balenaOS image
id: snapshot
if: steps.check.outputs.skip != 'true'
env:
AMI_NAME: ${{ steps.ami.outputs.name }}
VMIMPORT_S3_BUCKET: ${{ env.VMIMPORT_S3_BUCKET }}
S3_KEY: ${{ steps.s3.outputs.key }}
run: |
[ -z "$AMI_NAME" ] && exit 1
import_task_id=$(aws ec2 import-snapshot \
--description "snapshot-${AMI_NAME}" \
--disk-container "Description=balena-os,Format=RAW,UserBucket={S3Bucket=${VMIMPORT_S3_BUCKET},S3Key=preloaded-images/${S3_KEY}}" \
| jq -r .ImportTaskId)
while true; do
response="$(aws ec2 describe-import-snapshot-tasks --import-task-ids "${import_task_id}")"
status_message="$(echo "${response}" | jq -r ".ImportSnapshotTasks[].SnapshotTaskDetail.StatusMessage")"
progress="$(echo "${response}" | jq -r ".ImportSnapshotTasks[].SnapshotTaskDetail.Progress")"
status="$(echo "${response}" | jq -r ".ImportSnapshotTasks[].SnapshotTaskDetail.Status")"
echo "::info::${status_message}: ${progress}% (${status})"
if [[ "$status" =~ "completed" ]]; then
break
fi
if [[ "$status" =~ "deleting" ]]; then
echo "::error::${status_message}"
exit 1
fi
sleep $(( (RANDOM % 30) + 30))s
done
snapshot_id=$(aws ec2 describe-import-snapshot-tasks --import-task-ids "${import_task_id}" \
| jq -r '.ImportSnapshotTasks[].SnapshotTaskDetail.SnapshotId')
echo "id=${snapshot_id}" >>"${GITHUB_OUTPUT}"
- name: Create AWS/EC2 AMI from snapshot
id: image
if: steps.check.outputs.skip != 'true'
env:
AMI_ARCHITECTURE: ${{ steps.ami.outputs.arch }}
AMI_BOOT_MODE: uefi
AMI_EBS_DELETE_ON_TERMINATION: true
AMI_EBS_VOLUME_SIZE: 8
AMI_EBS_VOLUME_TYPE: gp3
AMI_NAME: ${{ steps.ami.outputs.name }}
AMI_ROOT_DEVICE_NAME: /dev/sda1
AMI_SNAPSHOT_ID: ${{ steps.snapshot.outputs.id }}
BALENA_API_KEY: ${{ secrets.BALENA_API_KEY }}
run: |
[ -z "$AMI_NAME" ] && exit 1
existing_image_id=$(aws ec2 describe-images --output text \
--filters "Name=name,Values=${AMI_NAME}" \
--query 'Images[*].[ImageId]')
if [ -n "$existing_image_id" ]; then
exit 1
fi
# only supported on x86_64
if [ "${AMI_ARCHITECTURE}" = "x86_64" ]; then
tpm_opts="--tpm-support v2.0"
fi
block_device_mappings="DeviceName=${AMI_ROOT_DEVICE_NAME},Ebs={
DeleteOnTermination=${AMI_EBS_DELETE_ON_TERMINATION},
SnapshotId=${AMI_SNAPSHOT_ID},
VolumeSize=${AMI_EBS_VOLUME_SIZE},
VolumeType=${AMI_EBS_VOLUME_TYPE}
}"
# shellcheck disable=SC2086
image_id=$(aws ec2 register-image \
--name "${AMI_NAME}" \
--architecture "${AMI_ARCHITECTURE}" \
--virtualization-type hvm \
${tpm_opts} \
--ena-support \
--root-device-name "${AMI_ROOT_DEVICE_NAME}" \
--boot-mode "${AMI_BOOT_MODE}" \
--block-device-mappings "${block_device_mappings}" | jq -r .ImageId)
[ -z "${image_id}" ] && exit 1
device_type='${{ matrix.target }}'
balena_os_version="$(printf '${{ matrix.BALENA_OS_VERSION }}' | jq -sRr '@uri')"
changelog_link="$(echo '${{ matrix.BALENA_OS_VERSION }}' | sed 's/\.//g' | sed 's/+//g')"
version_string="$(echo '${{ matrix.BALENA_OS_VERSION }}' | sed 's/^v//' | cut -d'+' -f1)"
semver_build="$(echo '${{ matrix.BALENA_OS_VERSION }}' | sed 's/^v//' | awk -F'+' '{print $2}')"
semver_major=$(echo "${version_string}" | cut -d'.' -f1)
semver_minor=$(echo "${version_string}" | cut -d'.' -f2)
semver_patch=$(echo "${version_string}" | cut -d'.' -f3)
revision="${semver_build/rev//}"
revision="${revision:-0}"
response="$(curl -sf "https://api.balena-cloud.com/v7/application?\$select=is_for__device_type&\$expand=application_tag(\$select=tag_key,value),is_for__device_type(\$select=slug),owns__release(\$select=id,known_issue_list,raw_version,variant,phase;\$expand=release_tag(\$select=tag_key,value),belongs_to__application(\$select=id);\$filter=(semver_major%20eq%20${semver_major})%20and%20(semver_minor%20eq%20${semver_minor})%20and%20(semver_patch%20eq%20${semver_patch})%20and%20(semver_prerelease%20eq%20%27%27)%20and%20(semver_build%20eq%20%27${semver_build}%27)%20and%20(revision%20eq%20${revision})%20and%20(variant%20in%20(%27%27,%20%27prod%27)))&\$filter=(is_host%20eq%20true)%20and%20(is_for__device_type/any(dt:dt/slug%20in%20(%27${device_type}%27)))" \
-H "authorization: Bearer ${BALENA_API_KEY}")"
hostapp_id="$(echo "${response}" | jq -re .d[].owns__release[].belongs_to__application[].id)"
release_id="$(echo "${response}" | jq -re .d[].owns__release[].id)"
hostapp_release_url="https://dashboard.balena-cloud.com/apps/${hostapp_id}/releases/${release_id}/summary"
changelog_url="https://github.com/balena-os/balena-generic/blob/${balena_os_version}/CHANGELOG.md#${changelog_link}"
aws ec2 create-tags --resources "${image_id}" \
--tags Key=Name,Value="${AMI_NAME}" \
Key=publisher,Value="belodetek" \
Key=email,Value="[email protected]" \
Key=github,Value="https://github.com/belodetek" \
Key=github-release,Value="https://github.com/balena-os/balena-generic/releases/tag/${balena_os_version}" \
Key=github-tag,Value="https://github.com/balena-os/balena-generic/tree/${balena_os_version}" \
Key=meta-changelog,Value='https://github.com/balena-os/meta-balena/blob/master/CHANGELOG.md' \
Key=changelog,Value="${changelog_url}" \
Key=hostapp-release,Value="${hostapp_release_url}" \
Key=license,Value='https://www.apache.org/licenses/LICENSE-2.0'
echo "id=${image_id}" >>"${GITHUB_OUTPUT}"
- name: generate SSH private key
if: steps.check.outputs.skip != 'true'
id: generate-key-pair
env:
AWS_DEFAULT_REGION: ${{ env.AWS_DEFAULT_REGION }}
run: |
key_name="${{ matrix.target }}-${GITHUB_RUN_ID}-${GITHUB_RUN_NUMBER}-${GITHUB_RUN_ATTEMPT}"
echo "key_name=${key_name}" >>"${GITHUB_OUTPUT}"
set +x
private_key_material="$(aws ec2 create-key-pair \
--key-name "${key_name}" | jq -r .KeyMaterial)"
public_key="$(aws ec2 describe-key-pairs --include-public-key \
--key-name "${key_name}" | jq -re .KeyPairs[].PublicKey)"
# https://stackoverflow.com/a/70384422/1559300
# https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#masking-a-value-in-log
while read -r line; do
echo "::add-mask::${line}"
done <<< "${private_key_material}"
ssh_private_key="$(cat << EOF
${private_key_material}
EOF
)"
# shellcheck disable=SC2129
echo "ssh_private_key<<EOF" >>"${GITHUB_OUTPUT}"
{ echo "${ssh_private_key}"; echo "EOF"; } >>"${GITHUB_OUTPUT}"
echo "ssh_public_key=${public_key}" >> "${GITHUB_OUTPUT}"
# https://github.com/webfactory/ssh-agent
- uses: webfactory/ssh-agent@a6f90b1f127823b31d4d4a8d96047790581349bd # v0.9.1
if: steps.check.outputs.skip != 'true'
with:
ssh-private-key: ${{ steps.generate-key-pair.outputs.ssh_private_key }}
- name: Crete balenaCloud fleet to test the image
id: test-fleet
if: steps.check.outputs.skip != 'true'
env:
BALENA_TEST_ORG: ${{ env.BALENA_TEST_ORG }}
SSH_PRIVATE_KEY: ${{ steps.generate-key-pair.outputs.ssh_private_key }}
SSH_PUBLIC_KEY: ${{ steps.generate-key-pair.outputs.ssh_public_key }}
run: |
ami_test_fleet=$(openssl rand -hex 4)
>&2 balena fleet create "${ami_test_fleet}" \
--organization "${BALENA_TEST_ORG}" \
--type '${{ matrix.target }}'
echo "${SSH_PRIVATE_KEY}" >"${HOME}/.ssh/id_rsa"
echo "${SSH_PUBLIC_KEY}" >"${HOME}/.ssh/id_rsa.pub"
for key in $(balena ssh-key list | grep -v ID | awk '{print $1}'); do
fp=$(balena ssh-key "${key}" | tail -n 1 | ssh-keygen -E md5 -lf /dev/stdin | awk '{print $2}')
if [[ $fp =~ $(ssh-keygen -E md5 -lf "${HOME}/.ssh/id_rsa" | awk '{print $2}') ]]; then
match="${key}"
break
fi
done
if [[ -z ${match:-} ]]; then
balena ssh-key add "${ami_test_fleet}" "${HOME}/.ssh/id_rsa.pub"
else
balena ssh-key "${match}"
fi
uuid="$(balena device register "${BALENA_TEST_ORG}/${ami_test_fleet}" | awk '{print $4}')"
echo "uuid=${uuid}" >>"${GITHUB_OUTPUT}"
if [ '${{ matrix.development_mode }}' = true ]; then
_dev_mode="--dev";
else
_dev_mode="";
fi
config_json=$(mktemp)
echo "config_json=${config_json}" >>"${GITHUB_OUTPUT}"
>&2 balena config generate \
--network ethernet \
--version '${{ matrix.BALENA_OS_VERSION }}' \
--device "${uuid}" \
--appUpdatePollInterval 5 \
--output "${config_json}" \
${_dev_mode}
if [ ! -f "${config_json}" ]; then
exit 1
else
new_uuid=$(jq -r '.uuid' "${config_json}")
if [ "${new_uuid}" != "${uuid}" ]; then
exit 1
fi
fi
tmpconf="$(mktemp)"
cat <"${config_json}" | jq -re --arg pub_key "${SSH_PUBLIC_KEY}" '.os.sshKeys += [$pub_key]' >"${tmpconf}"
cat <"${tmpconf}" | jq -re >"${config_json}"
rm -f "${tmpconf}"
echo "name=${BALENA_TEST_ORG}/${ami_test_fleet}" >>"${GITHUB_OUTPUT}"
- name: Test AWS/EC2 AMI image
id: test
if: steps.check.outputs.skip != 'true'
env:
AMI_NAME: ${{ steps.ami.outputs.name }}
AWS_EC2_KEY_NAME: ${{ steps.generate-key-pair.outputs.key_name }}
AWS_EC2_METADATA_V2: ${{ matrix.aws_ec2_metadata_v2 }}
AWS_SECURITY_GROUP_ID: ${{ env.AWS_SECURITY_GROUP_ID }}
AWS_SUBNET_IDS: ${{ env.AWS_SUBNET_IDS }}
CONFIG_JSON: ${{ steps.test-fleet.outputs.config_json }}
UUID: ${{ steps.test-fleet.outputs.uuid }}
run: |
[ -z "$AMI_NAME" ] && exit 1
_ami_image_id=$(aws ec2 describe-images --output text \
--filters "Name=name,Values=${AMI_NAME}" \
--query 'Images[*].[ImageId]')
if [ -z "$_ami_image_id" ]; then
exit 1
fi
echo "ami_image_id=${_ami_image_id}" >>"${GITHUB_OUTPUT}"
for subnet_id in ${AWS_SUBNET_IDS}; do
_instance_id=$(aws ec2 run-instances --image-id "${_ami_image_id}" --count 1 \
--instance-type '${{ matrix.ec2_instance_type }}' \
--tag-specifications \
"ResourceType=instance,Tags=[{Key=Name,Value=test-${AMI_NAME}}]" \
"ResourceType=volume,Tags=[{Key=Name,Value=test-${AMI_NAME}}]" \
--subnet-id "${subnet_id}" \
--security-group-ids "${AWS_SECURITY_GROUP_ID}" \
--key-name "${AWS_EC2_KEY_NAME}" \
--metadata-options "HttpEndpoint=enabled,HttpTokens=${AWS_EC2_METADATA_V2}" \
--user-data "file://${CONFIG_JSON}" | jq -r '.Instances[0].InstanceId' || true)
[ -n "$_instance_id" ] && break
done
if [ -z "${_instance_id}" ]; then
exit 1
fi
echo "instance_id=${_instance_id}" >>"${GITHUB_OUTPUT}"
aws ec2 wait instance-running --instance-ids "${_instance_id}"
aws ec2 wait instance-status-ok --instance-ids "${_instance_id}"
ssh-add -l
# FIXME: switch to ssh-uuid
until echo 'balena ps -q -f name=balena_supervisor | xargs balena inspect \
| jq -r ".[] | select(.State.Health.Status!=null).Name + \":\" + .State.Health.Status"; exit' \
| balena device ssh "${UUID}" | grep -q ":healthy"; do
echo "::info::Waiting for balena-supervisor..."
sleep $(( (RANDOM % 30) + 30 ))s
done
- name: Make AMI public
if: steps.test.outcome == 'success' && steps.check.outputs.skip != 'true'
env:
AMI_ARCHITECTURE: ${{ steps.ami.outputs.arch }}
AMI_IMAGE_ID: ${{ steps.test.outputs.ami_image_id }}
AWS_DEFAULT_REGION: ${{ env.AWS_DEFAULT_REGION }}
AMI_NAME: ${{ steps.ami.outputs.name }}
# https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ami-quotas.html
AWS_AMI_PUBLIC_QUOTA: 2
run: |
[ -z "$AMI_NAME" ] && exit 0
_ami_public_images_count=$(aws ec2 describe-images \
--owners "self" \
--filters "Name=name,Values=${AMI_NAME%%-*}-*" \
"Name=architecture,Values=${AMI_ARCHITECTURE}" \
"Name=is-public,Values=true" | jq '.Images | length')
if [ "$_ami_public_images_count" -ge "$AWS_AMI_PUBLIC_QUOTA" ]; then
_ami_oldest_image_id=$(aws ec2 describe-images \
--owners "self" \
--filters "Name=name,Values=${AMI_NAME%%-*}-*" \
"Name=architecture,Values=${AMI_ARCHITECTURE}" \
"Name=is-public,Values=true" \
--query 'sort_by(Images, &CreationDate)[0].ImageId')
if [ -n "$_ami_oldest_image_id" ]; then
if [ "$(aws ec2 describe-images --image-ids "${_ami_oldest_image_id}" \
| jq -r '.Images[].Public')" = "true" ]; then
if aws ec2 modify-image-attribute \
--image-id "${_ami_oldest_image_id}" \
--launch-permission '{"Remove":[{"Group":"all"}]}'; then
if ! [ "$(aws ec2 describe-images --image-ids "${_ami_oldest_image_id}" \
| jq -r '.Images[].Public')" = "false" ]; then
exit 1
fi
fi
fi
fi
fi
_ami_snapshot_id=$(aws ec2 describe-images \
--region="${AWS_DEFAULT_REGION}" \
--image-ids "${AMI_IMAGE_ID}" | jq -r '.Images[].BlockDeviceMappings[].Ebs.SnapshotId')
if [ -n "$_ami_snapshot_id" ]; then
if aws ec2 modify-snapshot-attribute --operation-type add \
--region "${AWS_DEFAULT_REGION}" \
--snapshot-id "${_ami_snapshot_id}" \
--attribute createVolumePermission \
--group-names all; then
if ! [ "$(aws ec2 describe-snapshot-attribute \
--region "${AWS_DEFAULT_REGION}" \
--snapshot-id "${_ami_snapshot_id}" \
--attribute createVolumePermission | jq -r '.CreateVolumePermissions[].Group')" == "all" ]; then
exit 1
fi
fi
else
exit 1
fi
if aws ec2 modify-image-attribute --image-id "${AMI_IMAGE_ID}" --launch-permission "Add=[{Group=all}]"; then
if ! [ "$(aws ec2 describe-images --image-ids "${AMI_IMAGE_ID}" | jq -r '.Images[].Public')" = "true" ]; then
exit 1
fi
fi
- name: Set image deprecation
if: steps.test.outcome == 'success' && steps.check.outputs.skip != 'true'
env:
AMI_IMAGE_ID: ${{ steps.test.outputs.ami_image_id }}
PERIOD: "now +1 year"
run: |
[ -z "$AMI_NAME" ] && exit 0
deprecate_at=$(date +%Y-%m-%dT%H:%M:%SZ -d "${PERIOD}")
aws ec2 enable-image-deprecation \
--image-id "${AMI_IMAGE_ID}" \
--deprecate-at "${deprecate_at}"
- name: Clean up EoL images
continue-on-error: true
if: always()
env:
AMI_NAME: ${{ steps.ami.outputs.name }}
# https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ami-quotas.html
PERIOD: "1 years ago"
run: |
[ -z "$AMI_NAME" ] && exit 0
_date=$(date +%Y-%m-%d -d "${PERIOD}")
image_ids=$(aws ec2 describe-images --output text \
--filters "Name=name,Values=${AMI_NAME%%-*}-*" \
--owners "self" \
--query 'Images[?CreationDate<`'"${_date}"'`].[ImageId]')
for image_id in ${image_ids}; do
_snapshots="$(aws ec2 describe-images --output text\
--image-ids "${image_id}" \
--query 'Images[*].BlockDeviceMappings[*].Ebs.SnapshotId')"
if aws ec2 deregister-image --image-id "${image_id}"; then
if [ -n "$_snapshots" ]; then
for snapshot in ${_snapshots}; do
if ! aws ec2 delete-snapshot --snapshot-id "${snapshot}"; then
echo "::warning::Could not remove snapshot ${snapshot}"
fi
done
fi
else
echo "::warning::Could not de-register image ${image_id}"
fi
done
- name: Clean up image on failure
continue-on-error: true
if: failure() || cancelled()
env:
AMI_IMAGE_ID: ${{ steps.image.outputs.id }}
run: |
if [ -n "$AMI_IMAGE_ID" ]; then
aws ec2 deregister-image --image-id "${AMI_IMAGE_ID}"
fi
- name: Clean up snapshot on failure
continue-on-error: true
if: failure() || cancelled()
env:
AMI_SNAPSHOT_ID: ${{ steps.snapshot.outputs.id }}
run: |
if [ -n "$AMI_SNAPSHOT_ID" ]; then
aws ec2 delete-snapshot --snapshot-id "${AMI_SNAPSHOT_ID}"
fi
- name: Terminate AWS/EC2 test instance
continue-on-error: true
if: always()
env:
EC2_INSTANCE_ID: ${{ steps.test.outputs.instance_id }}
run: |
[[ -z "$EC2_INSTANCE_ID" ]] && exit 0
aws ec2 terminate-instances --instance-ids "${EC2_INSTANCE_ID}"
- name: Delete temporary image from AWS/S3
continue-on-error: true
if: always()
env:
S3_URL: ${{ steps.s3.outputs.url }}
run: |
[[ -z "$S3_URL" ]] && exit 0
aws s3 rm "${S3_URL}"
- name: remove AWS/EC2 key-pair
if: always()
continue-on-error: true
env:
AWS_EC2_KEY_NAME: ${{ steps.generate-key-pair.outputs.key_name }}
run: |
[ -z "$AWS_EC2_KEY_NAME" ] && exit 0
aws ec2 delete-key-pair --key-name "${AWS_EC2_KEY_NAME}"
- name: Clean up test fleets
continue-on-error: true
if: always()
env:
FLEETS: '${{ steps.preload-fleet.outputs.name }} ${{ steps.test-fleet.outputs.name }}'
run: |
for fleet in ${FLEETS}; do
_key_id=$(balena ssh-key list | grep "${fleet#*/}" | awk '{print $1}' || echo)
if [ -n "$_key_id" ]; then
balena ssh-key rm "${_key_id}" --yes
fi
balena fleet rm "${fleet}" --yes
done
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
with:
persist-credentials: false
ref: ${{ github.event.pull_request.head.sha }}