diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000000..5005092c7e --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,661 @@ +# .circleci/config.yml +version: 2.1 + +executors: + ubuntu2204arm64: + machine: + image: ubuntu-2204:current + resource_class: arm-medium + ubuntu2204amd64: + machine: + image: ubuntu-2204:current + resource_class: medium + ubuntu2204arm64large: + machine: + image: ubuntu-2204:current + resource_class: arm-large + +jobs: + build-multi-arch: + parameters: + platforms: + type: string + machine-type: + type: executor + executor: << parameters.machine-type >> + environment: + NAMESPACE: seleniarm + BUILD_DATE: today + steps: + - run: + name: "Prepare workflow environment variables" + command: | + echo 'export BRANCH="${CIRCLE_BRANCH//\//-}"' >> $BASH_ENV + cat $BASH_ENV + source $BASH_ENV + echo "Workflow environment variables:" + echo $BRANCH + - run: uname -a + - run: docker info + - checkout + - run: + name: "Build Docker images" + command: | + echo "Branch is $BRANCH" + ARCH=$(echo << parameters.platforms >> | sed 's/linux\///') + NAME=${NAMESPACE} VERSION=${BRANCH}_${ARCH} BUILD_DATE=${BUILD_DATE} BUILD_ARGS=${BUILD_ARGS} make all_${ARCH} + - run: + name: "Inspect Docker Images" + command: | + VERSION=${CIRCLE_BRANCH//\//-} + ARCH=$(echo << parameters.platforms >> | sed 's/linux\///') + export TAG=${VERSION}_${ARCH}-${BUILD_DATE} + echo "TAG is ${TAG}" + docker image inspect $NAMESPACE/base:$TAG + docker image inspect $NAMESPACE/node-base:$TAG + docker image inspect $NAMESPACE/hub:$TAG + docker image inspect $NAMESPACE/node-chromium:$TAG + docker image inspect $NAMESPACE/standalone-chromium:$TAG + docker image inspect $NAMESPACE/node-firefox:$TAG + docker image inspect $NAMESPACE/standalone-firefox:$TAG + if [ "${ARCH}" = "amd64" ]; then + docker image inspect $NAMESPACE/node-chrome:$TAG + docker image inspect $NAMESPACE/standalone-chrome:$TAG + docker image inspect $NAMESPACE/node-edge:$TAG + docker image inspect $NAMESPACE/standalone-edge:$TAG + fi + - run: + name: "Save Docker Images in Cache" + command: | + export VERSION=${CIRCLE_BRANCH//\//-} + ARCH=$(echo << parameters.platforms >> | sed 's/linux\///') + export TAG=${VERSION}_${ARCH}-${BUILD_DATE} + mkdir images + echo "TAG is ${TAG}" + echo $NAMESPACE/base:$TAG + echo $NAMESPACE/node-base:$TAG + echo $NAMESPACE/hub:$TAG + echo $NAMESPACE/node-chromium:$TAG + echo $NAMESPACE/standalone-chromium:$TAG + echo $NAMESPACE/node-firefox:$TAG + echo $NAMESPACE/standalone-firefox:$TAG + if [ "${ARCH}" = "amd64" ]; then + echo $NAMESPACE/node-chrome:$TAG + echo $NAMESPACE/standalone-chrome:$TAG + echo $NAMESPACE/node-edge:$TAG + echo $NAMESPACE/standalone-edge:$TAG + fi + docker save -o images/${ARCH}.tar \ + $NAMESPACE/base:$TAG\ + $NAMESPACE/node-base:$TAG\ + $NAMESPACE/hub:$TAG\ + $NAMESPACE/node-chromium:$TAG\ + $NAMESPACE/standalone-chromium:$TAG\ + $NAMESPACE/node-firefox:$TAG\ + $NAMESPACE/standalone-firefox:$TAG\ + $(if [ "${ARCH}" = "amd64" ]; then echo "$NAMESPACE/node-chrome:$TAG $NAMESPACE/standalone-chrome:$TAG"; fi) \ + $(if [ "${ARCH}" = "amd64" ]; then echo "$NAMESPACE/node-edge:$TAG $NAMESPACE/standalone-edge:$TAG"; fi) + - save_cache: + key: multi-arch-images-{{ .Branch }}-{{ .Environment.CIRCLE_WORKFLOW_ID }}-<< parameters.platforms >> + paths: + - images + - store_artifacts: + path: images + + test-multi-arch: + parameters: + platforms: + type: string + machine-type: + type: executor + executor: << parameters.machine-type >> + environment: + NAMESPACE: seleniarm + BUILD_DATE: today + steps: + - checkout + - restore_cache: + keys: + - multi-arch-images-{{ .Branch }}-{{ .Environment.CIRCLE_WORKFLOW_ID }}-<< parameters.platforms >> + - run: uname -a + - run: docker info + - run: + name: "Load built images from cache into Docker" + command: | + echo "CIRCLE_WORKFLOW_ID = " $CIRCLE_WORKFLOW_ID + ARCH=$(echo << parameters.platforms >> | sed 's/linux\///') + docker load -i images/${ARCH}.tar + - run: + name: "Use Python3 and pip3 instead of Python2.7" + command: | + echo "Use Python3 and pip3 instead of Python2.7" + sed -i 's/pip /pip3 /g' tests/bootstrap.sh + sed -i 's/python /python3 /g' tests/bootstrap.sh + sed -i 's/-m pip3 /-m pip /g' tests/bootstrap.sh + - run: + name: "Test Docker images" + no_output_timeout: 2m + command: | + export USE_RANDOM_USER=false + export BRANCH=${CIRCLE_BRANCH//\//-} + ARCH=$(echo << parameters.platforms >> | sed 's/linux\///') + USE_RANDOM_USER_ID=${USE_RANDOM_USER} NAMESPACE=${NAMESPACE} VERSION=${BRANCH}_${ARCH} BUILD_DATE=${BUILD_DATE} SKIP_BUILD=true make test_${ARCH} + + test-video: + parameters: + platforms: + type: string + machine-type: + type: executor + executor: << parameters.machine-type >> + environment: + NAMESPACE: seleniarm + BUILD_DATE: today + steps: + - checkout + - run: uname -a + - run: docker info + - run: + name: "Use Python3 and pip3 instead of Python2.7" + command: | + echo "Use Python3 and pip3 instead of Python2.7" + sed -i 's/pip /pip3 /g' tests/bootstrap.sh + sed -i 's/python /python3 /g' tests/bootstrap.sh + sed -i 's/-m pip3 /-m pip /g' tests/bootstrap.sh + - run: + name: "Test and Build Docker images" + no_output_timeout: 2m + command: | + export USE_RANDOM_USER=false + export BRANCH=${CIRCLE_BRANCH//\//-} + ARCH=$(echo << parameters.platforms >> | sed 's/linux\///') + NAME=${NAMESPACE} USE_RANDOM_USER_ID=${USE_RANDOM_USER} NAMESPACE=${NAMESPACE} FFMPEG_TAG_VERSION=${BRANCH}_${ARCH} VERSION=${BRANCH}_${ARCH} BUILD_DATE=${BUILD_DATE} make test_video + - store_artifacts: + path: tests/videos + - run: + name: "Inspect Docker Images" + command: | + VERSION=${CIRCLE_BRANCH//\//-} + ARCH=$(echo << parameters.platforms >> | sed 's/linux\///') + export TAG=${VERSION}_${ARCH}-${BUILD_DATE} + echo "TAG is ${TAG}" + docker image inspect $NAMESPACE/video:$TAG + - run: + name: "Save Docker Image in Cache" + command: | + export VERSION=${CIRCLE_BRANCH//\//-} + ARCH=$(echo << parameters.platforms >> | sed 's/linux\///') + export TAG=${VERSION}_${ARCH}-${BUILD_DATE} + mkdir images + echo "TAG is ${TAG}" + echo $NAMESPACE/video:$TAG + docker save -o images/video.tar \ + $NAMESPACE/video:$TAG + - save_cache: + key: video-{{ .Branch }}-{{ .Environment.CIRCLE_WORKFLOW_ID }}-<< parameters.platforms >> + paths: + - images + - store_artifacts: + path: images + + manifest-multi-arch: + parameters: + image-name: + type: string + machine-type: + type: executor + executor: << parameters.machine-type >> + environment: + NAMESPACE: seleniarm + BUILD_DATE: today + steps: + - checkout + - restore_cache: + keys: + - multi-arch-images-{{ .Branch }}-{{ .Environment.CIRCLE_WORKFLOW_ID }}-linux/arm64 + - restore_cache: + keys: + - multi-arch-images-{{ .Branch }}-{{ .Environment.CIRCLE_WORKFLOW_ID }}-linux/amd64 + - run: uname -a + - run: docker info + - run: + name: "Load built images from cache into Docker" + command: | + echo "CIRCLE_WORKFLOW_ID = " $CIRCLE_WORKFLOW_ID + docker load -i images/arm64.tar + docker load -i images/amd64.tar + - run: + name: "Create manifest" + command: | + VERSION=${CIRCLE_BRANCH//\//-} + IMAGE_NAME=$NAMESPACE/<< parameters.image-name >> + MANIFEST_TAG=${VERSION}-${BUILD_DATE} + ARM_TAG=${VERSION}_arm64-${BUILD_DATE} + AMD_TAG=${VERSION}_amd64-${BUILD_DATE} + echo "Creating ${IMAGE_NAME}:${MANIFEST_TAG} based on ${IMAGE_NAME}:${ARM_TAG} and ${IMAGE_NAME}:${AMD_TAG}" + MANIFEST_IMAGE=${IMAGE_NAME}:${MANIFEST_TAG} + ARM_IMAGE=${IMAGE_NAME}_arm64:${MANIFEST_TAG} + AMD_IMAGE=${IMAGE_NAME}_amd64:${MANIFEST_TAG} + docker tag ${IMAGE_NAME}:${ARM_TAG} ${ARM_IMAGE} + docker tag ${IMAGE_NAME}:${AMD_TAG} ${AMD_IMAGE} + echo "${DOCKER_PASSWORD}" | docker login --username "${DOCKER_USERNAME}" --password-stdin + docker push ${ARM_IMAGE} + docker push ${AMD_IMAGE} + docker manifest create ${MANIFEST_IMAGE} ${ARM_IMAGE} ${AMD_IMAGE} + docker manifest push ${MANIFEST_IMAGE} + - run: + name: "Inspect manifest" + command: | + VERSION=${CIRCLE_BRANCH//\//-} + IMAGE_NAME=$NAMESPACE/<< parameters.image-name >> + MANIFEST_TAG=${VERSION}-${BUILD_DATE} + docker manifest inspect ${IMAGE_NAME}:${MANIFEST_TAG} + + manifest-amd-only-arch: + parameters: + image-name: + type: string + machine-type: + type: executor + executor: << parameters.machine-type >> + environment: + NAMESPACE: seleniarm + BUILD_DATE: today + steps: + - checkout + - restore_cache: + keys: + - multi-arch-images-{{ .Branch }}-{{ .Environment.CIRCLE_WORKFLOW_ID }}-linux/amd64 + - run: uname -a + - run: docker info + - run: + name: "Load built images from cache into Docker" + command: | + echo "CIRCLE_WORKFLOW_ID = " $CIRCLE_WORKFLOW_ID + docker load -i images/amd64.tar + - run: + name: "Create manifest" + command: | + VERSION=${CIRCLE_BRANCH//\//-} + IMAGE_NAME=$NAMESPACE/<< parameters.image-name >> + MANIFEST_TAG=${VERSION}-${BUILD_DATE} + AMD_TAG=${VERSION}_amd64-${BUILD_DATE} + echo "Creating ${IMAGE_NAME}:${MANIFEST_TAG} based on ${IMAGE_NAME}:${AMD_TAG}" + MANIFEST_IMAGE=${IMAGE_NAME}:${MANIFEST_TAG} + AMD_IMAGE=${IMAGE_NAME}_amd64:${MANIFEST_TAG} + docker tag ${IMAGE_NAME}:${AMD_TAG} ${AMD_IMAGE} + echo "${DOCKER_PASSWORD}" | docker login --username "${DOCKER_USERNAME}" --password-stdin + docker push ${AMD_IMAGE} + docker manifest create ${MANIFEST_IMAGE} ${AMD_IMAGE} + docker manifest push ${MANIFEST_IMAGE} + - run: + name: "Inspect manifest" + command: | + VERSION=${CIRCLE_BRANCH//\//-} + IMAGE_NAME=$NAMESPACE/<< parameters.image-name >> + MANIFEST_TAG=${VERSION}-${BUILD_DATE} + docker manifest inspect ${IMAGE_NAME}:${MANIFEST_TAG} + + manifest-amd-image: + parameters: + image-name: + type: string + machine-type: + type: executor + executor: << parameters.machine-type >> + environment: + NAMESPACE: seleniarm + BUILD_DATE: today + steps: + - checkout + - restore_cache: + keys: + - << parameters.image-name >>-{{ .Branch }}-{{ .Environment.CIRCLE_WORKFLOW_ID }}-linux/amd64 + - run: uname -a + - run: docker info + - run: + name: "Load built images from cache into Docker" + command: | + echo "CIRCLE_WORKFLOW_ID = " $CIRCLE_WORKFLOW_ID + docker load -i images/<< parameters.image-name >>.tar + - run: + name: "Create manifest" + command: | + VERSION=${CIRCLE_BRANCH//\//-} + IMAGE_NAME=$NAMESPACE/<< parameters.image-name >> + MANIFEST_TAG=${VERSION}-${BUILD_DATE} + AMD_TAG=${VERSION}_amd64-${BUILD_DATE} + echo "Creating ${IMAGE_NAME}:${MANIFEST_TAG} based on ${IMAGE_NAME}:${AMD_TAG}" + MANIFEST_IMAGE=${IMAGE_NAME}:${MANIFEST_TAG} + AMD_IMAGE=${IMAGE_NAME}_amd64:${MANIFEST_TAG} + docker tag ${IMAGE_NAME}:${AMD_TAG} ${AMD_IMAGE} + echo "${DOCKER_PASSWORD}" | docker login --username "${DOCKER_USERNAME}" --password-stdin + docker push ${AMD_IMAGE} + docker manifest create ${MANIFEST_IMAGE} ${AMD_IMAGE} + docker manifest push ${MANIFEST_IMAGE} + - run: + name: "Inspect manifest" + command: | + VERSION=${CIRCLE_BRANCH//\//-} + IMAGE_NAME=$NAMESPACE/<< parameters.image-name >> + MANIFEST_TAG=${VERSION}-${BUILD_DATE} + docker manifest inspect ${IMAGE_NAME}:${MANIFEST_TAG} + + deploy-multi-arch: + parameters: + platforms: + type: string + build-args: + type: string + machine-type: + type: executor + executor: << parameters.machine-type >> + environment: + NAMESPACE: seleniarm + PLATFORMS: << parameters.platforms >> + BUILD_ARGS: << parameters.build-args >> + DEPLOY_BRANCH: trunk + GITHUB_USER: seleniumhq-community + GITHUB_REPO: docker-seleniarm + steps: + - checkout + - run: + name: "Prepare workflow environment variables" + command: | + export SELENIUM_VERSION=$(grep selenium-server Base/Dockerfile | sed 's/.*-\([^-]*\)\.jar \\/\1/' | head -n 1) + echo "Prepare workflow environment variables" + echo 'export BRANCH='$SELENIUM_VERSION >> $BASH_ENV + echo 'export BUILD_DATE=$(date '+%Y%m%d')' >> $BASH_ENV + echo 'export RELEASE_TAG="seleniarm-v`echo $BRANCH`-`echo $BUILD_DATE`"' >> $BASH_ENV + source $BASH_ENV + echo "Workflow environment variables:" + echo BRANCH="$BRANCH" + echo BUILD_DATE="$BUILD_DATE" + echo RELEASE_TAG="$RELEASE_TAG" + echo NAMESPACE="$NAMESPACE" + echo PLATFORMS="$PLATFORMS" + echo BUILD_ARGS="$BUILD_ARGS" + echo DEPLOY_BRANCH="$DEPLOY_BRANCH" + echo GITHUB_USER="$GITHUB_USER" + echo GITHUB_REPO="$GITHUB_REPO" + - run: uname -a + - run: docker info + - run: + name: "Check if branch is deployable (contains [deploy] in commit msg on $DEPLOY_BRANCH" + command: | + echo BRANCH="$BRANCH" + echo BUILD_DATE="$BUILD_DATE" + echo RELEASE_TAG="$RELEASE_TAG" + export CI_DEPLOY=`git log --format=oneline -n 1 | grep '\[deploy\]'` && echo "$CI_DEPLOY" + if [ -z "$CI_DEPLOY" ] || [ "$CIRCLE_BRANCH" != "$DEPLOY_BRANCH" ]; then + echo "Cancelling run. Pass [deploy] in commit message on $DEPLOY_BRANCH to deploy" + circleci-agent step halt + else + echo "[deploy] is present in commit message to $DEPLOY_BRANCH. Running workflow to deploy container images" + fi + - run: + name: "Build and Push Docker images" + command: | + echo "Login to Docker, and setup to use a buildx builder and push built multi-arch images" + docker buildx use `docker buildx create` + docker buildx ls + docker login -u="$DOCKER_USERNAME" -p="$DOCKER_PASSWORD" + echo BRANCH="$BRANCH" + echo BUILD_DATE="$BUILD_DATE" + echo RELEASE_TAG="$RELEASE_TAG" + export CI_DEPLOY=`git log --format=oneline -n 1 | grep '\[deploy\]'` && echo "$CI_DEPLOY" + NAME=${NAMESPACE} VERSION=${BRANCH} BUILD_DATE=${BUILD_DATE} PLATFORMS=${PLATFORMS} BUILD_ARGS=${BUILD_ARGS} make build_multi + - run: + name: "Tag browser images and update latest tag" + command: | + NAME=${NAMESPACE} VERSION=${BRANCH} BUILD_DATE=${BUILD_DATE} PUSH_IMAGE=true make tag_and_push_multi_arch_browser_images + NAME=${NAMESPACE} VERSION=${BRANCH} BUILD_DATE=${BUILD_DATE} make tag_multi_arch_latest + - run: + name: "Generate release notes" + command: | + export LATEST_TAG=$(git describe --tags --abbrev=0) + sh generate_multi-arch-release_notes.sh $LATEST_TAG $CIRCLE_BRANCH $BRANCH $BUILD_DATE + sudo apt-get update -y && sudo apt-get install python3-venv + go install github.com/github-release/github-release@v0.10.0 + cat release_notes.md + export GITHUB_TOKEN=$(sh get-access-token.sh | tail -n 1) + github-release release --tag $RELEASE_TAG --name $RELEASE_TAG --description "`cat release_notes.md`" + + deploy-multi-arch-full-grid: + parameters: + platforms: + type: string + build-args: + type: string + machine-type: + type: executor + circle-job: + type: env_var_name + default: CIRCLE_JOB + make-targets: + type: string + executor: << parameters.machine-type >> + environment: + NAMESPACE: seleniarm + PLATFORMS: << parameters.platforms >> + BUILD_ARGS: << parameters.build-args >> + MAKE_TARGETS: << parameters.make-targets >> + DEPLOY_BRANCH: trunk + GITHUB_USER: seleniumhq-community + GITHUB_REPO: docker-seleniarm + steps: + - checkout + - run: + name: Debug + command: | + echo $CIRCLE_JOB + echo ${<< parameters.circle-job >>} + - when: + condition: + equal: [ base_multi, << parameters.make-targets >> ] + steps: + - run: echo "CIRCLE_JOB name is deploy-multi-arch-base" + - when: + condition: + equal: [ tag_and_push_multi_arch_browser_images, << parameters.make-targets >> ] + steps: + - run: echo "CIRCLE_JOB name is release notes, so we proceed" + - run: + name: "Prepare workflow environment variables" + command: | + export SELENIUM_VERSION=$(grep selenium-server Base/Dockerfile | sed 's/.*-\([^-]*\)\.jar \\/\1/' | head -n 1) + echo "Prepare workflow environment variables" + echo 'export BRANCH='$SELENIUM_VERSION >> $BASH_ENV + echo 'export BUILD_DATE=$(date '+%Y%m%d')' >> $BASH_ENV + #echo 'export BUILD_DATE=20230110' >> $BASH_ENV + echo 'export RELEASE_TAG="seleniarm-v`echo $BRANCH`-`echo $BUILD_DATE`"' >> $BASH_ENV + source $BASH_ENV + echo "Workflow environment variables:" + echo BRANCH="$BRANCH" + echo BUILD_DATE="$BUILD_DATE" + echo RELEASE_TAG="$RELEASE_TAG" + echo NAMESPACE="$NAMESPACE" + echo PLATFORMS="$PLATFORMS" + echo BUILD_ARGS="$BUILD_ARGS" + echo DEPLOY_BRANCH="$DEPLOY_BRANCH" + echo GITHUB_USER="$GITHUB_USER" + echo GITHUB_REPO="$GITHUB_REPO" + - run: uname -a + - run: docker info + - run: + name: "Check if branch is deployable (contains [deploy] in commit msg on $DEPLOY_BRANCH" + command: | + echo BRANCH="$BRANCH" + echo BUILD_DATE="$BUILD_DATE" + echo RELEASE_TAG="$RELEASE_TAG" + export CI_DEPLOY=`git log --format=oneline -n 1 | grep '\[deploy\]'` && echo "$CI_DEPLOY" + if [ -z "$CI_DEPLOY" ] || [ "$CIRCLE_BRANCH" != "$DEPLOY_BRANCH" ]; then + echo "Cancelling run. Pass [deploy] in commit message on $DEPLOY_BRANCH to deploy" + circleci-agent step halt + else + echo "[deploy] is present in commit message to $DEPLOY_BRANCH. Running workflow to deploy container images" + fi + - run: + name: "Build and Push Docker images" + command: | + echo "Login to Docker, and setup to use a buildx builder and push built multi-arch images" + docker buildx use `docker buildx create` + docker buildx ls + # For release notes, we'll pull images anonymously without login. + # if [ "$MAKE_TARGETS" != "tag_and_push_multi_arch_browser_images" ]; then + docker login -u="$DOCKER_USERNAME" -p="$DOCKER_PASSWORD" + # fi + echo BRANCH="$BRANCH" + echo BUILD_DATE="$BUILD_DATE" + echo RELEASE_TAG="$RELEASE_TAG" + export CI_DEPLOY=`git log --format=oneline -n 1 | grep '\[deploy\]'` && echo "$CI_DEPLOY" + #NAME=${NAMESPACE} VERSION=${BRANCH} BUILD_DATE=${BUILD_DATE} PLATFORMS=${PLATFORMS} BUILD_ARGS=${BUILD_ARGS} sh build-and-push.sh $MAKE_TARGETS + + export NAME=${NAMESPACE} + export VERSION=${BRANCH} + export BUILD_DATE=${BUILD_DATE} + export PLATFORMS=${PLATFORMS} + export BUILD_ARGS=${BUILD_ARGS} + # If there are build errors, let's retry + max=5; until sh build-and-push.sh $MAKE_TARGETS; do if [ $((--max)) = 0 ]; then echo Giving up; break; fi; done + + - when: + condition: + equal: [ tag_and_push_multi_arch_browser_images, << parameters.make-targets >> ] + steps: + - run: + name: "Push major/minor and browser tags to Docker Hub and update latest tag" + command: | + NAME=${NAMESPACE} VERSION=${BRANCH} BUILD_DATE=${BUILD_DATE} PUSH_IMAGE=true make tag_and_push_multi_arch_browser_images + NAME=${NAMESPACE} VERSION=${BRANCH} BUILD_DATE=${BUILD_DATE} make tag_multi_arch_latest + - run: + name: "Push major/minor tags to Docker Hub for non-browser images" + command: | + NAME=${NAMESPACE} VERSION=${BRANCH} BUILD_DATE=${BUILD_DATE} PUSH_IMAGE=true make tag_major_minor_multi_arch + - run: + name: "Generate release notes" + command: | + docker logout + export LATEST_TAG=$(git describe --tags --abbrev=0) + sh generate_multi-arch-release_notes.sh $LATEST_TAG $CIRCLE_BRANCH $BRANCH $BUILD_DATE + sudo apt-get update -y && sudo apt-get install python3-venv + go install github.com/github-release/github-release@v0.10.0 + cat release_notes.md + export GITHUB_TOKEN=$(sh get-access-token.sh | tail -n 1) + github-release release --tag $RELEASE_TAG --name $RELEASE_TAG --description "`cat release_notes.md`" + +workflows: + build-and-test-multi-arch: + jobs: + - build-multi-arch: + name: build-multi-arch-arm64 + platforms: linux/arm64 + machine-type: ubuntu2204arm64 + - build-multi-arch: + name: build-multi-arch-amd64 + platforms: linux/amd64 + machine-type: ubuntu2204amd64 + - test-multi-arch: + name: test-multi-arch-arm64 + requires: [build-multi-arch-arm64] + platforms: linux/arm64 + machine-type: ubuntu2204arm64 + - test-multi-arch: + name: test-multi-arch-amd64 + requires: [build-multi-arch-amd64] + platforms: linux/amd64 + machine-type: ubuntu2204amd64 + - manifest-multi-arch: + name: manifest-multi-arch-<< matrix.image-name >> + requires: [test-multi-arch-arm64, test-multi-arch-amd64] + machine-type: ubuntu2204amd64 + matrix: + parameters: + image-name: [ base, node-base, hub, node-chromium, standalone-chromium, node-firefox, standalone-firefox ] + - manifest-amd-only-arch: + name: manifest-amd-arch-<< matrix.image-name >> + requires: [test-multi-arch-amd64] + machine-type: ubuntu2204amd64 + matrix: + parameters: + image-name: [ node-chrome, standalone-chrome, node-edge, standalone-edge ] + + build-and-test-video: + jobs: + - test-video: + name: test-video-amd64 + platforms: linux/amd64 + machine-type: ubuntu2204amd64 + - manifest-amd-image: + name: manifest-video-amd64 + requires: [test-video-amd64] + machine-type: ubuntu2204amd64 + image-name: video + + deploy-multi-arch-full-grid: + jobs: + - deploy-multi-arch-full-grid: + name: deploy-multi-arch-base + platforms: linux/arm64,linux/amd64,linux/arm/v7 + build-args: --push + make-targets: base_multi + machine-type: ubuntu2204arm64large + filters: + branches: + only: + - trunk + - deploy-multi-arch-full-grid: + name: deploy-multi-arch-full-grid + requires: [deploy-multi-arch-base] + platforms: linux/arm64,linux/amd64,linux/arm/v7 + build-args: --push + make-targets: grid_multi + machine-type: ubuntu2204arm64 + filters: + branches: + only: + - trunk + - deploy-multi-arch-full-grid: + name: deploy-multi-arch-node-base + requires: [deploy-multi-arch-base] + platforms: linux/arm64,linux/amd64,linux/arm/v7 + build-args: --push + make-targets: node_base_multi + machine-type: ubuntu2204arm64large + filters: + branches: + only: + - trunk + - deploy-multi-arch-full-grid: + name: deploy-multi-arch-firefox + requires: [deploy-multi-arch-node-base] + platforms: linux/arm64,linux/amd64,linux/arm/v7 + build-args: --push + make-targets: firefox_multi + machine-type: ubuntu2204arm64large + filters: + branches: + only: + - trunk + - deploy-multi-arch-full-grid: + name: deploy-multi-arch-chromium + requires: [deploy-multi-arch-node-base] + platforms: linux/arm64,linux/amd64,linux/arm/v7 + build-args: --push + make-targets: chromium_multi + machine-type: ubuntu2204arm64large + filters: + branches: + only: + - trunk + - deploy-multi-arch-full-grid: + name: deploy-multi-arch-release-notes + requires: [deploy-multi-arch-firefox,deploy-multi-arch-chromium] + platforms: linux/arm64,linux/amd64,linux/arm/v7 + build-args: --push + make-targets: tag_and_push_multi_arch_browser_images + machine-type: ubuntu2204arm64 + filters: + branches: + only: + - trunk diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 637f89b292..5aec98bec2 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -6,6 +6,12 @@ updates: interval: daily time: '08:00' open-pull-requests-limit: 99 +- package-ecosystem: docker + directory: "/StandaloneChromium" + schedule: + interval: daily + time: '08:00' + open-pull-requests-limit: 99 - package-ecosystem: docker directory: "/StandaloneFirefox" schedule: @@ -36,6 +42,12 @@ updates: interval: daily time: '08:00' open-pull-requests-limit: 99 +- package-ecosystem: docker + directory: "/NodeChromium" + schedule: + interval: daily + time: '08:00' + open-pull-requests-limit: 99 - package-ecosystem: docker directory: "/" schedule: diff --git a/.github/workflows/build-test-multi-arch.yml b/.github/workflows/build-test-multi-arch.yml new file mode 100644 index 0000000000..b8e9c941d5 --- /dev/null +++ b/.github/workflows/build-test-multi-arch.yml @@ -0,0 +1,59 @@ +name: Build & test multi-arch + +on: + # push: + # branches: + # - multi-arch-tests + # - qemu-user-static + # pull_request: + # branches: + # - trunk + workflow_dispatch: + +jobs: + build-and-test-multi-arch: + # Skip job based on the commit message, only works in push to branches for now + if: contains(toJson(github.event.commits), '[skip ci]') == false + name: Build & test multi-arch + runs-on: ubuntu-20.04 + strategy: + matrix: + use-random-user: [false, true] + arch: [amd64, arm64] + fail-fast: false + + steps: + - uses: actions/checkout@v1 + - name: Output Docker info + run: docker info + - name: Set up Python 3.8 + uses: actions/setup-python@v2 + with: + python-version: 3.8 + - name: Get branch name (only for push to branch) + if: github.event_name == 'push' + run: echo "BRANCH=$(echo ${PUSH_BRANCH##*/})" >> $GITHUB_ENV + env: + PUSH_BRANCH: ${{ github.ref }} + - name: Get target branch name (only for PRs) + if: github.event_name == 'pull_request' + run: echo "BRANCH=$(echo ${TARGET_BRANCH##*/})" >> $GITHUB_ENV + env: + TARGET_BRANCH: ${{ github.head_ref }} + - name: Output branch name + run: echo ${BRANCH} + - name: Sets build date + run: echo "BUILD_DATE=$(date '+%Y%m%d')" >> $GITHUB_ENV + - name: Build Docker images + run: VERSION=${BRANCH} BUILD_DATE=${BUILD_DATE} ARCH=${ARCH} make build_multi + if: matrix.arch == 'arm64' && matrix.use-random-user == 'false' + - name: Test Docker images + run: | + docker run -d --platform linux/${ARCH} --rm -it -p 4444:4444 -p 7900:7900 --shm-size 2g selenium/standalone-firefox:${BRANCH}-${BUILD_DATE} + USE_RANDOM_USER_ID=${USE_RANDOM_USER} VERSION=${BRANCH} BUILD_DATE=${BUILD_DATE} ARCH=${ARCH} SKIP_BUILD=true make test_firefox_standalone_multi + #USE_RANDOM_USER_ID=${USE_RANDOM_USER} VERSION=${BRANCH} BUILD_DATE=${BUILD_DATE} ARCH=${ARCH} SKIP_BUILD=true make test_chromium_standalone_multi + env: + USE_RANDOM_USER: ${{ matrix.use-random-user }} + ARCH: ${{ matrix.arch }} + if: matrix.arch == 'arm64' && matrix.use-random-user == 'false' + diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index b40db3af6b..63b94252cd 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -2,7 +2,11 @@ name: Build & test on: push: + paths-ignore: + - '.circleci/**' pull_request: + paths-ignore: + - '.circleci/**' permissions: contents: read diff --git a/.github/workflows/helm-chart-test.yml b/.github/workflows/helm-chart-test.yml index 887e6b5daa..6bd18a4ec5 100644 --- a/.github/workflows/helm-chart-test.yml +++ b/.github/workflows/helm-chart-test.yml @@ -2,7 +2,11 @@ name: Lint and Test Helm Charts on: push: + paths-ignore: + - '.circleci/**' pull_request: + paths-ignore: + - '.circleci/**' workflow_dispatch: permissions: diff --git a/.github/workflows/test-video.yml b/.github/workflows/test-video.yml index 02aa7f7c46..4982447f5e 100644 --- a/.github/workflows/test-video.yml +++ b/.github/workflows/test-video.yml @@ -2,7 +2,11 @@ name: Test video files on: push: + paths-ignore: + - '.circleci/**' pull_request: + paths-ignore: + - '.circleci/**' permissions: contents: read @@ -41,6 +45,11 @@ jobs: with: name: chrome_video path: ./tests/videos/chrome_video.mp4 + - name: Upload recorded Chromium video + uses: actions/upload-artifact@v4 + with: + name: chromium_video + path: ./tests/videos/chromium_video.mp4 - name: Upload recorded Edge video uses: actions/upload-artifact@v4 with: diff --git a/Base/Dockerfile b/Base/Dockerfile index ec37f81107..a5189f6755 100644 --- a/Base/Dockerfile +++ b/Base/Dockerfile @@ -18,9 +18,12 @@ USER root #================================================ # Customize sources for apt-get #================================================ -RUN echo "deb http://archive.ubuntu.com/ubuntu jammy main universe\n" > /etc/apt/sources.list \ - && echo "deb http://archive.ubuntu.com/ubuntu jammy-updates main universe\n" >> /etc/apt/sources.list \ - && echo "deb http://security.ubuntu.com/ubuntu jammy-security main universe\n" >> /etc/apt/sources.list +RUN echo "deb [arch=amd64,i386] http://archive.ubuntu.com/ubuntu jammy main universe\n" > /etc/apt/sources.list \ + && echo "deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports jammy main universe\n" >> /etc/apt/sources.list \ + && echo "deb [arch=amd64,i386] http://archive.ubuntu.com/ubuntu jammy-updates main universe\n" >> /etc/apt/sources.list \ + && echo "deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports jammy-updates main universe\n" >> /etc/apt/sources.list \ + && echo "deb [arch=amd64,i386] http://security.ubuntu.com/ubuntu jammy-security main universe\n" >> /etc/apt/sources.list \ + && echo "deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports jammy-security main universe\n" >> /etc/apt/sources.list # No interactive frontend during docker build ENV DEBIAN_FRONTEND=noninteractive \ @@ -47,7 +50,8 @@ RUN apt-get -qqy update \ gnupg2 \ libnss3-tools \ && rm -rf /var/lib/apt/lists/* /var/cache/apt/* \ - && sed -i 's/securerandom\.source=file:\/dev\/random/securerandom\.source=file:\/dev\/urandom/' ./usr/lib/jvm/java-11-openjdk-amd64/conf/security/java.security + && ARCH=$(arch | sed s/aarch64/arm64/ | sed s/x86_64/amd64/) \ + && sed -i 's/securerandom\.source=file:\/dev\/random/securerandom\.source=file:\/dev\/urandom/' ./usr/lib/jvm/java-11-openjdk-${ARCH}/conf/security/java.security #=================== # Timezone settings diff --git a/Makefile b/Makefile index 5df2eb27ec..01f320233e 100644 --- a/Makefile +++ b/Makefile @@ -26,13 +26,29 @@ all: hub \ chrome \ edge \ firefox \ + chromium \ docker \ standalone_chrome \ standalone_edge \ standalone_firefox \ + standalone_chromium \ standalone_docker \ video +all_amd64: all + +all_arm64: hub \ + distributor \ + router \ + sessions \ + sessionqueue \ + event_bus \ + firefox \ + chromium \ + docker \ + standalone_firefox \ + standalone_chromium \ + standalone_docker build: all @@ -71,6 +87,9 @@ chrome_dev: chrome_beta: cd ./NodeChrome && docker build $(BUILD_ARGS) $(FROM_IMAGE_ARGS) --build-arg CHROME_VERSION=google-chrome-beta -t $(NAME)/node-chrome:beta . +chromium: node_base + cd ./NodeChromium && docker build $(BUILD_ARGS) $(FROM_IMAGE_ARGS) -t $(NAME)/node-chromium:$(TAG_VERSION) . + edge: node_base cd ./NodeEdge && docker build $(BUILD_ARGS) $(FROM_IMAGE_ARGS) -t $(NAME)/node-edge:$(TAG_VERSION) . @@ -113,6 +132,9 @@ standalone_chrome_dev: chrome_dev standalone_chrome_beta: chrome_beta cd ./Standalone && docker build $(BUILD_ARGS) --build-arg NAMESPACE=$(NAME) --build-arg VERSION=beta --build-arg BASE=node-chrome -t $(NAME)/standalone-chrome:beta . +standalone_chromium: chromium + cd ./Standalone && docker build $(BUILD_ARGS) $(FROM_IMAGE_ARGS) --build-arg BASE=node-chromium -t $(NAME)/standalone-chromium:$(TAG_VERSION) . + standalone_edge: edge cd ./Standalone && docker build $(BUILD_ARGS) $(FROM_IMAGE_ARGS) --build-arg BASE=node-edge -t $(NAME)/standalone-edge:$(TAG_VERSION) . @@ -128,11 +150,14 @@ video: # https://github.com/SeleniumHQ/docker-selenium/issues/992 # Additional tags for browser images -tag_and_push_browser_images: tag_and_push_chrome_images tag_and_push_firefox_images tag_and_push_edge_images +tag_and_push_browser_images: tag_and_push_chrome_images tag_and_push_firefox_images tag_and_push_edge_images tag_and_push_chromium_images tag_and_push_chrome_images: ./tag_and_push_browser_images.sh $(VERSION) $(BUILD_DATE) $(NAMESPACE) $(PUSH_IMAGE) chrome +tag_and_push_chromium_images: + ./tag_and_push_browser_images.sh $(VERSION) $(BUILD_DATE) $(NAMESPACE) $(PUSH_IMAGE) chromium + tag_and_push_edge_images: ./tag_and_push_browser_images.sh $(VERSION) $(BUILD_DATE) $(NAMESPACE) $(PUSH_IMAGE) edge @@ -149,10 +174,12 @@ tag_latest: docker tag $(NAME)/event-bus:$(TAG_VERSION) $(NAME)/event-bus:latest docker tag $(NAME)/node-base:$(TAG_VERSION) $(NAME)/node-base:latest docker tag $(NAME)/node-chrome:$(TAG_VERSION) $(NAME)/node-chrome:latest + docker tag $(NAME)/node-chromium:$(TAG_VERSION) $(NAME)/node-chromium:latest docker tag $(NAME)/node-edge:$(TAG_VERSION) $(NAME)/node-edge:latest docker tag $(NAME)/node-firefox:$(TAG_VERSION) $(NAME)/node-firefox:latest docker tag $(NAME)/node-docker:$(TAG_VERSION) $(NAME)/node-docker:latest docker tag $(NAME)/standalone-chrome:$(TAG_VERSION) $(NAME)/standalone-chrome:latest + docker tag $(NAME)/standalone-chromium:$(TAG_VERSION) $(NAME)/standalone-chromium:latest docker tag $(NAME)/standalone-edge:$(TAG_VERSION) $(NAME)/standalone-edge:latest docker tag $(NAME)/standalone-firefox:$(TAG_VERSION) $(NAME)/standalone-firefox:latest docker tag $(NAME)/standalone-docker:$(TAG_VERSION) $(NAME)/standalone-docker:latest @@ -168,10 +195,12 @@ release_latest: docker push $(NAME)/event-bus:latest docker push $(NAME)/node-base:latest docker push $(NAME)/node-chrome:latest + docker push $(NAME)/node-chromium:latest docker push $(NAME)/node-edge:latest docker push $(NAME)/node-firefox:latest docker push $(NAME)/node-docker:latest docker push $(NAME)/standalone-chrome:latest + docker push $(NAME)/standalone-chromium:latest docker push $(NAME)/standalone-edge:latest docker push $(NAME)/standalone-firefox:latest docker push $(NAME)/standalone-docker:latest @@ -187,10 +216,12 @@ tag_major_minor: docker tag $(NAME)/event-bus:$(TAG_VERSION) $(NAME)/event-bus:$(MAJOR) docker tag $(NAME)/node-base:$(TAG_VERSION) $(NAME)/node-base:$(MAJOR) docker tag $(NAME)/node-chrome:$(TAG_VERSION) $(NAME)/node-chrome:$(MAJOR) + docker tag $(NAME)/node-chromium:$(TAG_VERSION) $(NAME)/node-chromium:$(MAJOR) docker tag $(NAME)/node-edge:$(TAG_VERSION) $(NAME)/node-edge:$(MAJOR) docker tag $(NAME)/node-firefox:$(TAG_VERSION) $(NAME)/node-firefox:$(MAJOR) docker tag $(NAME)/node-docker:$(TAG_VERSION) $(NAME)/node-docker:$(MAJOR) docker tag $(NAME)/standalone-chrome:$(TAG_VERSION) $(NAME)/standalone-chrome:$(MAJOR) + docker tag $(NAME)/standalone-chromium:$(TAG_VERSION) $(NAME)/standalone-chromium:$(MAJOR) docker tag $(NAME)/standalone-edge:$(TAG_VERSION) $(NAME)/standalone-edge:$(MAJOR) docker tag $(NAME)/standalone-firefox:$(TAG_VERSION) $(NAME)/standalone-firefox:$(MAJOR) docker tag $(NAME)/standalone-docker:$(TAG_VERSION) $(NAME)/standalone-docker:$(MAJOR) @@ -203,10 +234,12 @@ tag_major_minor: docker tag $(NAME)/event-bus:$(TAG_VERSION) $(NAME)/event-bus:$(MAJOR).$(MINOR) docker tag $(NAME)/node-base:$(TAG_VERSION) $(NAME)/node-base:$(MAJOR).$(MINOR) docker tag $(NAME)/node-chrome:$(TAG_VERSION) $(NAME)/node-chrome:$(MAJOR).$(MINOR) + docker tag $(NAME)/node-chromium:$(TAG_VERSION) $(NAME)/node-chromium:$(MAJOR).$(MINOR) docker tag $(NAME)/node-edge:$(TAG_VERSION) $(NAME)/node-edge:$(MAJOR).$(MINOR) docker tag $(NAME)/node-firefox:$(TAG_VERSION) $(NAME)/node-firefox:$(MAJOR).$(MINOR) docker tag $(NAME)/node-docker:$(TAG_VERSION) $(NAME)/node-docker:$(MAJOR).$(MINOR) docker tag $(NAME)/standalone-chrome:$(TAG_VERSION) $(NAME)/standalone-chrome:$(MAJOR).$(MINOR) + docker tag $(NAME)/standalone-chromium:$(TAG_VERSION) $(NAME)/standalone-chromium:$(MAJOR).$(MINOR) docker tag $(NAME)/standalone-edge:$(TAG_VERSION) $(NAME)/standalone-edge:$(MAJOR).$(MINOR) docker tag $(NAME)/standalone-firefox:$(TAG_VERSION) $(NAME)/standalone-firefox:$(MAJOR).$(MINOR) docker tag $(NAME)/standalone-docker:$(TAG_VERSION) $(NAME)/standalone-docker:$(MAJOR).$(MINOR) @@ -219,10 +252,12 @@ tag_major_minor: docker tag $(NAME)/event-bus:$(TAG_VERSION) $(NAME)/event-bus:$(MAJOR_MINOR_PATCH) docker tag $(NAME)/node-base:$(TAG_VERSION) $(NAME)/node-base:$(MAJOR_MINOR_PATCH) docker tag $(NAME)/node-chrome:$(TAG_VERSION) $(NAME)/node-chrome:$(MAJOR_MINOR_PATCH) + docker tag $(NAME)/node-chromium:$(TAG_VERSION) $(NAME)/node-chromium:$(MAJOR_MINOR_PATCH) docker tag $(NAME)/node-edge:$(TAG_VERSION) $(NAME)/node-edge:$(MAJOR_MINOR_PATCH) docker tag $(NAME)/node-firefox:$(TAG_VERSION) $(NAME)/node-firefox:$(MAJOR_MINOR_PATCH) docker tag $(NAME)/node-docker:$(TAG_VERSION) $(NAME)/node-docker:$(MAJOR_MINOR_PATCH) docker tag $(NAME)/standalone-chrome:$(TAG_VERSION) $(NAME)/standalone-chrome:$(MAJOR_MINOR_PATCH) + docker tag $(NAME)/standalone-chromium:$(TAG_VERSION) $(NAME)/standalone-chromium:$(MAJOR_MINOR_PATCH) docker tag $(NAME)/standalone-edge:$(TAG_VERSION) $(NAME)/standalone-edge:$(MAJOR_MINOR_PATCH) docker tag $(NAME)/standalone-firefox:$(TAG_VERSION) $(NAME)/standalone-firefox:$(MAJOR_MINOR_PATCH) docker tag $(NAME)/standalone-docker:$(TAG_VERSION) $(NAME)/standalone-docker:$(MAJOR_MINOR_PATCH) @@ -237,10 +272,12 @@ release: tag_major_minor @if ! docker images $(NAME)/event-bus | awk '{ print $$2 }' | grep -q -F $(TAG_VERSION); then echo "$(NAME)/event-bus version $(TAG_VERSION) is not yet built. Please run 'make build'"; false; fi @if ! docker images $(NAME)/node-base | awk '{ print $$2 }' | grep -q -F $(TAG_VERSION); then echo "$(NAME)/node-base version $(TAG_VERSION) is not yet built. Please run 'make build'"; false; fi @if ! docker images $(NAME)/node-chrome | awk '{ print $$2 }' | grep -q -F $(TAG_VERSION); then echo "$(NAME)/node-chrome version $(TAG_VERSION) is not yet built. Please run 'make build'"; false; fi + @if ! docker images $(NAME)/node-chromium | awk '{ print $$2 }' | grep -q -F $(TAG_VERSION); then echo "$(NAME)/node-chromium version $(TAG_VERSION) is not yet built. Please run 'make build'"; false; fi @if ! docker images $(NAME)/node-edge | awk '{ print $$2 }' | grep -q -F $(TAG_VERSION); then echo "$(NAME)/node-edge version $(TAG_VERSION) is not yet built. Please run 'make build'"; false; fi @if ! docker images $(NAME)/node-firefox | awk '{ print $$2 }' | grep -q -F $(TAG_VERSION); then echo "$(NAME)/node-firefox version $(TAG_VERSION) is not yet built. Please run 'make build'"; false; fi @if ! docker images $(NAME)/node-docker | awk '{ print $$2 }' | grep -q -F $(TAG_VERSION); then echo "$(NAME)/node-docker version $(TAG_VERSION) is not yet built. Please run 'make build'"; false; fi @if ! docker images $(NAME)/standalone-chrome | awk '{ print $$2 }' | grep -q -F $(TAG_VERSION); then echo "$(NAME)/standalone-chrome version $(TAG_VERSION) is not yet built. Please run 'make build'"; false; fi + @if ! docker images $(NAME)/standalone-chromium | awk '{ print $$2 }' | grep -q -F $(TAG_VERSION); then echo "$(NAME)/standalone-chromium version $(TAG_VERSION) is not yet built. Please run 'make build'"; false; fi @if ! docker images $(NAME)/standalone-edge | awk '{ print $$2 }' | grep -q -F $(TAG_VERSION); then echo "$(NAME)/standalone-edge version $(TAG_VERSION) is not yet built. Please run 'make build'"; false; fi @if ! docker images $(NAME)/standalone-firefox | awk '{ print $$2 }' | grep -q -F $(TAG_VERSION); then echo "$(NAME)/standalone-firefox version $(TAG_VERSION) is not yet built. Please run 'make build'"; false; fi @if ! docker images $(NAME)/standalone-docker | awk '{ print $$2 }' | grep -q -F $(TAG_VERSION); then echo "$(NAME)/standalone-docker version $(TAG_VERSION) is not yet built. Please run 'make build'"; false; fi @@ -253,10 +290,12 @@ release: tag_major_minor docker push $(NAME)/event-bus:$(TAG_VERSION) docker push $(NAME)/node-base:$(TAG_VERSION) docker push $(NAME)/node-chrome:$(TAG_VERSION) + docker push $(NAME)/node-chromium:$(TAG_VERSION) docker push $(NAME)/node-edge:$(TAG_VERSION) docker push $(NAME)/node-firefox:$(TAG_VERSION) docker push $(NAME)/node-docker:$(TAG_VERSION) docker push $(NAME)/standalone-chrome:$(TAG_VERSION) + docker push $(NAME)/standalone-chromium:$(TAG_VERSION) docker push $(NAME)/standalone-edge:$(TAG_VERSION) docker push $(NAME)/standalone-firefox:$(TAG_VERSION) docker push $(NAME)/standalone-docker:$(TAG_VERSION) @@ -269,10 +308,12 @@ release: tag_major_minor docker push $(NAME)/event-bus:$(MAJOR) docker push $(NAME)/node-base:$(MAJOR) docker push $(NAME)/node-chrome:$(MAJOR) + docker push $(NAME)/node-chromium:$(MAJOR) docker push $(NAME)/node-edge:$(MAJOR) docker push $(NAME)/node-firefox:$(MAJOR) docker push $(NAME)/node-docker:$(MAJOR) docker push $(NAME)/standalone-chrome:$(MAJOR) + docker push $(NAME)/standalone-chromium:$(MAJOR) docker push $(NAME)/standalone-edge:$(MAJOR) docker push $(NAME)/standalone-firefox:$(MAJOR) docker push $(NAME)/standalone-docker:$(MAJOR) @@ -285,10 +326,12 @@ release: tag_major_minor docker push $(NAME)/event-bus:$(MAJOR).$(MINOR) docker push $(NAME)/node-base:$(MAJOR).$(MINOR) docker push $(NAME)/node-chrome:$(MAJOR).$(MINOR) + docker push $(NAME)/node-chromium:$(MAJOR).$(MINOR) docker push $(NAME)/node-edge:$(MAJOR).$(MINOR) docker push $(NAME)/node-firefox:$(MAJOR).$(MINOR) docker push $(NAME)/node-docker:$(MAJOR).$(MINOR) docker push $(NAME)/standalone-chrome:$(MAJOR).$(MINOR) + docker push $(NAME)/standalone-chromium:$(MAJOR).$(MINOR) docker push $(NAME)/standalone-edge:$(MAJOR).$(MINOR) docker push $(NAME)/standalone-firefox:$(MAJOR).$(MINOR) docker push $(NAME)/standalone-docker:$(MAJOR).$(MINOR) @@ -301,10 +344,12 @@ release: tag_major_minor docker push $(NAME)/event-bus:$(MAJOR_MINOR_PATCH) docker push $(NAME)/node-base:$(MAJOR_MINOR_PATCH) docker push $(NAME)/node-chrome:$(MAJOR_MINOR_PATCH) + docker push $(NAME)/node-chromium:$(MAJOR_MINOR_PATCH) docker push $(NAME)/node-edge:$(MAJOR_MINOR_PATCH) docker push $(NAME)/node-firefox:$(MAJOR_MINOR_PATCH) docker push $(NAME)/node-docker:$(MAJOR_MINOR_PATCH) docker push $(NAME)/standalone-chrome:$(MAJOR_MINOR_PATCH) + docker push $(NAME)/standalone-chromium:$(MAJOR_MINOR_PATCH) docker push $(NAME)/standalone-edge:$(MAJOR_MINOR_PATCH) docker push $(NAME)/standalone-firefox:$(MAJOR_MINOR_PATCH) docker push $(NAME)/standalone-docker:$(MAJOR_MINOR_PATCH) @@ -315,8 +360,16 @@ test: test_chrome \ test_chrome_standalone \ test_firefox_standalone \ test_edge \ - test_edge_standalone + test_edge_standalone \ + test_chromium \ + test_chromium_standalone +test_amd64: test + +test_arm64: test_chromium \ + test_firefox \ + test_chromium_standalone \ + test_firefox_standalone test_chrome: VERSION=$(TAG_VERSION) NAMESPACE=$(NAMESPACE) ./tests/bootstrap.sh NodeChrome @@ -324,6 +377,12 @@ test_chrome: test_chrome_standalone: VERSION=$(TAG_VERSION) NAMESPACE=$(NAMESPACE) ./tests/bootstrap.sh StandaloneChrome +test_chromium: + VERSION=$(TAG_VERSION) NAMESPACE=$(NAMESPACE) ./tests/bootstrap.sh NodeChromium + +test_chromium_standalone: + VERSION=$(TAG_VERSION) NAMESPACE=$(NAMESPACE) ./tests/bootstrap.sh StandaloneChromium + test_edge: VERSION=$(TAG_VERSION) NAMESPACE=$(NAMESPACE) ./tests/bootstrap.sh NodeEdge @@ -338,17 +397,22 @@ test_firefox_standalone: # This should run on its own CI job. There is no need to combine it with the other tests. # Its main purpose is to check that a video file was generated. -test_video: video hub chrome firefox edge +test_video: video hub chrome firefox edge chromium # Running a few tests with docker-compose to generate the videos - for node in NodeChrome NodeFirefox NodeEdge ; do \ + for node in NodeChrome NodeFirefox NodeEdge NodeChromium ; do \ cd ./tests || true ; \ echo VIDEO_TAG=$(FFMPEG_TAG_VERSION)-$(BUILD_DATE) > .env ; \ echo TAG=$(TAG_VERSION) >> .env ; \ + echo NAME=$(NAME) >> .env ; \ echo NODE=$$node >> .env ; \ if [ $$node = "NodeChrome" ] ; then \ echo BROWSER=chrome >> .env ; \ echo VIDEO_FILE_NAME=chrome_video.mp4 >> .env ; \ fi ; \ + if [ $$node = "NodeChromium" ] ; then \ + echo BROWSER=chromium >> .env ; \ + echo VIDEO_FILE_NAME=chromium_video.mp4 >> .env ; \ + fi ; \ if [ $$node = "NodeEdge" ] ; then \ echo BROWSER=edge >> .env ; \ echo VIDEO_FILE_NAME=edge_video.mp4 >> .env ; \ @@ -364,6 +428,7 @@ test_video: video hub chrome firefox edge docker run -v $$(pwd):$$(pwd) -w $$(pwd) $(FFMPEG_BASED_NAME)/ffmpeg:$(FFMPEG_BASED_TAG) -v error -i ./tests/videos/chrome_video.mp4 -f null - 2>error.log docker run -v $$(pwd):$$(pwd) -w $$(pwd) $(FFMPEG_BASED_NAME)/ffmpeg:$(FFMPEG_BASED_TAG) -v error -i ./tests/videos/firefox_video.mp4 -f null - 2>error.log docker run -v $$(pwd):$$(pwd) -w $$(pwd) $(FFMPEG_BASED_NAME)/ffmpeg:$(FFMPEG_BASED_TAG) -v error -i ./tests/videos/edge_video.mp4 -f null - 2>error.log + docker run -v $$(pwd):$$(pwd) -w $$(pwd) $(FFMPEG_BASED_NAME)/ffmpeg:$(FFMPEG_BASED_TAG) -v error -i ./tests/videos/chromium_video.mp4 -f null - 2>error.log chart_setup_env: ./tests/charts/make/chart_setup_env.sh @@ -380,7 +445,8 @@ chart_build: chart_test: chart_test_template \ chart_test_chrome \ chart_test_firefox \ - chart_test_edge + chart_test_edge \ + chart_test_chromium chart_test_template: ./tests/charts/bootstrap.sh @@ -388,6 +454,9 @@ chart_test_template: chart_test_chrome: VERSION=$(TAG_VERSION) NAMESPACE=$(NAMESPACE) ./tests/charts/make/chart_test.sh NodeChrome +chart_test_chromium: + VERSION=$(TAG_VERSION) NAMESPACE=$(NAMESPACE) ./tests/charts/make/chart_test.sh NodeChromium + chart_test_firefox: VERSION=$(TAG_VERSION) NAMESPACE=$(NAMESPACE) ./tests/charts/make/chart_test.sh NodeFirefox @@ -399,10 +468,13 @@ chart_test_parallel_autoscaling: .PHONY: \ all \ + all_amd64 \ + all_arm64 \ base \ build \ ci \ chrome \ + chromium \ edge \ firefox \ docker \ @@ -415,10 +487,13 @@ chart_test_parallel_autoscaling: node_base \ release \ standalone_chrome \ + standalone_chromium \ standalone_edge \ standalone_firefox \ standalone_docker \ tag_latest \ tag_and_push_browser_images \ test \ + test_amd64 \ + test_arm64 \ video diff --git a/NodeBase/start-xvfb.sh b/NodeBase/start-xvfb.sh index b4959a3902..2d97945090 100755 --- a/NodeBase/start-xvfb.sh +++ b/NodeBase/start-xvfb.sh @@ -19,5 +19,5 @@ if [ "${START_XVFB:-$SE_START_XVFB}" = true ] ; then --server-args="-screen 0 ${GEOMETRY} -fbdir /var/tmp -dpi ${SCREEN_DPI} -listen tcp -noreset -ac +extension RANDR" \ /usr/bin/fluxbox -display ${DISPLAY} else - echo "Xvfb and Fluxbox won't start. Chrome/Firefox/Edge can only run in headless mode. Remember to set the 'headless' flag in your test." + echo "Xvfb and Fluxbox won't start. Chrome/Firefox/Edge/Chromium can only run in headless mode. Remember to set the 'headless' flag in your test." fi diff --git a/NodeChromium/Dockerfile b/NodeChromium/Dockerfile new file mode 100644 index 0000000000..191ba7b8d9 --- /dev/null +++ b/NodeChromium/Dockerfile @@ -0,0 +1,55 @@ +ARG NAMESPACE +ARG VERSION +ARG AUTHORS +FROM ${NAMESPACE}/node-base:${VERSION} +LABEL authors=${AUTHORS} + +USER root + +#============================================ +# Chromium and chromedriver from Debian +# Available versions at: https://packages.debian.org/search?keywords=chromium +#============================================ +COPY chromium.pref /etc/apt/preferences.d/chromium.pref + +ARG DEBIAN_VERSION=bullseye +ARG REPO_FILE=/etc/apt/sources.list.d/debian.list +ARG KEY_SERVER=keyserver.ubuntu.com +ARG DEBIAN_KEY_LOCATION=/usr/share/keyrings/debian +ARG CHROMIUM_VERSION=120.0.6099.109-1~deb11u1 +ARG CHROMEDIVER_VERSION=${CHROMIUM_VERSION} +RUN mkdir /home/seluser/.gnupg && mkdir -p ${DEBIAN_KEY_LOCATION} \ + && gpg --no-default-keyring --keyring ${DEBIAN_KEY_LOCATION}/${DEBIAN_VERSION}.gpg \ + --keyserver ${KEY_SERVER} \ + --recv-keys 0E98404D386FA1D9 \ + && echo "deb [signed-by=${DEBIAN_KEY_LOCATION}/${DEBIAN_VERSION}.gpg] http://deb.debian.org/debian ${DEBIAN_VERSION} main" \ + > ${REPO_FILE} \ + && gpg --no-default-keyring --keyring ${DEBIAN_KEY_LOCATION}/${DEBIAN_VERSION}-updates.gpg \ + --keyserver ${KEY_SERVER} \ + --recv-keys 6ED0E7B82643E131 \ + && echo "deb [signed-by=${DEBIAN_KEY_LOCATION}/${DEBIAN_VERSION}-updates.gpg] http://deb.debian.org/debian ${DEBIAN_VERSION}-updates main" \ + >> ${REPO_FILE} \ + && gpg --no-default-keyring --keyring ${DEBIAN_KEY_LOCATION}/security-${DEBIAN_VERSION}.gpg \ + --keyserver ${KEY_SERVER} \ + --recv-keys 112695A0E562B32A \ + && echo "deb [signed-by=${DEBIAN_KEY_LOCATION}/security-${DEBIAN_VERSION}.gpg] http://deb.debian.org/debian-security ${DEBIAN_VERSION}-security main contrib non-free" \ + >> ${REPO_FILE} \ + && apt-get update -qqy \ + && apt-get -qqy --no-install-recommends install chromium=${CHROMIUM_VERSION} chromium-driver=${CHROMEDIVER_VERSION} \ + && rm ${REPO_FILE} \ + && rm -rf /home/seluser/.gnupg ${DEBIAN_KEY_LOCATION}/ /var/lib/apt/lists/* /var/cache/apt/* + +#================================= +# Chromium Launch Script Wrapper +#================================= +COPY wrap_chromium_binary /opt/bin/wrap_chromium_binary +RUN /opt/bin/wrap_chromium_binary + +USER ${SEL_UID} + +#============================================ +# Dumping Browser information for config +#============================================ +RUN echo "chrome" > /opt/selenium/browser_name +RUN chromium --version | awk '{print $2}' > /opt/selenium/browser_version +RUN echo "\"goog:chromeOptions\": {\"binary\": \"/usr/bin/chromium\"}" > /opt/selenium/browser_binary_location diff --git a/NodeChromium/chromium.pref b/NodeChromium/chromium.pref new file mode 100644 index 0000000000..33fb9ace5b --- /dev/null +++ b/NodeChromium/chromium.pref @@ -0,0 +1,14 @@ +# Note: 2 blank lines are required between entries +Package: * +Pin: release a=eoan +Pin-Priority: 500 + +Package: * +Pin: origin "deb.debian.org" +Pin-Priority: 300 + +# Pattern includes 'chromium', 'chromium-browser' and similarly +# named dependencies: +Package: chromium* +Pin: origin "deb.debian.org" +Pin-Priority: 700 diff --git a/NodeChromium/wrap_chromium_binary b/NodeChromium/wrap_chromium_binary new file mode 100755 index 0000000000..0cf5c25334 --- /dev/null +++ b/NodeChromium/wrap_chromium_binary @@ -0,0 +1,27 @@ +#!/bin/bash + +WRAPPER_PATH=$(readlink -f /usr/bin/chromium) +BASE_PATH="$WRAPPER_PATH-base" +mv "$WRAPPER_PATH" "$BASE_PATH" + +cat > "$WRAPPER_PATH" <<_EOF +#!/bin/bash + +# umask 002 ensures default permissions of files are 664 (rw-rw-r--) and directories are 775 (rwxrwxr-x). +umask 002 + +# Debian/Ubuntu seems to not respect --lang, it instead needs to be a LANGUAGE environment var +# See: https://stackoverflow.com/a/41893197/359999 +for var in "\$@"; do + if [[ \$var == --lang=* ]]; then + LANGUAGE=\${var//--lang=} + fi +done + +# Set language environment variable +export LANGUAGE="\$LANGUAGE" + +# Note: exec -a below is a bashism. +exec -a "\$0" "$BASE_PATH" --no-sandbox "\$@" +_EOF +chmod +x "$WRAPPER_PATH" diff --git a/NodeDocker/config.toml b/NodeDocker/config.toml index 3b63bf66a9..83c1b640a8 100644 --- a/NodeDocker/config.toml +++ b/NodeDocker/config.toml @@ -4,6 +4,7 @@ configs = [ "selenium/standalone-firefox:4.16.1-20231212", '{"browserName": "firefox", "platformName": "linux"}', "selenium/standalone-chrome:4.16.1-20231212", '{"browserName": "chrome", "platformName": "linux"}', + "selenium/standalone-chromium:4.16.1-20231212", '{"browserName": "chromium", "platformName": "linux"}', "selenium/standalone-edge:4.16.1-20231212", '{"browserName": "MicrosoftEdge", "platformName": "linux"}' ] diff --git a/NodeFirefox/Dockerfile b/NodeFirefox/Dockerfile index 0150b61e34..39c946189b 100644 --- a/NodeFirefox/Dockerfile +++ b/NodeFirefox/Dockerfile @@ -8,19 +8,15 @@ USER root #========= # Firefox +# Available versions at https://launchpad.net/~mozillateam/+archive/ubuntu/ppa #========= -ARG FIREFOX_VERSION=latest -RUN FIREFOX_DOWNLOAD_URL=$(if [ $FIREFOX_VERSION = "latest" ] || [ $FIREFOX_VERSION = "beta-latest" ] || [ $FIREFOX_VERSION = "nightly-latest" ] || [ $FIREFOX_VERSION = "devedition-latest" ] || [ $FIREFOX_VERSION = "esr-latest" ]; then echo "https://download.mozilla.org/?product=firefox-$FIREFOX_VERSION-ssl&os=linux64&lang=en-US"; else echo "https://download-installer.cdn.mozilla.net/pub/firefox/releases/$FIREFOX_VERSION/linux-x86_64/en-US/firefox-$FIREFOX_VERSION.tar.bz2"; fi) \ - && apt-get update -qqy \ - && apt-get -qqy --no-install-recommends install libavcodec-extra \ - libgtk-3-dev libdbus-glib-1-dev \ - && rm -rf /var/lib/apt/lists/* /var/cache/apt/* \ - && wget --no-verbose -O /tmp/firefox.tar.bz2 $FIREFOX_DOWNLOAD_URL \ - && rm -rf /opt/firefox \ - && tar -C /opt -xjf /tmp/firefox.tar.bz2 \ - && rm /tmp/firefox.tar.bz2 \ - && mv /opt/firefox /opt/firefox-$FIREFOX_VERSION \ - && ln -fs /opt/firefox-$FIREFOX_VERSION/firefox /usr/bin/firefox +ARG FIREFOX_VERSION=121.0+build1-0ubuntu0.22.04.1~mt1 +RUN apt-get -qqy update \ + && apt-get -qqy --no-install-recommends install libavcodec-extra software-properties-common \ + && add-apt-repository ppa:mozillateam/ppa \ + && apt-get -qqy update \ + && apt-get -qqy --no-install-recommends install -t 'o=LP-PPA-mozillateam' firefox=${FIREFOX_VERSION} \ + && rm -rf /var/lib/apt/lists/* /var/cache/apt/* #============ # GeckoDriver @@ -28,7 +24,13 @@ RUN FIREFOX_DOWNLOAD_URL=$(if [ $FIREFOX_VERSION = "latest" ] || [ $FIREFOX_VERS ARG GECKODRIVER_VERSION=latest RUN GK_VERSION=$(if [ ${GECKODRIVER_VERSION:-latest} = "latest" ]; then echo "0.33.0"; else echo $GECKODRIVER_VERSION; fi) \ && echo "Using GeckoDriver version: "$GK_VERSION \ - && wget --no-verbose -O /tmp/geckodriver.tar.gz https://github.com/mozilla/geckodriver/releases/download/v$GK_VERSION/geckodriver-v$GK_VERSION-linux64.tar.gz \ + && ARCH=$(arch | sed s/aarch64/arm64/ | sed s/x86_64/amd64/) \ + && if [ "$ARCH" = "arm64" ]; then \ + GK_DOWNLOAD_URL="https://github.com/mozilla/geckodriver/releases/download/v$GK_VERSION/geckodriver-v$GK_VERSION-linux-aarch64.tar.gz" ; \ + else \ + GK_DOWNLOAD_URL="https://github.com/mozilla/geckodriver/releases/download/v$GK_VERSION/geckodriver-v$GK_VERSION-linux64.tar.gz" ; \ + fi \ + && wget --no-verbose -O /tmp/geckodriver.tar.gz $GK_DOWNLOAD_URL \ && rm -rf /opt/geckodriver \ && tar -C /opt -zxf /tmp/geckodriver.tar.gz \ && rm /tmp/geckodriver.tar.gz \ diff --git a/NodeFirefox/README.md b/NodeFirefox/README.md new file mode 100644 index 0000000000..c0b0ef1c64 --- /dev/null +++ b/NodeFirefox/README.md @@ -0,0 +1,28 @@ +## Building Multi-arch NodeFirefox and StandaloneFirefox + +There are two Dockerfiles in NodeFirefox. `Dockerfile` is from the upstream repository for building the standard, official amd64 images. To build `seleniarm/node-firefox` for arm64 or armv7l (or possibly amd64 as well), we use the `Dockerfile.multi-arch` file. + +The easiest way to build the image is to use `make`. See examples below: + + +**To build node/firefox for arm64:** + +``` +$ NAME=local-seleniarm VERSION=4.5.0 BUILD_DATE=$(date '+%Y%m%d') PLATFORMS=linux/arm64 BUILD_ARGS=--load make firefox_multi +``` + +**To build standalone/firefox for arm64:** + +``` +$ NAME=local-seleniarm VERSION=4.5.0 BUILD_DATE=$(date '+%Y%m%d') PLATFORMS=linux/arm64 BUILD_ARGS=--load make standalone_firefox_multi +``` + +NOTE: Replace PLATFORMS environment variable with `linux/arm/v7` for armv7l/armhf, or `linux/amd64` for amd64. + +## Running the standalone image + +``` +$ docker run --rm -it --shm-size 2g -p 4444:4444 -p 5900:5900 -p 7900:7900 local-seleniarm/standalone-firefox:latest +``` + +As with the x86_64 images from upstream, this also includes noVNC on port 7900, which we can access via http://localhost:7900 diff --git a/build-and-push.sh b/build-and-push.sh new file mode 100644 index 0000000000..9f237fc8e5 --- /dev/null +++ b/build-and-push.sh @@ -0,0 +1,65 @@ +#!/bin/bash + +SELENIUM_VERSION=$(grep selenium-server Base/Dockerfile | sed 's/.*-\([^-]*\)\.jar \\/\1/' | head -n 1) +NAME="${NAME:-seleniarm}" +VERSION="${VERSION:-$SELENIUM_VERSION}" +BUILD_DATE="${BUILD_DATE:-$(date '+%Y%m%d')}" +PLATFORMS="${PLATFORMS:-linux/arm64,linux/arm/v7,linux/amd64}" +BUILD_ARGS=--push + +FROM_IMAGE_ARGS="--build-arg NAMESPACE=$NAME --build-arg VERSION=$VERSION-$BUILD_DATE" +TAG_VERSION=$VERSION-$BUILD_DATE + +START=$(date +'%s') +echo $START + +echo "Build and push images for target $1" + +docker run --rm --privileged aptman/qus -- -r +docker run --rm --privileged aptman/qus -s -- -p + +if [ "$1" = "base_multi" ]; then + cd ./Base && docker buildx build --platform ${PLATFORMS} ${BUILD_ARGS} -t ${NAME}/base:${TAG_VERSION} . + +elif [ "$1" = "grid_multi" ]; then + cd ./Hub && docker buildx build --platform ${PLATFORMS} ${BUILD_ARGS} ${FROM_IMAGE_ARGS} -t ${NAME}/hub:${TAG_VERSION} . + cd ../Distributor && docker buildx build --platform ${PLATFORMS} ${BUILD_ARGS} ${FROM_IMAGE_ARGS} -t ${NAME}/distributor:${TAG_VERSION} . + cd ../Router && docker buildx build --platform ${PLATFORMS} ${BUILD_ARGS} ${FROM_IMAGE_ARGS} -t ${NAME}/router:${TAG_VERSION} . + cd ../Sessions && docker buildx build --platform ${PLATFORMS} ${BUILD_ARGS} ${FROM_IMAGE_ARGS} -t ${NAME}/sessions:${TAG_VERSION} . + cd ../SessionQueue && docker buildx build --platform ${PLATFORMS} ${BUILD_ARGS} ${FROM_IMAGE_ARGS} -t ${NAME}/session-queue:${TAG_VERSION} . + cd ../NodeDocker && docker buildx build --platform ${PLATFORMS} ${BUILD_ARGS} ${FROM_IMAGE_ARGS} -t ${NAME}/node-docker:${TAG_VERSION} . + cd ../EventBus && docker buildx build --platform ${PLATFORMS} ${BUILD_ARGS} ${FROM_IMAGE_ARGS} -t ${NAME}/event-bus:${TAG_VERSION} . + # Prevent "failed to solve" errors by adding delay between NodeDocker and StandaloneDocker + # by building EventBus in between them. + cd ../StandaloneDocker && docker buildx build --platform ${PLATFORMS} ${BUILD_ARGS} ${FROM_IMAGE_ARGS} -t ${NAME}/standalone-docker:${TAG_VERSION} . + +elif [ "$1" = "node_base_multi" ]; then + cd ./NodeBase && docker buildx build --platform ${PLATFORMS} ${BUILD_ARGS} ${FROM_IMAGE_ARGS} -t ${NAME}/node-base:${TAG_VERSION} . + +elif [ "$1" = "firefox_multi" ]; then + FROM_IMAGE_ARGS="$FROM_IMAGE_ARGS --build-arg BASE=node-firefox" + cd ./NodeFirefox && docker buildx build --platform ${PLATFORMS} ${BUILD_ARGS} ${FROM_IMAGE_ARGS} -f Dockerfile.multi-arch -t ${NAME}/node-firefox:${TAG_VERSION} . + sleep 5 # Prevent "failed to solve" errors when trying to pull NodeFirefox dependency + cd ../Standalone && docker buildx build --platform ${PLATFORMS} ${BUILD_ARGS} ${FROM_IMAGE_ARGS} -t ${NAME}/standalone-firefox:${TAG_VERSION} . + +elif [ "$1" = "chromium_multi" ]; then + FROM_IMAGE_ARGS="$FROM_IMAGE_ARGS --build-arg BASE=node-chromium" + cd ./NodeChromium && docker buildx build --platform ${PLATFORMS} ${BUILD_ARGS} ${FROM_IMAGE_ARGS} -t ${NAME}/node-chromium:${TAG_VERSION} . + sleep 5 # Prevent "failed to solve" errors when trying to pull NodeChromium dependency + cd ../Standalone && docker buildx build --platform ${PLATFORMS} ${BUILD_ARGS} ${FROM_IMAGE_ARGS} -t ${NAME}/standalone-chromium:${TAG_VERSION} . + +elif [ "$1" = "tag_and_push_multi_arch_browser_images" ]; then + #make tag_and_push_multi_arch_browser_images + echo "Tag images and generate release notes" + +else + echo "$1 not found. Options are 'base_multi', 'grid_multi', 'node_base_multi', 'firefox_multi', and 'chromium_multi'" + SE_BUILD_CODE=1 +fi + +SE_BUILD_CODE=${SE_BUILD_CODE:-$(echo $?)} + +STOP=$(date +'%s') +echo $(( $STOP - $START )) seconds + +exit $SE_BUILD_CODE diff --git a/charts/selenium-grid/templates/_helpers.tpl b/charts/selenium-grid/templates/_helpers.tpl index 48c18bb952..7fbd6e094b 100644 --- a/charts/selenium-grid/templates/_helpers.tpl +++ b/charts/selenium-grid/templates/_helpers.tpl @@ -58,6 +58,13 @@ Chrome node fullname {{- default "selenium-chrome-node" .Values.chromeNode.nameOverride | trunc 63 | trimSuffix "-" -}} {{- end -}} +{{/* +Chromium node fullname +*/}} +{{- define "seleniumGrid.chromiumNode.fullname" -}} +{{- default "selenium-chromium-node" .Values.chromiumNode.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + {{/* Firefox node fullname */}} diff --git a/charts/selenium-grid/templates/chromium-node-deployment.yaml b/charts/selenium-grid/templates/chromium-node-deployment.yaml new file mode 100644 index 0000000000..5bdd0fb4a5 --- /dev/null +++ b/charts/selenium-grid/templates/chromium-node-deployment.yaml @@ -0,0 +1,30 @@ +{{- if and .Values.chromiumNode.enabled ((eq (include "seleniumGrid.useKEDA" .) "true") | ternary (eq .Values.autoscaling.scalingType "deployment") .Values.chromiumNode.deploymentEnabled) }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "seleniumGrid.chromiumNode.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "seleniumGrid.chromiumNode.fullname" . }} + app.kubernetes.io/name: {{ template "seleniumGrid.chromiumNode.fullname" . }} + {{- include "seleniumGrid.commonLabels" . | nindent 4 }} + {{- with .Values.chromiumNode.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.customLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and (not .Values.autoscaling.enabled) (not .Values.autoscaling.enableWithExistingKEDA) }} + replicas: {{ .Values.chromiumNode.replicas }} + {{end}} + selector: + matchLabels: + app: {{ template "seleniumGrid.chromiumNode.fullname" . }} + app.kubernetes.io/instance: {{ .Release.Name }} +{{- $podScope := deepCopy . -}} +{{- $_ := set $podScope "name" (include "seleniumGrid.chromiumNode.fullname" .) -}} +{{- $_ = set $podScope "node" .Values.chromiumNode -}} +{{- $_ = set $podScope "uploader" (get .Values.videoRecorder (.Values.videoRecorder.uploader | toString)) -}} +{{- include "seleniumGrid.podTemplate" $podScope | nindent 2 }} +{{- end }} diff --git a/charts/selenium-grid/templates/chromium-node-hpa.yaml b/charts/selenium-grid/templates/chromium-node-hpa.yaml new file mode 100644 index 0000000000..8777c003f6 --- /dev/null +++ b/charts/selenium-grid/templates/chromium-node-hpa.yaml @@ -0,0 +1,18 @@ +{{- if and .Values.chromiumNode.enabled (eq (include "seleniumGrid.useKEDA" .) "true") (eq .Values.autoscaling.scalingType "deployment") }} +apiVersion: keda.sh/v1alpha1 +kind: ScaledObject +metadata: + name: selenium-grid-chromium-scaledobject + namespace: {{ .Release.Namespace }} + annotations: + {{- with .Values.autoscaling.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + deploymentName: {{ template "seleniumGrid.chromiumNode.fullname" . }} +spec: + {{- $podScope := deepCopy . -}} + {{- $_ := set $podScope "name" (include "seleniumGrid.chromiumNode.fullname" .) -}} + {{- $_ = set $podScope "node" .Values.chromiumNode -}} + {{- include "seleniumGrid.autoscalingTemplate" $podScope | nindent 2 }} +{{- end }} diff --git a/charts/selenium-grid/templates/chromium-node-scaledjobs.yaml b/charts/selenium-grid/templates/chromium-node-scaledjobs.yaml new file mode 100644 index 0000000000..d7bf26fea1 --- /dev/null +++ b/charts/selenium-grid/templates/chromium-node-scaledjobs.yaml @@ -0,0 +1,28 @@ +{{- if and .Values.chromiumNode.enabled (include "seleniumGrid.useKEDA" .) (eq .Values.autoscaling.scalingType "job") }} +apiVersion: keda.sh/v1alpha1 +kind: ScaledJob +metadata: + name: {{ template "seleniumGrid.chromiumNode.fullname" . }} + namespace: {{ .Release.Namespace }} + annotations: + {{- with .Values.autoscaling.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + app: {{ template "seleniumGrid.chromiumNode.fullname" . }} + app.kubernetes.io/name: {{ template "seleniumGrid.chromiumNode.fullname" . }} + {{- include "seleniumGrid.commonLabels" . | nindent 4 }} + {{- with .Values.chromiumNode.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.customLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- $podScope := deepCopy . -}} + {{- $_ := set $podScope "name" (include "seleniumGrid.chromiumNode.fullname" .) -}} + {{- $_ = set $podScope "node" .Values.chromiumNode -}} + {{- $_ = set $podScope "uploader" (get .Values.videoRecorder (.Values.videoRecorder.uploader | toString)) -}} + {{- $_ = set $podScope "podTemplate" (include "seleniumGrid.podTemplate" $podScope | fromYaml) }} + {{- include "seleniumGrid.autoscalingTemplate" $podScope | nindent 2 }} +{{- end }} diff --git a/charts/selenium-grid/templates/chromium-node-service.yaml b/charts/selenium-grid/templates/chromium-node-service.yaml new file mode 100644 index 0000000000..b9982ee21c --- /dev/null +++ b/charts/selenium-grid/templates/chromium-node-service.yaml @@ -0,0 +1,40 @@ +{{- if and .Values.chromiumNode.enabled .Values.chromiumNode.service.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "seleniumGrid.chromiumNode.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + name: {{ template "seleniumGrid.chromiumNode.fullname" . }} + {{- include "seleniumGrid.commonLabels" . | nindent 4 }} + {{- with .Values.chromiumNode.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.chromiumNode.service.type }} + selector: + app: {{ template "seleniumGrid.chromiumNode.fullname" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + {{- if and (eq .Values.chromiumNode.service.type "LoadBalancer") (.Values.chromiumNode.service.loadBalancerIP) }} + loadBalancerIP: {{ .Values.chromiumNode.service.loadBalancerIP }} + {{- end }} + ports: + - name: tcp-chromium + protocol: TCP + port: {{ .Values.chromiumNode.seleniumServicePort }} + targetPort: {{ .Values.chromiumNode.seleniumPort }} + {{- with .Values.chromiumNode.service.ports }} + {{- range . }} + - name: {{ .name }} + port: {{ .port }} + targetPort: {{ .targetPort }} + {{- if .protocol }} + protocol: {{ .protocol }} + {{- end }} + {{- if and (eq $.Values.chromiumNode.service.type "NodePort") .nodePort }} + nodePort: {{ .nodePort }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/selenium-grid/values.yaml b/charts/selenium-grid/values.yaml index 5a82d207de..3489fb5887 100644 --- a/charts/selenium-grid/values.yaml +++ b/charts/selenium-grid/values.yaml @@ -796,6 +796,138 @@ edgeNode: # It should be set using the --set-json option sidecars: [] +# Configuration for chromium nodes +chromiumNode: + # Enable chromium nodes + enabled: true + + # NOTE: Only used when autoscaling.enabled is false + # Enable creation of Deployment + # true (default) - if you want long living pods + # false - for provisioning your own custom type such as Jobs + deploymentEnabled: true + + # Number of chromium nodes + replicas: 1 + # imageRegistry: selenium + # Image of chromium nodes + imageName: node-chromium + # Image of chromium nodes (this overwrites global.seleniumGrid.nodesImageTag) + # imageTag: 4.16.1-20231212 + # Image pull policy (see https://kubernetes.io/docs/concepts/containers/images/#updating-images) + imagePullPolicy: IfNotPresent + # Image pull secret (see https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/) + imagePullSecret: "" + + # Port list to enable on container + ports: + - 5555 + # Selenium port (spec.ports[0].targetPort in kubernetes service) + seleniumPort: 5900 + # Selenium port exposed in service (spec.ports[0].port in kubernetes service) + seleniumServicePort: 6900 + # Annotations for chromium-node pods + annotations: {} + # Labels for chromium-node pods + labels: {} + # Resources for chromium-node container + resources: + requests: + memory: "1Gi" + cpu: "1" + limits: + memory: "1Gi" + cpu: "1" + # SecurityContext for chromium-node container + securityContext: {} + # Tolerations for chromium-node pods + tolerations: [] + # Node selector for chromium-node pods + nodeSelector: {} + # Custom host aliases for chromium nodes + hostAliases: + # - ip: "198.51.100.0" + # hostnames: + # - "example.com" + # - "example.net" + # - ip: "203.0.113.0" + # hostnames: + # - "example.org" + # Custom environment variables for chromium nodes + extraEnvironmentVariables: + # - name: SE_JAVA_OPTS + # value: "-Xmx512m" + # - name: + # valueFrom: + # secretKeyRef: + # name: secret-name + # key: secret-key + # Custom environment variables by sourcing entire configMap, Secret, etc. for chromium nodes + extraEnvFrom: + # - configMapRef: + # name: proxy-settings + # - secretRef: + # name: mysecret + # Service configuration + service: + # Create a service for node + enabled: true + # Service type + type: ClusterIP + # Set specific loadBalancerIP when serviceType is LoadBalancer (see https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer) + loadBalancerIP: "" + # Extra ports exposed in node service + ports: + # - name: node-port + # port: 5555 + # targetPort: 5555 + # Custom annotations for service + annotations: {} + # Size limit for DSH volume mounted in container (if not set, default is "1Gi") + dshmVolumeSizeLimit: 1Gi + # Priority class name for chromium-node pods + priorityClassName: "" + + # Wait for pod startup + startupProbe: {} + # httpGet: + # path: /status + # port: 5555 + # failureThreshold: 120 + # periodSeconds: 5 + + # Liveness probe settings + livenessProbe: {} + + # Time to wait for pod termination + terminationGracePeriodSeconds: 30 + lifecycle: {} + extraVolumeMounts: [] + # - name: my-extra-volume + # mountPath: /home/seluser/Downloads + + extraVolumes: [] + # - name: my-extra-volume + # emptyDir: {} + # - name: my-extra-volume-from-pvc + # persistentVolumeClaim: + # claimName: my-pv-claim + + # Override the scaled options for chromium nodes + # scaledOptions: + # scaledJobOptions: + # scaledObjectOptions: + hpa: + url: '{{ include "seleniumGrid.graphqlURL" . }}' + browserName: chrome + # browserVersion: '91.0' # Optional. Only required when supporting multiple versions of browser in your Selenium Grid. + unsafeSsl: 'true' # Optional + + # It is used to add a sidecars proxy in the same pod of the browser node. + # It means it will add a new container to the deployment itself. + # It should be set using the --set-json option + sidecars: [] + videoRecorder: enabled: false # imageRegistry: selenium diff --git a/docker-add-related-tags.sh b/docker-add-related-tags.sh new file mode 100644 index 0000000000..1028cc51a0 --- /dev/null +++ b/docker-add-related-tags.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +NAMESPACE=${NAMESPACE:-seleniarm} +IMAGE=$1 +TAG=$2 +NO_PULL=$3 + +echo $NAMESPACE $IMAGE $TAG + +RELATED_TAGS=(`go run get-all-related-tags.go https://hub.docker.com/v2/repositories/$NAMESPACE/$IMAGE/tags/$TAG | tail -n 1`) + +for related_tag in "${RELATED_TAGS[@]}" + do + echo Add tag $NAMESPACE/$IMAGE:${related_tag} + docker tag $NAMESPACE/$IMAGE:$TAG $NAMESPACE/$IMAGE:$related_tag + done + diff --git a/docker-compose-v2-tracing.yml b/docker-compose-v2-tracing.yml index 19583fe13f..888e06a868 100644 --- a/docker-compose-v2-tracing.yml +++ b/docker-compose-v2-tracing.yml @@ -50,6 +50,21 @@ services: ports: - "6902:5900" + + chromium: + image: selenium/node-chromium:4.16.1-20231212 + shm_size: 2gb + depends_on: + - selenium-hub + environment: + - SE_EVENT_BUS_HOST=selenium-hub + - SE_EVENT_BUS_PUBLISH_PORT=4442 + - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 + - SE_ENABLE_TRACING=true + - JAVA_OPTS=-Dotel.traces.exporter=jaeger -Dotel.exporter.jaeger.endpoint=http://jaegar:14250 -Dotel.resource.attributes=service.name=selenium-node-chromium + ports: + - "6903:5900" + selenium-hub: image: selenium/hub:4.16.1-20231212 ports: diff --git a/docker-compose-v2.yml b/docker-compose-v2.yml index 4496c2fb37..b405cccc9a 100644 --- a/docker-compose-v2.yml +++ b/docker-compose-v2.yml @@ -39,6 +39,18 @@ services: ports: - "6902:5900" + chromium: + image: selenium/node-chromium:4.16.1-20231212 + shm_size: 2gb + depends_on: + - selenium-hub + environment: + - SE_EVENT_BUS_HOST=selenium-hub + - SE_EVENT_BUS_PUBLISH_PORT=4442 + - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 + ports: + - "6903:5900" + selenium-hub: image: selenium/hub:4.16.1-20231212 ports: diff --git a/docker-compose-v3-basicauth.yml b/docker-compose-v3-basicauth.yml index af16b19f22..9edadac768 100644 --- a/docker-compose-v3-basicauth.yml +++ b/docker-compose-v3-basicauth.yml @@ -33,6 +33,16 @@ services: - SE_EVENT_BUS_PUBLISH_PORT=4442 - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 + chromium: + image: selenium/node-chromium:4.16.1-20231212 + shm_size: 2gb + depends_on: + - selenium-hub + environment: + - SE_EVENT_BUS_HOST=selenium-hub + - SE_EVENT_BUS_PUBLISH_PORT=4442 + - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 + selenium-hub: image: selenium/hub:4.16.1-20231212 container_name: selenium-hub diff --git a/docker-compose-v3-dev.yml b/docker-compose-v3-dev.yml index b0720fe0ea..3503977c83 100644 --- a/docker-compose-v3-dev.yml +++ b/docker-compose-v3-dev.yml @@ -39,6 +39,18 @@ services: - SE_EVENT_BUS_PUBLISH_PORT=4442 - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 + chromium: + image: selenium/node-chromium:4.16.1-20231212 + shm_size: 2gb + volumes: + - ./selenium_server_deploy.jar:/opt/selenium/selenium-server.jar + depends_on: + - selenium-hub + environment: + - SE_EVENT_BUS_HOST=selenium-hub + - SE_EVENT_BUS_PUBLISH_PORT=4442 + - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 + selenium-hub: image: selenium/hub:4.16.1-20231212 container_name: selenium-hub diff --git a/docker-compose-v3-full-grid-dev.yml b/docker-compose-v3-full-grid-dev.yml index 6233a1a3f6..1022a6a921 100644 --- a/docker-compose-v3-full-grid-dev.yml +++ b/docker-compose-v3-full-grid-dev.yml @@ -109,3 +109,15 @@ services: - SE_EVENT_BUS_HOST=selenium-event-bus - SE_EVENT_BUS_PUBLISH_PORT=4442 - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 + + chromium: + image: selenium/node-chromium:4.16.1-20231212 + shm_size: 2gb + volumes: + - ./selenium_server_deploy.jar:/opt/selenium/selenium-server.jar + depends_on: + - selenium-event-bus + environment: + - SE_EVENT_BUS_HOST=selenium-event-bus + - SE_EVENT_BUS_PUBLISH_PORT=4442 + - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 diff --git a/docker-compose-v3-full-grid-swarm.yml b/docker-compose-v3-full-grid-swarm.yml index 0d555d75ac..116e158766 100644 --- a/docker-compose-v3-full-grid-swarm.yml +++ b/docker-compose-v3-full-grid-swarm.yml @@ -39,6 +39,17 @@ services: replicas: 1 entrypoint: bash -c 'SE_OPTS="--host $$HOSTNAME" /opt/bin/entry_point.sh' + chromium: + image: selenium/node-chromium:4.16.1-20231212 + shm_size: 2gb + environment: + - SE_EVENT_BUS_HOST=selenium-hub + - SE_EVENT_BUS_PUBLISH_PORT=4442 + - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 + deploy: + replicas: 1 + entrypoint: bash -c 'SE_OPTS="--host $$HOSTNAME" /opt/bin/entry_point.sh' + selenium-hub: image: selenium/hub:4.16.1-20231212 ports: diff --git a/docker-compose-v3-full-grid-tracing.yml b/docker-compose-v3-full-grid-tracing.yml index bc7db86f32..a303c5e587 100644 --- a/docker-compose-v3-full-grid-tracing.yml +++ b/docker-compose-v3-full-grid-tracing.yml @@ -76,7 +76,7 @@ services: - SE_SESSIONS_MAP_PORT=5556 - SE_SESSION_QUEUE_HOST=selenium-session-queue - SE_SESSION_QUEUE_PORT=5559 - - SE_ENABLE_TRACING=true + - SE_ENABLE_TRACING=true - JAVA_OPTS=-Dotel.traces.exporter=jaeger -Dotel.exporter.jaeger.endpoint=http://jaegar:14250 -Dotel.resource.attributes=service.name=selenium-router chrome: image: selenium/node-chrome:4.16.1-20231212 @@ -88,7 +88,7 @@ services: - SE_EVENT_BUS_PUBLISH_PORT=4442 - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 - SE_ENABLE_TRACING=true - - JAVA_OPTS=-Dotel.traces.exporter=jaeger -Dotel.exporter.jaeger.endpoint=http://jaegar:14250 -Dotel.resource.attributes=service.name=selenium-node-chrome + - JAVA_OPTS=-Dotel.traces.exporter=jaeger -Dotel.exporter.jaeger.endpoint=http://jaegar:14250 -Dotel.resource.attributes=service.name=selenium-node-chrome edge: image: selenium/node-edge:4.16.1-20231212 shm_size: 2gb @@ -98,7 +98,7 @@ services: - SE_EVENT_BUS_HOST=selenium-event-bus - SE_EVENT_BUS_PUBLISH_PORT=4442 - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 - - SE_ENABLE_TRACING=true + - SE_ENABLE_TRACING=true - JAVA_OPTS=-Dotel.traces.exporter=jaeger -Dotel.exporter.jaeger.endpoint=http://jaegar:14250 -Dotel.resource.attributes=service.name=selenium-node-edge firefox: image: selenium/node-firefox:4.16.1-20231212 @@ -110,4 +110,15 @@ services: - SE_EVENT_BUS_PUBLISH_PORT=4442 - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 - SE_ENABLE_TRACING=true - - JAVA_OPTS=-Dotel.traces.exporter=jaeger -Dotel.exporter.jaeger.endpoint=http://jaegar:14250 -Dotel.resource.attributes=service.name=selenium-node-firefox \ No newline at end of file + - JAVA_OPTS=-Dotel.traces.exporter=jaeger -Dotel.exporter.jaeger.endpoint=http://jaegar:14250 -Dotel.resource.attributes=service.name=selenium-node-firefox + chromium: + image: selenium/node-chromium:4.16.1-20231212 + shm_size: 2gb + depends_on: + - selenium-event-bus + environment: + - SE_EVENT_BUS_HOST=selenium-event-bus + - SE_EVENT_BUS_PUBLISH_PORT=4442 + - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 + - SE_ENABLE_TRACING=true + - JAVA_OPTS=-Dotel.traces.exporter=jaeger -Dotel.exporter.jaeger.endpoint=http://jaegar:14250 -Dotel.resource.attributes=service.name=selenium-node-chromium diff --git a/docker-compose-v3-full-grid.yml b/docker-compose-v3-full-grid.yml index 5bc20ad799..76a21c9389 100644 --- a/docker-compose-v3-full-grid.yml +++ b/docker-compose-v3-full-grid.yml @@ -92,4 +92,14 @@ services: environment: - SE_EVENT_BUS_HOST=selenium-event-bus - SE_EVENT_BUS_PUBLISH_PORT=4442 - - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 \ No newline at end of file + - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 + + chromium: + image: selenium/node-chromium:4.16.1-20231212 + shm_size: 2gb + depends_on: + - selenium-event-bus + environment: + - SE_EVENT_BUS_HOST=selenium-event-bus + - SE_EVENT_BUS_PUBLISH_PORT=4442 + - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 diff --git a/docker-compose-v3-swarm.yml b/docker-compose-v3-swarm.yml index 0d555d75ac..116e158766 100644 --- a/docker-compose-v3-swarm.yml +++ b/docker-compose-v3-swarm.yml @@ -39,6 +39,17 @@ services: replicas: 1 entrypoint: bash -c 'SE_OPTS="--host $$HOSTNAME" /opt/bin/entry_point.sh' + chromium: + image: selenium/node-chromium:4.16.1-20231212 + shm_size: 2gb + environment: + - SE_EVENT_BUS_HOST=selenium-hub + - SE_EVENT_BUS_PUBLISH_PORT=4442 + - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 + deploy: + replicas: 1 + entrypoint: bash -c 'SE_OPTS="--host $$HOSTNAME" /opt/bin/entry_point.sh' + selenium-hub: image: selenium/hub:4.16.1-20231212 ports: diff --git a/docker-compose-v3-tracing.yml b/docker-compose-v3-tracing.yml index faf7b2ec4f..938f4da869 100644 --- a/docker-compose-v3-tracing.yml +++ b/docker-compose-v3-tracing.yml @@ -44,6 +44,18 @@ services: - SE_ENABLE_TRACING=true - JAVA_OPTS=-Dotel.traces.exporter=jaeger -Dotel.exporter.jaeger.endpoint=http://jaegar:14250 -Dotel.resource.attributes=service.name=selenium-node-firefox + chromium: + image: selenium/node-chromium:4.16.1-20231212 + shm_size: 2gb + depends_on: + - selenium-hub + environment: + - SE_EVENT_BUS_HOST=selenium-hub + - SE_EVENT_BUS_PUBLISH_PORT=4442 + - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 + - SE_ENABLE_TRACING=true + - JAVA_OPTS=-Dotel.traces.exporter=jaeger -Dotel.exporter.jaeger.endpoint=http://jaegar:14250 -Dotel.resource.attributes=service.name=selenium-node-chromium + selenium-hub: image: selenium/hub:4.16.1-20231212 container_name: selenium-hub diff --git a/docker-compose-v3-video.yml b/docker-compose-v3-video.yml index f216bf8dd0..3f33c8c185 100644 --- a/docker-compose-v3-video.yml +++ b/docker-compose-v3-video.yml @@ -33,6 +33,16 @@ services: - SE_EVENT_BUS_PUBLISH_PORT=4442 - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 + chromium: + image: selenium/node-chromium:4.16.1-20231212 + shm_size: 2gb + depends_on: + - selenium-hub + environment: + - SE_EVENT_BUS_HOST=selenium-hub + - SE_EVENT_BUS_PUBLISH_PORT=4442 + - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 + chrome_video: image: selenium/video:ffmpeg-6.1-20231212 volumes: @@ -63,6 +73,16 @@ services: - DISPLAY_CONTAINER_NAME=firefox - FILE_NAME=firefox_video.mp4 + chromium_video: + image: selenium/video:ffmpeg-6.1-20231212 + volumes: + - /tmp/videos:/videos + depends_on: + - chrome + environment: + - DISPLAY_CONTAINER_NAME=chromium + - FILE_NAME=chromium_video.mp4 + selenium-hub: image: selenium/hub:4.16.1-20231212 container_name: selenium-hub diff --git a/docker-compose-v3.yml b/docker-compose-v3.yml index b7cfdefcf5..81790ec73c 100644 --- a/docker-compose-v3.yml +++ b/docker-compose-v3.yml @@ -33,6 +33,16 @@ services: - SE_EVENT_BUS_PUBLISH_PORT=4442 - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 + chromium: + image: selenium/node-chromium:4.16.1-20231212 + shm_size: 2gb + depends_on: + - selenium-hub + environment: + - SE_EVENT_BUS_HOST=selenium-hub + - SE_EVENT_BUS_PUBLISH_PORT=4442 + - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 + selenium-hub: image: selenium/hub:4.16.1-20231212 container_name: selenium-hub diff --git a/generate_multi-arch-release_notes.sh b/generate_multi-arch-release_notes.sh new file mode 100755 index 0000000000..3167e7db76 --- /dev/null +++ b/generate_multi-arch-release_notes.sh @@ -0,0 +1,78 @@ +#!/usr/bin/env bash + +LATEST_TAG=$1 +HEAD_BRANCH=$2 +GRID_VERSION=$3 +BUILD_DATE=$4 + +NAMESPACE="${NAMESPACE:-seleniarm}" +TAG_VERSION=${GRID_VERSION}-${BUILD_DATE} + +echo "" >> release_notes.md +echo "### Changelog" > release_notes.md +git --no-pager log "${LATEST_TAG}...${HEAD_BRANCH}" --pretty=format:"* [\`%h\`](http://github.com/seleniumhq-community/docker-seleniarm/commit/%H) - %s :: %an" --reverse >> release_notes.md + +############################################################## +# Pull the images so we can populate the release notes +# We'll pull using the TAG_VERSION and then add the other +# related tags separately to avoid exceeding the rate limits. +############################################################## +docker pull ${NAMESPACE}/base:${TAG_VERSION} +docker pull ${NAMESPACE}/hub:${TAG_VERSION} +docker pull ${NAMESPACE}/node-base:${TAG_VERSION} +docker pull ${NAMESPACE}/standalone-chromium:${TAG_VERSION} +docker pull ${NAMESPACE}/standalone-firefox:${TAG_VERSION} + +docker pull ${NAMESPACE}/node-chromium:${TAG_VERSION} +docker pull ${NAMESPACE}/node-firefox:${TAG_VERSION} +docker pull ${NAMESPACE}/node-docker:${TAG_VERSION} +docker pull ${NAMESPACE}/standalone-docker:${TAG_VERSION} +docker pull ${NAMESPACE}/sessions:${TAG_VERSION} +docker pull ${NAMESPACE}/session-queue:${TAG_VERSION} +docker pull ${NAMESPACE}/event-bus:${TAG_VERSION} +docker pull ${NAMESPACE}/router:${TAG_VERSION} +docker pull ${NAMESPACE}/distributor:${TAG_VERSION} + +###################################################################### +# Tags are already pushed to Docker Hub, but we need them set locally +# to generate release notes. Since we know the tags, we can set +# them locally to avoid exceeding the docker pull rate-limit. +###################################################################### +bash docker-add-related-tags.sh base ${TAG_VERSION} +bash docker-add-related-tags.sh hub ${TAG_VERSION} +bash docker-add-related-tags.sh node-base ${TAG_VERSION} +bash docker-add-related-tags.sh standalone-chromium ${TAG_VERSION} +bash docker-add-related-tags.sh standalone-firefox ${TAG_VERSION} +bash docker-add-related-tags.sh node-chromium ${TAG_VERSION} +bash docker-add-related-tags.sh node-firefox ${TAG_VERSION} +bash docker-add-related-tags.sh node-docker ${TAG_VERSION} +bash docker-add-related-tags.sh standalone-docker ${TAG_VERSION} +bash docker-add-related-tags.sh sessions ${TAG_VERSION} +bash docker-add-related-tags.sh session-queue ${TAG_VERSION} +bash docker-add-related-tags.sh event-bus ${TAG_VERSION} +bash docker-add-related-tags.sh router ${TAG_VERSION} +bash docker-add-related-tags.sh distributor ${TAG_VERSION} + +CHROMIUM_VERSION=$(docker run --rm ${NAMESPACE}/node-chromium:${TAG_VERSION} chromium --version | awk '{print $2}') +CHROMEDRIVER_VERSION=$(docker run --rm ${NAMESPACE}/node-chromium:${TAG_VERSION} chromedriver --version | awk '{print $2}') +FIREFOX_VERSION=$(docker run --rm ${NAMESPACE}/node-firefox:${TAG_VERSION} firefox --version | awk '{print $3}') +GECKODRIVER_VERSION=$(docker run --rm ${NAMESPACE}/node-firefox:${TAG_VERSION} geckodriver --version | awk 'NR==1{print $2}') + +echo "" >> release_notes.md +echo "### Released versions" >> release_notes.md +echo "* Selenium: ${GRID_VERSION}" >> release_notes.md +echo "* Chromium: ${CHROMIUM_VERSION}" >> release_notes.md +echo "* ChromiumDriver: ${CHROMEDRIVER_VERSION}" >> release_notes.md +echo "* Firefox: ${FIREFOX_VERSION}" >> release_notes.md +echo "* GeckoDriver: ${GECKODRIVER_VERSION}" >> release_notes.md + +echo "" >> release_notes.md +echo "### Published Docker images" >> release_notes.md +echo "<details>" >> release_notes.md +echo "<summary>Click to see published Docker images</summary>" >> release_notes.md +echo "" >> release_notes.md +echo '```' >> release_notes.md +docker images --filter=reference="seleniarm/*:*" --format "table {{.ID}}\t{{.Repository}}\t{{.Tag}}\t{{.Size}}" >> release_notes.md +echo '```' >> release_notes.md +echo "" >> release_notes.md +echo "</details>" >> release_notes.md diff --git a/generate_release_notes.sh b/generate_release_notes.sh index c2f4e40aeb..c17fbe344d 100755 --- a/generate_release_notes.sh +++ b/generate_release_notes.sh @@ -12,8 +12,10 @@ echo "### Changelog" > release_notes.md git --no-pager log "${LATEST_TAG}...${HEAD_BRANCH}" --pretty=format:"* [\`%h\`](http://github.com/seleniumhq/docker-selenium/commit/%H) - %s :: %an" --reverse >> release_notes.md CHROME_VERSION=$(docker run --rm selenium/node-chrome:${TAG_VERSION} google-chrome --version | awk '{print $3}') +CHROMIUM_VERSION=$(docker run --rm selenium/node-chromium:${TAG_VERSION} chromium --version | awk '{print $2}') EDGE_VERSION=$(docker run --rm selenium/node-edge:${TAG_VERSION} microsoft-edge --version | awk '{print $3}') CHROMEDRIVER_VERSION=$(docker run --rm selenium/node-chrome:${TAG_VERSION} chromedriver --version | awk '{print $2}') +CHROMIUMDRIVER_VERSION=$(docker run --rm selenium/node-chromium:${TAG_VERSION} chromedriver --version | awk '{print $2}') EDGEDRIVER_VERSION=$(docker run --rm selenium/node-edge:${TAG_VERSION} msedgedriver --version | awk '{print $4}') FIREFOX_VERSION=$(docker run --rm selenium/node-firefox:${TAG_VERSION} firefox --version | awk '{print $3}') GECKODRIVER_VERSION=$(docker run --rm selenium/node-firefox:${TAG_VERSION} geckodriver --version | awk 'NR==1{print $2}') @@ -29,6 +31,8 @@ echo "* Edge: ${EDGE_VERSION}" >> release_notes.md echo "* EdgeDriver: ${EDGEDRIVER_VERSION}" >> release_notes.md echo "* Firefox: ${FIREFOX_VERSION}" >> release_notes.md echo "* GeckoDriver: ${GECKODRIVER_VERSION}" >> release_notes.md +echo "* Chromium: ${CHROMIUM_VERSION}" >> release_notes.md +echo "* ChromiumDriver: ${CHROMIUMDRIVER_VERSION}" >> release_notes.md echo "* ffmpeg: ${FFMPEG_VERSION}" >> release_notes.md echo "" >> release_notes.md diff --git a/get-access-token.py b/get-access-token.py new file mode 100644 index 0000000000..630783bf68 --- /dev/null +++ b/get-access-token.py @@ -0,0 +1,40 @@ +import time +from cryptography.hazmat.backends import default_backend +import jwt +import os +import requests +import logging + +github_app_id = os.environ.get('GITHUB_APP_ID') +github_installation_id = os.environ.get('GITHUB_INSTALLATION_ID') +private_key = os.environ.get('GITHUB_APP_PEM') +private_key = private_key.replace("\\n", "\n") + +standard_error_msg = 'Seleniarm GitHub App installation environment variables are not set. ' +if github_app_id == '': + raise Exception(standard_error_msg + 'Valid GITHUB_APP_ID is required to obtain an access token.') +if github_installation_id == '': + raise Exception(standard_error_msg + 'Valid GITHUB_INSTALLATION_ID is required to obtain an access token.') +if private_key == '': + raise Exception(standard_error_msg + 'Valid GITHUB_APP_PEM token is required to obtain an access token.') + + +time_since_epoch_in_seconds = int(time.time()) + +payload = { + # issued at time + 'iat': time_since_epoch_in_seconds, + # JWT expiration time (10 minute maximum) + 'exp': time_since_epoch_in_seconds + (10 * 60), + # GitHub App's identifier + 'iss': github_app_id +} + +actual_jwt = jwt.encode(payload, private_key, algorithm='RS256') + +headers = {"Authorization": "Bearer " + actual_jwt, + "Accept": "application/vnd.github.v3+json"} + +resp = requests.post('https://api.github.com/app/installations/' + github_installation_id + '/access_tokens', headers=headers) + +print(resp.json()['token']) diff --git a/get-access-token.sh b/get-access-token.sh new file mode 100644 index 0000000000..3fc7c6daa2 --- /dev/null +++ b/get-access-token.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +python3 -m venv release_sandbox +. release_sandbox/bin/activate +if [ -z "$VIRTUAL_ENV" ]; then + echo "Virtual environment not activated." + exit 1 +fi + +pip3 install cryptography +pip3 install requests +pip3 install PyJWT + +export GITHUB_APP_ID="$SELENIARM_GITHUB_APP_ID" +export GITHUB_INSTALLATION_ID="$SELENIARM_GITHUB_INSTALLATION_ID" +export GITHUB_APP_PEM="$SELENIARM_GITHUB_APP_PEM" + +python3 get-access-token.py diff --git a/get-all-related-tags.go b/get-all-related-tags.go new file mode 100644 index 0000000000..650a9152bf --- /dev/null +++ b/get-all-related-tags.go @@ -0,0 +1,179 @@ +package main + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" + "os" + "strconv" + "strings" +) + +type Latest struct { + Images []struct { + Architecture string `json:"architecture"` + Digest string `json:"digest"` + } +} + +type Result struct { + Results []struct { + Images []struct { + Digest string `json:"digest"` + } + Name string `json:"name"` + } +} + +func main() { + argLen := len(os.Args) + if argLen < 2 { + showUsage() + os.Exit(1) + } + url := os.Args[1] // https://hub.docker.com/v2/repositories/selenium/standalone-chrome/tags/latest/ + var inputArch string + if argLen >= 3 { + inputArch = os.Args[2] + } + + if inputArch == "" { + fmt.Println("Get related tags using sha256 for random architecture...") + } else { + fmt.Println("Get related tags using sha256 for " + inputArch + " architecture...") + } + + arch, tagDigest := getDigestForTag(url, inputArch) + fmt.Println("getting related tags for " + arch + " digest = " + tagDigest) + + var allTagsUrl string + var theseRelatedTags []string + var relatedTagsStr string + + allTagsUrl = getAllTagsUrl(url) + theseRelatedTags = getRelatedTagsFromDigest(allTagsUrl, tagDigest) + relatedTagsStr = strings.Join(theseRelatedTags, " ") + for next := true; next; next = (len(theseRelatedTags) != 0) { + allTagsUrl = getAllTagsUrlForNextPage(allTagsUrl) + theseRelatedTags = getRelatedTagsFromDigest(allTagsUrl, tagDigest) + relatedTagsStr = relatedTagsStr + " " + strings.Join(theseRelatedTags, " ") + // fmt.Println(theseRelatedTags) + } + + fmt.Println(relatedTagsStr) +} + +func getDigestForTag(url string, inputArch string) (string, string) { + resp, err := http.Get(url) + if err != nil { + log.Fatalln(err) + } + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + log.Fatalln(err) + } + + var jsonResp Latest + sb := string(body) + json.Unmarshal([]byte(sb), &jsonResp) + + var digest string + var arch string + if inputArch != "" { + for _, image := range jsonResp.Images { + if inputArch == image.Architecture { + digest = image.Digest + arch = image.Architecture + } + } + } else { + for _, image := range jsonResp.Images { + digest = image.Digest + arch = image.Architecture + } + } + + return arch, digest +} + +func getAllTagsUrlForNextPage(specificTagUrl string) string { + urlPathArr := strings.Split(specificTagUrl, "?") + var pageNum string + if len(urlPathArr) > 1 { + pageKeyVal := strings.Split(urlPathArr[1], "=") + pageNumInt, err := strconv.Atoi(pageKeyVal[1]) + if err != nil { + log.Fatalln(err) + } + pageNum = "?page=" + strconv.Itoa(pageNumInt+1) + } else { + pageNum = "?page=1" + } + return urlPathArr[0] + pageNum +} + +func getAllTagsUrl(specificTagUrl string) string { + urlPathArr := strings.Split(specificTagUrl, "?") + var pageNum string + if len(urlPathArr) > 1 { + pageNum = "?" + urlPathArr[1] + } else { + pageNum = "?page=1" + } + + specificTagUrlWithoutPage := urlPathArr[0] + urlArr := strings.Split(specificTagUrlWithoutPage, "/") + // fmt.Println(urlArr[len(urlArr)-1]) + if urlArr[len(urlArr)-1] == "" { + urlArr[len(urlArr)-1] = "" + urlArr[len(urlArr)-2] = "" + } else { + urlArr[len(urlArr)-1] = "" + } + urlArr = urlArr[:len(urlArr)-1] + allTagsUrl := strings.Join(urlArr, "/") // // https://hub.docker.com/v2/repositories/selenium/standalone-chrome/tags/ + return allTagsUrl + pageNum +} + +func getRelatedTagsFromDigest(allTagsUrl string, digest string) []string { + + resp, err := http.Get(allTagsUrl) + if err != nil { + log.Fatalln(err) + } + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + log.Fatalln(err) + } + + var jsonResp Result + sb := string(body) + json.Unmarshal([]byte(sb), &jsonResp) + + var relatedTags []string + for _, results := range jsonResp.Results { + for _, image := range results.Images { + imageDigest := image.Digest + if imageDigest == digest { + relatedTags = append(relatedTags, results.Name) + } + } + } + return relatedTags +} + +func showUsage() { + fmt.Println(`Usage: + get-all-related-tags TAG_URL [ARCH] + + TAG_URL -> URL for a container image manifest (Required) + ARCH -> Architecture to use to obtain sha256 (Optional) + + Example Usage: + $ get-all-related-tags https://hub.docker.com/v2/repositories/selenium/standalone-chrome/tags/latest/ + `) +} diff --git a/get-image-sha256-digest.go b/get-image-sha256-digest.go new file mode 100644 index 0000000000..d51b58ca5c --- /dev/null +++ b/get-image-sha256-digest.go @@ -0,0 +1,56 @@ +package main + +import ( + "io/ioutil" + "log" + "net/http" + "fmt" + "encoding/json" + "os" +) + +type Latest struct { + Images []struct { + Architecture string `json:"architecture"` + Digest string `json:"digest"` + } +} + + +func main() { + argLen := len(os.Args) + if argLen < 2 { + showUsage() + os.Exit(1) + } + + url := os.Args[1] // https://hub.docker.com/v2/repositories/selenium/standalone-chrome/tags/latest/ + resp, err := http.Get(url) + if err != nil { + log.Fatalln(err) + } + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + log.Fatalln(err) + } + + var jsonResp Latest + sb := string(body) + json.Unmarshal([]byte(sb), &jsonResp) + + for _, image := range jsonResp.Images { + fmt.Printf(image.Architecture + " " + image.Digest + "\n") + } +} + +func showUsage() { + fmt.Println(`Usage: + get-image-sha256-digest TAG_URL + + TAG_URL -> URL for a container image manifest (Required) + + Example Usage: + $ get-image-sha256-digest https://hub.docker.com/v2/repositories/selenium/standalone-chrome/tags/latest/ + `) +} diff --git a/tag-and-push-multi-arch-image.sh b/tag-and-push-multi-arch-image.sh new file mode 100755 index 0000000000..7e993dced9 --- /dev/null +++ b/tag-and-push-multi-arch-image.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +VERSION=$1 +BUILD_DATE=$2 +NAMESPACE="${3:-seleniarm}" +IMAGE=$4 +NEW_TAG=$5 + +if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ] || [ -z "$4" ] || [ -z "$5" ]; then + echo "Be sure to pass in all of the values" + exit 1 +fi + + +AMD64_DIGEST=`go run get-image-sha256-digest.go https://hub.docker.com/v2/repositories/$NAMESPACE/$IMAGE/tags/$VERSION-$BUILD_DATE/ | grep -w "amd64" | awk '{print $2}'` +ARM_DIGEST=`go run get-image-sha256-digest.go https://hub.docker.com/v2/repositories/$NAMESPACE/$IMAGE/tags/$VERSION-$BUILD_DATE/ | grep -w "arm" | awk '{print $2}'` +ARM64_DIGEST=`go run get-image-sha256-digest.go https://hub.docker.com/v2/repositories/$NAMESPACE/$IMAGE/tags/$VERSION-$BUILD_DATE/ | grep -w "arm64" | awk '{print $2}'` + +docker manifest create $NAMESPACE/$IMAGE:$NEW_TAG \ + --amend $NAMESPACE/$IMAGE@$AMD64_DIGEST \ + --amend $NAMESPACE/$IMAGE@$ARM_DIGEST \ + --amend $NAMESPACE/$IMAGE@$ARM64_DIGEST + +docker manifest push $NAMESPACE/$IMAGE:$NEW_TAG + diff --git a/tag_and_push_multi-arch_browser_images.sh b/tag_and_push_multi-arch_browser_images.sh new file mode 100755 index 0000000000..f276f6e5a2 --- /dev/null +++ b/tag_and_push_multi-arch_browser_images.sh @@ -0,0 +1,126 @@ +#!/usr/bin/env bash + +VERSION=$1 +BUILD_DATE=$2 +NAMESPACE=$3 +PUSH_IMAGE="${4:-false}" +BROWSER=$5 + +TAG_VERSION=${VERSION}-${BUILD_DATE} + +function short_version() { + local __long_version=$1 + local __version_split=( ${__long_version//./ } ) + echo "${__version_split[0]}.${__version_split[1]}" +} + +MAJOR=$(cut -d. -f1 <<<"${VERSION}") +MAJOR_MINOR=$(cut -d. -f1-2 <<<"${VERSION}") + +echo "Tagging images for browser ${BROWSER}, version ${VERSION}, build date ${BUILD_DATE}, namespace ${NAMESPACE}" + +case "${BROWSER}" in + +chromium) + CHROMIUM_VERSION=$(docker run --rm ${NAMESPACE}/node-chromium:${TAG_VERSION} chromium --version | awk '{print $2}') + echo "Chromium version -> "${CHROMIUM_VERSION} + CHROME_SHORT_VERSION="$(short_version ${CHROMIUM_VERSION})" + echo "Short Chromium version -> "${CHROME_SHORT_VERSION} + + CHROMEDRIVER_VERSION=$(docker run --rm ${NAMESPACE}/node-chromium:${TAG_VERSION} chromedriver --version | awk '{print $2}') + echo "ChromeDriver version -> "${CHROMEDRIVER_VERSION} + CHROMEDRIVER_SHORT_VERSION="$(short_version ${CHROMEDRIVER_VERSION})" + echo "Short ChromeDriver version -> "${CHROMEDRIVER_SHORT_VERSION} + + CHROME_TAGS=( + # Major Selenium version (X) + ${MAJOR} + # Major-minor Selenium version (X.Y) + ${MAJOR_MINOR} + # Full Selenium version (X.Y.X) + ${VERSION} + ${CHROMIUM_VERSION}-chromedriver-${CHROMEDRIVER_VERSION}-grid-${TAG_VERSION} + # Browser version and browser driver version plus build date + ${CHROMIUM_VERSION}-chromedriver-${CHROMEDRIVER_VERSION}-${BUILD_DATE} + # Browser version and browser driver version + ${CHROMIUM_VERSION}-chromedriver-${CHROMEDRIVER_VERSION} + # Browser version and build date + ${CHROMIUM_VERSION}-${BUILD_DATE} + # Browser version + ${CHROMIUM_VERSION} + ## Short versions + ${CHROME_SHORT_VERSION}-chromedriver-${CHROMEDRIVER_SHORT_VERSION}-grid-${TAG_VERSION} + # Browser version and browser driver version plus build date + ${CHROME_SHORT_VERSION}-chromedriver-${CHROMEDRIVER_SHORT_VERSION}-${BUILD_DATE} + # Browser version and browser driver version + ${CHROME_SHORT_VERSION}-chromedriver-${CHROMEDRIVER_SHORT_VERSION} + # Browser version and build date + ${CHROME_SHORT_VERSION}-${BUILD_DATE} + # Browser version + ${CHROME_SHORT_VERSION} + ) + + for chrome_tag in "${CHROME_TAGS[@]}" + do + if [ "${PUSH_IMAGE}" = true ]; then + docker buildx imagetools create -t ${NAMESPACE}/node-chromium:${chrome_tag} ${NAMESPACE}/node-chromium:${TAG_VERSION} + docker buildx imagetools create -t ${NAMESPACE}/standalone-chromium:${chrome_tag} ${NAMESPACE}/standalone-chromium:${TAG_VERSION} + #sh tag-and-push-multi-arch-image.sh $VERSION $BUILD_DATE $NAMESPACE node-chromium ${chrome_tag} + #sh tag-and-push-multi-arch-image.sh $VERSION $BUILD_DATE $NAMESPACE standalone-chromium ${chrome_tag} + fi + done + + ;; +firefox) + FIREFOX_VERSION=$(docker run --rm ${NAMESPACE}/node-firefox:${TAG_VERSION} firefox --version | awk '{print $3}') + echo "Firefox version -> "${FIREFOX_VERSION} + FIREFOX_SHORT_VERSION="$(short_version ${FIREFOX_VERSION})" + echo "Short Firefox version -> "${FIREFOX_SHORT_VERSION} + GECKODRIVER_VERSION=$(docker run --rm ${NAMESPACE}/node-firefox:${TAG_VERSION} geckodriver --version | awk 'NR==1{print $2}') + echo "GeckoDriver version -> "${GECKODRIVER_VERSION} + GECKODRIVER_SHORT_VERSION="$(short_version ${GECKODRIVER_VERSION})" + echo "Short GeckoDriver version -> "${GECKODRIVER_SHORT_VERSION} + + FIREFOX_TAGS=( + # Major Selenium version (X) + ${MAJOR} + # Major-minor Selenium version (X.Y) + ${MAJOR_MINOR} + # Full Selenium version (X.Y.X) + ${VERSION} + ${FIREFOX_VERSION}-geckodriver-${GECKODRIVER_VERSION}-grid-${TAG_VERSION} + # Browser version and browser driver version plus build date + ${FIREFOX_VERSION}-geckodriver-${GECKODRIVER_VERSION}-${BUILD_DATE} + # Browser version and browser driver version + ${FIREFOX_VERSION}-geckodriver-${GECKODRIVER_VERSION} + # Browser version and build date + ${FIREFOX_VERSION}-${BUILD_DATE} + # Browser version + ${FIREFOX_VERSION} + ## Short versions + ${FIREFOX_SHORT_VERSION}-geckodriver-${GECKODRIVER_SHORT_VERSION}-grid-${TAG_VERSION} + # Browser version and browser driver version plus build date + ${FIREFOX_SHORT_VERSION}-geckodriver-${GECKODRIVER_SHORT_VERSION}-${BUILD_DATE} + # Browser version and browser driver version + ${FIREFOX_SHORT_VERSION}-geckodriver-${GECKODRIVER_SHORT_VERSION} + # Browser version and build date + ${FIREFOX_SHORT_VERSION}-${BUILD_DATE} + # Browser version + ${FIREFOX_SHORT_VERSION} + ) + + for firefox_tag in "${FIREFOX_TAGS[@]}" + do + if [ "${PUSH_IMAGE}" = true ]; then + docker buildx imagetools create -t ${NAMESPACE}/node-firefox:${firefox_tag} ${NAMESPACE}/node-firefox:${TAG_VERSION} + docker buildx imagetools create -t ${NAMESPACE}/standalone-firefox:${firefox_tag} ${NAMESPACE}/standalone-firefox:${TAG_VERSION} + #sh tag-and-push-multi-arch-image.sh $VERSION $BUILD_DATE $NAMESPACE node-firefox ${firefox_tag} + #sh tag-and-push-multi-arch-image.sh $VERSION $BUILD_DATE $NAMESPACE standalone-firefox ${firefox_tag} + fi + done + + ;; +*) + echo "Unknown browser!" + ;; +esac diff --git a/tag_and_push_multi-arch_major_minor.sh b/tag_and_push_multi-arch_major_minor.sh new file mode 100755 index 0000000000..b7f563754c --- /dev/null +++ b/tag_and_push_multi-arch_major_minor.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +VERSION=$1 +BUILD_DATE=$2 +NAMESPACE=$3 +PUSH_IMAGE="${4:-false}" +IMAGE=$5 + +TAG_VERSION=${VERSION}-${BUILD_DATE} + +MAJOR=$(cut -d. -f1 <<<"${VERSION}") +MAJOR_MINOR=$(cut -d. -f1-2 <<<"${VERSION}") + +TAGS=( + $MAJOR + $MAJOR_MINOR + $VERSION +) + +for tag in "${TAGS[@]}" + do + if [ "${PUSH_IMAGE}" = true ]; then + docker buildx imagetools create -t ${NAMESPACE}/${IMAGE}:${tag} ${NAMESPACE}/${IMAGE}:${TAG_VERSION} + #sh tag-and-push-multi-arch-image.sh $VERSION $BUILD_DATE $NAMESPACE $IMAGE ${tag} + fi + done diff --git a/tests/SeleniumTests/__init__.py b/tests/SeleniumTests/__init__.py index fa95acefaf..c74b0d98b9 100644 --- a/tests/SeleniumTests/__init__.py +++ b/tests/SeleniumTests/__init__.py @@ -80,7 +80,7 @@ def test_download_file(self): if is_continue: file_link.click() wait.until( - lambda d: str(d.get_downloadable_files()[0]).endswith(file_name) + lambda d: len(d.get_downloadable_files()) > 0 and str(d.get_downloadable_files()[0]).endswith(file_name) ) self.assertTrue(str(driver.get_downloadable_files()[0]).endswith(file_name)) diff --git a/tests/charts/ci/NodeChrome-values.yaml b/tests/charts/ci/NodeChrome-values.yaml index 09396f42d0..f92bfd952b 100644 --- a/tests/charts/ci/NodeChrome-values.yaml +++ b/tests/charts/ci/NodeChrome-values.yaml @@ -5,6 +5,9 @@ chromeNode: extraEnvironmentVariables: - name: SE_OPTS value: "--enable-managed-downloads true" +# Configuration for chromium nodes +chromiumNode: + enabled: false # Configuration for edge nodes edgeNode: enabled: false diff --git a/tests/charts/ci/NodeChromium-values.yaml b/tests/charts/ci/NodeChromium-values.yaml new file mode 100644 index 0000000000..fc015db606 --- /dev/null +++ b/tests/charts/ci/NodeChromium-values.yaml @@ -0,0 +1,16 @@ +# This is used in Helm chart testing +# Configuration for chrome nodes +chromeNode: + enabled: false +# Configuration for chromium nodes +chromiumNode: + nameOverride: my-chromium-name + extraEnvironmentVariables: + - name: SE_OPTS + value: "--enable-managed-downloads true" +# Configuration for edge nodes +edgeNode: + enabled: false +# Configuration for firefox nodes +firefoxNode: + enabled: false diff --git a/tests/charts/ci/NodeEdge-values.yaml b/tests/charts/ci/NodeEdge-values.yaml index 27220e2759..d90b7707db 100644 --- a/tests/charts/ci/NodeEdge-values.yaml +++ b/tests/charts/ci/NodeEdge-values.yaml @@ -2,6 +2,9 @@ # Configuration for chrome nodes chromeNode: enabled: false +# Configuration for chromium nodes +chromiumNode: + enabled: false # Configuration for edge nodes edgeNode: nameOverride: my-edge-name diff --git a/tests/charts/ci/NodeFirefox-values.yaml b/tests/charts/ci/NodeFirefox-values.yaml index 21bb6a2856..04822a5c24 100644 --- a/tests/charts/ci/NodeFirefox-values.yaml +++ b/tests/charts/ci/NodeFirefox-values.yaml @@ -2,6 +2,9 @@ # Configuration for chrome nodes chromeNode: enabled: false +# Configuration for chromium nodes +chromiumNode: + enabled: false # Configuration for edge nodes edgeNode: enabled: false diff --git a/tests/charts/ci/ParallelAutoscaling-values.yaml b/tests/charts/ci/ParallelAutoscaling-values.yaml index 39ea9434c8..2e1d428196 100644 --- a/tests/charts/ci/ParallelAutoscaling-values.yaml +++ b/tests/charts/ci/ParallelAutoscaling-values.yaml @@ -9,6 +9,11 @@ chromeNode: extraEnvironmentVariables: - name: SE_OPTS value: "--enable-managed-downloads true" +chromiumNode: + nameOverride: my-chromium-name + extraEnvironmentVariables: + - name: SE_OPTS + value: "--enable-managed-downloads true" # Configuration for edge nodes edgeNode: nameOverride: my-edge-name diff --git a/tests/charts/templates/render/dummy.yaml b/tests/charts/templates/render/dummy.yaml index 52d672a8ac..185cc41919 100644 --- a/tests/charts/templates/render/dummy.yaml +++ b/tests/charts/templates/render/dummy.yaml @@ -48,6 +48,9 @@ components: chromeNode: affinity: *affinity +chromiumNode: + affinity: *affinity + firefoxNode: affinity: *affinity diff --git a/tests/charts/templates/test.py b/tests/charts/templates/test.py index f05c7629d7..08ea8d8a9b 100644 --- a/tests/charts/templates/test.py +++ b/tests/charts/templates/test.py @@ -17,7 +17,7 @@ def load_template(yaml_file): class ChartTemplateTests(unittest.TestCase): def test_set_affinity(self): - resources_name = ['selenium-chrome-node', 'selenium-distributor', 'selenium-edge-node', 'selenium-firefox-node', + resources_name = ['selenium-chrome-node', 'selenium-distributor', 'selenium-edge-node', 'selenium-firefox-node', 'selenium-chromium-node', 'selenium-event-bus', 'selenium-router', 'selenium-session-map', 'selenium-session-queue'] count = 0 logger.info(f"Assert affinity is set in global and nodes") diff --git a/tests/docker-compose-v3-test-video.yml b/tests/docker-compose-v3-test-video.yml index bbfb6f6abe..dd07a4b982 100644 --- a/tests/docker-compose-v3-test-video.yml +++ b/tests/docker-compose-v3-test-video.yml @@ -4,7 +4,7 @@ version: "3" services: browser: - image: selenium/node-${BROWSER}:${TAG} + image: ${NAME}/node-${BROWSER}:${TAG} shm_size: 2gb depends_on: - selenium-hub @@ -17,7 +17,7 @@ services: - "6900:5900" browser_video: - image: selenium/video:${VIDEO_TAG} + image: ${NAME}/video:${VIDEO_TAG} volumes: - ./videos:/videos depends_on: @@ -27,7 +27,7 @@ services: - FILE_NAME=${VIDEO_FILE_NAME} selenium-hub: - image: selenium/hub:${TAG} + image: ${NAME}/hub:${TAG} container_name: selenium-hub ports: - "4442:4442" diff --git a/tests/test.py b/tests/test.py index 0d260e3300..02fb810a01 100644 --- a/tests/test.py +++ b/tests/test.py @@ -41,6 +41,10 @@ # Firefox Images 'NodeFirefox': 'node-firefox', 'StandaloneFirefox': 'standalone-firefox', + + # Chromium Images + 'NodeChromium': 'node-chromium', + 'StandaloneChromium': 'standalone-chromium', } TEST_NAME_MAP = { @@ -56,6 +60,10 @@ 'NodeFirefox': 'FirefoxTests', 'StandaloneFirefox': 'FirefoxTests', + # Chromium Images + 'NodeChromium': 'ChromeTests', + 'StandaloneChromium': 'ChromeTests', + # Chart Parallel Test 'ParallelAutoscaling': 'ParallelAutoscalingTests' } @@ -165,7 +173,7 @@ def get_build_path(container): def standalone_browser_container_matches(container): - return re.match("(Standalone)(Chrome|Firefox|Edge)", container) + return re.match("(Standalone)(Chrome|Firefox|Edge|Chromium)", container) if __name__ == '__main__':