Skip to content

Commit

Permalink
feat(chart): videoRecorder getting scripts from external files (#2095)
Browse files Browse the repository at this point in the history
Signed-off-by: Viet Nguyen Duc <nguyenducviet4496@gmail.com>
  • Loading branch information
VietND96 committed Jan 19, 2024
1 parent b62a56f commit e521d99
Show file tree
Hide file tree
Showing 19 changed files with 320 additions and 135 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/build-test.yml
Expand Up @@ -2,7 +2,11 @@ name: Build & test

on:
push:
paths-ignore:
- '**.md'
pull_request:
paths-ignore:
- '**.md'

permissions:
contents: read
Expand Down
8 changes: 6 additions & 2 deletions .github/workflows/helm-chart-test.yml
Expand Up @@ -2,7 +2,11 @@ name: Lint and Test Helm Charts

on:
push:
paths-ignore:
- '**.md'
pull_request:
paths-ignore:
- '**.md'
workflow_dispatch:

permissions:
Expand All @@ -15,7 +19,7 @@ jobs:
strategy:
fail-fast: false
matrix:
test-strategy: [chart_test, chart_test_parallel_autoscaling, chart_test_https_tls]
test-strategy: [chart_test, chart_test_parallel_autoscaling, chart_test_https, chart_test_parallel_autoscaling_https]
steps:
- uses: actions/checkout@v4
- name: Output Docker info
Expand Down Expand Up @@ -49,7 +53,7 @@ jobs:
- name: Setup Kubernetes environment
run: make chart_setup_env
- name: Build Docker images
run: NAME=${IMAGE_REGISTRY} VERSION=${BRANCH} BUILD_DATE=${BUILD_DATE} make build
run: NAME=${IMAGE_REGISTRY} VERSION=${BRANCH} BUILD_DATE=${BUILD_DATE} make build_nightly
- name: Build and lint charts
run: |
BUILD_DATE=${BUILD_DATE} make chart_build
Expand Down
10 changes: 8 additions & 2 deletions .github/workflows/nightly.yaml
Expand Up @@ -87,7 +87,7 @@ jobs:
echo "CHART_PACKAGE_PATH=$(cat /tmp/selenium_chart_version)" >> $GITHUB_ENV
echo "CHART_FILE_NAME=$(basename $(cat /tmp/selenium_chart_version))" >> $GITHUB_ENV
- name: Delete previous nightly tag if any
uses: cb80/delrel@latest
uses: cb80/delrel@main
with:
tag: ${{ env.BASE_RELEASE }}
token: ${{ secrets.GITHUB_TOKEN }}
Expand All @@ -104,4 +104,10 @@ jobs:
generate_release_notes: true
draft: false
prerelease: true
append_body: true
append_body: false
- name: Update tag nightly
uses: richardsimko/update-tag@v1.0.11
with:
tag_name: ${{ env.BASE_RELEASE }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
4 changes: 4 additions & 0 deletions .github/workflows/test-video.yml
Expand Up @@ -2,7 +2,11 @@ name: Test video files

on:
push:
paths-ignore:
- '**.md'
pull_request:
paths-ignore:
- '**.md'

permissions:
contents: read
Expand Down
10 changes: 6 additions & 4 deletions Makefile
Expand Up @@ -426,6 +426,9 @@ chart_build_nightly:
chart_build:
VERSION=$(TAG_VERSION) ./tests/charts/make/chart_build.sh

chart_test_https:
SELENIUM_GRID_PROTOCOL=https SELENIUM_GRID_PORT=443 make chart_test

chart_test: chart_test_template \
chart_test_chrome \
chart_test_firefox \
Expand All @@ -443,13 +446,12 @@ chart_test_firefox:
chart_test_edge:
VERSION=$(TAG_VERSION) NAMESPACE=$(NAMESPACE) ./tests/charts/make/chart_test.sh NodeEdge

chart_test_parallel_autoscaling_https:
SELENIUM_GRID_PROTOCOL=https SELENIUM_GRID_PORT=443 make chart_test_parallel_autoscaling

chart_test_parallel_autoscaling:
VERSION=$(TAG_VERSION) NAMESPACE=$(NAMESPACE) ./tests/charts/make/chart_test.sh JobAutoscaling

chart_test_https_tls:
VERSION=$(TAG_VERSION) NAMESPACE=$(NAMESPACE) SELENIUM_GRID_PROTOCOL=https SELENIUM_GRID_PORT=443 \
./tests/charts/make/chart_test.sh JobAutoscaling

.PHONY: \
all \
base \
Expand Down
7 changes: 7 additions & 0 deletions charts/selenium-grid/README.md
Expand Up @@ -524,6 +524,8 @@ This table contains the configuration parameters of the chart and their default
| `chromeNode.hpa.url` | `{{ include "seleniumGrid.graphqlURL" . }}` | Graphql Url of the hub or the router |
| `chromeNode.hpa.browserName` | `chrome` | BrowserName from the capability |
| `chromeNode.hpa.browserVersion` | `` | BrowserVersion from the capability |
| `chromeNode.sidecars` | `[]` | Add a sidecars proxy in the same pod of the browser node |
| `chromeNode.initContainers` | `[]` | Add initContainers in the same pod of the browser node |
| `chromeNode.scaledOptions` | See `values.yaml` | Override the global `autoscaling.scaledOptions` with specific scaled options for chrome nodes |
| `chromeNode.scaledJobOptions` | See `values.yaml` | Override the global `autoscaling.scaledJobOptions` with specific scaled options for chrome nodes |
| `chromeNode.scaledObjectOptions` | See `values.yaml` | Override the global `autoscaling.scaledObjectOptions` with specific scaled options for chrome nodes |
Expand Down Expand Up @@ -565,6 +567,8 @@ This table contains the configuration parameters of the chart and their default
| `firefoxNode.hpa.url` | `{{ include "seleniumGrid.graphqlURL" . }}` | Graphql Url of the hub or the router |
| `firefoxNode.hpa.browserName` | `firefox` | BrowserName from the capability |
| `firefoxNode.hpa.browserVersion` | `` | BrowserVersion from the capability |
| `firefoxNode.sidecars` | `[]` | Add a sidecars proxy in the same pod of the browser node |
| `firefoxNode.initContainers` | `[]` | Add initContainers in the same pod of the browser node |
| `firefoxNode.scaledOptions` | See `values.yaml` | Override the global `autoscaling.scaledOptions` with specific scaled options for firefox nodes |
| `firefoxNode.scaledJobOptions` | See `values.yaml` | Override the global `autoscaling.scaledJobOptions` with specific scaled options for firefox nodes |
| `firefoxNode.scaledObjectOptions` | See `values.yaml` | Override the global `autoscaling.scaledObjectOptions` with specific scaled options for firefox nodes |
Expand Down Expand Up @@ -606,6 +610,8 @@ This table contains the configuration parameters of the chart and their default
| `edgeNode.hpa.url` | `{{ include "seleniumGrid.graphqlURL" . }}` | Graphql Url of the hub or the router |
| `edgeNode.hpa.browserName` | `edge` | BrowserName from the capability |
| `edgeNode.hpa.browserVersion` | `` | BrowserVersion from the capability |
| `edgeNode.sidecars` | `[]` | Add a sidecars proxy in the same pod of the browser node |
| `edgeNode.initContainers` | `[]` | Add initContainers in the same pod of the browser node |
| `edgeNode.scaledOptions` | See `values.yaml` | Override the global `autoscaling.scaledOptions` with specific scaled options for edge nodes |
| `edgeNode.scaledJobOptions` | See `values.yaml` | Override the global `autoscaling.scaledJobOptions` with specific scaled options for edge nodes |
| `edgeNode.scaledObjectOptions` | See `values.yaml` | Override the global `autoscaling.scaledObjectOptions` with specific scaled options for edge nodes |
Expand All @@ -623,6 +629,7 @@ This table contains the configuration parameters of the chart and their default
| `videoRecorder.terminationGracePeriodSeconds` | `30` | Time to graceful terminate container (default: 30s) |
| `videoRecorder.startupProbe` | `{}` | Probe to check pod is started successfully |
| `videoRecorder.livenessProbe` | `{}` | Liveness probe settings |
| `videoRecorder.lifecycle` | `{}` | Define lifecycle events for video recorder |
| `videoRecorder.volume.name.folder` | `video` | Name is used to set for the volume to persist and share output video folder in container |
| `videoRecorder.volume.name.scripts` | `video-scripts` | Name is used to set for the volume to persist and share video recorder scripts in container |
| `videoRecorder.extraVolumeMounts` | `[]` | Extra mounts of declared ExtraVolumes into pod |
Expand Down
7 changes: 7 additions & 0 deletions charts/selenium-grid/configs/node/nodePreStop.sh
@@ -0,0 +1,7 @@
#!/bin/bash
if curl -sfk ${SE_SERVER_PROTOCOL}://127.0.0.1:${SE_NODE_PORT}/status; then
curl -k -X POST ${SE_SERVER_PROTOCOL}://127.0.0.1:${SE_NODE_PORT}/se/grid/node/drain --header 'X-REGISTRATION-SECRET;'
while curl -sfk ${SE_SERVER_PROTOCOL}://127.0.0.1:${SE_NODE_PORT}/status; do sleep 1; done
else
echo "Node is already drained. Shutting down gracefully!"
fi
44 changes: 44 additions & 0 deletions charts/selenium-grid/configs/uploader/s3/entry_point.sh
@@ -0,0 +1,44 @@
#!/usr/bin/env bash

SE_VIDEO_FOLDER=${SE_VIDEO_FOLDER:-"/videos"}

if [[ -z "${AWS_REGION}" ]] || [[ -z "${AWS_ACCESS_KEY_ID}" ]] || [[ -z "${AWS_SECRET_ACCESS_KEY}" ]];
then
echo "AWS credentials needed to provide for configuring AWS CLI"
fi

aws configure set region ${AWS_REGION} --profile s3-profile
aws configure set aws_access_key_id ${AWS_ACCESS_KEY_ID} --profile s3-profile
aws configure set aws_secret_access_key ${AWS_SECRET_ACCESS_KEY} --profile s3-profile
aws configure --profile s3-profile

function consume_force_exit() {
rm -f ${SE_VIDEO_FOLDER}/force_exit
echo "Force exit signal consumed"
}
trap consume_force_exit EXIT

while [ ! -p ${SE_VIDEO_FOLDER}/uploadpipe ];
do
echo "Waiting for ${SE_VIDEO_FOLDER}/uploadpipe to be created"
sleep 1
done

echo "Waiting for video files put into pipe for proceeding to upload"

while read FILE DESTINATION < ${SE_VIDEO_FOLDER}/uploadpipe
do
if [ "${FILE}" = "exit" ];
then
exit
else [ "$FILE" != "" ] && [ "$DESTINATION" != "" ];
echo "Uploading ${FILE} to ${DESTINATION}"
aws s3 cp "${FILE}" "${DESTINATION}"
fi
if [ -f ${SE_VIDEO_FOLDER}/force_exit ] && [ ! -s ${SE_VIDEO_FOLDER}/uploadpipe ];
then
exit
fi
done

consume_force_exit
136 changes: 136 additions & 0 deletions charts/selenium-grid/configs/video/video.sh
@@ -0,0 +1,136 @@
#!/usr/bin/env bash

function create_pipe() {
if [[ "$UPLOAD_DESTINATION_PREFIX" != "false" ]];
then
echo "Create pipe if not exists for video upload stream"
if [ ! -p ${SE_VIDEO_FOLDER}/uploadpipe ];
then
mkfifo ${SE_VIDEO_FOLDER}/uploadpipe
fi
fi
}
create_pipe

function wait_util_force_exit_consume() {
if [[ "$UPLOAD_DESTINATION_PREFIX" != "false" ]];
then
while [[ -f ${SE_VIDEO_FOLDER}/force_exit ]]
do
echo "Waiting for force exit file to be consumed by uploader"
sleep 1
done
echo "Ready to shutdown the recorder"
fi
}

function add_exit_signal() {
if [[ "$UPLOAD_DESTINATION_PREFIX" != "false" ]];
then
echo "exit" > ${SE_VIDEO_FOLDER}/uploadpipe &
echo "exit" > ${SE_VIDEO_FOLDER}/force_exit
fi
}

function exit_on_max_session_reach() {
if [ $max_recorded_count -gt 0 ] && [ $recorded_count -ge $max_recorded_count ];
then
echo "Node will be drained since max sessions reached count number ($max_recorded_count)"
exit
fi
}

function finish {
add_exit_signal
wait_util_force_exit_consume
kill -INT `cat /var/run/supervisor/supervisord.pid`
}
trap finish EXIT

FRAME_RATE=${FRAME_RATE:-$SE_FRAME_RATE}
CODEC=${CODEC:-$SE_CODEC}
PRESET=${PRESET:-$SE_PRESET}
DISPLAY_CONTAINER_NAME=${DISPLAY_CONTAINER_NAME:-"localhost"}
export DISPLAY=${DISPLAY_CONTAINER_NAME}:${DISPLAY_NUM}.0

max_attempts=600
attempts=0
if [[ "$UPLOAD_DESTINATION_PREFIX" = "" ]]
then
echo Upload destination not known since UPLOAD_DESTINATION_PREFIX is not set. Exiting video recorder.
exit
fi
echo Checking if the display is open
until xset b off || [[ $attempts = $max_attempts ]]
do
echo Waiting before next display check
sleep 0.5
attempts=$((attempts+1))
done
if [[ $attempts = $max_attempts ]]
then
echo Can not open display, exiting.
exit
fi
VIDEO_SIZE=$(xdpyinfo | grep 'dimensions:' | awk '{print $2}')

recording_started="false"
video_file_name=""
video_file=""
prev_session_id=""
attempts=0
max_recorded_count=${SE_DRAIN_AFTER_SESSION_COUNT:-0}
recorded_count=0
echo Checking if node API responds
until curl -sk --request GET ${SE_SERVER_PROTOCOL}://${DISPLAY_CONTAINER_NAME}:${SE_NODE_PORT}/status || [[ $attempts = $max_attempts ]]
do
echo Waiting before next API check
sleep 0.5
attempts=$((attempts+1))
done
if [[ $attempts = $max_attempts ]]
then
echo Can not reach node API, exiting.
exit
fi
while curl -sk --request GET ${SE_SERVER_PROTOCOL}://${DISPLAY_CONTAINER_NAME}:${SE_NODE_PORT}/status > /tmp/status.json
do
session_id=$(jq -r '.[]?.node?.slots | .[0]?.session?.sessionId' /tmp/status.json)
echo $session_id
if [[ "$session_id" != "null" && "$session_id" != "" && "$recording_started" = "false" ]]
then
video_file_name="$session_id.mp4"
video_file="${SE_VIDEO_FOLDER}/$video_file_name"
echo "Starting to record video"
ffmpeg -nostdin -y -f x11grab -video_size ${VIDEO_SIZE} -r ${FRAME_RATE} -i ${DISPLAY} -codec:v ${CODEC} ${PRESET} -pix_fmt yuv420p $video_file &
recording_started="true"
echo "Video recording started"
elif [[ "$session_id" != "$prev_session_id" && "$recording_started" = "true" ]]
then
echo "Stopping to record video"
pkill -INT ffmpeg
recorded_count=$((recorded_count+1))
recording_started="false"
if [[ "$UPLOAD_DESTINATION_PREFIX" != "false" ]]
then
upload_destination=${UPLOAD_DESTINATION_PREFIX}/${video_file_name}
echo "Uploading video to $upload_destination"
echo $video_file $upload_destination >> ${SE_VIDEO_FOLDER}/uploadpipe &
fi
if [ $max_recorded_count -gt 0 ] && [ $recorded_count -ge $max_recorded_count ];
then
echo "Node will be drained since max sessions reached count number ($max_recorded_count)"
exit
fi

elif [[ $recording_started = "true" ]]
then
echo "Video recording in progress"
sleep 1
else
echo "No session in progress"
sleep 1
fi
prev_session_id=$session_id
done
echo "Node API is not responding, exiting."

0 comments on commit e521d99

Please sign in to comment.