test: add temporary Guacamole fixture access helper
This commit is contained in:
@@ -0,0 +1 @@
|
||||
.runtime/
|
||||
@@ -0,0 +1,118 @@
|
||||
# Interactive Windows VM access
|
||||
|
||||
This directory is an explicitly temporary, manual-recovery path to the Helium
|
||||
Windows fixture desktop. It is for the small class of actions that require an
|
||||
interactive UAC consent dialog. Normal setup, testing, collection, and reset
|
||||
remain `scripts/windows/test-host` plus VirtualBox Guest Control.
|
||||
|
||||
The helper builds this private path:
|
||||
|
||||
```text
|
||||
browser -- HTTPS/self-signed --> nginx + Guacamole containers
|
||||
|
|
||||
private Docker gateway
|
||||
|
|
||||
controller SSH tunnel --> Helium 127.0.0.1:3389 --> VirtualBox VRDE --> VM console
|
||||
```
|
||||
|
||||
Only the HTTPS listener can be made public, and that requires an explicit
|
||||
`--bind 0.0.0.0`. The VirtualBox VRDE endpoint stays on Helium loopback and the
|
||||
SSH tunnel binds only to the Docker network gateway; neither is publicly
|
||||
exposed. Guacamole requires the fixture login before it forwards the entered
|
||||
password to the VM. Clipboard, drives, printing, audio, microphone input, GFX,
|
||||
and display-resize extensions are disabled because the fixture's VirtualBox
|
||||
RDP4 server does not handle them reliably.
|
||||
|
||||
## Lifecycle
|
||||
|
||||
Run commands from the repository root. First prepare the disposable VM using a
|
||||
dedicated run ID. This restores the snapshot, starts the VM headlessly, and
|
||||
holds the exclusive fixture lease while the manual action is in progress:
|
||||
|
||||
```sh
|
||||
scripts/windows/test-host prepare --run-id interactive-rdp
|
||||
```
|
||||
|
||||
For browser access from another machine, deliberately expose the temporary
|
||||
HTTPS listener and name the host or IP users will enter in the browser:
|
||||
|
||||
```sh
|
||||
test/rdp-access/rdp-access up \
|
||||
--bind 0.0.0.0 \
|
||||
--public-host x1.example.net
|
||||
```
|
||||
|
||||
The command prompts without echo for the fixture password. It stores only its
|
||||
MD5 verifier in `test/rdp-access/.runtime/config/user-mapping.xml`, mode 600;
|
||||
the plaintext password is not placed in a command line, environment variable,
|
||||
log, or repository file. Browse to the printed `https://.../guacamole/` URL,
|
||||
accept the short-lived self-signed certificate warning, and sign in as
|
||||
`rvboxtest` with the fixture password.
|
||||
|
||||
For localhost-only use, omit `--bind` and `--public-host`. The default listener
|
||||
is `127.0.0.1:5002`; use a local SSH forward or a browser on the controller.
|
||||
Choose alternate ports with `--http-port` and `--tunnel-port` if either is in
|
||||
use. The VM must already be running. `up` checks the documented VM/snapshot
|
||||
identity but intentionally does not restore, start, stop, or reset the VM.
|
||||
|
||||
All fixture-specific values have embedded, working defaults: the
|
||||
`helium-remote` SSH alias, Helium's loopback VRDE endpoint (`127.0.0.1:3389`),
|
||||
`rvboxtest`, the browser listener (`127.0.0.1:5002`), and the private tunnel
|
||||
port (`54001`). They can be overridden without editing tracked files through
|
||||
`RVBOX_TEST_VBOX_HOST`, `RDP_ACCESS_VRDE_HOST`, `RDP_ACCESS_VRDE_PORT`,
|
||||
`RDP_ACCESS_WEB_USER`, `RDP_ACCESS_RDP_USER`, `RDP_ACCESS_BIND`,
|
||||
`RDP_ACCESS_HTTP_PORT`, `RDP_ACCESS_TUNNEL_PORT`, and
|
||||
`RDP_ACCESS_PUBLIC_HOST`. The helper deliberately limits the VRDE host to
|
||||
Helium loopback (`127.0.0.1` or `localhost`) so an override cannot accidentally
|
||||
turn the diagnostic server into a remote target.
|
||||
|
||||
After the interactive action, close the browser connection and remove the
|
||||
temporary access path before releasing the fixture lease:
|
||||
|
||||
```sh
|
||||
test/rdp-access/rdp-access down
|
||||
scripts/windows/test-host reset --run-id interactive-rdp
|
||||
```
|
||||
|
||||
`down` stops containers and the SSH master/tunnel but retains the one-day
|
||||
certificate and password verifier for a quick restart. To remove all generated
|
||||
state, including the certificate and verifier:
|
||||
|
||||
```sh
|
||||
test/rdp-access/rdp-access clean
|
||||
```
|
||||
|
||||
To also reclaim the exact Guacamole and nginx images when they have no
|
||||
container dependency, use:
|
||||
|
||||
```sh
|
||||
test/rdp-access/rdp-access clean --images
|
||||
```
|
||||
|
||||
`clean --images` deliberately leaves `alpine:3.20` alone because it may be
|
||||
shared by unrelated containers. Docker will refuse removal if any other
|
||||
container still depends on an image.
|
||||
|
||||
## Operational checks and recovery
|
||||
|
||||
```sh
|
||||
test/rdp-access/rdp-access status
|
||||
test/rdp-access/rdp-access logs --tail=100
|
||||
test/rdp-access/rdp-access url
|
||||
```
|
||||
|
||||
If the browser reaches Guacamole but stays on “Waiting for response”, verify
|
||||
that the VM is running and the private tunnel is active with `status`. This
|
||||
helper already uses `security=rdp` and disables Guacamole's GFX extension,
|
||||
which are required by the fixture's legacy VRDE server. Do not switch the
|
||||
helper to native Windows RDP: `TermService` is intentionally disabled in the
|
||||
baseline. If VRDE remains unusable, stop this helper and use Guest Control for
|
||||
the deterministic portion of the work; record the blocked interactive step in
|
||||
the native test report.
|
||||
|
||||
The helper requires Docker/Docker Compose, SSH access through the existing
|
||||
`helium-remote` alias, and the fixture password file documented in
|
||||
[`docs/testing-vm.md`](../../docs/testing-vm.md). It does not install host
|
||||
packages, write credentials into Git, or alter VM settings. The tracked files
|
||||
are Docker-only configuration and the controller script; all generated content
|
||||
is ignored beneath `.runtime/`.
|
||||
@@ -0,0 +1,46 @@
|
||||
services:
|
||||
guacd:
|
||||
image: guacamole/guacd:1.6.0
|
||||
|
||||
guacamole:
|
||||
image: guacamole/guacamole:1.6.0
|
||||
depends_on:
|
||||
- guacd
|
||||
environment:
|
||||
GUACD_HOSTNAME: guacd
|
||||
GUACD_PORT: "4822"
|
||||
volumes:
|
||||
- ${RDP_ACCESS_RUNTIME_DIR}/config:/etc/guacamole:ro
|
||||
|
||||
certgen:
|
||||
image: alpine:3.20
|
||||
environment:
|
||||
RDP_ACCESS_CERT_NAME: ${RDP_ACCESS_CERT_NAME}
|
||||
RDP_ACCESS_CERT_SAN: ${RDP_ACCESS_CERT_SAN}
|
||||
RDP_ACCESS_HOST_UID: ${RDP_ACCESS_HOST_UID}
|
||||
RDP_ACCESS_HOST_GID: ${RDP_ACCESS_HOST_GID}
|
||||
volumes:
|
||||
- ${RDP_ACCESS_RUNTIME_DIR}/tls:/tls
|
||||
entrypoint: /bin/sh
|
||||
command:
|
||||
- -ec
|
||||
- >-
|
||||
apk add --no-cache openssl >/dev/null &&
|
||||
(test -s /tls/cert.pem && test -s /tls/key.pem &&
|
||||
openssl x509 -checkend 3600 -noout -in /tls/cert.pem) ||
|
||||
(umask 077 &&
|
||||
openssl req -x509 -newkey rsa:3072 -sha256 -nodes -days 1
|
||||
-keyout /tls/key.pem -out /tls/cert.pem
|
||||
-subj /CN=$${RDP_ACCESS_CERT_NAME}
|
||||
-addext subjectAltName=$${RDP_ACCESS_CERT_SAN} &&
|
||||
chown $${RDP_ACCESS_HOST_UID}:$${RDP_ACCESS_HOST_GID} /tls /tls/cert.pem /tls/key.pem)
|
||||
|
||||
gateway:
|
||||
image: nginx:1.27-alpine
|
||||
depends_on:
|
||||
- guacamole
|
||||
ports:
|
||||
- ${RDP_ACCESS_BIND}:${RDP_ACCESS_HTTP_PORT}:8443
|
||||
volumes:
|
||||
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
|
||||
- ${RDP_ACCESS_RUNTIME_DIR}/tls:/etc/nginx/tls:ro
|
||||
@@ -0,0 +1,19 @@
|
||||
server {
|
||||
listen 8443 ssl;
|
||||
server_name _;
|
||||
|
||||
ssl_certificate /etc/nginx/tls/cert.pem;
|
||||
ssl_certificate_key /etc/nginx/tls/key.pem;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
|
||||
location / {
|
||||
proxy_pass http://guacamole:8080;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto https;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_buffering off;
|
||||
}
|
||||
}
|
||||
Executable
+280
@@ -0,0 +1,280 @@
|
||||
#!/bin/sh
|
||||
# Temporary browser access to the Helium fixture's loopback-only VirtualBox
|
||||
# VRDE endpoint. This is a manual-recovery helper, never a normal test channel.
|
||||
set -eu
|
||||
|
||||
helper_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
||||
repo_root=$(CDPATH= cd -- "$helper_dir/../.." && pwd)
|
||||
runtime_dir=$helper_dir/.runtime
|
||||
compose_file=$helper_dir/compose.yaml
|
||||
mapping_template=$helper_dir/user-mapping.xml.in
|
||||
project=rvbox-rdp-access
|
||||
|
||||
: "${RDP_ACCESS_BIND:=127.0.0.1}"
|
||||
: "${RDP_ACCESS_HTTP_PORT:=5002}"
|
||||
: "${RDP_ACCESS_TUNNEL_PORT:=54001}"
|
||||
: "${RDP_ACCESS_PUBLIC_HOST:=localhost}"
|
||||
: "${RDP_ACCESS_WEB_USER:=rvboxtest}"
|
||||
: "${RDP_ACCESS_RDP_USER:=rvboxtest}"
|
||||
: "${RVBOX_TEST_VBOX_HOST:=helium-remote}"
|
||||
: "${RDP_ACCESS_VRDE_HOST:=127.0.0.1}"
|
||||
: "${RDP_ACCESS_VRDE_PORT:=3389}"
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
usage: test/rdp-access/rdp-access ACTION [OPTIONS]
|
||||
|
||||
Actions:
|
||||
up start a private VRDE SSH tunnel and self-signed HTTPS Guacamole
|
||||
status show gateway, tunnel, and fixture status without changing anything
|
||||
url print the current browser URL
|
||||
logs follow or print Compose logs (pass Docker Compose log options)
|
||||
down stop containers and the private SSH tunnel; retain generated state
|
||||
clean run down and delete generated state; pass --images to also remove
|
||||
the exact unused Guacamole/nginx images
|
||||
|
||||
up options:
|
||||
--bind ADDRESS listener address (default 127.0.0.1; use 0.0.0.0 only
|
||||
for a temporary, deliberately public endpoint)
|
||||
--http-port PORT HTTPS listener port (default 5002)
|
||||
--tunnel-port PORT private VRDE tunnel port (default 54001)
|
||||
--public-host NAME browser-visible hostname or IP for the URL and cert SAN
|
||||
--web-user USER Guacamole and Windows account (default rvboxtest)
|
||||
--reset-auth discard the saved password hash and prompt again
|
||||
--web-password-stdin read the password once from stdin instead of prompting
|
||||
|
||||
Environment equivalents: RDP_ACCESS_BIND, RDP_ACCESS_HTTP_PORT,
|
||||
RDP_ACCESS_TUNNEL_PORT, RDP_ACCESS_PUBLIC_HOST, RDP_ACCESS_WEB_USER,
|
||||
RDP_ACCESS_RDP_USER, RVBOX_TEST_VBOX_HOST, RDP_ACCESS_VRDE_HOST, and
|
||||
RDP_ACCESS_VRDE_PORT.
|
||||
EOF
|
||||
}
|
||||
|
||||
fail() { printf '%s\n' "rdp-access: $*" >&2; exit 2; }
|
||||
|
||||
safe_name() {
|
||||
case $2 in ''|*[!A-Za-z0-9.-]*) fail "$1 contains unsupported characters" ;; esac
|
||||
}
|
||||
|
||||
safe_port() {
|
||||
case $2 in ''|*[!0-9]*) fail "$1 must be a port number" ;; esac
|
||||
[ "$2" -ge 1024 ] && [ "$2" -le 65535 ] || fail "$1 must be between 1024 and 65535"
|
||||
}
|
||||
|
||||
safe_bind() {
|
||||
case $1 in 127.0.0.1|0.0.0.0) ;; *) fail "--bind must be 127.0.0.1 or 0.0.0.0" ;; esac
|
||||
}
|
||||
|
||||
compose() {
|
||||
RDP_ACCESS_RUNTIME_DIR=$runtime_dir \
|
||||
RDP_ACCESS_BIND=$RDP_ACCESS_BIND \
|
||||
RDP_ACCESS_HTTP_PORT=$RDP_ACCESS_HTTP_PORT \
|
||||
RDP_ACCESS_CERT_NAME=$RDP_ACCESS_PUBLIC_HOST \
|
||||
RDP_ACCESS_CERT_SAN=$cert_san \
|
||||
RDP_ACCESS_HOST_UID=$(id -u) \
|
||||
RDP_ACCESS_HOST_GID=$(id -g) \
|
||||
docker compose --project-name "$project" -f "$compose_file" "$@"
|
||||
}
|
||||
|
||||
socket_path=$runtime_dir/ssh-control.socket
|
||||
session_file=$runtime_dir/session.env
|
||||
cert_name_file=$runtime_dir/cert-name
|
||||
|
||||
stop_tunnel() {
|
||||
if [ -S "$socket_path" ]; then
|
||||
ssh -S "$socket_path" -O exit "$RVBOX_TEST_VBOX_HOST" >/dev/null 2>&1 || true
|
||||
fi
|
||||
rm -f "$socket_path"
|
||||
}
|
||||
|
||||
gateway_for_network() {
|
||||
docker network inspect --format '{{(index .IPAM.Config 0).Gateway}}' "${project}_default"
|
||||
}
|
||||
|
||||
assert_fixture_running() {
|
||||
fixture_status=$("$repo_root/scripts/windows/test-host" status) || fail "fixture identity check failed"
|
||||
printf '%s\n' "$fixture_status"
|
||||
case $fixture_status in *'state=running') ;; *) fail "VM is not running; prepare it first with scripts/windows/test-host prepare --run-id interactive-rdp" ;; esac
|
||||
}
|
||||
|
||||
password_hash_from_terminal() {
|
||||
password=
|
||||
restore_tty=false
|
||||
if [ "$password_stdin" = true ]; then
|
||||
IFS= read -r password || fail "could not read password from stdin"
|
||||
else
|
||||
[ -t 0 ] || fail "stdin is not a terminal; use --web-password-stdin"
|
||||
printf 'Fixture password for %s: ' "$RDP_ACCESS_WEB_USER" >&2
|
||||
stty -echo
|
||||
restore_tty=true
|
||||
trap 'test "$restore_tty" = true && stty echo || true' EXIT HUP INT TERM
|
||||
IFS= read -r password || fail "could not read password"
|
||||
stty echo
|
||||
restore_tty=false
|
||||
trap - EXIT HUP INT TERM
|
||||
printf '\n' >&2
|
||||
fi
|
||||
[ -n "$password" ] || fail "password must not be empty"
|
||||
hash=$(printf '%s' "$password" | docker run --rm -i --entrypoint md5sum alpine:3.20 | awk '{print $1}')
|
||||
unset password
|
||||
case $hash in ''|*[!0-9a-f]*) fail "could not generate password hash" ;; esac
|
||||
[ "${#hash}" -eq 32 ] || fail "could not generate password hash"
|
||||
printf '%s\n' "$hash"
|
||||
}
|
||||
|
||||
render_mapping() {
|
||||
umask 077
|
||||
mkdir -p "$runtime_dir/config" "$runtime_dir/tls"
|
||||
chmod 700 "$runtime_dir" "$runtime_dir/config" "$runtime_dir/tls"
|
||||
if [ "$reset_auth" = true ]; then rm -f "$runtime_dir/config/user-mapping.xml"; fi
|
||||
if [ -s "$runtime_dir/config/user-mapping.xml" ]; then
|
||||
password_hash=$(sed -n 's/.*password="\([0-9a-f][0-9a-f]*\)".*/\1/p' "$runtime_dir/config/user-mapping.xml" | head -n 1)
|
||||
case $password_hash in ''|*[!0-9a-f]*) password_hash=$(password_hash_from_terminal) ;; esac
|
||||
[ "${#password_hash}" -eq 32 ] || password_hash=$(password_hash_from_terminal)
|
||||
else
|
||||
password_hash=$(password_hash_from_terminal)
|
||||
fi
|
||||
sed \
|
||||
-e "s/@WEB_USER@/$RDP_ACCESS_WEB_USER/g" \
|
||||
-e "s/@WEB_PASSWORD_MD5@/$password_hash/g" \
|
||||
-e "s/@DOCKER_GATEWAY@/$docker_gateway/g" \
|
||||
-e "s/@TUNNEL_PORT@/$RDP_ACCESS_TUNNEL_PORT/g" \
|
||||
-e "s/@RDP_USER@/$RDP_ACCESS_RDP_USER/g" \
|
||||
"$mapping_template" >"$runtime_dir/config/user-mapping.xml"
|
||||
chmod 600 "$runtime_dir/config/user-mapping.xml"
|
||||
if [ -f "$cert_name_file" ] && [ "$(cat "$cert_name_file")" != "$RDP_ACCESS_PUBLIC_HOST" ]; then
|
||||
rm -f "$runtime_dir/tls/cert.pem" "$runtime_dir/tls/key.pem"
|
||||
fi
|
||||
printf '%s\n' "$RDP_ACCESS_PUBLIC_HOST" >"$cert_name_file"
|
||||
chmod 600 "$cert_name_file"
|
||||
printf 'url=https://%s:%s/guacamole/\n' "$RDP_ACCESS_PUBLIC_HOST" "$RDP_ACCESS_HTTP_PORT" >"$session_file"
|
||||
printf 'docker_gateway=%s\n' "$docker_gateway" >>"$session_file"
|
||||
printf 'tunnel_port=%s\n' "$RDP_ACCESS_TUNNEL_PORT" >>"$session_file"
|
||||
chmod 600 "$session_file"
|
||||
}
|
||||
|
||||
start_tunnel() {
|
||||
stop_tunnel
|
||||
ssh -M -S "$socket_path" -fN \
|
||||
-o BatchMode=yes \
|
||||
-o ExitOnForwardFailure=yes \
|
||||
-o ServerAliveInterval=30 \
|
||||
-o ServerAliveCountMax=3 \
|
||||
-L "$docker_gateway:$RDP_ACCESS_TUNNEL_PORT:$RDP_ACCESS_VRDE_HOST:$RDP_ACCESS_VRDE_PORT" \
|
||||
"$RVBOX_TEST_VBOX_HOST"
|
||||
ssh -S "$socket_path" -O check "$RVBOX_TEST_VBOX_HOST" >/dev/null 2>&1 || fail "private VRDE tunnel did not start"
|
||||
}
|
||||
|
||||
action=${1-}
|
||||
[ -n "$action" ] || { usage >&2; exit 2; }
|
||||
shift || true
|
||||
case $action in --help|-h) usage; exit 0 ;; esac
|
||||
|
||||
reset_auth=false
|
||||
password_stdin=false
|
||||
remove_images=false
|
||||
while [ "$#" -gt 0 ]; do
|
||||
case $1 in
|
||||
--bind) [ "$#" -ge 2 ] || fail "--bind needs a value"; RDP_ACCESS_BIND=$2; shift 2 ;;
|
||||
--http-port) [ "$#" -ge 2 ] || fail "--http-port needs a value"; RDP_ACCESS_HTTP_PORT=$2; shift 2 ;;
|
||||
--tunnel-port) [ "$#" -ge 2 ] || fail "--tunnel-port needs a value"; RDP_ACCESS_TUNNEL_PORT=$2; shift 2 ;;
|
||||
--public-host) [ "$#" -ge 2 ] || fail "--public-host needs a value"; RDP_ACCESS_PUBLIC_HOST=$2; shift 2 ;;
|
||||
--web-user) [ "$#" -ge 2 ] || fail "--web-user needs a value"; RDP_ACCESS_WEB_USER=$2; RDP_ACCESS_RDP_USER=$2; shift 2 ;;
|
||||
--reset-auth) reset_auth=true; shift ;;
|
||||
--web-password-stdin) password_stdin=true; shift ;;
|
||||
--images) remove_images=true; shift ;;
|
||||
--help|-h) usage; exit 0 ;;
|
||||
*) break ;;
|
||||
esac
|
||||
done
|
||||
|
||||
safe_bind "$RDP_ACCESS_BIND"
|
||||
safe_port RDP_ACCESS_HTTP_PORT "$RDP_ACCESS_HTTP_PORT"
|
||||
safe_port RDP_ACCESS_TUNNEL_PORT "$RDP_ACCESS_TUNNEL_PORT"
|
||||
[ "$RDP_ACCESS_HTTP_PORT" != "$RDP_ACCESS_TUNNEL_PORT" ] || fail "HTTPS and tunnel ports must differ"
|
||||
safe_name RDP_ACCESS_PUBLIC_HOST "$RDP_ACCESS_PUBLIC_HOST"
|
||||
safe_name RDP_ACCESS_WEB_USER "$RDP_ACCESS_WEB_USER"
|
||||
safe_name RDP_ACCESS_RDP_USER "$RDP_ACCESS_RDP_USER"
|
||||
safe_name RVBOX_TEST_VBOX_HOST "$RVBOX_TEST_VBOX_HOST"
|
||||
case $RDP_ACCESS_VRDE_HOST in 127.0.0.1|localhost) ;; *) fail "RDP_ACCESS_VRDE_HOST must be 127.0.0.1 or localhost" ;; esac
|
||||
safe_port RDP_ACCESS_VRDE_PORT "$RDP_ACCESS_VRDE_PORT"
|
||||
|
||||
case $RDP_ACCESS_PUBLIC_HOST in
|
||||
*[!0-9.]* ) cert_san="DNS:$RDP_ACCESS_PUBLIC_HOST" ;;
|
||||
* ) cert_san="IP:$RDP_ACCESS_PUBLIC_HOST" ;;
|
||||
esac
|
||||
|
||||
[ "$remove_images" = false ] || [ "$action" = clean ] || fail "--images is valid only with clean"
|
||||
[ "$reset_auth" = false ] || [ "$action" = up ] || fail "--reset-auth is valid only with up"
|
||||
[ "$password_stdin" = false ] || [ "$action" = up ] || fail "--web-password-stdin is valid only with up"
|
||||
|
||||
case $action in
|
||||
up)
|
||||
[ "$#" -eq 0 ] || { usage >&2; fail "unknown up option $1"; }
|
||||
if [ "$RDP_ACCESS_BIND" = 0.0.0.0 ] && [ "$RDP_ACCESS_PUBLIC_HOST" = localhost ]; then
|
||||
fail "a public bind requires --public-host with the browser-visible hostname or IP"
|
||||
fi
|
||||
docker version >/dev/null
|
||||
docker compose version >/dev/null
|
||||
assert_fixture_running
|
||||
if compose ps -q | grep -q .; then
|
||||
fail "gateway already exists; use status or down first"
|
||||
fi
|
||||
mkdir -p "$runtime_dir"
|
||||
compose up -d guacd
|
||||
docker_gateway=$(gateway_for_network) || { compose down --remove-orphans; fail "could not determine private Docker gateway"; }
|
||||
render_mapping
|
||||
if ! start_tunnel; then
|
||||
compose down --remove-orphans
|
||||
fail "could not create private SSH tunnel"
|
||||
fi
|
||||
if ! compose run --rm certgen; then
|
||||
stop_tunnel
|
||||
compose down --remove-orphans
|
||||
fail "could not generate self-signed certificate"
|
||||
fi
|
||||
if ! compose up -d guacamole gateway; then
|
||||
stop_tunnel
|
||||
compose down --remove-orphans
|
||||
fail "could not start Guacamole gateway"
|
||||
fi
|
||||
printf 'Guacamole is ready at https://%s:%s/guacamole/\n' "$RDP_ACCESS_PUBLIC_HOST" "$RDP_ACCESS_HTTP_PORT"
|
||||
printf 'Accept the self-signed certificate warning, then sign in as %s with the fixture password.\n' "$RDP_ACCESS_WEB_USER"
|
||||
;;
|
||||
status)
|
||||
[ "$#" -eq 0 ] || { usage >&2; fail "status accepts no options"; }
|
||||
"$repo_root/scripts/windows/test-host" status || true
|
||||
if [ -f "$session_file" ]; then sed -n '1p' "$session_file"; fi
|
||||
compose ps
|
||||
if [ -S "$socket_path" ] && ssh -S "$socket_path" -O check "$RVBOX_TEST_VBOX_HOST" >/dev/null 2>&1; then
|
||||
printf 'private_tunnel=active\n'
|
||||
else
|
||||
printf 'private_tunnel=inactive\n'
|
||||
fi
|
||||
;;
|
||||
url)
|
||||
[ "$#" -eq 0 ] || { usage >&2; fail "url accepts no options"; }
|
||||
[ -f "$session_file" ] || fail "no saved gateway session; run up first"
|
||||
sed -n '1s/^url=//p' "$session_file"
|
||||
;;
|
||||
logs)
|
||||
compose logs "$@"
|
||||
;;
|
||||
down)
|
||||
[ "$#" -eq 0 ] || { usage >&2; fail "down accepts no options"; }
|
||||
stop_tunnel
|
||||
compose down --remove-orphans || true
|
||||
printf 'Temporary gateway and private tunnel stopped; generated certificate and password hash retained in %s.\n' "$runtime_dir"
|
||||
;;
|
||||
clean)
|
||||
[ "$#" -eq 0 ] || { usage >&2; fail "clean accepts only --images"; }
|
||||
stop_tunnel
|
||||
compose down --remove-orphans || true
|
||||
case $runtime_dir in "$helper_dir"/.runtime) rm -rf "$runtime_dir" ;; *) fail "unsafe runtime path" ;; esac
|
||||
if [ "$remove_images" = true ]; then
|
||||
docker image rm guacamole/guacamole:1.6.0 guacamole/guacd:1.6.0 nginx:1.27-alpine >/dev/null 2>&1 || true
|
||||
fi
|
||||
printf 'Temporary gateway state removed.\n'
|
||||
;;
|
||||
*) usage >&2; fail "unknown action $action" ;;
|
||||
esac
|
||||
@@ -0,0 +1,21 @@
|
||||
<user-mapping>
|
||||
<authorize username="@WEB_USER@" password="@WEB_PASSWORD_MD5@" encoding="md5">
|
||||
<connection name="RVBox Windows test VM">
|
||||
<protocol>rdp</protocol>
|
||||
<param name="hostname">@DOCKER_GATEWAY@</param>
|
||||
<param name="port">@TUNNEL_PORT@</param>
|
||||
<param name="security">rdp</param>
|
||||
<param name="username">@RDP_USER@</param>
|
||||
<param name="password">${GUAC_PASSWORD}</param>
|
||||
<param name="ignore-cert">true</param>
|
||||
<param name="disable-audio">true</param>
|
||||
<param name="enable-audio-input">false</param>
|
||||
<param name="enable-drive">false</param>
|
||||
<param name="enable-printing">false</param>
|
||||
<param name="enable-wallpaper">false</param>
|
||||
<param name="enable-theming">false</param>
|
||||
<param name="enable-font-smoothing">false</param>
|
||||
<param name="disable-gfx">true</param>
|
||||
</connection>
|
||||
</authorize>
|
||||
</user-mapping>
|
||||
Reference in New Issue
Block a user