From 14f6ec4bdbad5cfc9c32425bef3d34c0b88f84dd Mon Sep 17 00:00:00 2001 From: 3alpha <15694175+3alpha@users.noreply.github.com> Date: Thu, 28 May 2026 12:03:31 +0200 Subject: [PATCH 1/4] feat: add AMI build step to release workflow Appends a build-ami job that runs after the release job: - Authenticates via OIDC (gha-imagebuilder role, no stored credentials) - Patch-bumps the Image Builder recipe version - Triggers EC2 Image Builder pipeline on Ubuntu 24 LTS All ARNs stored as repo secrets. --- .github/workflows/release.yml | 59 +++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f6cd00b..0f2cba5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,4 +1,9 @@ name: Pre-release + +permissions: + id-token: write + contents: write + on: workflow_dispatch: inputs: @@ -262,3 +267,57 @@ jobs: body_path: CHANGELOG.md env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + build-ami: + name: Build DAppNode AMI + runs-on: ubuntu-latest + needs: release + steps: + - name: Configure AWS credentials via OIDC + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.IMAGE_BUILDER_ROLE_ARN }} + aws-region: us-east-1 + + - name: Bump recipe version and trigger AMI build + env: + PIPELINE_ARN: ${{ secrets.IMAGE_BUILDER_PIPELINE_ARN }} + INFRA_ARN: ${{ secrets.IMAGE_BUILDER_INFRA_ARN }} + DIST_ARN: ${{ secrets.IMAGE_BUILDER_DIST_ARN }} + COMPONENT_ARN: ${{ secrets.IMAGE_BUILDER_COMPONENT_ARN }} + run: | + # Get current recipe version and patch bump + CURRENT_RECIPE=$(aws imagebuilder get-image-pipeline \ + --image-pipeline-arn "$PIPELINE_ARN" \ + --query 'imagePipeline.imageRecipeArn' --output text) + CURRENT_VERSION=$(echo "$CURRENT_RECIPE" | grep -oP '[0-9]+\.[0-9]+\.[0-9]+$') + IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT_VERSION" + NEW_VERSION="${MAJOR}.${MINOR}.$((PATCH + 1))" + echo "Bumping recipe: $CURRENT_VERSION -> $NEW_VERSION" + + # Create new recipe version (same component, fresh Ubuntu 24 base) + RECIPE_ARN=$(aws imagebuilder create-image-recipe \ + --name "dappnode-image" \ + --semantic-version "$NEW_VERSION" \ + --parent-image "arn:aws:imagebuilder:us-east-1:aws:image/ubuntu-server-24-lts-x86/x.x.x" \ + --components "[{\"componentArn\":\"$COMPONENT_ARN\"}]" \ + --block-device-mappings '[{"deviceName":"/dev/sda1","ebs":{"volumeSize":8,"volumeType":"gp2","deleteOnTermination":true}}]' \ + --working-directory "/tmp" \ + --query 'imageRecipeArn' --output text) + + # Update pipeline and trigger build + aws imagebuilder update-image-pipeline \ + --image-pipeline-arn "$PIPELINE_ARN" \ + --image-recipe-arn "$RECIPE_ARN" \ + --infrastructure-configuration-arn "$INFRA_ARN" \ + --distribution-configuration-arn "$DIST_ARN" \ + --image-tests-configuration "imageTestsEnabled=false" + + EXECUTION=$(aws imagebuilder start-image-pipeline-execution \ + --image-pipeline-arn "$PIPELINE_ARN" \ + --query 'imageBuildVersionArn' --output text) + + echo "🚀 AMI build started: $EXECUTION (recipe $NEW_VERSION)" + echo "### AMI Build Triggered" >> "$GITHUB_STEP_SUMMARY" + echo "- **Recipe version:** $NEW_VERSION" >> "$GITHUB_STEP_SUMMARY" + echo "- **Image ARN:** $EXECUTION" >> "$GITHUB_STEP_SUMMARY" From 28f2069d09c63197b79136f38d569a4456c99149 Mon Sep 17 00:00:00 2001 From: 3alpha <15694175+3alpha@users.noreply.github.com> Date: Thu, 28 May 2026 15:23:30 +0200 Subject: [PATCH 2/4] feat: add dedicated AMI build script Replaces fragile 'head -n -12' line-stripping of the prerequisites script with a self-contained build script that: - Installs Docker, wireguard, lsof, iptables - Sets up /etc/rc.local for first-boot DAppNode installation - Skips network connectivity checks (not needed during AMI build) - Handles Ubuntu 24 LTS properly --- scripts/dappnode_ami_build.sh | 139 ++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100755 scripts/dappnode_ami_build.sh diff --git a/scripts/dappnode_ami_build.sh b/scripts/dappnode_ami_build.sh new file mode 100755 index 0000000..1213393 --- /dev/null +++ b/scripts/dappnode_ami_build.sh @@ -0,0 +1,139 @@ +#!/bin/bash +# DAppNode AMI Build Script +# Purpose: Install prerequisites, pre-download core Docker images, and set up +# first-boot installer for EC2 Image Builder. +# +# The installer still runs at first boot (via rc.local), but finds the heavy +# Docker images already cached in /usr/src/dappnode/DNCORE/, making boot fast +# and not dependent on network for bulk downloads. + +set -euo pipefail + +DAPPNODE_DIR="/usr/src/dappnode" +DNCORE_DIR="$DAPPNODE_DIR/DNCORE" +LOGS_DIR="$DAPPNODE_DIR/logs" +LOG_FILE="$LOGS_DIR/ami_build.log" + +mkdir -p "$DAPPNODE_DIR/scripts" "$DNCORE_DIR" "$LOGS_DIR" +touch "$LOG_FILE" + +log() { echo "[AMI-BUILD] $*" | tee -a "$LOG_FILE"; } + +lsb_dist="$(. /etc/os-release && echo "$ID")" +log "Detected OS: $lsb_dist" + +# ─── Docker ─────────────────────────────────────────────────────────────────── +install_docker() { + log "Installing Docker..." + apt-get update -y + apt-get remove -y docker docker-engine docker.io containerd runc || true + + apt-get install -y ca-certificates curl lsb-release + install -m 0755 -d /etc/apt/keyrings + curl -fsSL "https://download.docker.com/linux/${lsb_dist}/gpg" -o /etc/apt/keyrings/docker.asc + chmod a+r /etc/apt/keyrings/docker.asc + + echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/$lsb_dist $(lsb_release -cs) stable" \ + | tee /etc/apt/sources.list.d/docker.list >/dev/null + + apt-get update -y + apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin + [ -f "/usr/bin/xz" ] || apt-get install -y xz-utils + log "Docker installed successfully" +} + +# ─── Docker Compose alias (legacy compatibility) ────────────────────────────── +install_compose_alias() { + cat >/usr/local/bin/docker-compose <<'EOL' +#!/bin/bash +docker compose "$@" +EOL + chmod +x /usr/local/bin/docker-compose +} + +# ─── Prerequisites ──────────────────────────────────────────────────────────── +log "=== Phase 1: Prerequisites ===" + +apt-get update -y | tee -a "$LOG_FILE" + +if ! docker -v >/dev/null 2>&1; then + install_docker 2>&1 | tee -a "$LOG_FILE" +else + log "Docker already installed" +fi + +install_compose_alias + +modprobe wireguard 2>/dev/null || apt-get install -y wireguard-dkms || apt-get install -y wireguard-tools || true +apt-get install -y lsof iptables xz-utils || true + +# ─── Pre-download core Docker images ───────────────────────────────────────── +log "=== Phase 2: Pre-downloading core images ===" + +# Download latest released profile (contains version pins) +wget -O "$DNCORE_DIR/.dappnode_profile" \ + "https://github.com/dappnode/DAppNode/releases/latest/download/dappnode_profile.sh" + +# Source only the version variables (up to ISOBUILD marker) +sed '/^\#\!ISOBUILD/q' "$DNCORE_DIR/.dappnode_profile" > /tmp/vars.sh +source /tmp/vars.sh + +COMPONENTS=(BIND IPFS WIREGUARD DAPPMANAGER WIFI HTTPS) + +for comp in "${COMPONENTS[@]}"; do + ver="${comp}_VERSION" + comp_lower="$(echo "$comp" | tr '[:upper:]' '[:lower:]')" + VERSION="${!ver}" + + if [[ "$VERSION" == /ipfs/* ]]; then + log "Skipping $comp (IPFS-based version)" + continue + fi + + BASE_URL="https://github.com/dappnode/DNP_${comp}/releases/download/v${VERSION}" + + log "Downloading $comp v${VERSION}..." + wget -q -O "$DNCORE_DIR/${comp_lower}.dnp.dappnode.eth_${VERSION}_linux-amd64.txz" \ + "${BASE_URL}/${comp_lower}.dnp.dappnode.eth_${VERSION}_linux-amd64.txz" || \ + log "WARNING: Failed to download $comp image" + + wget -q -O "$DNCORE_DIR/docker-compose-${comp_lower}.yml" \ + "${BASE_URL}/docker-compose.yml" || \ + log "WARNING: Failed to download $comp compose" + + wget -q -O "$DNCORE_DIR/dappnode_package-${comp_lower}.json" \ + "${BASE_URL}/dappnode_package.json" || \ + log "WARNING: Failed to download $comp manifest" +done + +# Grab content hashes for execution/consensus clients +CONTENT_HASH_PKGS=(besu geth nethermind erigon prysm teku lighthouse lodestar nimbus) +HASH_FILE="$DNCORE_DIR/packages-content-hash.csv" +rm -f "$HASH_FILE" +for pkg in "${CONTENT_HASH_PKGS[@]}"; do + HASH=$(wget -q -O- "https://github.com/dappnode/DAppNodePackage-${pkg}/releases/latest/download/content-hash" || true) + if [ -n "$HASH" ]; then + echo "${pkg}.dnp.dappnode.eth,${HASH}" >> "$HASH_FILE" + log "Got content hash for $pkg" + fi +done + +log "Pre-download complete:" +ls -lh "$DNCORE_DIR/" +du -sh "$DNCORE_DIR/" + +# ─── Set up first-boot installer ───────────────────────────────────────────── +log "=== Phase 3: First-boot installer ===" + +wget -O "$DAPPNODE_DIR/scripts/dappnode_install.sh" https://installer.dappnode.io +chmod +x "$DAPPNODE_DIR/scripts/dappnode_install.sh" + +cat > /etc/rc.local << 'RC' +#!/bin/sh -e +/usr/src/dappnode/scripts/dappnode_install.sh +exit 0 +RC +chmod +x /etc/rc.local +touch "$DAPPNODE_DIR/.firstboot" + +log "=== AMI build complete. First boot will find pre-cached images in DNCORE/ ===" From 529782aa127cc0fa8c48e5c3e02de3aee4f6d5e6 Mon Sep 17 00:00:00 2001 From: 3alpha <15694175+3alpha@users.noreply.github.com> Date: Thu, 28 May 2026 15:59:27 +0200 Subject: [PATCH 3/4] refactor: separate AMI build into workflow_run triggered workflow - Create standalone .github/workflows/build-ami.yml triggered on Pre-release workflow completion - Remove build-ami job and OIDC permissions from release.yml - Update scripts/dappnode_ami_build.sh to require PROFILE_URL env var - Workflow creates thin per-release component that downloads and runs the repo script with pinned PROFILE_URL for that specific release tag - Remove IMAGE_BUILDER_COMPONENT_ARN secret (no longer needed) --- .github/workflows/build-ami.yml | 109 ++++++++++++++++++++++++++++++++ .github/workflows/release.yml | 58 ----------------- scripts/dappnode_ami_build.sh | 68 ++++++++------------ 3 files changed, 136 insertions(+), 99 deletions(-) create mode 100644 .github/workflows/build-ami.yml diff --git a/.github/workflows/build-ami.yml b/.github/workflows/build-ami.yml new file mode 100644 index 0000000..0ad9dd3 --- /dev/null +++ b/.github/workflows/build-ami.yml @@ -0,0 +1,109 @@ +name: Build DAppNode AMI + +on: + workflow_run: + workflows: ["Pre-release"] + types: [completed] + +permissions: + id-token: write + contents: read + +jobs: + build-ami: + name: Build DAppNode AMI + runs-on: ubuntu-latest + if: ${{ github.event.workflow_run.conclusion == 'success' }} + steps: + - name: Get release tag + id: tag + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + # Get the latest pre-release tag (the one just created by the triggering workflow) + TAG=$(gh release list --repo ${{ github.repository }} \ + --limit 1 --json tagName --jq '.[0].tagName') + echo "tag=$TAG" >> "$GITHUB_OUTPUT" + echo "Release tag: $TAG" + + - name: Configure AWS credentials via OIDC + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.IMAGE_BUILDER_ROLE_ARN }} + aws-region: us-east-1 + + - name: Create component, recipe, and trigger AMI build + env: + PIPELINE_ARN: ${{ secrets.IMAGE_BUILDER_PIPELINE_ARN }} + INFRA_ARN: ${{ secrets.IMAGE_BUILDER_INFRA_ARN }} + DIST_ARN: ${{ secrets.IMAGE_BUILDER_DIST_ARN }} + TAG: ${{ steps.tag.outputs.tag }} + run: | + PROFILE_URL="https://github.com/dappnode/DAppNode/releases/download/${TAG}/dappnode_profile.sh" + SCRIPT_URL="https://raw.githubusercontent.com/dappnode/DAppNode/${TAG}/scripts/dappnode_ami_build.sh" + + # Derive component version from tag (v0.2.47 -> 0.2.47) + COMP_VERSION="${TAG#v}" + + # Create per-release component (thin wrapper: downloads repo script and runs it) + COMPONENT_ARN=$(aws imagebuilder create-component \ + --name "dappnode-build" \ + --semantic-version "$COMP_VERSION" \ + --platform "Linux" \ + --supported-os-versions "Ubuntu" \ + --data "$(cat < $NEW_VERSION" + + # Create recipe with per-release component + RECIPE_ARN=$(aws imagebuilder create-image-recipe \ + --name "dappnode-image" \ + --semantic-version "$NEW_VERSION" \ + --parent-image "arn:aws:imagebuilder:us-east-1:aws:image/ubuntu-server-24-lts-x86/x.x.x" \ + --components "[{\"componentArn\":\"$COMPONENT_ARN\"}]" \ + --block-device-mappings '[{"deviceName":"/dev/sda1","ebs":{"volumeSize":16,"volumeType":"gp3","deleteOnTermination":true}}]' \ + --working-directory "/tmp" \ + --query 'imageRecipeArn' --output text) + + # Update pipeline and trigger + aws imagebuilder update-image-pipeline \ + --image-pipeline-arn "$PIPELINE_ARN" \ + --image-recipe-arn "$RECIPE_ARN" \ + --infrastructure-configuration-arn "$INFRA_ARN" \ + --distribution-configuration-arn "$DIST_ARN" \ + --image-tests-configuration "imageTestsEnabled=false" + + EXECUTION=$(aws imagebuilder start-image-pipeline-execution \ + --image-pipeline-arn "$PIPELINE_ARN" \ + --query 'imageBuildVersionArn' --output text) + + echo "### AMI Build Triggered 🚀" >> "$GITHUB_STEP_SUMMARY" + echo "- **Tag:** ${TAG}" >> "$GITHUB_STEP_SUMMARY" + echo "- **Recipe:** ${NEW_VERSION}" >> "$GITHUB_STEP_SUMMARY" + echo "- **Profile:** ${PROFILE_URL}" >> "$GITHUB_STEP_SUMMARY" + echo "- **Image ARN:** ${EXECUTION}" >> "$GITHUB_STEP_SUMMARY" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0f2cba5..d87f87b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,9 +1,5 @@ name: Pre-release -permissions: - id-token: write - contents: write - on: workflow_dispatch: inputs: @@ -267,57 +263,3 @@ jobs: body_path: CHANGELOG.md env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - build-ami: - name: Build DAppNode AMI - runs-on: ubuntu-latest - needs: release - steps: - - name: Configure AWS credentials via OIDC - uses: aws-actions/configure-aws-credentials@v4 - with: - role-to-assume: ${{ secrets.IMAGE_BUILDER_ROLE_ARN }} - aws-region: us-east-1 - - - name: Bump recipe version and trigger AMI build - env: - PIPELINE_ARN: ${{ secrets.IMAGE_BUILDER_PIPELINE_ARN }} - INFRA_ARN: ${{ secrets.IMAGE_BUILDER_INFRA_ARN }} - DIST_ARN: ${{ secrets.IMAGE_BUILDER_DIST_ARN }} - COMPONENT_ARN: ${{ secrets.IMAGE_BUILDER_COMPONENT_ARN }} - run: | - # Get current recipe version and patch bump - CURRENT_RECIPE=$(aws imagebuilder get-image-pipeline \ - --image-pipeline-arn "$PIPELINE_ARN" \ - --query 'imagePipeline.imageRecipeArn' --output text) - CURRENT_VERSION=$(echo "$CURRENT_RECIPE" | grep -oP '[0-9]+\.[0-9]+\.[0-9]+$') - IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT_VERSION" - NEW_VERSION="${MAJOR}.${MINOR}.$((PATCH + 1))" - echo "Bumping recipe: $CURRENT_VERSION -> $NEW_VERSION" - - # Create new recipe version (same component, fresh Ubuntu 24 base) - RECIPE_ARN=$(aws imagebuilder create-image-recipe \ - --name "dappnode-image" \ - --semantic-version "$NEW_VERSION" \ - --parent-image "arn:aws:imagebuilder:us-east-1:aws:image/ubuntu-server-24-lts-x86/x.x.x" \ - --components "[{\"componentArn\":\"$COMPONENT_ARN\"}]" \ - --block-device-mappings '[{"deviceName":"/dev/sda1","ebs":{"volumeSize":8,"volumeType":"gp2","deleteOnTermination":true}}]' \ - --working-directory "/tmp" \ - --query 'imageRecipeArn' --output text) - - # Update pipeline and trigger build - aws imagebuilder update-image-pipeline \ - --image-pipeline-arn "$PIPELINE_ARN" \ - --image-recipe-arn "$RECIPE_ARN" \ - --infrastructure-configuration-arn "$INFRA_ARN" \ - --distribution-configuration-arn "$DIST_ARN" \ - --image-tests-configuration "imageTestsEnabled=false" - - EXECUTION=$(aws imagebuilder start-image-pipeline-execution \ - --image-pipeline-arn "$PIPELINE_ARN" \ - --query 'imageBuildVersionArn' --output text) - - echo "🚀 AMI build started: $EXECUTION (recipe $NEW_VERSION)" - echo "### AMI Build Triggered" >> "$GITHUB_STEP_SUMMARY" - echo "- **Recipe version:** $NEW_VERSION" >> "$GITHUB_STEP_SUMMARY" - echo "- **Image ARN:** $EXECUTION" >> "$GITHUB_STEP_SUMMARY" diff --git a/scripts/dappnode_ami_build.sh b/scripts/dappnode_ami_build.sh index 1213393..8a172c9 100755 --- a/scripts/dappnode_ami_build.sh +++ b/scripts/dappnode_ami_build.sh @@ -3,76 +3,63 @@ # Purpose: Install prerequisites, pre-download core Docker images, and set up # first-boot installer for EC2 Image Builder. # +# Env vars: +# PROFILE_URL — URL to dappnode_profile.sh with pinned versions (required) +# # The installer still runs at first boot (via rc.local), but finds the heavy -# Docker images already cached in /usr/src/dappnode/DNCORE/, making boot fast -# and not dependent on network for bulk downloads. +# Docker images already cached in /usr/src/dappnode/DNCORE/, making boot fast. set -euo pipefail +: "${PROFILE_URL:?PROFILE_URL env var is required}" + DAPPNODE_DIR="/usr/src/dappnode" DNCORE_DIR="$DAPPNODE_DIR/DNCORE" LOGS_DIR="$DAPPNODE_DIR/logs" LOG_FILE="$LOGS_DIR/ami_build.log" +export DEBIAN_FRONTEND=noninteractive + mkdir -p "$DAPPNODE_DIR/scripts" "$DNCORE_DIR" "$LOGS_DIR" touch "$LOG_FILE" +exec > >(tee -a "$LOG_FILE") 2>&1 -log() { echo "[AMI-BUILD] $*" | tee -a "$LOG_FILE"; } +log() { echo "[AMI-BUILD] $*"; } lsb_dist="$(. /etc/os-release && echo "$ID")" -log "Detected OS: $lsb_dist" +log "OS: $lsb_dist | Profile: $PROFILE_URL" + +# ─── Phase 1: Prerequisites ────────────────────────────────────────────────── +log "=== Phase 1: Prerequisites ===" -# ─── Docker ─────────────────────────────────────────────────────────────────── -install_docker() { +apt-get update -y + +if ! docker -v >/dev/null 2>&1; then log "Installing Docker..." - apt-get update -y apt-get remove -y docker docker-engine docker.io containerd runc || true - apt-get install -y ca-certificates curl lsb-release install -m 0755 -d /etc/apt/keyrings curl -fsSL "https://download.docker.com/linux/${lsb_dist}/gpg" -o /etc/apt/keyrings/docker.asc chmod a+r /etc/apt/keyrings/docker.asc - echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/$lsb_dist $(lsb_release -cs) stable" \ | tee /etc/apt/sources.list.d/docker.list >/dev/null - apt-get update -y apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin - [ -f "/usr/bin/xz" ] || apt-get install -y xz-utils - log "Docker installed successfully" -} +fi -# ─── Docker Compose alias (legacy compatibility) ────────────────────────────── -install_compose_alias() { - cat >/usr/local/bin/docker-compose <<'EOL' +cat >/usr/local/bin/docker-compose <<'EOL' #!/bin/bash docker compose "$@" EOL - chmod +x /usr/local/bin/docker-compose -} - -# ─── Prerequisites ──────────────────────────────────────────────────────────── -log "=== Phase 1: Prerequisites ===" - -apt-get update -y | tee -a "$LOG_FILE" - -if ! docker -v >/dev/null 2>&1; then - install_docker 2>&1 | tee -a "$LOG_FILE" -else - log "Docker already installed" -fi - -install_compose_alias +chmod +x /usr/local/bin/docker-compose modprobe wireguard 2>/dev/null || apt-get install -y wireguard-dkms || apt-get install -y wireguard-tools || true apt-get install -y lsof iptables xz-utils || true -# ─── Pre-download core Docker images ───────────────────────────────────────── +# ─── Phase 2: Pre-download core images ─────────────────────────────────────── log "=== Phase 2: Pre-downloading core images ===" -# Download latest released profile (contains version pins) -wget -O "$DNCORE_DIR/.dappnode_profile" \ - "https://github.com/dappnode/DAppNode/releases/latest/download/dappnode_profile.sh" +wget -O "$DNCORE_DIR/.dappnode_profile" "$PROFILE_URL" # Source only the version variables (up to ISOBUILD marker) sed '/^\#\!ISOBUILD/q' "$DNCORE_DIR/.dappnode_profile" > /tmp/vars.sh @@ -106,7 +93,7 @@ for comp in "${COMPONENTS[@]}"; do log "WARNING: Failed to download $comp manifest" done -# Grab content hashes for execution/consensus clients +# Content hashes for execution/consensus clients CONTENT_HASH_PKGS=(besu geth nethermind erigon prysm teku lighthouse lodestar nimbus) HASH_FILE="$DNCORE_DIR/packages-content-hash.csv" rm -f "$HASH_FILE" @@ -114,16 +101,15 @@ for pkg in "${CONTENT_HASH_PKGS[@]}"; do HASH=$(wget -q -O- "https://github.com/dappnode/DAppNodePackage-${pkg}/releases/latest/download/content-hash" || true) if [ -n "$HASH" ]; then echo "${pkg}.dnp.dappnode.eth,${HASH}" >> "$HASH_FILE" - log "Got content hash for $pkg" + log "Got content hash: $pkg" fi done log "Pre-download complete:" -ls -lh "$DNCORE_DIR/" du -sh "$DNCORE_DIR/" -# ─── Set up first-boot installer ───────────────────────────────────────────── -log "=== Phase 3: First-boot installer ===" +# ─── Phase 3: First-boot installer ─────────────────────────────────────────── +log "=== Phase 3: First-boot setup ===" wget -O "$DAPPNODE_DIR/scripts/dappnode_install.sh" https://installer.dappnode.io chmod +x "$DAPPNODE_DIR/scripts/dappnode_install.sh" @@ -136,4 +122,4 @@ RC chmod +x /etc/rc.local touch "$DAPPNODE_DIR/.firstboot" -log "=== AMI build complete. First boot will find pre-cached images in DNCORE/ ===" +log "=== AMI build complete ===" From b9624aee8aec0a6edf063ecab8d9f42a6e97ca5d Mon Sep 17 00:00:00 2001 From: 3alpha <15694175+3alpha@users.noreply.github.com> Date: Thu, 28 May 2026 16:35:09 +0200 Subject: [PATCH 4/4] feat: automated AMI build on release via workflow_run - Add .github/workflows/build-ami.yml (triggers after Release completes) - Add scripts/dappnode_ami_build.sh (prerequisites + pre-download + rc.local) - release.yml: rename to Release, mark as full release (not prerelease) - Workflow reuses existing AWS component, just bumps recipe and triggers - IAM role updated: added GetImageRecipe, removed unused CreateComponent --- .github/workflows/build-ami.yml | 65 +++++++-------------------------- .github/workflows/release.yml | 6 +-- scripts/dappnode_ami_build.sh | 4 +- 3 files changed, 18 insertions(+), 57 deletions(-) diff --git a/.github/workflows/build-ami.yml b/.github/workflows/build-ami.yml index 0ad9dd3..285a47b 100644 --- a/.github/workflows/build-ami.yml +++ b/.github/workflows/build-ami.yml @@ -2,7 +2,7 @@ name: Build DAppNode AMI on: workflow_run: - workflows: ["Pre-release"] + workflows: ["Release"] types: [completed] permissions: @@ -15,72 +15,35 @@ jobs: runs-on: ubuntu-latest if: ${{ github.event.workflow_run.conclusion == 'success' }} steps: - - name: Get release tag - id: tag - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - # Get the latest pre-release tag (the one just created by the triggering workflow) - TAG=$(gh release list --repo ${{ github.repository }} \ - --limit 1 --json tagName --jq '.[0].tagName') - echo "tag=$TAG" >> "$GITHUB_OUTPUT" - echo "Release tag: $TAG" - - name: Configure AWS credentials via OIDC uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: ${{ secrets.IMAGE_BUILDER_ROLE_ARN }} aws-region: us-east-1 - - name: Create component, recipe, and trigger AMI build + - name: Bump recipe and trigger AMI build env: PIPELINE_ARN: ${{ secrets.IMAGE_BUILDER_PIPELINE_ARN }} INFRA_ARN: ${{ secrets.IMAGE_BUILDER_INFRA_ARN }} DIST_ARN: ${{ secrets.IMAGE_BUILDER_DIST_ARN }} - TAG: ${{ steps.tag.outputs.tag }} run: | - PROFILE_URL="https://github.com/dappnode/DAppNode/releases/download/${TAG}/dappnode_profile.sh" - SCRIPT_URL="https://raw.githubusercontent.com/dappnode/DAppNode/${TAG}/scripts/dappnode_ami_build.sh" - - # Derive component version from tag (v0.2.47 -> 0.2.47) - COMP_VERSION="${TAG#v}" - - # Create per-release component (thin wrapper: downloads repo script and runs it) - COMPONENT_ARN=$(aws imagebuilder create-component \ - --name "dappnode-build" \ - --semantic-version "$COMP_VERSION" \ - --platform "Linux" \ - --supported-os-versions "Ubuntu" \ - --data "$(cat < $NEW_VERSION" - # Create recipe with per-release component + # Get component from current recipe + COMPONENT_ARN=$(aws imagebuilder get-image-recipe \ + --image-recipe-arn "$CURRENT_RECIPE_ARN" \ + --query 'imageRecipe.components[0].componentArn' --output text) + echo "Component: $COMPONENT_ARN" + + # Create new recipe version (same component, latest Ubuntu 24) RECIPE_ARN=$(aws imagebuilder create-image-recipe \ --name "dappnode-image" \ --semantic-version "$NEW_VERSION" \ @@ -103,7 +66,5 @@ jobs: --query 'imageBuildVersionArn' --output text) echo "### AMI Build Triggered 🚀" >> "$GITHUB_STEP_SUMMARY" - echo "- **Tag:** ${TAG}" >> "$GITHUB_STEP_SUMMARY" echo "- **Recipe:** ${NEW_VERSION}" >> "$GITHUB_STEP_SUMMARY" - echo "- **Profile:** ${PROFILE_URL}" >> "$GITHUB_STEP_SUMMARY" echo "- **Image ARN:** ${EXECUTION}" >> "$GITHUB_STEP_SUMMARY" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d87f87b..cf89b82 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,4 +1,4 @@ -name: Pre-release +name: Release on: workflow_dispatch: @@ -248,11 +248,11 @@ jobs: run: | echo "Images directory content:" ls -lrt images/ - - name: Create pre-release + - name: Create release uses: softprops/action-gh-release@v2 with: tag_name: ${{ needs.set-versions.outputs.core }} - prerelease: true + prerelease: false files: | ./images/Dappnode-*-debian-*-attended.iso ./images/Dappnode-*-debian-*-unattended.iso diff --git a/scripts/dappnode_ami_build.sh b/scripts/dappnode_ami_build.sh index 8a172c9..d4f9f87 100755 --- a/scripts/dappnode_ami_build.sh +++ b/scripts/dappnode_ami_build.sh @@ -4,14 +4,14 @@ # first-boot installer for EC2 Image Builder. # # Env vars: -# PROFILE_URL — URL to dappnode_profile.sh with pinned versions (required) +# PROFILE_URL — URL to dappnode_profile.sh (defaults to latest release) # # The installer still runs at first boot (via rc.local), but finds the heavy # Docker images already cached in /usr/src/dappnode/DNCORE/, making boot fast. set -euo pipefail -: "${PROFILE_URL:?PROFILE_URL env var is required}" +: "${PROFILE_URL:=https://github.com/dappnode/DAppNode/releases/latest/download/dappnode_profile.sh}" DAPPNODE_DIR="/usr/src/dappnode" DNCORE_DIR="$DAPPNODE_DIR/DNCORE"