diff --git a/.github/README.md b/.github/README.md index 1fc40c4..c20b4b7 100644 --- a/.github/README.md +++ b/.github/README.md @@ -128,6 +128,8 @@ The version should be bumped prior to starting the release workflow using `npm v The library previously used `node-pre-gyp`, allowing the dependents to build it themselves if no prebuilt package was available for their platform. However this is no longer the case, as we already publish prebuilt packages for every supported platform, this change simply makes this policy more explicit. +Some workflows necessitate testing on arm64 platforms. These workflows have two additional steps that are implied in the following descriptions, to launch and terminate EC2 runners which will run the jobs using our [custom action](https://github.com/solarwindscloud/ec2-runner-action). + ## Usage ### Prep - Push Dockerfile @@ -166,7 +168,8 @@ manual (image?) ─► └────────────────── * Creating a pull request will trigger [review.yml](./workflows/review.yml). * Workflow will: - Build the code for all supported platforms and Node versions. - - Run the tests on each platform in the x64 group. + - Start EC2 runners for testing on arm64 platforms. + - Run the tests on each platform in the test group for both x64 and arm64. * Workflow confirms code can be built in each of the required variations. * Manual trigger supported. ``` @@ -184,7 +187,7 @@ manual ──────────► └──────────── * Workflow will: - Build the code for all supported platforms and Node versions. - Publish each platform-specific packages generated in the `npm` directory. - - Run the tests on each platform in the x64 group using the published packages. + - Run the tests on each platform in the test group for both x64 and arm64 using the published packages. - Publish the `solarwinds-apm-bindings` NPM package upon successful completion of all steps above. When version tag is `prerelease`, package will be NPM tagged same. When it is a release version, package will be NPM tagged `latest`. * Workflow ensures `optionalDependencies` setup is working in *production* for a wide variety of potential customer configurations. * Workflow publishing to NPM registry exposes the NPM package to the public. @@ -214,7 +217,7 @@ manual ──────────►│Confirm Publishable│ ### Definitions * Local images are defined in [docker-node](./docker-node). -* [x64 Group](./config/x64.json) images include a wide variety of x64 (x86_64) OS and Node version combinations. +* [Test Group](./config/test-group.json) images include a wide variety of OS and Node version combinations. ### Adding an image to GitHub Container Registry diff --git a/.github/config/x64-group.json b/.github/config/test-group.json similarity index 69% rename from .github/config/x64-group.json rename to .github/config/test-group.json index ff836ce..3015825 100644 --- a/.github/config/x64-group.json +++ b/.github/config/test-group.json @@ -4,19 +4,7 @@ "image": "node:14-alpine3.12" }, { - "image": "node:14-alpine3.13" - }, - { - "image": "node:14-alpine3.14" - }, - { - "image": "node:14-alpine3.15" - }, - { - "image": "node:14-alpine3.16" - }, - { - "image": "node:14-alpine3.17" + "image": "node:14-alpine" }, { "image": "node:14-buster" @@ -34,16 +22,10 @@ "image": "ghcr.io/$GITHUB_REPOSITORY/node:14-amazonlinux2" }, { - "image": "node:16-alpine3.14" + "image": "node:16-alpine3.12" }, { - "image": "node:16-alpine3.15" - }, - { - "image": "node:16-alpine3.16" - }, - { - "image": "node:16-alpine3.17" + "image": "node:16-alpine" }, { "image": "node:16-buster" @@ -67,13 +49,7 @@ "image": "node:18-alpine3.14" }, { - "image": "node:18-alpine3.15" - }, - { - "image": "node:18-alpine3.16" - }, - { - "image": "node:18-alpine3.17" + "image": "node:18-alpine" }, { "image": "node:18-buster" diff --git a/.github/scripts/matrix-from-json.sh b/.github/scripts/matrix-from-json.sh index 88a76b7..60183fc 100755 --- a/.github/scripts/matrix-from-json.sh +++ b/.github/scripts/matrix-from-json.sh @@ -16,5 +16,15 @@ for env_var in $(printenv); do JSON="${JSON//\$${arr[0]}/"${arr[1]}"}" done +JSON_WITH_ARCH=$(echo "$JSON" | jq -c '.include = [.include[] | .+{ arch: ["arm64", "x64"][] }]') +# temporary fix for gha not supporting old arm64 alpine whatsoever +JSON_WITH_ARCH=$(echo "$JSON_WITH_ARCH" | jq -c '.include = [.include[] | select((.arch == "arm64") and (.image | contains("alpine")) and (.image | endswith("alpine") | not) | not)]') + +ARM64_IMAGES=$(echo "$JSON_WITH_ARCH" | jq -r '.include[] | select(.arch == "arm64") | .image') + # return a value echo "matrix=$JSON" >> $GITHUB_OUTPUT +echo "matrix-with-arch=$JSON_WITH_ARCH" >> $GITHUB_OUTPUT +echo "arm64-images<> $GITHUB_OUTPUT +echo "$ARM64_IMAGES" >> $GITHUB_OUTPUT +echo "EOF" >> $GITHUB_OUTPUT diff --git a/.github/workflows/docker-node.yml b/.github/workflows/docker-node.yml index 722a88d..388327b 100644 --- a/.github/workflows/docker-node.yml +++ b/.github/workflows/docker-node.yml @@ -48,6 +48,8 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 - name: Log in to the Container registry uses: docker/login-action@v2 @@ -62,4 +64,5 @@ jobs: context: ./.github/docker-node/ file: ./.github/docker-node/${{ matrix.tag }}.Dockerfile push: true + platforms: linux/amd64,linux/arm64 tags: ghcr.io/${{ github.repository }}/node:${{ matrix.tag }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2286d83..34d6801 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -80,29 +80,59 @@ jobs: env: NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} - load-x64-group: - name: Load x64 Group Config JSON + load-test-group: + name: Load Test Group Config JSON runs-on: ubuntu-latest outputs: - matrix: ${{ steps.set-matrix.outputs.matrix }} + matrix: ${{ steps.set-matrix.outputs.matrix-with-arch }} + arm64-images: ${{ steps.set-matrix.outputs.arm64-images }} steps: - name: Checkout ${{ github.ref }} uses: actions/checkout@v3 - - name: Load x64 group data + - name: Load test group data id: set-matrix - run: .github/scripts/matrix-from-json.sh .github/config/x64-group.json + run: .github/scripts/matrix-from-json.sh .github/config/test-group.json - x64-group-install: - name: x64 Group Install - runs-on: ubuntu-latest - needs: [load-x64-group, build-publish-prebuilt] + launch-arm64: + name: Launch arm64 Runners + runs-on: ubuntu-latest + needs: load-test-group + outputs: + matrix: ${{ steps.launch.outputs.matrix }} + steps: + - name: Setup AWS Credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.CI_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.CI_SECRET_ACCESS_KEY }} + aws-region: us-east-1 + + - name: Launch Runners + id: launch + uses: solarwindscloud/ec2-runner-action@main + with: + action: launch + github-token: ${{ secrets.CI_GITHUB_TOKEN }} + matrix: ${{ needs.load-test-group.outputs.arm64-images }} + runner-user: github + runner-directory: /gh + instance-type: t4g.medium + ami-name: gha-arm64-ubuntu22-.* + ami-owner: ${{ secrets.CI_AMI_OWNER }} + subnet-id: ${{ secrets.CI_SUBNET }} + security-group-ids: ${{ secrets.CI_SECURITY_GROUP }} + + test-group-install: + name: Test Group Install + runs-on: ${{ matrix.arch == 'arm64' && fromJson(needs.launch-arm64.outputs.matrix)[matrix.image].label || 'ubuntu-latest' }} + needs: [load-test-group, launch-arm64, build-publish-prebuilt] strategy: fail-fast: false - matrix: ${{ fromJson(needs.load-x64-group.outputs.matrix) }} + matrix: ${{ fromJson(needs.load-test-group.outputs.matrix) }} container: - image: ${{ matrix.image }} + image: ${{ matrix.image }} env: SW_APM_SERVICE_KEY: ${{ secrets.SW_APM_SERVICE_KEY }} @@ -115,6 +145,13 @@ jobs: - name: Change Owner of Container Working Directory run: chown root:root . if: ${{ contains(matrix.image, 'ghcr.io/solarwindscloud/solarwinds-bindings-node/node') }} + # install deps and spoof os-release to get gha to work on arm64 alpine + # https://github.com/actions/runner/issues/801#issuecomment-1374967227 + - name: Prepare Alpine arm64 + run: | + apk add gcompat + sed -i "s/ID=alpine/ID=armpine/" /etc/os-release + if: ${{ matrix.arch == 'arm64' && contains(matrix.image, 'alpine') }} - name: Checkout ${{ github.ref }} uses: actions/checkout@v3 @@ -135,10 +172,30 @@ jobs: - name: Run Tests run: npm test + terminate-arm64: + name: Terminate arm64 Runners + runs-on: ubuntu-latest + needs: [launch-arm64, test-group-install] + if: always() + steps: + - name: Setup AWS Credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.CI_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.CI_SECRET_ACCESS_KEY }} + aws-region: us-east-1 + + - name: Terminate Runners + uses: solarwindscloud/ec2-runner-action@main + with: + action: terminate + github-token: ${{ secrets.CI_GITHUB_TOKEN }} + matrix: ${{ needs.launch-arm64.outputs.matrix }} + npm-publish: name: NPM Publish runs-on: ubuntu-latest - needs: x64-group-install + needs: test-group-install steps: - name: Checkout ${{ github.ref }} @@ -176,8 +233,8 @@ jobs: unpublish-prebuilt: name: Unpublish prebuilt platform-specific packages runs-on: ubuntu-latest - needs: [build-publish-prebuilt, x64-group-install] - if: ${{ always() && contains(needs.*.result, 'failure') }} + needs: [build-publish-prebuilt, test-group-install] + if: always() && contains(needs.*.result, 'failure') strategy: matrix: node: ['14', '16', '18'] diff --git a/.github/workflows/review.yml b/.github/workflows/review.yml index e2535ec..b568cec 100644 --- a/.github/workflows/review.yml +++ b/.github/workflows/review.yml @@ -54,27 +54,57 @@ jobs: path: npm/* retention-days: 1 - load-x64-group: - name: Load x64 Group Config JSON + load-test-group: + name: Load Test Group Config JSON runs-on: ubuntu-latest outputs: - matrix: ${{ steps.set-matrix.outputs.matrix }} + matrix: ${{ steps.set-matrix.outputs.matrix-with-arch }} + arm64-images: ${{ steps.set-matrix.outputs.arm64-images }} steps: - name: Checkout ${{ github.ref }} uses: actions/checkout@v3 - - name: Load x64 group data + - name: Load test group data id: set-matrix - run: .github/scripts/matrix-from-json.sh .github/config/x64-group.json + run: .github/scripts/matrix-from-json.sh .github/config/test-group.json - x64-group-test: - name: x64 Group Test + launch-arm64: + name: Launch arm64 Runners runs-on: ubuntu-latest - needs: [load-x64-group, build] + needs: load-test-group + outputs: + matrix: ${{ steps.launch.outputs.matrix }} + steps: + - name: Setup AWS Credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.CI_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.CI_SECRET_ACCESS_KEY }} + aws-region: us-east-1 + + - name: Launch Runners + id: launch + uses: solarwindscloud/ec2-runner-action@main + with: + action: launch + github-token: ${{ secrets.CI_GITHUB_TOKEN }} + matrix: ${{ needs.load-test-group.outputs.arm64-images }} + runner-user: github + runner-directory: /gh + instance-type: t4g.medium + ami-name: gha-arm64-ubuntu22-.* + ami-owner: ${{ secrets.CI_AMI_OWNER }} + subnet-id: ${{ secrets.CI_SUBNET }} + security-group-ids: ${{ secrets.CI_SECURITY_GROUP }} + + test-group: + name: Group Test + runs-on: ${{ matrix.arch == 'arm64' && fromJson(needs.launch-arm64.outputs.matrix)[matrix.image].label || 'ubuntu-latest' }} + needs: [load-test-group, launch-arm64, build] strategy: fail-fast: false - matrix: ${{ fromJson(needs.load-x64-group.outputs.matrix) }} + matrix: ${{ fromJson(needs.load-test-group.outputs.matrix) }} container: image: ${{ matrix.image }} @@ -93,6 +123,13 @@ jobs: - name: Change Owner of Container Working Directory run: chown root:root . if: ${{ contains(matrix.image, 'ghcr.io/solarwindscloud/solarwinds-bindings-node/node') }} + # install deps and spoof os-release to get gha to work on arm64 alpine + # https://github.com/actions/runner/issues/801#issuecomment-1374967227 + - name: Prepare Alpine arm64 + run: | + apk add gcompat + sed -i "s/ID=alpine/ID=armpine/" /etc/os-release + if: ${{ matrix.arch == 'arm64' && contains(matrix.image, 'alpine') }} - name: Checkout ${{ github.ref }} uses: actions/checkout@v3 @@ -106,16 +143,19 @@ jobs: # Download all prebuilt packages - name: Download Node 14 packages + if: ${{ contains(matrix.image, '14') }} uses: actions/download-artifact@v3 with: name: npm-14 path: npm/ - name: Download Node 16 packages + if: ${{ contains(matrix.image, '16') }} uses: actions/download-artifact@v3 with: name: npm-16 path: npm/ - name: Download Node 18 packages + if: ${{ contains(matrix.image, '18') }} uses: actions/download-artifact@v3 with: name: npm-18 @@ -127,41 +167,25 @@ jobs: - name: Run tests run: npm test - # we should find a way to properly test on arm hardware - arm64-test: - name: ARMv8 Test + terminate-arm64: + name: Terminate arm64 Runners runs-on: ubuntu-latest - needs: build - strategy: - matrix: - image: ['node:18', 'node:18-alpine'] - + needs: [launch-arm64, test-group] + if: always() steps: - - name: Checkout ${{ github.ref }} - uses: actions/checkout@v3 - - - name: Download Node 18 packages - uses: actions/download-artifact@v3 + - name: Setup AWS Credentials + uses: aws-actions/configure-aws-credentials@v1 with: - name: npm-18 - path: npm/ - - - name: Setup QEMU - uses: docker/setup-qemu-action@v2 + aws-access-key-id: ${{ secrets.CI_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.CI_SECRET_ACCESS_KEY }} + aws-region: us-east-1 - - name: Run tests in ARM container using QEMU - run: | - sudo docker run \ - --entrypoint /bin/sh \ - --platform linux/arm64 \ - -e CI=$CI \ - -e SW_APM_SERVICE_KEY=${{ secrets.SW_APM_SERVICE_KEY }} \ - -e SW_APM_COLLECTOR=${{ secrets.SW_APM_COLLECTOR }} \ - -e SW_TEST_PROD_SERVICE_KEY=${{ secrets.SW_TEST_PROD_SERVICE_KEY }} \ - -e SKIP=test/expose-gc \ - -v $(pwd):/work \ - --rm ${{ matrix.image }} \ - -c 'cat /etc/os-release && cd /work && npm install && npm test' + - name: Terminate Runners + uses: solarwindscloud/ec2-runner-action@main + with: + action: terminate + github-token: ${{ secrets.CI_GITHUB_TOKEN }} + matrix: ${{ needs.launch-arm64.outputs.matrix }} checksum: name: Checksum Liboboe