diff --git a/.github/actions/test/integration/build/action.yml b/.github/actions/test/integration/build/action.yml index faf2200c..adcf018c 100644 --- a/.github/actions/test/integration/build/action.yml +++ b/.github/actions/test/integration/build/action.yml @@ -103,6 +103,7 @@ runs: PASSWORD=$(openssl passwd "password") echo "PASSWORD=$PASSWORD" >> $GITHUB_ENV sed -i "s|PASSWORD_GOES_HERE|$PASSWORD|g" ./.github/actions/test/integration/build/dev-user-butane.yaml + sed -i "s|TAG_GOES_HERE|${{ inputs.image_tag }}|g" ./.github/actions/test/integration/build/dev-user-butane.yaml butane --pretty --strict ./.github/actions/test/integration/build/dev-user-butane.yaml > "/opt/${TAG}.ign" - name: Download ubuntu cloud image diff --git a/.github/actions/test/integration/build/dev-user-butane.yaml b/.github/actions/test/integration/build/dev-user-butane.yaml index 885a3165..b8486454 100644 --- a/.github/actions/test/integration/build/dev-user-butane.yaml +++ b/.github/actions/test/integration/build/dev-user-butane.yaml @@ -50,12 +50,14 @@ storage: contents: inline: | NON_HUGEPAGES_PM=1000 - # pull the image from GHCR instead of keppel - path: /opt/persist/gl-oci.conf mode: 0644 contents: inline: | + # pull the image from GHCR instead of keppel OCI_REPO=ghcr.io/gardenlinux/gardenlinux-ccloud + # point to a custom tag to download for the persist step + OCI_TAG=TAG_GOES_HERE # Enable unlimited core dumps for all systemd services - path: /etc/systemd/system.conf.d/10-core.conf mode: 0644 diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml index c6edf08b..0ee231fd 100644 --- a/.github/workflows/dev.yml +++ b/.github/workflows/dev.yml @@ -7,11 +7,13 @@ on: - "**/README.md" - "docs/**" pull_request: + types: [opened, synchronize, reopened, closed] paths-ignore: - "**/README.md" - "docs/**" jobs: set_version: + if: ${{ github.event_name != 'pull_request' || github.event.action != 'closed' }} runs-on: ubuntu-latest outputs: VERSION: ${{ steps.version.outputs.VERSION }} @@ -23,9 +25,16 @@ jobs: - name: use VERSION file to support dev build on rel-branch id: version - run: echo "VERSION=$(cat VERSION)" >> $GITHUB_OUTPUT + run: | + if [ "${{ github.event_name }}" = "pull_request" ]; then + echo "VERSION=today" >> $GITHUB_OUTPUT + else + echo "VERSION=$(cat VERSION)" >> $GITHUB_OUTPUT + fi + build: needs: [set_version] + if: ${{ github.event_name != 'pull_request' || github.event.action != 'closed' }} uses: gardenlinux/gardenlinux/.github/workflows/build.yml@3b5ec77e4873462d56658c4ecd56caa0ff63542b with: version: ${{ needs.set_version.outputs.VERSION }} @@ -39,3 +48,93 @@ jobs: # aws_kms_role: ${{ secrets.KMS_SIGNING_IAM_ROLE }} # aws_oidc_session: ${{ secrets.AWS_OIDC_SESSION }} # secureboot_db_kms_arn: ${{ secrets.SECUREBOOT_DB_KMS_ARN }} + + meta: + name: Compute image metadata + if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository && github.event.action != 'closed' }} + runs-on: ubuntu-latest + outputs: + UPLOAD_VERSION: ${{ steps.meta.outputs.upload_version }} + COMMIT_SHA: ${{ steps.meta.outputs.sha }} + steps: + - name: Derive image version + id: meta + run: | + PR_NUMBER=${{ github.event.pull_request.number }} + UPLOAD_VERSION="pr-${PR_NUMBER}" + echo "upload_version=${UPLOAD_VERSION}" >> $GITHUB_OUTPUT + SHA="${GITHUB_SHA::8}" + echo "sha=${SHA}" >> $GITHUB_OUTPUT + + upload: + name: Upload PR image to OCI + needs: [build, meta, set_version] + if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository && github.event.action != 'closed' }} + uses: ./.github/workflows/upload_oci.yml + with: + version: ${{ needs.set_version.outputs.VERSION }} + upload_version: ${{ needs.meta.outputs.UPLOAD_VERSION }} + flavor_filter: '--include-only "metal-sci_usi-amd64"' + secrets: inherit + + test: + name: Test PR image + needs: [set_version, meta, upload] + if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository && github.event.action != 'closed' }} + uses: ./.github/workflows/test.yml + with: + image_tag: "${{ needs.meta.outputs.UPLOAD_VERSION }}-metal-sci-usi-amd64-${{ needs.meta.outputs.COMMIT_SHA }}-amd64" + + cleanup_images: + name: Cleanup PR images + if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository && github.event.action == 'closed' }} + runs-on: ubuntu-latest + steps: + - name: Cleanup OCI images via GitHub API + run: | + PR_NUMBER=${{ github.event.pull_request.number }} + UPLOAD_VERSION="pr-${PR_NUMBER}" + + all_version_ids="" + page=1 + page_size=100 + + # Collect all matching version IDs across pages + while true; do + response=$(curl -s -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "https://api.github.com/orgs/gardenlinux/packages/container/gardenlinux-ccloud/versions?per_page=$page_size&page=$page") + + page_ids=$(echo "$response" | jq -r --arg prefix "${UPLOAD_VERSION}" ' + .[] | select(.metadata.container.tags[]? | test("^" + $prefix + "(-.*)?$")) | .id + ') + if [ -n "$page_ids" ]; then + all_version_ids="$all_version_ids $page_ids" + fi + + page_count=$(echo "$response" | jq '. | length') + if [ "$page_count" -lt "$page_size" ]; then + # Stop if this was the last page + break + fi + + page=$((page + 1)) + done + + if [ -z "$all_version_ids" ]; then + echo "No images found for PR ${PR_NUMBER}" + exit 0 + fi + + for version_id in $all_version_ids; do + echo "Deleting version $version_id" + http_code=$(curl -s -w "%{http_code}" -o /dev/null -X DELETE \ + -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "https://api.github.com/orgs/gardenlinux/packages/container/gardenlinux-ccloud/versions/$version_id") + if [ "$http_code" != "204" ]; then + echo "Failed to delete version $version_id (HTTP $http_code)" + fi + done diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 76a1587e..83a0f461 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,6 +14,12 @@ on: description: "Image tag to test (must be usi-sci)" type: string default: "" + workflow_call: + inputs: + image_tag: + description: "Image tag to test (must be usi-sci)" + type: string + required: true jobs: test: diff --git a/.github/workflows/upload_oci.yml b/.github/workflows/upload_oci.yml index 78d772e6..f68456db 100644 --- a/.github/workflows/upload_oci.yml +++ b/.github/workflows/upload_oci.yml @@ -5,12 +5,18 @@ on: version: type: string default: today + upload_version: + type: string + default: "" + flavor_filter: + type: string + default: '--exclude "bare-*"' jobs: generate_matrix_publish: name: Generate flavors matrix to publish uses: gardenlinux/gardenlinux/.github/workflows/build_flavors_matrix.yml@3b5ec77e4873462d56658c4ecd56caa0ff63542b with: - flags: '--exclude "bare-*" --no-arch --json-by-arch --build --test' + flags: '${{ inputs.flavor_filter }} --no-arch --json-by-arch --build --test' upload_gl_artifacts: name: upload to OCI needs: [ generate_matrix_publish ] @@ -71,8 +77,8 @@ jobs: echo ${{ secrets.GITHUB_TOKEN }} | oras login -u ${{ github.repository_owner }} --password-stdin ghcr.io CNAME2=${CNAME//_/-} CNAME2=${CNAME2//-${{ inputs.version }}/} - echo "Adding additional tag: ${{ inputs.version }}-${CNAME2}-${{ matrix.arch }}" - oras tag ghcr.io/${{ github.repository }}:${{ inputs.version }}-${CNAME}-${{ matrix.arch }} ${{ inputs.version }}-${CNAME2}-${{ matrix.arch }} + echo "Adding additional tag: ${{ inputs.upload_version || inputs.version }}-${CNAME2}-${{ matrix.arch }}" + oras tag ghcr.io/${{ github.repository }}:${{ inputs.version }}-${CNAME}-${{ matrix.arch }} ${{ inputs.upload_version || inputs.version }}-${CNAME2}-${{ matrix.arch }} - uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # pin@v4.2.3 with: path: oci_manifest_entry_${{ env.CNAME }}.json @@ -125,5 +131,5 @@ jobs: gl-oci update-index \ --container "ghcr.io/${{ github.repository }}" \ - --version ${{ inputs.version }} \ + --version ${{ inputs.upload_version || inputs.version }} \ --manifest_folder manifests diff --git a/features/_usi/initrd.include/usr/bin/persist b/features/_usi/initrd.include/usr/bin/persist index 66171ee7..280ce539 100755 --- a/features/_usi/initrd.include/usr/bin/persist +++ b/features/_usi/initrd.include/usr/bin/persist @@ -62,20 +62,19 @@ if [ ! -f "$OS_RELEASE_FILE" ]; then echo "File not found '$OS_RELEASE_FILE', exiting" exit 1 fi - -# source optional config file -[ -f /sysroot/opt/persist/gl-oci.conf ] && . /sysroot/opt/persist/gl-oci.conf -OCI_REPO="${OCI_REPO:-keppel.global.cloud.sap/ccloud-ghcr-io-mirror/gardenlinux/gardenlinux-ccloud}" -OCI_ARCH="${OCI_ARCH:-amd64}" - # source os-release file . "$OS_RELEASE_FILE" # oras needs a proper HOME variable export HOME=/root +# source optional config file +[ -f /sysroot/opt/persist/gl-oci.conf ] && . /sysroot/opt/persist/gl-oci.conf +OCI_REPO="${OCI_REPO:-keppel.global.cloud.sap/ccloud-ghcr-io-mirror/gardenlinux/gardenlinux-ccloud}" +OCI_ARCH="${OCI_ARCH:-amd64}" + # setup OCI_TAG, UKI_SHA and fetch UKI -OCI_TAG="$GARDENLINUX_VERSION-$VARIANT_ID-$GARDENLINUX_COMMIT_ID-$OCI_ARCH" +OCI_TAG=${OCI_TAG:-"$GARDENLINUX_VERSION-$VARIANT_ID-$GARDENLINUX_COMMIT_ID-$OCI_ARCH"} OCI_TAG=${OCI_TAG//_/-} # replace underscores with dashes UKI_SHA=$(oras manifest fetch "$OCI_REPO:${OCI_TAG}" | jq -r '.layers[] | select(.mediaType=="application/io.gardenlinux.uki") | .digest') oras blob fetch "$OCI_REPO@$UKI_SHA" -o "$esp_dir/EFI/Linux/uki.efi"