feat(detmir): ship ops, dlp, 1c and mcp updates

This commit is contained in:
igor04091968
2026-05-27 05:56:43 +03:00
parent 033ae810f3
commit 3042bd5042
85 changed files with 12028 additions and 460 deletions
+103 -12
View File
@@ -4,7 +4,15 @@ set -euo pipefail
AW_URL="${AW_URL:-http://127.0.0.1:5600}"
HOST="${AW_WORKTIME_HOST:-SHARKON2025}"
PYTHON_BIN="${PYTHON_BIN:-/usr/bin/python3}"
WORKTIME_REPORT_URL="${WORKTIME_REPORT_URL:-http://127.0.0.1:5610/reports/worktime/today?format=csv}"
WORKTIME_HEALTH_URL="${WORKTIME_HEALTH_URL:-http://127.0.0.1:5610/health}"
WORKTIME_REPORT_TIMEOUT_SECONDS="${WORKTIME_REPORT_TIMEOUT_SECONDS:-20}"
WORKTIME_MANAGEMENT_WARM_ENABLED="${WORKTIME_MANAGEMENT_WARM_ENABLED:-1}"
WORKTIME_MANAGEMENT_WARM_URL="${WORKTIME_MANAGEMENT_WARM_URL:-http://127.0.0.1:5610/reports/worktime/management?day=today&format=json}"
WORKTIME_MANAGEMENT_WARM_TIMEOUT_SECONDS="${WORKTIME_MANAGEMENT_WARM_TIMEOUT_SECONDS:-25}"
WORKTIME_TODAY_PROBE_ENABLED="${WORKTIME_TODAY_PROBE_ENABLED:-1}"
WORKTIME_TODAY_PROBE_URL="${WORKTIME_TODAY_PROBE_URL:-http://127.0.0.1:5610/reports/worktime/today?day=today&format=json}"
WORKTIME_TODAY_PROBE_TIMEOUT_SECONDS="${WORKTIME_TODAY_PROBE_TIMEOUT_SECONDS:-20}"
WORKTIME_SESSION_FRESHNESS_SECONDS="${WORKTIME_SESSION_FRESHNESS_SECONDS:-600}"
LOG_TAG="aw-worktime-autoheal"
log() {
@@ -12,38 +20,116 @@ log() {
printf '%s %s\n' "$(date '+%F %T')" "$*"
}
if ! curl -fsS --max-time 8 "$WORKTIME_REPORT_URL" >/dev/null 2>&1; then
log "worktime API check failed, restarting aw-worktime-api.service"
probe_url() {
local url="$1"
local timeout="$2"
curl -fsS --max-time "$timeout" "$url" >/dev/null 2>&1
}
probe_reports() {
probe_url "$WORKTIME_HEALTH_URL" "$WORKTIME_REPORT_TIMEOUT_SECONDS" || return 1
probe_url "$WORKTIME_MANAGEMENT_WARM_URL" "$WORKTIME_MANAGEMENT_WARM_TIMEOUT_SECONDS" || return 1
if [[ "$WORKTIME_TODAY_PROBE_ENABLED" == "1" ]]; then
probe_url "$WORKTIME_TODAY_PROBE_URL" "$WORKTIME_TODAY_PROBE_TIMEOUT_SECONDS" || return 1
fi
}
worktime_ok=1
if ! probe_reports; then
log "worktime API probe failed, restarting aw-worktime-api.service"
systemctl restart aw-worktime-api.service || true
sleep 2
if ! curl -fsS --max-time 8 "$WORKTIME_REPORT_URL" >/dev/null 2>&1; then
log "worktime API still unavailable after restart"
if ! probe_reports; then
log "worktime API still degraded after restart"
worktime_ok=0
else
log "worktime API recovered after restart"
fi
fi
if [[ "$worktime_ok" != "1" ]]; then
log "skip warm/heal because worktime API is still unavailable"
exit 0
fi
if [[ "$WORKTIME_MANAGEMENT_WARM_ENABLED" == "1" ]]; then
if probe_url "$WORKTIME_MANAGEMENT_WARM_URL" "$WORKTIME_MANAGEMENT_WARM_TIMEOUT_SECONDS"; then
log "management cache warm ok"
else
log "management cache warm failed"
fi
fi
need_heal="$("$PYTHON_BIN" - <<'PY'
import json, urllib.request, datetime, os, sys
AW=os.environ.get("AW_URL","http://127.0.0.1:5600")
host=os.environ.get("HOST","SHARKON2025")
bucket=f"aw-rdp-window_{host}"
window_bucket=f"aw-rdp-window_{host}"
session_bucket=f"aw-worktime-sessions_{host}"
freshness=int(os.environ.get("WORKTIME_SESSION_FRESHNESS_SECONDS","600"))
msk=datetime.timezone(datetime.timedelta(hours=3))
start=datetime.datetime.now(msk).replace(hour=0,minute=0,second=0,microsecond=0).astimezone(datetime.timezone.utc)
now=datetime.datetime.now(datetime.timezone.utc)
def p(ts):
if ts.endswith("Z"): ts=ts[:-1] + "+00:00"
return datetime.datetime.fromisoformat(ts).astimezone(datetime.timezone.utc)
def is_active(d):
if isinstance(d.get("active"), bool) and d.get("active"):
return True
st=str(d.get("state","")).strip().lower()
if st in ("active","активно"):
return True
if st == "unknown":
try:
sid=int(d.get("sessionId"))
except Exception:
sid=-1
u=str(d.get("username","")).strip().lower()
sn=str(d.get("sessionName","")).strip().lower()
if sid > 0 and u and (not u.endswith("$")) and (sn.startswith("rdp-") or sn == "console"):
return True
return False
try:
with urllib.request.urlopen(f"{AW}/api/0/buckets/{bucket}/events?limit=12000", timeout=25) as r:
ev=json.loads(r.read().decode("utf-8"))
with urllib.request.urlopen(f"{AW}/api/0/buckets/{window_bucket}/events?limit=12000", timeout=25) as r:
window_events=json.loads(r.read().decode("utf-8"))
with urllib.request.urlopen(f"{AW}/api/0/buckets/{session_bucket}/events?limit=12000", timeout=25) as r:
session_events=json.loads(r.read().decode("utf-8"))
except Exception:
print("1")
sys.exit(0)
latest_ts=None
active_users=set()
for e in session_events:
ts=e.get("timestamp")
if not ts:
continue
try:
cur=p(ts)
except Exception:
continue
if latest_ts is None or cur > latest_ts:
latest_ts=cur
active_users.clear()
if cur == latest_ts:
d=e.get("data") or {}
u=str(d.get("username","")).strip()
if u and is_active(d):
active_users.add(u)
if latest_ts is None or (now - latest_ts).total_seconds() > freshness:
print("0")
sys.exit(0)
if not active_users:
print("0")
sys.exit(0)
active=0.0
for e in ev:
for e in window_events:
ts=e.get("timestamp")
if not ts:
continue
@@ -85,9 +171,14 @@ def req(method,path,payload=None):
if payload is not None:
data=json.dumps(payload,ensure_ascii=False).encode("utf-8"); headers["Content-Type"]="application/json"
r=urllib.request.Request(AW+path,data=data,headers=headers,method=method)
with urllib.request.urlopen(r,timeout=30) as resp:
body=resp.read()
return json.loads(body.decode("utf-8")) if body else None
try:
with urllib.request.urlopen(r,timeout=30) as resp:
body=resp.read()
return json.loads(body.decode("utf-8")) if body else None
except urllib.error.HTTPError as e:
if e.code in (304, 409):
return None
raise
def reset_bucket(bucket_id, event_type, client, hostname):
try: