diff --git a/.github/scripts/test-testbed-server.py b/.github/scripts/test-testbed-server.py new file mode 100644 index 00000000000..3c645d2135b --- /dev/null +++ b/.github/scripts/test-testbed-server.py @@ -0,0 +1,30 @@ +# Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS + +import time +from urllib.request import Request, urlopen + + +def can_connect_to_testbed(r: Request) -> bool: + MAX_RETRIES = 10 + DURATION_BETWEEN_RETRIES = 1 + + for i in range(MAX_RETRIES): + try: + urlopen(r) + except Exception as exc: + print(f"Try {i + 1}/{MAX_RETRIES}: {exc}") + time.sleep(DURATION_BETWEEN_RETRIES) + continue + else: + return True + return False + + +if __name__ == "__main__": + r = Request("http://127.0.0.1:6777/testbed/new/empty", method="POST") + print(f"Will connect to testbed server on: {r.get_full_url()}") + + if can_connect_to_testbed(r): + print("Success") + else: + raise SystemExit("Cannot connect to testbed server :(") diff --git a/.github/workflows/docker-testbed.yml b/.github/workflows/docker-testbed.yml new file mode 100644 index 00000000000..9b636ccfda2 --- /dev/null +++ b/.github/workflows/docker-testbed.yml @@ -0,0 +1,119 @@ +name: Build & Publish docker testbed + +# cspell:words buildx + +on: + # This job must be manually triggered to publish a new version usable from + # other CI runs. + # (see https://github.com/Scille/parsec-cloud/pkgs/container/parsec-cloud%2Fparsec-testbed-server) + workflow_dispatch: + pull_request: + paths: + # Testbed code also depends on `libparsec/**`, but this code change very often + # and we consider the server tests are good enough on this part. + - server/tests/scripts/run_testbed_server.py + - server/packaging/testbed-server/** + - .github/workflows/docker-testbed.yml + push: + branches: + - master + paths: + # Testbed code also depends on `libparsec/**`, but this code change very often + # and we consider the server tests are good enough on this part. + - server/tests/scripts/run_testbed_server.py + - server/packaging/testbed-server/** + - .github/workflows/docker-testbed.yml + +permissions: + contents: write + packages: write + +# We set `concurrency` to prevent having this workflow being run on code that is not up-to-date on a PR (a user make multiple push in a quick manner). +# But on the main branch, we don't want that behavior. +# Having the workflow run on each merge commit is something we would like, that could help us where a regression was made and missed by previous checks. +concurrency: + group: docker-testbed-${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +jobs: + docker-testbed: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # pin v4.1.1 + timeout-minutes: 5 + + # Set up BuildKit Docker container builder to be able to build + # multi-platform images and export cache + # https://github.com/docker/setup-buildx-action + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 + + - name: Log in to the Github Container registry + uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Get current version + id: version + run: | + sed -n 's/^.*Tool.Parsec: "\(.*\)",$/current=\1/p' misc/version_updater.py | tee $GITHUB_OUTPUT + timeout-minutes: 1 + + - name: Generate build metadata + uses: docker/metadata-action@96383f45573cb7f253c731d3b3ab81c87ef81934 # v5.0.0 + id: metadata + with: + images: + ghcr.io/scille/parsec-cloud/parsec-testbed-server + tags: | + type=raw,value=${{ steps.version.outputs.current }}+{{ date 'YYYYMMDD' }}.sha.{{ sha }} + flavor: | + latest=${{ github.event_name == 'workflow_dispatch' }} + + - name: Build and export to Docker + uses: docker/build-push-action@0565240e2d4ab88bba5387d719585280857ece09 # v5.0.0 + id: build + with: + context: . + file: server/packaging/testbed-server/testbed-server.dockerfile + load: true + tags: ${{ steps.metadata.outputs.tags }} + labels: ${{ steps.metadata.outputs.labels }} + push: false + cache-from: type=gha + cache-to: type=gha,mode=max + timeout-minutes: 20 + + - name: Start docker test container + id: test-container + run: | + ( + echo -n "id="; + docker run --detach --publish 6777:6777 --rm --name=parsec-testbed-server ${{ steps.build.outputs.imageid }} + ) | tee $GITHUB_OUTPUT + timeout-minutes: 1 + + - name: Test docker image + run: python .github/scripts/test-testbed-server.py + timeout-minutes: 1 + + - name: Stop docker test container + run: docker container stop ${{ steps.test-container.outputs.id }} + timeout-minutes: 1 + + - name: Image to be published + run: echo ${{ steps.metadata.outputs.tags }} + + - name: Build and publish + if: github.event_name == 'workflow_dispatch' + uses: docker/build-push-action@0565240e2d4ab88bba5387d719585280857ece09 # v5.0.0 + with: + context: . + file: server/packaging/testbed-server/testbed-server.dockerfile + tags: ${{ steps.metadata.outputs.tags }} + labels: ${{ steps.metadata.outputs.labels }} + push: true + cache-from: type=gha + timeout-minutes: 5 diff --git a/.github/workflows/publish-testbed.yml b/.github/workflows/publish-testbed.yml deleted file mode 100644 index 4bd51800749..00000000000 --- a/.github/workflows/publish-testbed.yml +++ /dev/null @@ -1,88 +0,0 @@ -name: Publish docker testbed - -on: - # This job must be manually triggered to publish a new version usable from - # other CI runs. - # (see https://github.com/Scille/parsec-cloud/pkgs/container/parsec-cloud%2Fparsec-testbed-server) - workflow_dispatch: - pull_request: - paths: - # Testbed code also depends on `libparsec/**`, but this code change very often - # and we consider the server tests are good enough on this part. - - server/tests/scripts/run_testbed_server.py - - server/packaging/testbed-server/** - - .github/workflows/publish-testbed.yml - push: - branches: - - master - paths: - # Testbed code also depends on `libparsec/**`, but this code change very often - # and we consider the server tests are good enough on this part. - - server/tests/scripts/run_testbed_server.py - - server/packaging/testbed-server/** - - .github/workflows/publish-testbed.yml - -permissions: - contents: write - packages: write - -jobs: - publish-testbed: - runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # pin v4.1.1 - timeout-minutes: 5 - - - name: Log in to the Container registry - uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Build docker image - run: bash server/packaging/testbed-server/build.sh 2>&1 - env: - WRITE_ENV: 1 - timeout-minutes: 20 - - - name: Test docker image - run: | - set -ex - - source parsec-testbed.env - - docker run --publish 6777:6777 --rm --name=parsec-testbed-server $PREFIX/parsec-testbed-server:$UNIQ_TAG & - - python -c " - import time - from urllib.request import Request, urlopen - - r = Request('http://127.0.0.1:6777/testbed/new/empty', method='POST') - for i in range(10): - try: - urlopen(r) - except Exception as exc: - print(f'Try {i + 1}/10: {exc}') - time.sleep(1) - continue - else: - break - else: - raise SystemExit('Cannot connect to testbed server :(') - " - - kill %1 - - - name: Publish docker image - if: github.event_name == 'workflow_dispatch' - run: | - set -ex - - source parsec-testbed.env - - for tag in $UNIQ_TAG; do - echo "Pushing tag \`$tag\` to \`$PREFIX\`" - docker push $PREFIX/parsec-testbed-server:$tag - done - timeout-minutes: 5 diff --git a/server/packaging/testbed-server/testbed-server.dockerfile b/server/packaging/testbed-server/testbed-server.dockerfile index f9ad95325e1..d80a72faec7 100644 --- a/server/packaging/testbed-server/testbed-server.dockerfile +++ b/server/packaging/testbed-server/testbed-server.dockerfile @@ -18,7 +18,7 @@ ADD --link \ Cargo.toml \ make.py \ server/packaging/testbed-server/in-docker-build.sh \ - . + ./ ADD --link libparsec/ libparsec/ ADD --link server/ server/ ADD --link bindings/ bindings/