Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 118 additions & 0 deletions jenkins/groovy/release-selenium-grid-node/Jenkinsfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
def utils
def imageTag

pipeline {
agent any
options {
ansiColor('xterm')
timestamps()
buildDiscarder(logRotator(numToKeepStr: '10', artifactNumToKeepStr: '10'))
}
stages {
stage('Prepare/Checkout') {
steps {
script {
def rootDir = pwd()
utils = load "${rootDir}/jenkins/groovy/Utils.groovy"
utils.SetupRepos(env.VIDEO_INFRA_BRANCH)
utils.SetupOCI()
}
}
}
stage('Resolve Tag') {
steps {
script {
if (env.TAG?.trim()) {
imageTag = env.TAG.trim()
} else {
dir('infra-provisioning') {
imageTag = sh(
returnStdout: true,
script: 'git rev-parse --short HEAD'
).trim()
}
}
echo "Using image tag: ${imageTag}"
}
}
}
stage('Build Docker Image') {
when {
expression { env.SKIP_BUILD != 'true' }
}
steps {
script {
build job: 'build-docker-image-selenium-grid-node', parameters: [
[$class: 'StringParameterValue', name: 'VIDEO_INFRA_BRANCH', value: env.VIDEO_INFRA_BRANCH],
[$class: 'StringParameterValue', name: 'TAG', value: imageTag]
]
}
}
}
stage('Deploy to Test Grid') {
steps {
script {
echo "Deploying to test grid: ${env.TEST_GRID_NAME} with image tag: ${imageTag}"
dir('infra-provisioning') {
withCredentials([
string(credentialsId: 'jenkins-aws-secret', variable: 'AWS_SECRET_ACCESS_KEY'),
string(credentialsId: 'jenkins-aws-id', variable: 'AWS_ACCESS_KEY_ID')
]) {
sh """#!/bin/bash
export SELENIUM_GRID_IMAGE_VERSION="${imageTag}"
GRID=${env.TEST_GRID_NAME} scripts/deploy-nomad-selenium-grid-hub.sh
GRID=${env.TEST_GRID_NAME} scripts/deploy-nomad-selenium-grid-node.sh
RET=\$?
if [[ \$RET -eq 2 ]]; then
echo "Complete but failed to place all allocations (expected)"
exit 0
else
exit \$RET
fi
"""
}
}
}
}
}
stage('Smoke Test') {
steps {
script {
echo "Running browser smoke test against test grid: ${env.TEST_GRID_NAME}"
dir('infra-provisioning') {
sh """#!/bin/bash
export GRID="${env.TEST_GRID_NAME}"
scripts/test-selenium-grid-browsers.sh
"""
}
}
}
}
stage('Deploy to Production Grid') {
steps {
script {
echo "Deploying to production grid: ${env.PROD_GRID_NAME} with image tag: ${imageTag}"
dir('infra-provisioning') {
withCredentials([
string(credentialsId: 'jenkins-aws-secret', variable: 'AWS_SECRET_ACCESS_KEY'),
string(credentialsId: 'jenkins-aws-id', variable: 'AWS_ACCESS_KEY_ID')
]) {
sh """#!/bin/bash
export SELENIUM_GRID_IMAGE_VERSION="${imageTag}"
GRID=${env.PROD_GRID_NAME} scripts/deploy-nomad-selenium-grid-hub.sh
GRID=${env.PROD_GRID_NAME} scripts/deploy-nomad-selenium-grid-node.sh
RET=\$?
if [[ \$RET -eq 2 ]]; then
echo "Complete but failed to place all allocations (expected)"
exit 0
else
exit \$RET
fi
"""
}
}
}
}
}
}
}
68 changes: 68 additions & 0 deletions jenkins/jobs/release-selenium-grid-node.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
- job:
name: release-selenium-grid-node
display-name: release selenium grid node
concurrent: true
parameters:
- string:
name: VIDEO_INFRA_BRANCH
default: main
description: "Controls checkout branch for infra repos, defaults to 'main'."
trim: true
- string:
name: TAG
description: "Docker image tag; defaults to git short hash if not set."
trim: true
- string:
name: ENVIRONMENT
default: torture-test
description: "Environment to deploy in, defaults to 'torture-test'."
trim: true
- string:
name: ORACLE_REGION
default: us-phoenix-1
description: "Oracle Region to deploy in"
trim: true
- string:
name: TEST_GRID_NAME
default: aaron
description: "Grid name for initial test deployment"
trim: true
- string:
name: PROD_GRID_NAME
default: validate
description: "Grid name for production deployment after smoke test passes"
trim: true
- bool:
name: SKIP_BUILD
description: "Check to skip the Docker image build (use when deploying an existing tag)"
default: false
- string:
name: SELENIUM_GRID_HUB_VERSION
description: "Selenium Grid Hub version (e.g., '4.41'). If empty, latest is resolved from Docker Hub."
trim: true
- string:
name: INFRA_CONFIGURATION_REPO
default: git@github.com:jitsi/infra-configuration.git
description: "Repo for configuration code (ansible etc), defaults to 'git@github.com:jitsi/infra-configuration.git'."
trim: true
- string:
name: INFRA_CUSTOMIZATIONS_REPO
default: git@github.com:jitsi/infra-customizations.git
description: "Repo with customized configurations, defaults to 'git@github.com:jitsi/infra-customizations.git'."
trim: true

