diff --git a/.github/workflows/helm-chart-test.yml b/.github/workflows/helm-chart-test.yml index 136e387fb8..3a2d53a98b 100644 --- a/.github/workflows/helm-chart-test.yml +++ b/.github/workflows/helm-chart-test.yml @@ -156,7 +156,7 @@ jobs: max_attempts: 3 command: | NAME=${IMAGE_REGISTRY} VERSION=${BRANCH} BUILD_DATE=${BUILD_DATE} TEST_UPGRADE_CHART=false make chart_test_autoscaling_${{ matrix.test-strategy }} \ - && make test_video_integrity + && NAME=${IMAGE_REGISTRY} VERSION=${BRANCH} BUILD_DATE=${BUILD_DATE} make test_video_integrity - name: Test chart upgrade if: (matrix.test-upgrade == true) run: | diff --git a/Makefile b/Makefile index 9ce18dc901..1d5a93e574 100644 --- a/Makefile +++ b/Makefile @@ -18,9 +18,9 @@ MAJOR := $(word 1,$(subst ., ,$(TAG_VERSION))) MINOR := $(word 2,$(subst ., ,$(TAG_VERSION))) MAJOR_MINOR_PATCH := $(word 1,$(subst -, ,$(TAG_VERSION))) FFMPEG_TAG_PREV_VERSION := $(or $(FFMPEG_TAG_PREV_VERSION),$(FFMPEG_TAG_PREV_VERSION),ffmpeg-7.0.1) -FFMPEG_TAG_VERSION := $(or $(FFMPEG_TAG_VERSION),$(FFMPEG_TAG_VERSION),ffmpeg-7.0.1) +FFMPEG_TAG_VERSION := $(or $(FFMPEG_TAG_VERSION),$(FFMPEG_TAG_VERSION),ffmpeg-7.0.2) FFMPEG_BASED_NAME := $(or $(FFMPEG_BASED_NAME),$(FFMPEG_BASED_NAME),linuxserver) -FFMPEG_BASED_TAG := $(or $(FFMPEG_BASED_TAG),$(FFMPEG_BASED_TAG),7.0.1) +FFMPEG_BASED_TAG := $(or $(FFMPEG_BASED_TAG),$(FFMPEG_BASED_TAG),7.0.2) PLATFORMS := $(or $(PLATFORMS),$(shell echo $$PLATFORMS),linux/amd64) SEL_PASSWD := $(or $(SEL_PASSWD),$(SEL_PASSWD),secret) @@ -560,18 +560,21 @@ test_chromium: test_chromium_standalone: PLATFORMS=$(PLATFORMS) VERSION=$(TAG_VERSION) NAMESPACE=$(NAMESPACE) BASE_RELEASE=$(BASE_RELEASE) BASE_VERSION=$(BASE_VERSION) BINDING_VERSION=$(BINDING_VERSION) SKIP_BUILD=true ./tests/bootstrap.sh StandaloneChromium -test_parallel: hub chrome firefox edge chromium +test_parallel: hub chrome firefox edge chromium video sudo rm -rf ./tests/tests sudo rm -rf ./tests/videos; mkdir -p ./tests/videos sudo cp -r ./charts/selenium-grid/certs ./tests/videos for node in DeploymentAutoscaling JobAutoscaling ; do \ cd ./tests || true ; \ echo TAG=$(TAG_VERSION) > .env ; \ - echo TEST_DRAIN_AFTER_SESSION_COUNT=$(or $(TEST_DRAIN_AFTER_SESSION_COUNT), 0) >> .env ; \ + echo VIDEO_TAG=$(FFMPEG_TAG_VERSION)-$(BUILD_DATE) >> .env ; \ + echo TEST_DELAY_AFTER_TEST=$(or $(TEST_DELAY_AFTER_TEST), 2) >> .env ; \ + echo TEST_DRAIN_AFTER_SESSION_COUNT=$(or $(TEST_DRAIN_AFTER_SESSION_COUNT), 2) >> .env ; \ echo TEST_PARALLEL_HARDENING=$(or $(TEST_PARALLEL_HARDENING), "true") >> .env ; \ echo TEST_PARALLEL_COUNT=$(or $(TEST_PARALLEL_COUNT), 5) >> .env ; \ + echo HUB_CHECKS_INTERVAL=$(or $(HUB_CHECKS_INTERVAL), 45) >> .env ; \ echo LOG_LEVEL=$(or $(LOG_LEVEL), "INFO") >> .env ; \ - echo REQUEST_TIMEOUT=$(or $(REQUEST_TIMEOUT), 300) >> .env ; \ + echo REQUEST_TIMEOUT=$(or $(REQUEST_TIMEOUT), 600) >> .env ; \ echo NODE=$$node >> .env ; \ echo UID=$$(id -u) >> .env ; \ echo BINDING_VERSION=$(BINDING_VERSION) >> .env ; \ @@ -586,14 +589,15 @@ test_parallel: hub chrome firefox edge chromium export $$(cat .env | xargs) ; \ DOCKER_DEFAULT_PLATFORM=$(PLATFORMS) docker compose --profile $(PLATFORMS) -f docker-compose-v3-test-parallel.yml up -d --remove-orphans --no-log-prefix ; \ RUN_IN_DOCKER_COMPOSE=true bash ./bootstrap.sh $$node ; \ - done ; \ - docker compose -f docker-compose-v3-test-parallel.yml down + docker compose -f docker-compose-v3-test-parallel.yml down ; \ + done + make test_video_integrity test_video_standalone: standalone_chrome standalone_chromium standalone_firefox standalone_edge - DOCKER_COMPOSE_FILE=docker-compose-v3-test-standalone.yml make test_video + DOCKER_COMPOSE_FILE=docker-compose-v3-test-standalone.yml TEST_DELAY_AFTER_TEST=2 make test_video test_video_dynamic_name: - VIDEO_FILE_NAME=auto \ + VIDEO_FILE_NAME=auto TEST_DELAY_AFTER_TEST=2 \ make test_video # This should run on its own CI job. There is no need to combine it with the other tests. @@ -617,7 +621,7 @@ test_video: video hub chrome firefox edge chromium echo NODE=$$node >> .env ; \ echo UID=$$(id -u) >> .env ; \ echo BINDING_VERSION=$(BINDING_VERSION) >> .env ; \ - echo TEST_DELAY_AFTER_TEST=$(or $(TEST_DELAY_AFTER_TEST), 0) >> .env ; \ + echo TEST_DELAY_AFTER_TEST=$(or $(TEST_DELAY_AFTER_TEST), 2) >> .env ; \ echo SELENIUM_ENABLE_MANAGED_DOWNLOADS=$(or $(SELENIUM_ENABLE_MANAGED_DOWNLOADS), "true") >> .env ; \ echo BASIC_AUTH_USERNAME=$(or $(BASIC_AUTH_USERNAME), "admin") >> .env ; \ echo BASIC_AUTH_PASSWORD=$(or $(BASIC_AUTH_PASSWORD), "admin") >> .env ; \ @@ -697,7 +701,7 @@ test_node_relay: hub node_base standalone_firefox test_standalone_docker: standalone_docker DOCKER_COMPOSE_FILE=docker-compose-v3-test-standalone-docker.yaml CONFIG_FILE=standalone_docker_config.toml \ - RECORD_STANDALONE=true GRID_URL=http://0.0.0.0:4444 LIST_OF_TESTS_AMD64="DeploymentAutoscaling" TEST_PARALLEL_HARDENING=true \ + RECORD_STANDALONE=true GRID_URL=http://0.0.0.0:4444 LIST_OF_TESTS_AMD64="DeploymentAutoscaling" TEST_PARALLEL_HARDENING=true TEST_DELAY_AFTER_TEST=2 \ SELENIUM_ENABLE_MANAGED_DOWNLOADS=true LOG_LEVEL=SEVERE SKIP_CHECK_DOWNLOADS_VOLUME=true make test_node_docker test_node_docker: hub standalone_docker standalone_chrome standalone_firefox standalone_edge standalone_chromium video @@ -725,7 +729,7 @@ test_node_docker: hub standalone_docker standalone_chrome standalone_firefox sta echo LOG_LEVEL=$(or $(LOG_LEVEL), "INFO") >> .env ; \ echo REQUEST_TIMEOUT=$(or $(REQUEST_TIMEOUT), 300) >> .env ; \ echo SELENIUM_ENABLE_MANAGED_DOWNLOADS=$(or $(SELENIUM_ENABLE_MANAGED_DOWNLOADS), "false") >> .env ; \ - echo TEST_DELAY_AFTER_TEST=$(or $(TEST_DELAY_AFTER_TEST), 0) >> .env ; \ + echo TEST_DELAY_AFTER_TEST=$(or $(TEST_DELAY_AFTER_TEST), 2) >> .env ; \ echo RECORD_STANDALONE=$(or $(RECORD_STANDALONE), "true") >> .env ; \ echo GRID_URL=$(or $(GRID_URL), "") >> .env ; \ echo NODE=$$node >> .env ; \ @@ -790,7 +794,7 @@ test_video_integrity: fi; \ for file in $$list_files; do \ echo "Checking video file: $$file"; \ - docker run -u $$(id -u) -v $$(pwd):$$(pwd) -w $$(pwd) --entrypoint="" $(FFMPEG_BASED_NAME)/ffmpeg:$(FFMPEG_BASED_TAG) ffmpeg -v error -i "$$file" -f null - ; \ + docker run -u $$(id -u) -v $$(pwd):$$(pwd) -w $$(pwd) --entrypoint="" $(NAME)/video:$(FFMPEG_TAG_VERSION)-$(BUILD_DATE) ffmpeg -v error -i "$$file" -f null - ; \ if [ $$? -ne 0 ]; then \ echo "Video file $$file is corrupted"; \ number_corrupted_files=$$((number_corrupted_files+1)); \ diff --git a/README.md b/README.md index 650ec09472..8a834f9006 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,7 @@ Talk to us at https://www.selenium.dev/support/ * [Execution with Docker Compose](#execution-with-docker-compose) * [Configuring the child containers](#configuring-the-child-containers) * [Video recording, screen resolution, and time zones in a Dynamic Grid](#video-recording-screen-resolution-and-time-zones-in-a-dynamic-grid) + * [Time zone configuration via env variable](#time-zone-configuration-via-env-variable) * [Deploying to Kubernetes](#deploying-to-kubernetes) * [Configuring the containers](#configuring-the-containers) * [SE_OPTS Selenium Configuration Options](#se_opts-selenium-configuration-options) @@ -712,13 +713,13 @@ When using in Dynamic Grid, those variables should be combined with the prefix ` ### Environment variables and default values for upload feature -| Environment variable | Default value | Description | -|-------------------------------|------------------------------------|-------------------------------------------------------------------------------------------| -| `SE_UPLOAD_RETAIN_LOCAL_FILE` | `false` | Keep local file after uploading successfully | -| `SE_UPLOAD_COMMAND` | `copy` | RCLONE command is used to transfer file. Enforce `move` when retain local file is `false` | -| `SE_UPLOAD_OPTS` | `-P --cutoff-mode SOFT --metadata` | Other options belong to RCLONE command can be set. | -| `SE_UPLOAD_CONFIG_FILE_NAME` | `upload.conf` | Config file for remote host instead of set via env variable prefix SE_RCLONE_* | -| `SE_UPLOAD_CONFIG_DIRECTORY` | `/opt/bin` | Directory of config file (change it when conf file in another directory is mounted) | +| Environment variable | Default value | Description | +|-------------------------------|---------------------------------------------|-------------------------------------------------------------------------------------------| +| `SE_UPLOAD_RETAIN_LOCAL_FILE` | `false` | Keep local file after uploading successfully | +| `SE_UPLOAD_COMMAND` | `copy` | RCLONE command is used to transfer file. Enforce `move` when retain local file is `false` | +| `SE_UPLOAD_OPTS` | `-P --cutoff-mode SOFT --metadata--inplace` | Other options belong to RCLONE command can be set. | +| `SE_UPLOAD_CONFIG_FILE_NAME` | `upload.conf` | Config file for remote host instead of set via env variable prefix SE_RCLONE_* | +| `SE_UPLOAD_CONFIG_DIRECTORY` | `/opt/bin` | Directory of config file (change it when conf file in another directory is mounted) | ___ @@ -971,8 +972,6 @@ docker run --rm --name selenium-docker -p 4444:4444 ` selenium/standalone-docker:4.23.1-20240820 ``` - - ### Video recording, screen resolution, and time zones in a Dynamic Grid To record your WebDriver session, you need to add a `se:recordVideo` field set to `true`. You can also set a time zone and a screen resolution, @@ -1009,6 +1008,18 @@ driver.quit() After test executed, under (`${PWD}/assets`) you can see the video file name in path `//test_visit_basic_auth_secured_page_ChromeTests.mp4` The file name will be trimmed to 255 characters to avoid long file names. Moreover, the `space` character will be replaced by `_`, and only the characters alphabets, numbers, `-` (hyphen), and `_` (underscore) are retained in the file name. (This feat is available once this [PR](https://github.com/SeleniumHQ/selenium/pull/13907) merged) + +### Time zone configuration via env variable + +`tzdata` is installed in based images, and you can set the time zone in container by using the env variable `TZ`. +By default, the time zone is set to `UTC`. +List of supported time zones can be found [here](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). For example: + +```bash +$ docker run --rm --entrypoint="" -e TZ=Asia/Ho_Chi_Minh selenium/node-chromium:latest date +%FT%T%Z +2024-08-28T18:19:26+07 +``` + ___ ## Deploying to Kubernetes diff --git a/Video/Dockerfile b/Video/Dockerfile index 1d46cf86df..3b08061493 100755 --- a/Video/Dockerfile +++ b/Video/Dockerfile @@ -83,7 +83,7 @@ RUN curl -fLo /tmp/rclone.zip https://downloads.rclone.org/rclone-${RCLONE_VERSI && rm -rf /tmp/rclone-* COPY --chown="${SEL_UID}:${SEL_GID}" upload.sh upload.conf /opt/bin/ ENV SE_VIDEO_UPLOAD_ENABLED=false \ - SE_VIDEO_INTERNAL_UPLOAD=false \ + SE_VIDEO_INTERNAL_UPLOAD=true \ SE_UPLOAD_DESTINATION_PREFIX="" RUN mkdir -p /var/run/supervisor /var/log/supervisor ${VIDEO_FOLDER} \ @@ -101,6 +101,7 @@ CMD ["/opt/bin/entry_point.sh"] ENV DISPLAY_NUM=99 \ DISPLAY_CONTAINER_NAME=selenium \ SE_SERVER_PROTOCOL="http" \ + SE_VIDEO_POLL_INTERVAL=1 \ SE_SCREEN_WIDTH=1920 \ SE_SCREEN_HEIGHT=1080 \ SE_FRAME_RATE=15 \ diff --git a/Video/supervisord.conf b/Video/supervisord.conf index c379beb205..faa5ee25c6 100755 --- a/Video/supervisord.conf +++ b/Video/supervisord.conf @@ -12,12 +12,14 @@ minfds=1024 ; (min. avail startup file descrip minprocs=200 ; (min. avail process descriptors;default 200) [program:video-recording] -priority=0 +priority=10 command=/opt/bin/video.sh killasgroup=true autostart=true startsecs=0 autorestart=true +stopsignal=TERM +stopwaitsecs=30 ;Logs (all activity redirected to stdout so it can be seen through "docker logs" redirect_stderr=true @@ -25,11 +27,13 @@ stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 [program:video-ready] -priority=5 +priority=0 command=python3 /opt/bin/video_ready.py killasgroup=true autostart=true +startsecs=0 autorestart=true +stopsignal=KILL ;Logs (all activity redirected to stdout so it can be seen through "docker logs" redirect_stderr=true @@ -37,11 +41,14 @@ stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 [program:video-upload] -priority=10 +priority=5 command=/opt/bin/upload.sh killasgroup=true autostart=%(ENV_SE_VIDEO_INTERNAL_UPLOAD)s +startsecs=0 autorestart=%(ENV_SE_VIDEO_INTERNAL_UPLOAD)s +stopsignal=TERM +stopwaitsecs=30 ;Logs (all activity redirected to stdout so it can be seen through "docker logs" redirect_stderr=true diff --git a/Video/upload.sh b/Video/upload.sh index 42cf6d9f65..bac19c3339 100755 --- a/Video/upload.sh +++ b/Video/upload.sh @@ -4,14 +4,14 @@ VIDEO_FOLDER=${VIDEO_FOLDER} UPLOAD_CONFIG_DIRECTORY=${SE_UPLOAD_CONFIG_DIRECTORY:-"/opt/bin"} UPLOAD_CONFIG_FILE_NAME=${SE_UPLOAD_CONFIG_FILE_NAME:-"upload.conf"} UPLOAD_COMMAND=${SE_UPLOAD_COMMAND:-"copy"} -UPLOAD_OPTS=${SE_UPLOAD_OPTS:-"-P --cutoff-mode SOFT --metadata"} +UPLOAD_OPTS=${SE_UPLOAD_OPTS:-"-P --cutoff-mode SOFT --metadata --inplace"} UPLOAD_RETAIN_LOCAL_FILE=${SE_UPLOAD_RETAIN_LOCAL_FILE:-"false"} UPLOAD_PIPE_FILE_NAME=${SE_UPLOAD_PIPE_FILE_NAME:-"uploadpipe"} -SE_VIDEO_INTERNAL_UPLOAD=${SE_VIDEO_INTERNAL_UPLOAD:-"false"} +VIDEO_INTERNAL_UPLOAD=${VIDEO_INTERNAL_UPLOAD:-$SE_VIDEO_INTERNAL_UPLOAD} VIDEO_UPLOAD_BATCH_CHECK=${SE_VIDEO_UPLOAD_BATCH_CHECK:-"10"} process_name="video.uploader" -if [ "${SE_VIDEO_INTERNAL_UPLOAD}" = "true" ]; +if [ "${VIDEO_INTERNAL_UPLOAD}" = "true" ]; then # If using RCLONE in the same container, write signal to /tmp internally UPLOAD_PIPE_FILE="/tmp/${UPLOAD_PIPE_FILE_NAME}" @@ -65,78 +65,71 @@ function rclone_upload() { check_and_clear_background } -function consume_pipe_file() { +function check_if_pid_alive() { + local pid=$1 + if kill -0 "${pid}" > /dev/null 2>&1; then + return 0 + fi + return 1 +} + +function consume_pipe_file_in_background() { + echo "$(date +%FT%T%Z) [${process_name}] - Start consuming pipe file to upload" while read FILE DESTINATION < ${UPLOAD_PIPE_FILE}; do if [ "${FILE}" = "exit" ]; then - FORCE_EXIT=true - exit + echo "$(date +%FT%T%Z) [${process_name}] - Received exit signal. Aborting upload process" + return 0 elif [ "$FILE" != "" ] && [ "$DESTINATION" != "" ]; then rclone_upload "${FILE}" "${DESTINATION}" - elif [ -f ${FORCE_EXIT_FILE} ]; - then - echo "$(date +%FT%T%Z) [${process_name}] - Force exit signal detected" - exit fi done + echo "$(date +%FT%T%Z) [${process_name}] - Stopped consuming pipe file. Upload process is done" + return 0 } -function graceful_exit() { - echo "$(date +%FT%T%Z) [${process_name}] - Uploader is shutting down" - if [ "${FORCE_EXIT}" != "true" ]; then - consume_pipe_file +# Function to check if the named pipe exists +check_if_pipefile_exists() { + if [ -p "${UPLOAD_PIPE_FILE}" ]; then + echo "$(date +%FT%T%Z) [${process_name}] - Named pipe ${UPLOAD_PIPE_FILE} exists" + return 0 fi - echo "$(date +%FT%T%Z) [${process_name}] - Uploader consumed all files in the pipe" - rm -rf ${FORCE_EXIT_FILE} - echo "$(date +%FT%T%Z) [${process_name}] - Uploader is ready to shutdown" + return 1 } -trap graceful_exit SIGTERM SIGINT EXIT -# Function to create the named pipe if it doesn't exist -function create_named_pipe() { - if [ ! -p "${UPLOAD_PIPE_FILE}" ]; - then - if [ -e "${UPLOAD_PIPE_FILE}" ]; - then - rm -f "${UPLOAD_PIPE_FILE}" - fi - mkfifo "${UPLOAD_PIPE_FILE}" - echo "$(date +%FT%T%Z) [${process_name}] - Created named pipe ${UPLOAD_PIPE_FILE}" +function wait_until_pipefile_exists() { + echo "$(date +%FT%T%Z) [${process_name}] - Waiting for ${UPLOAD_PIPE_FILE} to be present" + until check_if_pipefile_exists; do + sleep 1 + done +} + +function graceful_exit() { + echo "$(date +%FT%T%Z) [${process_name}] - Trapped SIGTERM/SIGINT/x so shutting down uploader" + if ! check_if_pid_alive "${UPLOAD_PID}"; then + consume_pipe_file_in_background & + UPLOAD_PID=$! fi + echo "exit" >> "${UPLOAD_PIPE_FILE}" & + wait "${UPLOAD_PID}" + echo "$(date +%FT%T%Z) [${process_name}] - Uploader consumed all files in the pipe" + rm -rf "${FORCE_EXIT_FILE}" + echo "$(date +%FT%T%Z) [${process_name}] - Uploader is ready to shutdown" + exit 0 } -TIMEOUT=300 # Timeout in seconds (5 minutes) -START_TIME=$(date +%s) +rename_rclone_env +trap graceful_exit SIGTERM SIGINT EXIT while true; do - if [ -e "${UPLOAD_PIPE_FILE}" ]; - then - if [ -p "${UPLOAD_PIPE_FILE}" ]; - then - break - else - echo "$(date +%FT%T%Z) [${process_name}] - ${UPLOAD_PIPE_FILE} exists but is not a named pipe" - create_named_pipe - fi - else - create_named_pipe - fi - - CURRENT_TIME=$(date +%s) - ELAPSED_TIME=$((CURRENT_TIME - START_TIME)) - if [ ${ELAPSED_TIME} -ge ${TIMEOUT} ]; - then - echo "$(date +%FT%T%Z) [${process_name}] - Timeout waiting for ${UPLOAD_PIPE_FILE} to be created" - exit 1 + wait_until_pipefile_exists + if ! check_if_pid_alive "${UPLOAD_PID}"; then + consume_pipe_file_in_background & + UPLOAD_PID=$! fi - - echo "$(date +%FT%T%Z) [${process_name}] - Waiting for ${UPLOAD_PIPE_FILE} to be created" - sleep 1 + while check_if_pid_alive "${UPLOAD_PID}"; do + sleep 1 + done done - -echo "$(date +%FT%T%Z) [${process_name}] - Waiting for video files put into pipe for proceeding to upload" - -rename_rclone_env -consume_pipe_file diff --git a/Video/video.sh b/Video/video.sh index d41ab8e80d..312aea159d 100755 --- a/Video/video.sh +++ b/Video/video.sh @@ -9,11 +9,12 @@ CODEC=${CODEC:-$SE_CODEC} PRESET=${PRESET:-$SE_PRESET} VIDEO_FOLDER=${VIDEO_FOLDER} VIDEO_UPLOAD_ENABLED=${VIDEO_UPLOAD_ENABLED:-$SE_VIDEO_UPLOAD_ENABLED} +VIDEO_INTERNAL_UPLOAD=${VIDEO_INTERNAL_UPLOAD:-$SE_VIDEO_INTERNAL_UPLOAD} VIDEO_CONFIG_DIRECTORY=${VIDEO_CONFIG_DIRECTORY:-"/opt/bin"} UPLOAD_DESTINATION_PREFIX=${UPLOAD_DESTINATION_PREFIX:-$SE_UPLOAD_DESTINATION_PREFIX} UPLOAD_PIPE_FILE_NAME=${SE_UPLOAD_PIPE_FILE_NAME:-"uploadpipe"} -SE_VIDEO_INTERNAL_UPLOAD=${SE_VIDEO_INTERNAL_UPLOAD:-"false"} SE_SERVER_PROTOCOL=${SE_SERVER_PROTOCOL:-"http"} +poll_interval=${SE_VIDEO_POLL_INTERVAL:-1} max_attempts=${SE_VIDEO_WAIT_ATTEMPTS:-50} process_name="video.recorder" @@ -35,7 +36,7 @@ else exit 1 fi -if [ "${SE_VIDEO_INTERNAL_UPLOAD}" = "true" ]; +if [ "${VIDEO_INTERNAL_UPLOAD}" = "true" ]; then # If using RCLONE in the same container, write signal to /tmp internally UPLOAD_PIPE_FILE="/tmp/${UPLOAD_PIPE_FILE_NAME}" @@ -46,41 +47,52 @@ else FORCE_EXIT_FILE="${VIDEO_FOLDER}/force_exit" fi -function create_pipe() { - if [[ "${VIDEO_UPLOAD_ENABLED}" != "false" ]] && [[ -n "${UPLOAD_DESTINATION_PREFIX}" ]]; - then - echo "$(date +%FT%T%Z) [${process_name}] - Create pipe if not exists for video upload stream" - if [[ ! -p ${UPLOAD_PIPE_FILE} ]]; - then - mkfifo ${UPLOAD_PIPE_FILE} - fi - fi +# Function to create the named pipe if it doesn't exist +function create_named_pipe() { + if [ "${VIDEO_UPLOAD_ENABLED}" = "true" ]; then + if [ ! -p "${UPLOAD_PIPE_FILE}" ]; then + if [ -e "${UPLOAD_PIPE_FILE}" ]; then + rm -f "${UPLOAD_PIPE_FILE}" + fi + mkfifo "${UPLOAD_PIPE_FILE}" + echo "$(date +%FT%T%Z) [${process_name}] - Created named pipe ${UPLOAD_PIPE_FILE}" + fi + fi } function wait_for_display() { - export DISPLAY=${DISPLAY_CONTAINER_NAME}:${DISPLAY_NUM}.0 - attempts=0 - - echo "$(date +%FT%T%Z) [${process_name}] - Checking if the display is open" - until xset b off || [[ $attempts = "$max_attempts" ]] + DISPLAY=${DISPLAY_CONTAINER_NAME}:${DISPLAY_NUM}.0 + export DISPLAY=${DISPLAY} + echo "$(date +%FT%T%Z) [${process_name}] - Waiting for the display ${DISPLAY} is open" + until xset b off > /dev/null 2>&1 do - echo "$(date +%FT%T%Z) [${process_name}] - Waiting before next display check" - sleep 0.5 - attempts=$((attempts+1)) + sleep ${poll_interval} done - if [[ $attempts = "$max_attempts" ]]; - then - echo "$(date +%FT%T%Z) [${process_name}] - Can not open display, exiting." - exit + VIDEO_SIZE=$(xdpyinfo | grep 'dimensions:' | awk '{print $2}') + echo "$(date +%FT%T%Z) [${process_name}] - Display ${DISPLAY} is open with dimensions ${VIDEO_SIZE}" +} + +function check_if_api_respond() { + endpoint_checks=$(curl --noproxy "*" -sk -o /dev/null -w "%{http_code}" "${NODE_STATUS_ENDPOINT}") + if [[ "${endpoint_checks}" != "200" ]]; then + return 1 fi + return 0 +} - VIDEO_SIZE=$(xdpyinfo | grep 'dimensions:' | awk '{print $2}') +function wait_for_api_respond() { + echo "$(date +%FT%T%Z) [${process_name}] - Waiting for Node endpoint responds" + until check_if_api_respond; do + sleep ${poll_interval} + done + return 0 } + function wait_util_uploader_shutdown() { max_wait=5 wait=0 - if [[ "${VIDEO_UPLOAD_ENABLED}" != "false" ]] && [[ -n "${UPLOAD_DESTINATION_PREFIX}" ]]; + if [[ "${VIDEO_UPLOAD_ENABLED}" = "true" ]] && [[ -n "${UPLOAD_DESTINATION_PREFIX}" ]] && [[ "${VIDEO_INTERNAL_UPLOAD}" != "true" ]]; then while [[ -f ${FORCE_EXIT_FILE} ]] && [[ ${wait} -lt ${max_wait} ]]; do @@ -90,7 +102,7 @@ function wait_util_uploader_shutdown() { wait=$((wait+1)) done fi - if [[ "${VIDEO_UPLOAD_ENABLED}" != "false" ]] && [[ -n "${UPLOAD_DESTINATION_PREFIX}" ]] && [[ "${SE_VIDEO_INTERNAL_UPLOAD}" = "true" ]]; + if [[ "${VIDEO_UPLOAD_ENABLED}" = "true" ]] && [[ -n "${UPLOAD_DESTINATION_PREFIX}" ]] && [[ "${VIDEO_INTERNAL_UPLOAD}" = "true" ]]; then while [[ $(pgrep rclone | wc -l) -gt 0 ]] do @@ -99,11 +111,10 @@ function wait_util_uploader_shutdown() { sleep 1 done fi - echo "$(date +%FT%T%Z) [${process_name}] - Ready to shutdown the recorder" } function send_exit_signal_to_uploader() { - if [[ "${VIDEO_UPLOAD_ENABLED}" != "false" ]] && [[ -n "${UPLOAD_DESTINATION_PREFIX}" ]]; + if [[ "${VIDEO_UPLOAD_ENABLED}" = "true" ]] && [[ -n "${UPLOAD_DESTINATION_PREFIX}" ]]; then echo "$(date +%FT%T%Z) [${process_name}] - Sending a signal to force exit the uploader" echo "exit" >> ${UPLOAD_PIPE_FILE} & @@ -129,28 +140,36 @@ function stop_ffmpeg() { if ! pgrep -f ffmpeg > /dev/null; then break fi - sleep 0.5 + sleep ${poll_interval} done } function stop_recording() { - echo "$(date +%FT%T%Z) [${process_name}] - Recorder is shutting down" stop_ffmpeg + echo "$(date +%FT%T%Z) [${process_name}] - Video recording stopped" recorded_count=$((recorded_count+1)) - if [[ "${VIDEO_UPLOAD_ENABLED}" != "false" ]] && [[ -n "${UPLOAD_DESTINATION_PREFIX}" ]]; + if [[ "${VIDEO_UPLOAD_ENABLED}" = "true" ]] && [[ -n "${UPLOAD_DESTINATION_PREFIX}" ]]; then upload_destination=${UPLOAD_DESTINATION_PREFIX}/${video_file_name} echo "$(date +%FT%T%Z) [${process_name}] - Add to pipe a signal Uploading video to $upload_destination" - echo $video_file ${UPLOAD_DESTINATION_PREFIX} >> ${UPLOAD_PIPE_FILE} & - elif [[ "${VIDEO_UPLOAD_ENABLED}" != "false" ]] && [[ -z "${UPLOAD_DESTINATION_PREFIX}" ]]; + echo "$video_file ${UPLOAD_DESTINATION_PREFIX}" >> ${UPLOAD_PIPE_FILE} & + elif [[ "${VIDEO_UPLOAD_ENABLED}" = "true" ]] && [[ -z "${UPLOAD_DESTINATION_PREFIX}" ]]; then echo "$(date +%FT%T%Z) [${process_name}] - Upload destination not known since UPLOAD_DESTINATION_PREFIX is not set. Continue without uploading." fi recording_started="false" } -function check_if_recording_inprogress() { - if [[ "$recording_started" = "true" ]] +function check_if_ffmpeg_running() { + if pgrep -f ffmpeg > /dev/null; + then + return 0 + fi + return 1 +} + +function stop_if_recording_inprogress() { + if [[ "$recording_started" = "true" ]] || check_if_ffmpeg_running; then stop_recording fi @@ -163,33 +182,26 @@ function log_node_response() { } function graceful_exit() { - check_if_recording_inprogress + echo "$(date +%FT%T%Z) [${process_name}] - Trapped SIGTERM/SIGINT/x so shutting down recorder" + stop_if_recording_inprogress send_exit_signal_to_uploader wait_util_uploader_shutdown - kill -SIGTERM "$(cat /var/run/supervisor/supervisord.pid)" + kill -SIGTERM "$(cat /var/run/supervisor/supervisord.pid)" 2>/dev/null + echo "$(date +%FT%T%Z) [${process_name}] - Ready to shutdown the recorder" + exit 0 } if [[ "${VIDEO_UPLOAD_ENABLED}" != "true" ]] && [[ "${VIDEO_FILE_NAME}" != "auto" ]] && [[ -n "${VIDEO_FILE_NAME}" ]]; then - return_code=1 - attempts=0 - echo "$(date +%FT%T%Z) [${process_name}] - Checking if the display is open..." - until [[ $return_code -eq 0 ]] || [[ $attempts -eq $max_attempts ]]; do - xset -display ${DISPLAY_CONTAINER_NAME}:${DISPLAY_NUM} b off > /dev/null 2>&1 - return_code=$? - if [[ $return_code -ne 0 ]]; then - echo "$(date +%FT%T%Z) [${process_name}] - Waiting before next display check..." - sleep 0.5 - fi - attempts=$((attempts+1)) - done - + trap graceful_exit SIGTERM SIGINT EXIT + wait_for_display # exec replaces the video.sh process with ffmpeg, this makes easier to pass the process termination signal - exec ffmpeg -hide_banner -loglevel warning -flags low_delay -threads 2 -fflags nobuffer+genpts -strict experimental -y -f x11grab \ - -video_size ${VIDEO_SIZE} -r ${FRAME_RATE} -i ${DISPLAY_CONTAINER_NAME}:${DISPLAY_NUM}.0 -codec:v ${CODEC} ${PRESET} -pix_fmt yuv420p "$VIDEO_FOLDER/$VIDEO_FILE_NAME" + ffmpeg -hide_banner -loglevel warning -flags low_delay -threads 2 -fflags nobuffer+genpts -strict experimental -y -f x11grab \ + -video_size ${VIDEO_SIZE} -r ${FRAME_RATE} -i ${DISPLAY} -codec:v ${CODEC} ${PRESET} -pix_fmt yuv420p "$VIDEO_FOLDER/$VIDEO_FILE_NAME" & + wait $! else trap graceful_exit SIGTERM SIGINT EXIT - create_pipe + create_named_pipe wait_for_display recording_started="false" video_file_name="" @@ -199,21 +211,7 @@ else max_recorded_count=${SE_DRAIN_AFTER_SESSION_COUNT:-0} recorded_count=0 - echo "$(date +%FT%T%Z) [${process_name}] - Checking if node API responds" - until curl --noproxy "*" -sk --request GET ${NODE_STATUS_ENDPOINT} || [[ $attempts = "$max_attempts" ]] - do - if [ $(($attempts % 60)) -eq 0 ]; - then - echo "$(date +%FT%T%Z) [${process_name}] - Waiting before next API check" - fi - sleep 0.5 - attempts=$((attempts+1)) - done - if [[ $attempts = "$max_attempts" ]]; - then - echo "$(date +%FT%T%Z) [${process_name}] - Can not reach node API, reach the max attempts $max_attempts, exiting." - exit - fi + wait_for_api_respond while curl --noproxy "*" -sk --request GET ${NODE_STATUS_ENDPOINT} > /tmp/status.json do session_id=$(jq -r "${JQ_SESSION_ID_QUERY}" /tmp/status.json) @@ -234,7 +232,7 @@ else -video_size ${VIDEO_SIZE} -r ${FRAME_RATE} -i ${DISPLAY} -codec:v ${CODEC} ${PRESET} -pix_fmt yuv420p "$video_file" & recording_started="true" echo "$(date +%FT%T%Z) [${process_name}] - Video recording started" - sleep 1 + sleep ${poll_interval} elif [[ "$session_id" != "$prev_session_id" && "$recording_started" = "true" ]]; then stop_recording @@ -245,15 +243,12 @@ else fi elif [[ $recording_started = "true" ]]; then - echo "$(date +%FT%T%Z) [${process_name}] - Video recording in progress " - sleep 1 + echo "$(date +%FT%T%Z) [${process_name}] - Video recording in progress" + sleep ${poll_interval} else - sleep 1 + sleep ${poll_interval} fi prev_session_id=$session_id done - echo "$(date +%FT%T%Z) [${process_name}] - Last response from node API..." - log_node_response echo "$(date +%FT%T%Z) [${process_name}] - Node API is not responding now, exiting..." - exit fi diff --git a/Video/video_graphQLQuery.sh b/Video/video_graphQLQuery.sh index 87c37ff571..cf918dbe4d 100755 --- a/Video/video_graphQLQuery.sh +++ b/Video/video_graphQLQuery.sh @@ -1,12 +1,19 @@ #!/usr/bin/env bash +max_time=1 +retry_time=3 + # Define parameters SESSION_ID=$1 if [ -n "${SE_NODE_GRID_GRAPHQL_URL}" ]; then GRAPHQL_ENDPOINT=${SE_NODE_GRID_GRAPHQL_URL} else - GRAPHQL_ENDPOINT="$(/opt/bin/video_gridUrl.sh)/graphql" + GRAPHQL_ENDPOINT="$(/opt/bin/video_gridUrl.sh)" +fi +if [[ -n ${GRAPHQL_ENDPOINT} ]] && [[ ! ${GRAPHQL_ENDPOINT} == */graphql ]]; then + GRAPHQL_ENDPOINT="${GRAPHQL_ENDPOINT}/graphql" fi + VIDEO_CAP_NAME=${VIDEO_CAP_NAME:-"se:recordVideo"} TEST_NAME_CAP=${TEST_NAME_CAP:-"se:name"} VIDEO_NAME_CAP=${VIDEO_NAME_CAP:-"se:videoName"} @@ -14,24 +21,28 @@ VIDEO_FILE_NAME_TRIM=${SE_VIDEO_FILE_NAME_TRIM_REGEX:-"[:alnum:]-_"} VIDEO_FILE_NAME_SUFFIX=${SE_VIDEO_FILE_NAME_SUFFIX:-"true"} if [ -n "${GRAPHQL_ENDPOINT}" ]; then + current_check=1 while true; do # Send GraphQL query - curl --noproxy "*" --retry 3 -k -X POST \ + endpoint_checks=$(curl --noproxy "*" -m ${max_time} -k -X POST \ -H "Content-Type: application/json" \ --data '{"query":"{ session (id: \"'${SESSION_ID}'\") { id, capabilities, startTime, uri, nodeId, nodeUri, sessionDurationMillis, slot { id, stereotype, lastStarted } } } "}' \ - -s "${GRAPHQL_ENDPOINT}" > /tmp/graphQL_${SESSION_ID}.json + -s "${GRAPHQL_ENDPOINT}" -o "/tmp/graphQL_${SESSION_ID}.json" -w "%{http_code}") + current_check=$((current_check + 1)) # Check if the response contains "capabilities" - if jq -e '.data.session.capabilities' /tmp/graphQL_${SESSION_ID}.json > /dev/null; then + if [[ "$endpoint_checks" = "404" ]] || [[ $current_check -eq $retry_time ]]; then + break + elif [[ "$endpoint_checks" = "200" ]] && [[ $(jq -e '.data.session.capabilities' /tmp/graphQL_${SESSION_ID}.json > /dev/null) -eq 0 ]]; then break - else - sleep 0.5 fi done - # Extract the values from the response - RECORD_VIDEO=$(jq -r '.data.session.capabilities | fromjson | ."'${VIDEO_CAP_NAME}'"' /tmp/graphQL_${SESSION_ID}.json) - TEST_NAME=$(jq -r '.data.session.capabilities | fromjson | ."'${TEST_NAME_CAP}'"' /tmp/graphQL_${SESSION_ID}.json) - VIDEO_NAME=$(jq -r '.data.session.capabilities | fromjson | ."'${VIDEO_NAME_CAP}'"' /tmp/graphQL_${SESSION_ID}.json) + if [[ -f "/tmp/graphQL_${SESSION_ID}.json" ]]; then + # Extract the values from the response + RECORD_VIDEO=$(jq -r '.data.session.capabilities | fromjson | ."'${VIDEO_CAP_NAME}'"' /tmp/graphQL_${SESSION_ID}.json) + TEST_NAME=$(jq -r '.data.session.capabilities | fromjson | ."'${TEST_NAME_CAP}'"' /tmp/graphQL_${SESSION_ID}.json) + VIDEO_NAME=$(jq -r '.data.session.capabilities | fromjson | ."'${VIDEO_NAME_CAP}'"' /tmp/graphQL_${SESSION_ID}.json) + fi fi # Check if enabling to record video diff --git a/Video/video_ready.py b/Video/video_ready.py index eee1f42a81..dfd1ca82c2 100755 --- a/Video/video_ready.py +++ b/Video/video_ready.py @@ -2,6 +2,8 @@ from os import environ import json import psutil +import signal +import sys video_ready_port = int(environ.get('VIDEO_READY_PORT', 9000)) @@ -18,5 +20,13 @@ def do_GET(self): self.end_headers() self.wfile.write(json.dumps({'status': response_text}).encode('utf-8')) +def graceful_shutdown(signum, frame): + print("Trapped SIGTERM/SIGINT/x so shutting down video-ready...") + httpd.shutdown() + sys.exit(0) + +signal.signal(signal.SIGINT, graceful_shutdown) +signal.signal(signal.SIGTERM, graceful_shutdown) + httpd = HTTPServer( ('0.0.0.0', video_ready_port), Handler ) httpd.serve_forever() diff --git a/charts/selenium-grid/configs/node/nodePreStop.sh b/charts/selenium-grid/configs/node/nodePreStop.sh index 2bf663a0d2..dc6c33607b 100644 --- a/charts/selenium-grid/configs/node/nodePreStop.sh +++ b/charts/selenium-grid/configs/node/nodePreStop.sh @@ -13,6 +13,7 @@ tmp_node_file="/tmp/nodeProbe${ID}" function on_exit() { rm -rf ${tmp_node_file} echo "$(date +%FT%T%Z) [${probe_name}] - Exiting Node preStop..." + exit 0 } trap on_exit EXIT diff --git a/charts/selenium-grid/configs/node/nodeProbe.sh b/charts/selenium-grid/configs/node/nodeProbe.sh index 56779434b3..281f942746 100644 --- a/charts/selenium-grid/configs/node/nodeProbe.sh +++ b/charts/selenium-grid/configs/node/nodeProbe.sh @@ -12,6 +12,7 @@ tmp_grid_file="/tmp/gridProbe${ID}" function on_exit() { rm -rf ${tmp_node_file} rm -rf ${tmp_grid_file} + exit 0 } trap on_exit EXIT diff --git a/charts/selenium-grid/configs/uploader/s3/upload.sh b/charts/selenium-grid/configs/uploader/s3/upload.sh index 4cb72546f9..311a881f0e 100644 --- a/charts/selenium-grid/configs/uploader/s3/upload.sh +++ b/charts/selenium-grid/configs/uploader/s3/upload.sh @@ -22,6 +22,7 @@ function consume_force_exit() { done rm -rf ${SE_VIDEO_FOLDER}/force_exit echo "Force exit signal consumed" + exit 0 } trap consume_force_exit EXIT diff --git a/docker-compose-v3-video-upload-dynamic-grid.yml b/docker-compose-v3-video-upload-dynamic-grid.yml index e326754c16..0f591f1af8 100644 --- a/docker-compose-v3-video-upload-dynamic-grid.yml +++ b/docker-compose-v3-video-upload-dynamic-grid.yml @@ -12,6 +12,7 @@ services: volumes: # Mount the local directory `/tmp/upload` to the FTP server's `/ftp/seluser` directory to check out the uploaded videos - /tmp/upload:/ftp/seluser + command: ["/bin/sh", "-c", "/sbin/tini -- /bin/start_vsftpd.sh && tail -f /dev/null"] stop_grace_period: 30s node-docker: diff --git a/docker-compose-v3-video-upload-standalone.yml b/docker-compose-v3-video-upload-standalone.yml index d21056183c..f7a0d8774c 100644 --- a/docker-compose-v3-video-upload-standalone.yml +++ b/docker-compose-v3-video-upload-standalone.yml @@ -7,11 +7,13 @@ services: # Start a local FTP server to demonstrate video upload with RCLONE (https://github.com/delfer/docker-alpine-ftp-server) ftp_server: image: delfer/alpine-ftp-server:latest + container_name: ftp_server environment: - USERS=seluser|selenium.dev volumes: # Mount the local directory `/home/${USER}/Videos/upload` to the FTP server's `/ftp/seluser` directory to check out the uploaded videos - /tmp/upload:/ftp/seluser + command: ["/bin/sh", "-c", "/sbin/tini -- /bin/start_vsftpd.sh && tail -f /dev/null"] stop_grace_period: 30s standalone_chrome: diff --git a/docker-compose-v3-video-upload.yml b/docker-compose-v3-video-upload.yml index 8259e5f2a5..7772dc3e8c 100644 --- a/docker-compose-v3-video-upload.yml +++ b/docker-compose-v3-video-upload.yml @@ -13,6 +13,7 @@ services: volumes: # Mount the local directory `/tmp/upload` to the FTP server's `/ftp/seluser` directory to check out the uploaded videos - /tmp/upload:/ftp/seluser + command: ["/bin/sh", "-c", "/sbin/tini -- /bin/start_vsftpd.sh && tail -f /dev/null"] stop_grace_period: 30s chrome: diff --git a/tests/charts/ci/local-pvc.yaml b/tests/charts/ci/local-pvc.yaml index d68d63369b..731fb91101 100644 --- a/tests/charts/ci/local-pvc.yaml +++ b/tests/charts/ci/local-pvc.yaml @@ -23,32 +23,11 @@ spec: value: "21005" - name: TINI_SUBREAPER value: "true" - command: - - /bin/sh - - -c - - | - max_attempts=5; - attempt_num=1; - while [ $attempt_num -le $max_attempts ]; - do - output=$(eval "/sbin/tini -- /bin/start_vsftpd.sh"); - status=$?; - if [ $status -eq 0 ]; then - break; - else - echo "Attempt $attempt_num failed! Trying again in 3 seconds..."; - attempt_num=$((attempt_num+1)); - sleep 3; - fi - done; - if [ $attempt_num -gt $max_attempts ]; then - echo "All attempts to start vsftpd failed."; - exit 1; - fi volumeMounts: - mountPath: /ftp/seluser name: ftp-upload subPath: seluser + command: ["/bin/sh", "-c", "/sbin/tini -- /bin/start_vsftpd.sh && tail -f /dev/null"] volumes: - name: ftp-upload persistentVolumeClaim: diff --git a/tests/docker-compose-v3-test-node-docker.yaml b/tests/docker-compose-v3-test-node-docker.yaml index b6136c9a52..b974e29502 100644 --- a/tests/docker-compose-v3-test-node-docker.yaml +++ b/tests/docker-compose-v3-test-node-docker.yaml @@ -53,34 +53,13 @@ services: ftp_server: image: delfer/alpine-ftp-server:latest container_name: ftp_server + command: ["/bin/sh", "-c", "/sbin/tini -- /bin/start_vsftpd.sh && tail -f /dev/null"] environment: - USERS=seluser|selenium.dev - MAX_PORT=21010 - TINI_SUBREAPER=true volumes: - ./videos/upload:/ftp/seluser - entrypoint: > - /bin/sh -c ' - max_attempts=5; - attempt_num=1; - while [ $attempt_num -le $max_attempts ]; - do - output=$(eval "/sbin/tini -- /bin/start_vsftpd.sh"); - status=$?; - if [ $status -eq 0 ]; then - break; - else - echo "Attempt $attempt_num failed! Trying again in 3 seconds..."; - attempt_num=$((attempt_num+1)); - sleep 3; - fi - done; - if [ $attempt_num -gt $max_attempts ]; then - echo "All attempts to start vsftpd failed."; - exit 1; - fi - ' - restart: unless-stopped stop_grace_period: 30s tests: diff --git a/tests/docker-compose-v3-test-parallel.yml b/tests/docker-compose-v3-test-parallel.yml index 2399a4462e..bfc0ebc158 100644 --- a/tests/docker-compose-v3-test-parallel.yml +++ b/tests/docker-compose-v3-test-parallel.yml @@ -9,7 +9,7 @@ services: - linux/arm64 deploy: mode: replicated - replicas: 10 + replicas: 5 image: selenium/node-${NODE_CHROME}:${TAG} user: ${UID} depends_on: @@ -17,7 +17,6 @@ services: volumes: - ./videos/certs:/opt/selenium/secrets environment: - - SE_DRAIN_AFTER_SESSION_COUNT=${TEST_DRAIN_AFTER_SESSION_COUNT} - SE_EVENT_BUS_HOST=selenium-hub - SE_EVENT_BUS_PUBLISH_PORT=4442 - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 @@ -29,15 +28,27 @@ services: - SE_NODE_GRACEFUL_SHUTDOWN=true - SE_DRAIN_AFTER_SESSION_COUNT=1 - SE_ENABLE_TLS=true + - SE_JAVA_OPTS=-Dwebdriver.httpclient.readTimeout=${REQUEST_TIMEOUT} restart: always + chrome_video: + image: selenium/video:${VIDEO_TAG} + user: ${UID} + volumes: + - ./videos:/videos + environment: + - DISPLAY_CONTAINER_NAME=chrome + - SE_VIDEO_FILE_NAME=auto + - SE_SERVER_PROTOCOL=https + stop_grace_period: 30s + firefox: profiles: - linux/amd64 - linux/arm64 deploy: mode: replicated - replicas: 10 + replicas: 5 image: selenium/node-firefox:${TAG} user: ${UID} shm_size: 2gb @@ -46,7 +57,6 @@ services: volumes: - ./videos/certs:/opt/selenium/secrets environment: - - SE_DRAIN_AFTER_SESSION_COUNT=${TEST_DRAIN_AFTER_SESSION_COUNT} - SE_EVENT_BUS_HOST=selenium-hub - SE_EVENT_BUS_PUBLISH_PORT=4442 - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 @@ -56,14 +66,26 @@ services: - SE_NODE_GRACEFUL_SHUTDOWN=true - SE_DRAIN_AFTER_SESSION_COUNT=3 - SE_ENABLE_TLS=true + - SE_JAVA_OPTS=-Dwebdriver.httpclient.readTimeout=${REQUEST_TIMEOUT} restart: always + firefox_video: + image: selenium/video:${VIDEO_TAG} + user: ${UID} + volumes: + - ./videos:/videos + environment: + - DISPLAY_CONTAINER_NAME=firefox + - SE_VIDEO_FILE_NAME=auto + - SE_SERVER_PROTOCOL=https + stop_grace_period: 30s + edge: profiles: - linux/amd64 deploy: mode: replicated - replicas: 10 + replicas: 5 image: selenium/node-edge:${TAG} user: ${UID} shm_size: 2gb @@ -72,7 +94,6 @@ services: volumes: - ./videos/certs:/opt/selenium/secrets environment: - - SE_DRAIN_AFTER_SESSION_COUNT=${TEST_DRAIN_AFTER_SESSION_COUNT} - SE_EVENT_BUS_HOST=selenium-hub - SE_EVENT_BUS_PUBLISH_PORT=4442 - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 @@ -82,8 +103,20 @@ services: - SE_NODE_GRACEFUL_SHUTDOWN=true - SE_DRAIN_AFTER_SESSION_COUNT=2 - SE_ENABLE_TLS=true + - SE_JAVA_OPTS=-Dwebdriver.httpclient.readTimeout=${REQUEST_TIMEOUT} restart: always + edge_video: + image: selenium/video:${VIDEO_TAG} + user: ${UID} + volumes: + - ./videos:/videos + environment: + - DISPLAY_CONTAINER_NAME=edge + - SE_VIDEO_FILE_NAME=auto + - SE_SERVER_PROTOCOL=https + stop_grace_period: 30s + selenium-hub: image: selenium/hub:${TAG} user: ${UID} @@ -100,9 +133,10 @@ services: - SE_SUPERVISORD_LOG_LEVEL=error - SE_ENABLE_TLS=true - SE_SERVER_PROTOCOL=https + - SE_JAVA_OPTS=-Dwebdriver.httpclient.readTimeout=${REQUEST_TIMEOUT} healthcheck: test: "/opt/bin/check-grid.sh --host 0.0.0.0 --port 4444" - interval: 15s + interval: 20s timeout: 30s retries: 5 diff --git a/tests/docker-compose-v3-test-standalone-docker.yaml b/tests/docker-compose-v3-test-standalone-docker.yaml index 56f321a4e9..d0084b7068 100644 --- a/tests/docker-compose-v3-test-standalone-docker.yaml +++ b/tests/docker-compose-v3-test-standalone-docker.yaml @@ -39,34 +39,13 @@ services: ftp_server: image: delfer/alpine-ftp-server:latest container_name: ftp_server + command: ["/bin/sh", "-c", "/sbin/tini -- /bin/start_vsftpd.sh && tail -f /dev/null"] environment: - USERS=seluser|selenium.dev - MAX_PORT=21010 - TINI_SUBREAPER=true volumes: - ./videos/upload:/ftp/seluser - entrypoint: > - /bin/sh -c ' - max_attempts=5; - attempt_num=1; - while [ $attempt_num -le $max_attempts ]; - do - output=$(eval "/sbin/tini -- /bin/start_vsftpd.sh"); - status=$?; - if [ $status -eq 0 ]; then - break; - else - echo "Attempt $attempt_num failed! Trying again in 3 seconds..."; - attempt_num=$((attempt_num+1)); - sleep 3; - fi - done; - if [ $attempt_num -gt $max_attempts ]; then - echo "All attempts to start vsftpd failed."; - exit 1; - fi - ' - restart: unless-stopped stop_grace_period: 30s tests: diff --git a/tests/docker-compose-v3-test-standalone.yml b/tests/docker-compose-v3-test-standalone.yml index 5db69080fa..deb3c105d5 100644 --- a/tests/docker-compose-v3-test-standalone.yml +++ b/tests/docker-compose-v3-test-standalone.yml @@ -55,34 +55,13 @@ services: ftp_server: image: delfer/alpine-ftp-server:latest container_name: ftp_server + command: ["/bin/sh", "-c", "/sbin/tini -- /bin/start_vsftpd.sh && tail -f /dev/null"] environment: - USERS=seluser|selenium.dev - MAX_PORT=21010 - TINI_SUBREAPER=true volumes: - ./videos/upload:/ftp/seluser - entrypoint: > - /bin/sh -c ' - max_attempts=5; - attempt_num=1; - while [ $attempt_num -le $max_attempts ]; - do - output=$(eval "/sbin/tini -- /bin/start_vsftpd.sh"); - status=$?; - if [ $status -eq 0 ]; then - break; - else - echo "Attempt $attempt_num failed! Trying again in 3 seconds..."; - attempt_num=$((attempt_num+1)); - sleep 3; - fi - done; - if [ $attempt_num -gt $max_attempts ]; then - echo "All attempts to start vsftpd failed."; - exit 1; - fi - ' - restart: unless-stopped stop_grace_period: 30s tests: diff --git a/tests/docker-compose-v3-test-video.yml b/tests/docker-compose-v3-test-video.yml index 109cec84f4..ef89673e95 100644 --- a/tests/docker-compose-v3-test-video.yml +++ b/tests/docker-compose-v3-test-video.yml @@ -28,7 +28,7 @@ services: - DISPLAY_CONTAINER_NAME=browser - SE_VIDEO_FILE_NAME=${VIDEO_FILE_NAME} - SE_VIDEO_FILE_NAME_SUFFIX=${VIDEO_FILE_NAME_SUFFIX} - - SE_SUPERVISORD_LOG_LEVEL=error + - SE_SUPERVISORD_LOG_LEVEL=info - SE_VIDEO_UPLOAD_ENABLED=true - SE_VIDEO_INTERNAL_UPLOAD=true - SE_UPLOAD_DESTINATION_PREFIX=myftp://ftp/seluser @@ -43,34 +43,13 @@ services: ftp_server: image: delfer/alpine-ftp-server:latest container_name: ftp_server + command: ["/bin/sh", "-c", "/sbin/tini -- /bin/start_vsftpd.sh && tail -f /dev/null"] environment: - USERS=seluser|selenium.dev - MAX_PORT=21010 - TINI_SUBREAPER=true volumes: - ./videos/upload:/ftp/seluser - entrypoint: > - /bin/sh -c ' - max_attempts=5; - attempt_num=1; - while [ $attempt_num -le $max_attempts ]; - do - output=$(eval "/sbin/tini -- /bin/start_vsftpd.sh"); - status=$?; - if [ $status -eq 0 ]; then - break; - else - echo "Attempt $attempt_num failed! Trying again in 3 seconds..."; - attempt_num=$((attempt_num+1)); - sleep 3; - fi - done; - if [ $attempt_num -gt $max_attempts ]; then - echo "All attempts to start vsftpd failed."; - exit 1; - fi - ' - restart: unless-stopped stop_grace_period: 30s selenium-hub: