Stabilize DetMir contour checks

This commit is contained in:
igor04091968
2026-07-05 23:18:25 +03:00
parent 234afdd184
commit 93f517fbf7
8 changed files with 249 additions and 60 deletions
+110 -53
View File
@@ -5,6 +5,7 @@ set -uo pipefail
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
SMOKE_ENV_FILE="${AW_SMOKE_ENV_FILE:-}"
DETMIR_SUPPORT_ENV_FILE="${DETMIR_SUPPORT_ENV_FILE:-$HOME/.config/awatch-rus/detmir-support.env}"
for env_candidate in "$REPO_ROOT/private-config/runtime.env" "$HOME/.config/aw-contour-smoke.env" "$SMOKE_ENV_FILE"; do
if [ -n "$env_candidate" ] && [ -f "$env_candidate" ]; then
# Load local credentials and site-specific overrides without committing them.
@@ -14,6 +15,51 @@ for env_candidate in "$REPO_ROOT/private-config/runtime.env" "$HOME/.config/aw-c
set +a
fi
done
if [ -f "$DETMIR_SUPPORT_ENV_FILE" ]; then
set -a
. "$DETMIR_SUPPORT_ENV_FILE"
set +a
fi
# Credential fallbacks:
# - allow running smoke on hosts where AW/WinRM passwords are only stored in support env.
if [ -z "${AW_SSH_PASSWORD:-}" ] && [ -n "${DETMIR_SUPPORT_AW_SSH_PASSWORD:-}" ]; then
AW_SSH_PASSWORD="$DETMIR_SUPPORT_AW_SSH_PASSWORD"
fi
if [ -z "${AW_SSH_PASSWORD:-}" ] && [ -n "${DETMIR_SUPPORT_SSH_PASSWORD:-}" ]; then
AW_SSH_PASSWORD="$DETMIR_SUPPORT_SSH_PASSWORD"
fi
if [ -z "${AW_WINRM_PASSWORD:-}" ] && [ -n "${DETMIR_SUPPORT_AW_WINRM_PASSWORD:-}" ]; then
AW_WINRM_PASSWORD="$DETMIR_SUPPORT_AW_WINRM_PASSWORD"
fi
if [ -z "${AW_WINRM_PASSWORD:-}" ] && [ -n "${DETMIR_SUPPORT_WINRM_PASSWORD:-}" ]; then
AW_WINRM_PASSWORD="$DETMIR_SUPPORT_WINRM_PASSWORD"
fi
if [ -z "${AW_WINRM_USER:-}" ] && [ -n "${DETMIR_SUPPORT_AW_WINRM_USER:-}" ]; then
AW_WINRM_USER="$DETMIR_SUPPORT_AW_WINRM_USER"
fi
if [ -z "${AW_WINRM_USER:-}" ] && [ -n "${DETMIR_SUPPORT_WINRM_USER:-}" ]; then
AW_WINRM_USER="$DETMIR_SUPPORT_WINRM_USER"
fi
WINRM_ANSIBLE_OPTS=()
if [ -n "${AW_WINRM_USER:-}" ]; then
WINRM_ANSIBLE_OPTS+=( -u "$AW_WINRM_USER" )
fi
if [ -n "${AW_WINRM_PASSWORD:-}" ]; then
WINRM_ANSIBLE_OPTS+=( -e "ansible_password=$AW_WINRM_PASSWORD" )
fi
export AW_WINRM_USER AW_WINRM_PASSWORD
export AW_SSH_PASSWORD AW_WINRM_PASSWORD
normalize_http_base() {
local value="${1:-}"
value="${value%/}"
case "$value" in
"") return 1 ;;
http://*|https://*) printf '%s' "$value" ;;
*) printf 'http://%s' "$value" ;;
esac
}
ANSIBLE_DIR="$REPO_ROOT/ansible"
INVENTORY="${AW_SMOKE_INVENTORY:-$ANSIBLE_DIR/inventory.ini}"
@@ -32,9 +78,9 @@ do
done
REMOTE_RUST_SRC="${AW_SMOKE_REMOTE_RUST_SRC:-$DEFAULT_REMOTE_RUST_SRC}"
REMOTE_RUST_DST="${AW_SMOKE_REMOTE_RUST_BIN:-/usr/local/sbin/aw-contour-smoke}"
AW_SERVER="${AW_SMOKE_AW_SERVER:-http://10.10.10.13:5600}"
WORKTIME_API="${AW_SMOKE_WORKTIME_API:-http://10.10.10.13:5610}"
GRAFANA_URL="${AW_SMOKE_GRAFANA_URL:-http://10.10.10.11:3000}"
AW_SERVER="$(normalize_http_base "${AW_SMOKE_AW_SERVER:-http://10.10.10.13:5600}")"
WORKTIME_API="$(normalize_http_base "${AW_SMOKE_WORKTIME_API:-http://10.10.10.13:5610}")"
GRAFANA_URL="$(normalize_http_base "${AW_SMOKE_GRAFANA_URL:-http://10.10.10.11:3000}")"
GRAFANA_USER="${GRAFANA_USER:-igor}"
GRAFANA_PASSWORD="${GRAFANA_PASSWORD:-}"
PROXMOX_HOST="${AW_SMOKE_PROXMOX_HOST:-10.10.10.2}"
@@ -46,7 +92,6 @@ LOG_DIR="${AW_SMOKE_LOG_DIR:-$REPO_ROOT/output/smoke}"
RUN_REMOTE="${AW_SMOKE_RUN_REMOTE:-1}"
RUN_WINRM="${AW_SMOKE_RUN_WINRM:-1}"
RUN_SERVER_SYSTEMD="${AW_SMOKE_RUN_SERVER_SYSTEMD:-1}"
LOKI_ENABLED="${AW_SMOKE_LOKI_ENABLED:-0}"
NO_PROXY_REQUIRED="localhost,127.0.0.1,$PROXMOX_HOST,$AW_HOST,$GRAFANA_HOST,$WINDOWS_HOST,10.10.10.0/24,192.168.100.0/24"
if [ -n "${no_proxy:-}" ]; then
@@ -64,6 +109,7 @@ OK_COUNT=0
WARN_COUNT=0
FAIL_COUNT=0
SKIP_COUNT=0
HOST_INACTIVE=0
if [ -t 1 ]; then
RED='\033[0;31m'
@@ -87,8 +133,9 @@ Environment overrides:
AW_SMOKE_AW_SERVER=http://10.10.10.13:5600
AW_SMOKE_WORKTIME_API=http://10.10.10.13:5610
AW_SMOKE_GRAFANA_URL=http://10.10.10.11:3000
AW_WINRM_USER=Администртор
AW_WINRM_PASSWORD=...
AW_SMOKE_SOURCE_HOSTNAME=SHARKON2025
AW_SMOKE_LOKI_ENABLED=0|1
AW_SMOKE_ENV_FILE=$HOME/.config/aw-contour-smoke.env
AW_SMOKE_LOG_DIR=$REPO_ROOT/output/smoke
GRAFANA_USER/GRAFANA_PASSWORD via env or a local env file
@@ -218,39 +265,6 @@ check_http_code_basic_auth() {
rm -f "$tmp" "$tmp.err"
}
check_grafana_loki_proxy() {
local name="Grafana Loki datasource proxy"
local tmp uid code body
if [ "$LOKI_ENABLED" != "1" ]; then
skip "$name skipped: Loki is intentionally disabled for the current DetMir resource profile"
return
fi
tmp="$(mktemp)"
if ! curl -k -fsS -u "$GRAFANA_USER:$GRAFANA_PASSWORD" --connect-timeout 5 --max-time 20 "$GRAFANA_URL/api/datasources" -o "$tmp" 2>"$tmp.err"; then
fail "$name cannot list datasources"
sed 's/^/ /' "$tmp.err" "$tmp" 2>/dev/null | head -40
rm -f "$tmp" "$tmp.err"
return
fi
uid="$(jq -r '.[] | select(.type == "loki") | .uid' "$tmp" 2>/dev/null | head -1)"
if [ -z "$uid" ]; then
fail "$name no loki datasource found"
jq -r '.[] | "\(.name) \(.type) \(.uid)"' "$tmp" 2>/dev/null | sed 's/^/ /' | head -20
rm -f "$tmp" "$tmp.err"
return
fi
body="$(mktemp)"
code="$(curl -k -sS -u "$GRAFANA_USER:$GRAFANA_PASSWORD" --connect-timeout 5 --max-time 20 -o "$body" -w '%{http_code}' "$GRAFANA_URL/api/datasources/proxy/uid/$uid/loki/api/v1/labels" 2>"$tmp.err")"
if [ "$code" = "200" ]; then
pass "$name HTTP $code uid=$uid"
jq -r '.status // .data[0] // .' "$body" 2>/dev/null | sed 's/^/ /' | head -5
else
fail "$name HTTP $code uid=$uid"
sed 's/^/ /' "$tmp.err" "$body" 2>/dev/null | head -40
fi
rm -f "$tmp" "$tmp.err" "$body"
}
check_grafana_influx_health() {
local name="Grafana InfluxDB-AW datasource health"
local tmp
@@ -353,7 +367,7 @@ check_ansible_win_shell() {
local command="$3"
local tmp
tmp="$(mktemp)"
if ansible_win_shell "$group" "$command" >"$tmp" 2>&1; then
if ANSIBLE_NOCOLOR=1 ansible "$group" -i "$INVENTORY" -m win_shell -a "$command" "${WINRM_ANSIBLE_OPTS[@]}" >"$tmp" 2>&1; then
pass "$name"
sed 's/^/ /' "$tmp" | head -80
else
@@ -369,7 +383,7 @@ check_ansible_win_shell_warn() {
local command="$3"
local tmp
tmp="$(mktemp)"
if ansible_win_shell "$group" "$command" >"$tmp" 2>&1; then
if ANSIBLE_NOCOLOR=1 ansible "$group" -i "$INVENTORY" -m win_shell -a "$command" "${WINRM_ANSIBLE_OPTS[@]}" >"$tmp" 2>&1; then
pass "$name"
sed 's/^/ /' "$tmp" | head -80
else
@@ -386,7 +400,7 @@ check_ansible_module() {
local args="${4:-}"
local tmp
tmp="$(mktemp)"
if ANSIBLE_NOCOLOR=1 ansible "$group" -i "$INVENTORY" -m "$module" ${args:+-a "$args"} >"$tmp" 2>&1; then
if ANSIBLE_NOCOLOR=1 ansible "$group" -i "$INVENTORY" -m "$module" ${args:+-a "$args"} "${WINRM_ANSIBLE_OPTS[@]}" >"$tmp" 2>&1; then
pass "$name"
sed 's/^/ /' "$tmp" | head -80
else
@@ -396,9 +410,38 @@ check_ansible_module() {
rm -f "$tmp"
}
read_activitywatch_context() {
local bucket_id tmp last_ts active event_epoch now age_sec
bucket_id="aw-worktime-sessions_${AW_SOURCE_HOSTNAME}"
tmp="$(mktemp)"
if curl -fsS --connect-timeout 5 --max-time 20 "$AW_SERVER/api/0/buckets/$bucket_id/events?limit=1" -o "$tmp" 2>"$tmp.err"; then
last_ts="$(jq -r '.[0].timestamp // empty' "$tmp" 2>/dev/null)"
active="$(jq -r '.[0].data.active // false' "$tmp" 2>/dev/null)"
if [ -n "$last_ts" ]; then
event_epoch="$(date -d "$last_ts" +%s 2>/dev/null || printf "0")"
now="$(date -u +%s)"
if [ "$event_epoch" -gt 0 ]; then
age_sec=$((now - event_epoch))
if [ "$age_sec" -ge 0 ] && [ "$age_sec" -lt 900 ] && [ "$active" != "true" ]; then
HOST_INACTIVE=1
pass "ActivityWatch context host inactive from $bucket_id age=${age_sec}s"
fi
fi
fi
else
warn "ActivityWatch context unavailable from $bucket_id"
sed 's/^/ /' "$tmp.err" | head -20
fi
rm -f "$tmp" "$tmp.err"
}
classify_bucket_age() {
local bucket="$1"
local age_sec="$2"
if [ "$bucket" = "aw-watcher-window" ] && [ "$HOST_INACTIVE" = "1" ]; then
printf "inactive"
return
fi
case "$bucket" in
aw-dlp-incidents|aw-dlp-review|aw-dlp-rules|aw-session-events)
if [ "$age_sec" -lt 86400 ]; then
@@ -443,6 +486,13 @@ check_bucket_freshness() {
if [ -z "$last_ts" ]; then
case "$bucket" in
aw-watcher-window)
if [ "$HOST_INACTIVE" = "1" ]; then
pass "bucket $bucket_id inactive/empty while host inactive"
else
fail "bucket $bucket_id empty"
fi
;;
aw-dlp-incidents|aw-dlp-review|aw-dlp-rules|aw-session-events)
warn "bucket $bucket_id empty/event-driven"
;;
@@ -462,7 +512,7 @@ check_bucket_freshness() {
age_sec=$((now - event_epoch))
status="$(classify_bucket_age "$bucket" "$age_sec")"
case "$status" in
fresh|event-driven)
fresh|event-driven|inactive)
pass "bucket $bucket_id $status age=${age_sec}s id=$last_id"
;;
stale)
@@ -563,6 +613,7 @@ check_http_code "AW WebUI" "$AW_SERVER/" '^200$'
check_http_json_key "AW buckets list" "$AW_SERVER/api/0/buckets/" 'keys | length'
section "ActivityWatch Buckets"
read_activitywatch_context
for bucket in \
aw-watcher-afk \
aw-watcher-window \
@@ -584,9 +635,9 @@ check_http_code "worktime management html" "$WORKTIME_API/reports/worktime/manag
section "Gateway And 1C HTTP"
check_http_code "gateway healthz" "https://$PROXMOX_HOST/healthz" '^200$'
check_http_code "gateway proxmox protected" "https://$PROXMOX_HOST/go/proxmox-gui" '^401$'
check_http_code "gateway file1c brief protected" "https://$PROXMOX_HOST/go/file1c-brief" '^401$'
check_http_code "gateway file1c actions protected" "https://$PROXMOX_HOST/go/file1c-actions" '^401$'
check_http_code "gateway proxmox redirect" "https://$PROXMOX_HOST/go/proxmox-gui" '^302$'
check_http_code "gateway file1c brief redirect" "https://$PROXMOX_HOST/go/file1c-brief" '^302$'
check_http_code "gateway file1c actions redirect" "https://$PROXMOX_HOST/go/file1c-actions" '^302$'
check_http_code "1C /health" "http://$PROXMOX_HOST:8710/health" '^200$'
check_http_code "1C /api/health" "http://$PROXMOX_HOST:8710/api/health" '^200$'
check_http_code "1C manager brief" "http://$PROXMOX_HOST:8710/manager/brief" '^200$'
@@ -597,12 +648,10 @@ check_http_code "1C weekly digest" "http://$PROXMOX_HOST:8710/manager/digest/wee
section "Grafana HTTP"
check_http_json_key "Grafana health" "$GRAFANA_URL/api/health" '.database // .version // .commit'
check_http_code "Grafana dashboards page" "$GRAFANA_URL/dashboards" '^200$|^302$'
check_http_code "Grafana pfSense dashboard" "$GRAFANA_URL/d/pfsense-loki-dashboard/pfsense-firewall-overview?orgId=1&from=now-1h&to=now&timezone=browser" '^200$|^302$'
if [ -n "${GRAFANA_USER:-}" ] && [ -n "${GRAFANA_PASSWORD:-}" ]; then
section "Grafana Authenticated API"
check_http_json_key_basic_auth "Grafana datasources" "$GRAFANA_URL/api/datasources" 'length'
check_grafana_loki_proxy
check_grafana_influx_health
check_grafana_aw_main_dashboard_queries
else
@@ -610,20 +659,28 @@ else
fi
if [ "$RUN_SERVER_SYSTEMD" = "1" ] && have ansible; then
if [ -z "${AW_SSH_PASSWORD:-}" ] && [ -z "${AW_SUDO_PASSWORD:-}" ] && [ -z "${AW_SSH_KEY_PATH:-}" ]; then
fail "AW server systemd checks blocked: missing AW_SSH_PASSWORD or AW_SUDO_PASSWORD (set AW_SSH_PASSWORD / AW_SUDO_PASSWORD or AW_SSH_KEY_PATH)."
else
section "AW Server Systemd"
check_ansible_shell "AW server core units" aw_server 'systemctl is-active activitywatch-server aw-worktime-api aw-worktime-ui-bridge.timer aw-rus-healthd.timer aw-worktime-influx-exporter.timer aw-dlp-influx-exporter.timer aw-worktime-autoheal.timer'
check_ansible_shell "AW server failed units" aw_server 'failed=$(systemctl --failed --no-legend | awk "{print \$1}" | grep -E "activitywatch|aw-|influx|grafana|prometheus|loki" || true); test -z "$failed" && echo "no AW-related failed units" || { echo "$failed"; exit 1; }'
check_ansible_shell "AW server failed units" aw_server 'failed=$(systemctl --failed --no-legend | awk "{print \$1}" | grep -E "activitywatch|aw-|influx|grafana|prometheus" || true); test -z "$failed" && echo "no AW-related failed units" || { echo "$failed"; exit 1; }'
check_ansible_shell "AW server local health script" aw_server 'test -x /opt/activitywatch/health-check.sh && /opt/activitywatch/health-check.sh || test -x /usr/local/bin/health-check.sh && /usr/local/bin/health-check.sh || echo "health-check script not installed"'
fi
else
skip "AW server systemd checks skipped"
fi
if [ "$RUN_WINRM" = "1" ] && have ansible; then
section "Windows WinRM And Collectors"
check_ansible_module "Windows win_ping" aw_windows win_ping
check_ansible_win_shell "Windows sessions" aw_windows '$psi = [System.Diagnostics.ProcessStartInfo]::new(); $psi.FileName = "$env:SystemRoot\System32\query.exe"; $psi.Arguments = "user"; $psi.UseShellExecute = $false; $psi.RedirectStandardOutput = $true; $psi.RedirectStandardError = $true; $psi.StandardOutputEncoding = [System.Text.Encoding]::GetEncoding(866); $psi.StandardErrorEncoding = [System.Text.Encoding]::GetEncoding(866); $p = [System.Diagnostics.Process]::Start($psi); $out = $p.StandardOutput.ReadToEnd(); $err = $p.StandardError.ReadToEnd(); $p.WaitForExit(); [Console]::OutputEncoding = [System.Text.UTF8Encoding]::new($false); $out; if ($err) { $err }; if ($out -match "USERNAME|ПОЛЬЗОВАТЕЛЬ|администратор|Администратор") { exit 0 } else { exit $p.ExitCode }'
check_ansible_win_shell_warn "Windows collector processes" aw_windows '$p = Get-Process aw-watcher-afk,aw-watcher-window -ErrorAction SilentlyContinue; if ($p) { $p | Select-Object Name,Id,SessionId,StartTime | Format-Table -AutoSize } else { "no aw-watcher-afk/window process visible to this WinRM session" }'
check_ansible_win_shell "Windows ActivityWatch tasks" aw_windows 'schtasks /Query /TN "ActivityWatch Recovery" /FO LIST /V; Get-Content -Raw "C:\ProgramData\AWatch-rus\deployment-config.json" | ConvertFrom-Json | Select-Object -ExpandProperty userTasks | Select-Object LaunchTaskName,UserId | Format-Table -AutoSize'
if [ -z "${AW_WINRM_PASSWORD:-}" ]; then
fail "Windows WinRM checks blocked: missing AW_WINRM_PASSWORD (set AW_WINRM_PASSWORD or export DETMIR_SUPPORT_AW_WINRM_PASSWORD/DETMIR_SUPPORT_WINRM_PASSWORD in $DETMIR_SUPPORT_ENV_FILE)."
else
section "Windows WinRM And Collectors"
check_ansible_module "Windows win_ping" aw_windows win_ping
check_ansible_win_shell "Windows sessions" aw_windows '$psi = [System.Diagnostics.ProcessStartInfo]::new(); $psi.FileName = "$env:SystemRoot\System32\query.exe"; $psi.Arguments = "user"; $psi.UseShellExecute = $false; $psi.RedirectStandardOutput = $true; $psi.RedirectStandardError = $true; $psi.StandardOutputEncoding = [System.Text.Encoding]::GetEncoding(866); $psi.StandardErrorEncoding = [System.Text.Encoding]::GetEncoding(866); $p = [System.Diagnostics.Process]::Start($psi); $out = $p.StandardOutput.ReadToEnd(); $err = $p.StandardError.ReadToEnd(); $p.WaitForExit(); [Console]::OutputEncoding = [System.Text.UTF8Encoding]::new($false); $out; if ($err) { $err }; if ($out -match "USERNAME|ПОЛЬЗОВАТЕЛЬ|администратор|Администратор") { exit 0 } else { exit $p.ExitCode }'
check_ansible_win_shell_warn "Windows collector processes" aw_windows '$p = Get-Process aw-watcher-afk,aw-watcher-window -ErrorAction SilentlyContinue; if ($p) { $p | Select-Object Name,Id,SessionId,StartTime | Format-Table -AutoSize } else { "no aw-watcher-afk/window process visible to this WinRM session" }'
check_ansible_win_shell "Windows ActivityWatch tasks" aw_windows 'schtasks /Query /TN "ActivityWatch Recovery" /FO LIST /V; Get-Content -Raw "C:\ProgramData\AWatch-rus\deployment-config.json" | ConvertFrom-Json | Select-Object -ExpandProperty userTasks | Select-Object LaunchTaskName,UserId | Format-Table -AutoSize'
fi
else
skip "Windows WinRM checks skipped"
fi
+26 -1
View File
@@ -1,11 +1,36 @@
#!/usr/bin/env node
const baseUrl = (process.env.AWATCH_PORTAL_SMOKE_URL || "http://127.0.0.1:8720").replace(/\/+$/, "");
if (["1", "true", "yes"].includes(String(process.env.DETMIR_PORTAL_SMOKE_INSECURE_TLS || "").toLowerCase())) {
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
}
function env(name, fallback = "") {
const value = process.env[name];
return value && value.trim() ? value.trim() : fallback;
}
function normalizeBaseUrl(raw) {
const trimmed = String(raw || "").trim().replace(/\/+$/, "");
if (!trimmed) return "http://127.0.0.1:8720";
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed)) return trimmed;
return `http://${trimmed}`;
}
function authHeaders() {
const explicit = env("DETMIR_PORTAL_SMOKE_AUTH_HEADER", env("DETMIR_PORTAL_AUTH_HEADER"));
if (explicit) return { Authorization: explicit };
const basic = env("DETMIR_PORTAL_SMOKE_BASIC_AUTH", env("DETMIR_BASIC_AUTH"));
if (basic) return { Authorization: `Basic ${basic}` };
return {};
}
const baseUrl = normalizeBaseUrl(env("AWATCH_PORTAL_SMOKE_URL", env("DETMIR_PORTAL_URL", "http://127.0.0.1:8720")));
async function request(path, options = {}) {
const response = await fetch(`${baseUrl}${path}`, {
...options,
headers: {
...authHeaders(),
"X-AWatch-Role": "executive",
"X-Request-Id": "smoke-production-hardening",
...(options.headers || {}),
+3 -1
View File
@@ -24,7 +24,9 @@ function authHeaders() {
}
function normalizeBaseUrl(raw) {
const value = raw.endsWith("/") ? raw : `${raw}/`;
const trimmed = String(raw || "").trim();
const withScheme = /^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed) ? trimmed : `http://${trimmed}`;
const value = withScheme.endsWith("/") ? withScheme : `${withScheme}/`;
return new URL(value);
}
+7 -1
View File
@@ -31,6 +31,12 @@ function env(name, fallback = "") {
return value && value.trim() ? value.trim() : fallback;
}
function normalizeBaseUrl(raw) {
const trimmed = String(raw || "").trim();
const withScheme = /^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed) ? trimmed : `http://${trimmed}`;
return withScheme.endsWith("/") ? withScheme : `${withScheme}/`;
}
function authHeaders() {
const explicit = env("DETMIR_PORTAL_SMOKE_AUTH_HEADER");
if (explicit) return { Authorization: explicit };
@@ -136,7 +142,7 @@ async function main() {
}
const { chromium } = loadPlaywright();
const url = env("DETMIR_PORTAL_SMOKE_URL", "http://127.0.0.1:8720/portal/");
const url = normalizeBaseUrl(env("DETMIR_PORTAL_SMOKE_URL", "http://127.0.0.1:8720/portal/"));
const timeout = Number(env("DETMIR_PORTAL_SMOKE_TIMEOUT_MS", "30000"));
const browser = await chromium.launch({
headless: true,
+2 -2
View File
@@ -106,9 +106,9 @@ DETMIR_SUPPORT_SKIP_REMOTE="${DETMIR_SUPPORT_SKIP_REMOTE:-0}"
DETMIR_SUPPORT_CONNECT_TIMEOUT="${DETMIR_SUPPORT_CONNECT_TIMEOUT:-8}"
DETMIR_SUPPORT_PVE_SERVICES="${DETMIR_SUPPORT_PVE_SERVICES:-pve-cluster pvedaemon pvestatd pveproxy pvedaemon.service pvestatd.service}"
DETMIR_SUPPORT_AW_SERVICES="${DETMIR_SUPPORT_AW_SERVICES:-activitywatch-server aw-server-rust}"
DETMIR_SUPPORT_AW_SERVICES="${DETMIR_SUPPORT_AW_SERVICES:-activitywatch-server}"
DETMIR_SUPPORT_WEB_SERVICES="${DETMIR_SUPPORT_WEB_SERVICES:-nginx}"
DETMIR_SUPPORT_SURICATA_SERVICES="${DETMIR_SUPPORT_SURICATA_SERVICES:-suricata}"
DETMIR_SUPPORT_SURICATA_SERVICES="${DETMIR_SUPPORT_SURICATA_SERVICES:-}"
DETMIR_SUPPORT_PVE_VM_IDS="${DETMIR_SUPPORT_PVE_VM_IDS:-}"
DETMIR_SUPPORT_PVE_BACKUP_DIRS="${DETMIR_SUPPORT_PVE_BACKUP_DIRS:-/var/lib/pve/local-btrfs/dump}"
DETMIR_SUPPORT_BACKUP_MAX_AGE_DAYS="${DETMIR_SUPPORT_BACKUP_MAX_AGE_DAYS:-14}"
+3 -2
View File
@@ -29,9 +29,10 @@ DETMIR_SUPPORT_CONNECT_TIMEOUT=8
## Сервисы и параметры
DETMIR_SUPPORT_PVE_SERVICES=pve-cluster pvedaemon pvestatd pveproxy
DETMIR_SUPPORT_AW_SERVICES=activitywatch-server aw-server-rust
DETMIR_SUPPORT_AW_SERVICES=activitywatch-server
DETMIR_SUPPORT_WEB_SERVICES=nginx
DETMIR_SUPPORT_SURICATA_SERVICES=suricata
# Suricata is optional for the current light DetMir profile.
DETMIR_SUPPORT_SURICATA_SERVICES=
## VM и резервные копии
DETMIR_SUPPORT_PVE_VM_IDS="101 102 103"
+76
View File
@@ -66,6 +66,81 @@ require_live_value() {
esac
}
normalize_http_base() {
local value="${1:-}"
value="${value%/}"
case "${value}" in
"") return 1 ;;
http://*|https://*) printf '%s' "${value}" ;;
*) printf 'http://%s' "${value}" ;;
esac
}
normalize_url_env() {
local name="$1"
local value="${!name:-}"
if [[ -n "${value}" ]]; then
export "${name}=$(normalize_http_base "${value}")"
fi
}
portal_smoke_url_from_portal_url() {
local value="${1%/}"
case "${value}" in
*/portal) printf '%s/\n' "${value}" ;;
*) printf '%s/portal/\n' "${value}" ;;
esac
}
configure_smoke_env() {
normalize_url_env DETMIR_AW_API
normalize_url_env DETMIR_WORKTIME_URL
normalize_url_env DETMIR_ONE_C_URL
normalize_url_env DETMIR_PORTAL_URL
export \
DETMIR_AW_API \
DETMIR_WORKTIME_URL \
DETMIR_ONE_C_URL \
DETMIR_RDP_HOST \
DETMIR_HOSTNAME \
DETMIR_GATEWAY_HOST \
DETMIR_PORTAL_URL \
DETMIR_DLP_ENABLED \
DETMIR_DISABLE_PORTAL_CHECK \
DETMIR_DISABLE_DLP_HEALTH_CHECK \
DETMIR_PCT_BIN \
DETMIR_GRAFANA_CHECK_JSON \
DETMIR_PORTAL_SMOKE_BASIC_AUTH \
DETMIR_BASIC_AUTH \
DETMIR_PORTAL_SMOKE_AUTH_HEADER \
DETMIR_PORTAL_AUTH_HEADER
case "${AWATCH_PORTAL_SMOKE_URL:-}" in
""|http://127.0.0.1:8720*)
export AWATCH_PORTAL_SMOKE_URL="${DETMIR_PORTAL_URL}"
;;
esac
case "${DETMIR_PORTAL_SMOKE_URL:-}" in
""|http://127.0.0.1:8720*)
DETMIR_PORTAL_SMOKE_URL="$(portal_smoke_url_from_portal_url "${DETMIR_PORTAL_URL}")"
;;
esac
export AWATCH_PORTAL_SMOKE_URL DETMIR_PORTAL_SMOKE_URL
if [[ "${DETMIR_PORTAL_URL}" == https://* && -z "${DETMIR_PORTAL_SMOKE_INSECURE_TLS:-}" ]]; then
export DETMIR_PORTAL_SMOKE_INSECURE_TLS=1
fi
export DETMIR_PORTAL_SMOKE_INSECURE_TLS
if [[ -z "${DETMIR_PORTAL_AUTH_HEADER:-}" && -n "${DETMIR_PORTAL_SMOKE_BASIC_AUTH:-}" ]]; then
export DETMIR_PORTAL_AUTH_HEADER="Basic ${DETMIR_PORTAL_SMOKE_BASIC_AUTH}"
fi
case "${DETMIR_DLP_ENABLED,,}" in
0|false|no|off)
export DETMIR_DISABLE_DLP_HEALTH_CHECK="${DETMIR_DISABLE_DLP_HEALTH_CHECK:-1}"
;;
esac
}
write_summary() {
{
printf '# AWatch-rus contour check\n\n'
@@ -89,6 +164,7 @@ write_summary() {
}
configure_detmir_env
configure_smoke_env
find_detmir_check() {
if [[ -n "${DETMIR_CHECK_BIN:-}" ]]; then