fix(smoke): align contour checks with production routes
This commit is contained in:
@@ -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) => {
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user