fix(smoke): align contour checks with production routes

This commit is contained in:
igor04091968
2026-06-12 10:55:21 +03:00
parent 61a9887ebb
commit 7919051688
3 changed files with 89 additions and 96 deletions
+20 -56
View File
@@ -116,7 +116,7 @@ fn run_proxmox_remote() -> Result<i32> {
check_tcp(&mut counts, "nginx http", "127.0.0.1", 80);
check_tcp(&mut counts, "nginx https", "127.0.0.1", 443);
check_tcp(&mut counts, "proxmox web", "127.0.0.1", 8006);
check_tcp(&mut counts, "1C company API", "192.0.2.2", 8710);
check_tcp(&mut counts, "1C company API", "10.10.10.2", 8710);
check_tcp(&mut counts, "clickhouse native", "127.0.0.1", 9000);
check_tcp(&mut counts, "clickhouse http", "127.0.0.1", 8123);
if let Ok(out) = command_output("ss", &["-tulpn"]) {
@@ -135,29 +135,26 @@ fn run_proxmox_remote() -> Result<i32> {
"https://127.0.0.1/healthz",
&[200],
);
check_http_redirect(
check_http_code(
&mut counts,
&no_redirect_http,
"go proxmox gui",
&http,
"go proxmox gui protected",
"https://127.0.0.1/go/proxmox-gui",
&[301, 302, 307, 308],
Some("https://192.0.2.2:8006/"),
&[401],
);
check_http_redirect(
check_http_code(
&mut counts,
&no_redirect_http,
"go file1c brief",
&http,
"go file1c brief protected",
"https://127.0.0.1/go/file1c-brief",
&[301, 302, 307, 308],
Some("http://192.0.2.2:8710/manager/brief"),
&[401],
);
check_http_redirect(
check_http_code(
&mut counts,
&no_redirect_http,
"go file1c actions",
&http,
"go file1c actions protected",
"https://127.0.0.1/go/file1c-actions",
&[301, 302, 307, 308],
Some("http://192.0.2.2:8710/manager/actions"),
&[401],
);
section("1C Company API");
@@ -165,24 +162,24 @@ fn run_proxmox_remote() -> Result<i32> {
&mut counts,
&no_redirect_http,
"1C root redirect",
"http://192.0.2.2:8710/",
"http://10.10.10.2:8710/",
&[307],
);
for (name, url) in [
("1C /health", "http://192.0.2.2:8710/health"),
("1C /api/health", "http://192.0.2.2:8710/api/health"),
("1C manager brief", "http://192.0.2.2:8710/manager/brief"),
("1C /health", "http://10.10.10.2:8710/health"),
("1C /api/health", "http://10.10.10.2:8710/api/health"),
("1C manager brief", "http://10.10.10.2:8710/manager/brief"),
(
"1C manager actions",
"http://192.0.2.2:8710/manager/actions",
"http://10.10.10.2:8710/manager/actions",
),
(
"1C manager recovery",
"http://192.0.2.2:8710/manager/recovery",
"http://10.10.10.2:8710/manager/recovery",
),
(
"1C weekly digest",
"http://192.0.2.2:8710/manager/digest/weekly",
"http://10.10.10.2:8710/manager/digest/weekly",
),
] {
check_http_code(&mut counts, &http, name, url, &[200]);
@@ -345,39 +342,6 @@ fn check_http_code(counts: &mut Counts, client: &Client, name: &str, url: &str,
}
}
fn check_http_redirect(
counts: &mut Counts,
client: &Client,
name: &str,
url: &str,
expected: &[u16],
expected_location: Option<&str>,
) {
match client.head(url).send() {
Ok(response) => {
let code = response.status().as_u16();
let location = response
.headers()
.get(reqwest::header::LOCATION)
.and_then(|value| value.to_str().ok())
.unwrap_or("");
let location_ok = expected_location.is_none_or(|expected| location.contains(expected));
if expected.contains(&code) && location_ok {
counts.pass(format!(
"{name} HTTP {code} {}",
if location.is_empty() { url } else { location }
));
} else {
counts.fail(format!(
"{name} HTTP {code} {}",
if location.is_empty() { url } else { location }
));
}
}
Err(err) => counts.fail(format!("{name} HTTP error {url}: {err}")),
}
}
fn check_command(counts: &mut Counts, name: &str, cmd: &str, args: &[&str]) {
match command_output(cmd, args) {
Ok(out) => {
+12 -12
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
# Smoke checks for the Proxmox/gateway/1C host 192.0.2.2.
# Smoke checks for the Proxmox/gateway/1C host 10.10.10.2.
set -uo pipefail
@@ -193,25 +193,25 @@ section "Ports"
check_tcp "nginx http" 127.0.0.1 80
check_tcp "nginx https" 127.0.0.1 443
check_tcp "proxmox web" 127.0.0.1 8006
check_tcp "1C company API" 192.0.2.2 8710
check_tcp "1C company API" 10.10.10.2 8710
check_tcp "clickhouse native" 127.0.0.1 9000
check_tcp "clickhouse http" 127.0.0.1 8123
ss -tulpn | grep -E ':(80|443|8006|8710|8123|9000)\b' | sed 's/^/ /' || true
section "Gateway HTTP"
check_http_code "nginx healthz" "https://127.0.0.1/healthz" '^200$'
check_http_redirect "go proxmox gui" "https://127.0.0.1/go/proxmox-gui" '^30[1278]$' 'https://192.0.2.2:8006/'
check_http_redirect "go file1c brief" "https://127.0.0.1/go/file1c-brief" '^30[1278]$' 'http://192.0.2.2:8710/manager/brief'
check_http_redirect "go file1c actions" "https://127.0.0.1/go/file1c-actions" '^30[1278]$' 'http://192.0.2.2:8710/manager/actions'
check_http_code "go proxmox gui protected" "https://127.0.0.1/go/proxmox-gui" '^401$'
check_http_code "go file1c brief protected" "https://127.0.0.1/go/file1c-brief" '^401$'
check_http_code "go file1c actions protected" "https://127.0.0.1/go/file1c-actions" '^401$'
section "1C Company API"
check_http_code "1C root redirect" "http://192.0.2.2:8710/" '^307$'
check_http_code "1C /health" "http://192.0.2.2:8710/health" '^200$'
check_http_code "1C /api/health" "http://192.0.2.2:8710/api/health" '^200$'
check_http_code "1C manager brief" "http://192.0.2.2:8710/manager/brief" '^200$'
check_http_code "1C manager actions" "http://192.0.2.2:8710/manager/actions" '^200$'
check_http_code "1C manager recovery" "http://192.0.2.2:8710/manager/recovery" '^200$'
check_http_code "1C weekly digest" "http://192.0.2.2:8710/manager/digest/weekly" '^200$'
check_http_code "1C root redirect" "http://10.10.10.2:8710/" '^307$'
check_http_code "1C /health" "http://10.10.10.2:8710/health" '^200$'
check_http_code "1C /api/health" "http://10.10.10.2:8710/api/health" '^200$'
check_http_code "1C manager brief" "http://10.10.10.2:8710/manager/brief" '^200$'
check_http_code "1C manager actions" "http://10.10.10.2:8710/manager/actions" '^200$'
check_http_code "1C manager recovery" "http://10.10.10.2:8710/manager/recovery" '^200$'
check_http_code "1C weekly digest" "http://10.10.10.2:8710/manager/digest/weekly" '^200$'
section "ClickHouse"
check_docker_container "aw-rus-1c-clickhouse"
+57 -28
View File
@@ -19,24 +19,35 @@ ANSIBLE_DIR="$REPO_ROOT/ansible"
INVENTORY="${AW_SMOKE_INVENTORY:-$ANSIBLE_DIR/inventory.ini}"
REMOTE_SCRIPT_SRC="$REPO_ROOT/scripts/aw-contour-smoke-gateway.sh"
REMOTE_SCRIPT_DST="${AW_SMOKE_REMOTE_SCRIPT:-/usr/local/sbin/aw-contour-smoke.sh}"
REMOTE_RUST_SRC="${AW_SMOKE_REMOTE_RUST_SRC:-${CARGO_TARGET_DIR:-$REPO_ROOT/adk-rust/target}/release/aw-contour-smoke}"
DEFAULT_REMOTE_RUST_SRC=""
for rust_candidate in \
"${CARGO_TARGET_DIR:-}/release/aw-contour-smoke" \
"$HOME/.cache/detmir-adk-rust-target/release/aw-contour-smoke" \
"$REPO_ROOT/adk-rust/target/release/aw-contour-smoke"
do
if [ -n "$rust_candidate" ] && [ -x "$rust_candidate" ]; then
DEFAULT_REMOTE_RUST_SRC="$rust_candidate"
break
fi
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://192.0.2.13:5600}"
WORKTIME_API="${AW_SMOKE_WORKTIME_API:-http://192.0.2.13:5610}"
GRAFANA_URL="${AW_SMOKE_GRAFANA_URL:-http://192.0.2.11:3000}"
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}"
GRAFANA_USER="${GRAFANA_USER:-igor}"
GRAFANA_PASSWORD="${GRAFANA_PASSWORD:-}"
PROXMOX_HOST="${AW_SMOKE_PROXMOX_HOST:-192.0.2.2}"
AW_HOST="${AW_SMOKE_AW_HOST:-192.0.2.13}"
GRAFANA_HOST="${AW_SMOKE_GRAFANA_HOST:-192.0.2.11}"
WINDOWS_HOST="${AW_SMOKE_WINDOWS_HOST:-198.51.100.18}"
AW_SOURCE_HOSTNAME="${AW_SMOKE_SOURCE_HOSTNAME:-HOST-EXAMPLE}"
PROXMOX_HOST="${AW_SMOKE_PROXMOX_HOST:-10.10.10.2}"
AW_HOST="${AW_SMOKE_AW_HOST:-10.10.10.13}"
GRAFANA_HOST="${AW_SMOKE_GRAFANA_HOST:-10.10.10.11}"
WINDOWS_HOST="${AW_SMOKE_WINDOWS_HOST:-192.168.100.18}"
AW_SOURCE_HOSTNAME="${AW_SMOKE_SOURCE_HOSTNAME:-SHARKON2025}"
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}"
NO_PROXY_REQUIRED="localhost,127.0.0.1,$PROXMOX_HOST,$AW_HOST,$GRAFANA_HOST,$WINDOWS_HOST,192.0.2.0/24,198.51.100.0/24"
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
export no_proxy="$no_proxy,$NO_PROXY_REQUIRED"
else
@@ -72,10 +83,10 @@ usage() {
Usage: $(basename "$0") [--skip-remote] [--skip-winrm] [--skip-server-systemd]
Environment overrides:
AW_SMOKE_AW_SERVER=http://192.0.2.13:5600
AW_SMOKE_WORKTIME_API=http://192.0.2.13:5610
AW_SMOKE_GRAFANA_URL=http://192.0.2.11:3000
AW_SMOKE_SOURCE_HOSTNAME=HOST-EXAMPLE
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_SMOKE_SOURCE_HOSTNAME=SHARKON2025
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
@@ -249,19 +260,36 @@ check_grafana_influx_health() {
}
check_grafana_aw_main_dashboard_queries() {
local name="Grafana detmir-aw-main window/AFK panel queries"
local name="Grafana detmir-aw-main worktime panel queries"
local tmp
tmp="$(mktemp)"
if curl -k -fsS -u "$GRAFANA_USER:$GRAFANA_PASSWORD" --connect-timeout 5 --max-time 20 "$GRAFANA_URL/api/dashboards/uid/detmir-aw-main" -o "$tmp" 2>"$tmp.err" && \
jq -e '
def fixed:
(.targets[0].query // "") | contains("keep(columns: [\"_time\", \"_value\", \"host\"]");
([.dashboard.panels[] | select(.title == "Активность окон (сумма за 5 минут)" or .title == "AFK (сумма за 5 минут)") | fixed] | length == 2 and all(. == true))
def query: (.targets[0].query // "");
def has_panel($title; $checks):
any(.dashboard.panels[]?; .title == $title and (query as $q | all($checks[]; $q | contains(.))));
has_panel("Активность RDP по часам"; [
"aw_rdp_worktime_hourly",
"r.user_id !~ /\\$$/",
"r.user_id !~ //",
"group(columns: [\"_time\", \"user\"])",
"max(column: \"_value\")"
]) and
has_panel("Сегодня: активность по сотрудникам"; [
"aw_rdp_worktime_daily",
"group(columns: [\"report_date\", \"user\"])",
"max(column: \"_value\")",
"last()"
]) and
has_panel("Все сотрудники: активное время по дням"; [
"aw_rdp_worktime_summary_daily",
"Все сотрудники, ч"
])
' "$tmp" >/dev/null 2>&1; then
pass "$name"
else
fail "$name missing keep(_time,_value,host) after aggregateWindow"
jq -r '.dashboard.panels[]? | select(.title == "Активность окон (сумма за 5 минут)" or .title == "AFK (сумма за 5 минут)") | "\(.title): " + ((.targets[0].query // "") | gsub("\n"; " "))' "$tmp" 2>/dev/null | sed 's/^/ /' | head -20
fail "$name missing expected DetMir worktime/dedupe query contract"
jq -r '.dashboard.panels[]? | select(.title == "Активность RDP по часам" or .title == "Сегодня: активность по сотрудникам" or .title == "Все сотрудники: активное время по дням") | "\(.title): " + ((.targets[0].query // "") | gsub("\n"; " "))' "$tmp" 2>/dev/null | sed 's/^/ /' | head -20
sed 's/^/ /' "$tmp.err" 2>/dev/null | head -20
fi
rm -f "$tmp" "$tmp.err"
@@ -436,7 +464,7 @@ check_bucket_freshness() {
run_remote_proxmox_script() {
if [ "$RUN_REMOTE" != "1" ]; then
skip "remote 192.0.2.2 smoke skipped"
skip "remote 10.10.10.2 smoke skipped"
return
fi
if ! have ansible; then
@@ -448,7 +476,7 @@ run_remote_proxmox_script() {
return
fi
section "Deploy Remote Script To 192.0.2.2"
section "Deploy Remote Script To 10.10.10.2"
if [ -x "$REMOTE_RUST_SRC" ]; then
if ANSIBLE_NOCOLOR=1 ansible proxmox -i "$INVENTORY" -m copy -a "src=$REMOTE_RUST_SRC dest=$REMOTE_RUST_DST owner=root group=root mode=0755" >/tmp/aw-smoke-copy-rust.$$ 2>&1; then
pass "remote Rust smoke deployed to $REMOTE_RUST_DST"
@@ -471,14 +499,14 @@ run_remote_proxmox_script() {
fi
rm -f /tmp/aw-smoke-copy.$$
section "Remote 192.0.2.2 Smoke"
section "Remote 10.10.10.2 Smoke"
local tmp
tmp="$(mktemp)"
if ANSIBLE_NOCOLOR=1 ansible proxmox -i "$INVENTORY" -m shell -a "$REMOTE_SCRIPT_DST" >"$tmp" 2>&1; then
pass "remote 192.0.2.2 smoke completed"
pass "remote 10.10.10.2 smoke completed"
sed 's/^/ /' "$tmp"
else
fail "remote 192.0.2.2 smoke failed"
fail "remote 10.10.10.2 smoke failed"
sed 's/^/ /' "$tmp"
fi
rm -f "$tmp"
@@ -544,8 +572,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_redirect "gateway proxmox redirect" "https://$PROXMOX_HOST/go/proxmox-gui" '^30[1278]$' "https://$PROXMOX_HOST:8006/"
check_http_redirect "gateway file1c brief redirect" "https://$PROXMOX_HOST/go/file1c-brief" '^30[1278]$' "http://$PROXMOX_HOST:8710/manager/brief"
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 "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$'
@@ -582,7 +611,7 @@ if [ "$RUN_WINRM" = "1" ] && have ansible; then
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; schtasks /Query /TN "ActivityWatch Launch [HOST-EXAMPLE_Администратор]" /FO LIST /V'
check_ansible_win_shell "Windows ActivityWatch tasks" aw_windows 'schtasks /Query /TN "ActivityWatch Recovery" /FO LIST /V; schtasks /Query /TN "ActivityWatch Launch [SHARKON2025_Администратор]" /FO LIST /V'
else
skip "Windows WinRM checks skipped"
fi