project-type: pipeline
sandbox: true
pipeline-scm:
scm:
- git:
url: git@github.com:jitsi/infra-provisioning.git
credentials-id: "video-infra"
branches:
- "origin/${{VIDEO_INFRA_BRANCH}}"
browser: githubweb
browser-url: https://github.com/jitsi/infra-provisioning
submodule:
recursive: true
script-path: jenkins/groovy/release-selenium-grid-node/Jenkinsfile
lightweight-checkout: true
109 changes: 109 additions & 0 deletions scripts/test-selenium-grid-browsers.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
#!/bin/bash
#
# Smoke test for a selenium grid: creates Chrome and Firefox sessions
# via the W3C WebDriver API, then cleans them up.
#
# Required env vars (or pass GRID_URL directly):
# GRID_URL - full WebDriver hub URL (e.g. https://...:4444/wd/hub)
# OR all of: ENVIRONMENT, ORACLE_REGION, GRID
#
# Optional:
# RETRY_ATTEMPTS - number of retries waiting for grid readiness (default: 10)
# RETRY_DELAY - seconds between retries (default: 30)

set -euo pipefail

LOCAL_PATH=$(dirname "${BASH_SOURCE[0]}")

# Source environment configs if needed to resolve DNS zone
[ -e "$LOCAL_PATH/../clouds/all.sh" ] && . "$LOCAL_PATH/../clouds/all.sh"

# Build GRID_URL from components if not provided directly
if [ -z "${GRID_URL:-}" ]; then
if [ -z "${ENVIRONMENT:-}" ] || [ -z "${ORACLE_REGION:-}" ] || [ -z "${GRID:-}" ]; then
echo "ERROR: Either GRID_URL or (ENVIRONMENT, ORACLE_REGION, GRID) must be set"
exit 2
fi
DNS_ZONE="${TOP_LEVEL_DNS_ZONE_NAME:-jitsi.net}"
GRID_URL="https://${ENVIRONMENT}-${ORACLE_REGION}-${GRID}-grid.${DNS_ZONE}/wd/hub"
fi

echo "## Selenium Grid smoke test against: $GRID_URL"

RETRY_ATTEMPTS="${RETRY_ATTEMPTS:-10}"
RETRY_DELAY="${RETRY_DELAY:-30}"

# Wait for grid to become ready
echo "## Waiting for grid to become ready..."
for i in $(seq 1 "$RETRY_ATTEMPTS"); do
STATUS=$(curl -sf --connect-timeout 10 --max-time 30 "${GRID_URL}/status" 2>/dev/null || true)
if [ -n "$STATUS" ]; then
READY=$(echo "$STATUS" | jq -r '.value.ready // false' 2>/dev/null || echo "false")
if [ "$READY" = "true" ]; then
echo "## Grid is ready (attempt $i/$RETRY_ATTEMPTS)"
break
fi
fi
if [ "$i" -eq "$RETRY_ATTEMPTS" ]; then
echo "ERROR: Grid not ready after $RETRY_ATTEMPTS attempts"
exit 1
fi
echo "## Grid not ready, retrying in ${RETRY_DELAY}s (attempt $i/$RETRY_ATTEMPTS)..."
sleep "$RETRY_DELAY"
done

SUCCESS=0

# Test a browser session: create, verify, delete
# Usage: test_browser <browser_name> <capabilities_json>
test_browser() {
local BROWSER="$1"
local CAPS="$2"

echo "## Testing $BROWSER session..."

RESPONSE=$(curl -sf --connect-timeout 30 --max-time 120 \
-X POST "${GRID_URL}/session" \
-H "Content-Type: application/json" \
-d "$CAPS" 2>&1) || {
echo "ERROR: Failed to create $BROWSER session"
echo "$RESPONSE"
return 1
}

SESSION_ID=$(echo "$RESPONSE" | jq -r '.value.sessionId // empty' 2>/dev/null)
if [ -z "$SESSION_ID" ]; then
echo "ERROR: No session ID returned for $BROWSER"
echo "$RESPONSE"
return 1
fi

echo "## $BROWSER session created: $SESSION_ID"

# Clean up session
curl -sf --connect-timeout 10 --max-time 30 \
-X DELETE "${GRID_URL}/session/${SESSION_ID}" > /dev/null 2>&1 || true

echo "## $BROWSER session deleted successfully"
return 0
}

# Test Chrome
CHROME_CAPS='{"capabilities":{"alwaysMatch":{"browserName":"chrome","goog:chromeOptions":{"args":["--headless","--no-sandbox","--disable-dev-shm-usage"]}}}}'
if ! test_browser "Chrome" "$CHROME_CAPS"; then
SUCCESS=1
fi

# Test Firefox
FIREFOX_CAPS='{"capabilities":{"alwaysMatch":{"browserName":"firefox","moz:firefoxOptions":{"args":["-headless"]}}}}'
if ! test_browser "Firefox" "$FIREFOX_CAPS"; then
SUCCESS=1
fi

if [ $SUCCESS -eq 0 ]; then
echo "## Smoke test PASSED: Chrome and Firefox sessions verified"
else
echo "## Smoke test FAILED"
fi

exit $SUCCESS