CHAT_OUTPUT_BEGIN
COMMAND_ID=SUPPORT-260919-HOME-GRAM1-EDGE-HEALTH-EXECSTART-RCA-READONLY-580R1
STATUS=OK
RC=0
HOST=pve01
MODE=read-only
COMPONENT=home-gram1-edge-health-execstart-rca-readonly
REFERENCE_REGISTER_CHECK=OK
REFERENCE_SHA256=5a3d8e5154c41cb582a4e0aca68090be1f0138918bf82131a948df326f9d8d66
ERROR_REGISTER_CHECK=OK
ERROR_REGISTER_SHA256=3b09a553ec0f527ed3afeed4753f52a74ee3036045bbfb3c685e9f8af4ba7ba0
COMMAND_SHA256=b54be6889c67c56a364b9db78a4733f57e9559aaba8a3150f703b46d103162cb
DUPLICATE_FAILED_COMMAND_BLOCKED=false
EXECUTION_STARTED=true
CHANGE_DECLARED=false
RESULT_CONTRACT_VALID=true
RESULT_CONTRACT_STATUS=NOT_APPLICABLE
RESULT_CONTRACT_ERROR=NONE
COMMAND_RC=0
CHANGES_MADE=false
ROLLBACK_STARTED=false
ROLLBACK_RESTORED=null
MUTATION_OUTCOME=NO_MUTATION
SANITIZED=yes
SECRETS_INCLUDED=no
PRIVATE_ADDRESSES_INCLUDED=no
RAW_EVIDENCE_SHA256=9ef50dd89f2a7f3f727c26804c4c668b415eb1a0021208e8028c61e40e130ff1
SANITIZED_OUTPUT_SHA256=bb9329225da751ed6bf84a8199846f44b2be424f678370b813bec5e66a138dda
OUTPUT_BEGIN
ERROR_REGISTER_CHECK=OK
REFERENCE_CHECK=OK
EDGE130_RC=0
EDGE130_BEGIN
{
   "exitcode" : 0,
   "exited" : 1,
   "out-data" : "HOST=edge-vm\nFILE=/usr/local/sbin/homelab-router-moscow-health-http|exists=True|exec=True\nSHA=/usr/local/sbin/homelab-router-moscow-health-http|c1cd98bed29ed7cc83aad30f5b6d9afcfbd721f954f46f38fe6008a0a2db2df2|size=781\nROUTE_MARKERS=/usr/local/sbin/homelab-router-moscow-health-http|backup=False|npmplus=False|router=False\nHEAD=/usr/local/sbin/homelab-router-moscow-health-http\n#!/usr/bin/env python3\nfrom http.server import BaseHTTPRequestHandler, HTTPServer\nimport socket\nTARGET = (\"[PRIVATE_IP]\", 5080)\nclass H(BaseHTTPRequestHandler):\n    def log_message(self, *args):\n        return\n    def do_GET(self):\n        ok = False\n        try:\n            with socket.create_connection(TARGET, 3):\n                ok = True\n        except Exception:\n            ok = False\n        code = 200 if ok else 503\n        body = (\"OK router_moscow_tcp_5080\\n\" if ok else \"FAIL router_moscow_tcp_5080\\n\").encode()\n        self.send_response(code)\n        self.send_header(\"Content-Type\", \"text/plain\")\n        self.send_header(\"Content-Length\", str(len(body)))\n        self.end_headers()\n        self.wfile.write(body)\nHTTPServer((\"0.0.0.0\", 18083), H).serve_forever()\nFILE=/usr/local/sbin/router-moscow-health|exists=True|exec=True\nSHA=/usr/local/sbin/router-moscow-health|ccf25de98494625cd88015411c82c9be2d4349970d6d4c6c353c45f787225225|size=6704\nROUTE_MARKERS=/usr/local/sbin/router-moscow-health|backup=False|npmplus=True|router=True\nHEAD=/usr/local/sbin/router-moscow-health\n#!/usr/bin/env python3\nimport json\nimport socket\nimport ssl\nimport subprocess\nimport time\nimport urllib.error\nimport urllib.request\nfrom http.server import BaseHTTPRequestHandler, HTTPServer\n\nHOST = \"[PRIVATE_IP]\"\nPORT = 18091\n\ndef tcp(host, port, timeout=3):\n    try:\n        with socket.create_connection((host, int(port)), timeout=timeout):\n            return True\n    except Exception:\n        return False\n\ndef docker_running(name):\n    try:\n        out = subprocess.check_output([\"docker\", \"inspect\", \"-f\", \"{{.State.Running}}\", name], text=True, timeout=5)\n        return out.strip() == \"true\"\n    except Exception:\n        return False\n\ndef http_probe(url, timeout=5, ok_statuses=None, accept_2xx_4xx=False):\n    result = {\"url\": url, \"ok\": False, \"reachable\": False, \"status\": None, \"error\": None}\n    try:\n        ctx = ssl._create_unverified_context()\n        req = urllib.request.Request(url, headers={\"User-Agent\": \"homelab-health/1.0\"})\n        try:\n            with urllib.request.urlopen(req, timeout=timeout, context=ctx) as r:\n                result[\"status\"] = int(getattr(r, \"status\", 0) or 0)\n                result[\"reachable\"] = True\n        except urllib.error.HTTPError as e:\n            result[\"status\"] = int(e.code)\n            result[\"reachable\"] = True\n\n        status = int(result[\"status\"] or 0)\n        if ok_statuses is not None:\n            result[\"ok\"] = status in set(ok_statuses)\n        elif accept_2xx_4xx:\n            result[\"ok\"] = 200 <= status < 500\n        else:\n            result[\"ok\"] = 200 <= status < 400\n    except Exception as e:\n        result[\"error\"] = type(e).__name__ + \": \" + str(e)[:160]\n    return result\n\ndef response(service, ok, checks, note=\"\"):\n    return {\"service\": service, \"ok\": bool(ok), \"checks\": checks, \"note\": note, \"ts\": int(time.time())}\n\ndef router_status():\n    checks = {\n        \"lan_http_5080\": http_probe(\"http://[PRIVATE_IP]:5080/\", accept_2xx_4xx=True),\n        \"lan_https_5083\": http_probe(\"https://[PRIVATE_IP]:5083/\", accept_2xx_4xx=True),\n        \"public_https_5083\": http_probe(\"https://aleisaevn.netcraze.pro:5083/\", accept_2xx_4xx=True),\n        \"tcp_egress_1_1_1_1_443\": {\"ok\": tcp(\"1.1.1.1\", 443), \"host\": \"1.1.1.1\", \"port\": 443},\n    }\n    ok = checks[\"lan_http_5080\"][\"ok\"] or checks[\"lan_https_5083\"][\"ok\"] or checks[\"public_https_5083\"][\"ok\"]\n    return response(\"router-moscow-health\", ok, checks, \"HTTP 401/403 from router UI is accepted as reachable.\")\n\ndef npmplus_status():\n    checks = {\n        \"container_running\": {\"ok\": docker_running(\"npmplus\")},\n        \"tcp_127_0_0_1_80\": {\"ok\": tcp(\"127.0.0.1\", 80)},\n        \"tcp_127_0_0_1_443\": {\"ok\": tcp(\"127.0.0.1\", 443)},\n        \"tcp_127_0_0_1_81\": {\"ok\": tcp(\"127.0.0.1\", 81)},\n    }\n    return response(\"npmplus-health\", all(v.get(\"ok\") for v in checks.values()), checks)\n\ndef loki_status():\n    checks = {\n        \"container_running\": {\"ok\": docker_running(\"loki\")},\n        \"ready\": http_probe(\"http://127.0.0.1:3100/ready\", ok_statuses={200}),\n    }\n    return response(\"loki-health\", checks[\"container_running\"][\"ok\"] and checks[\"ready\"][\"ok\"], checks)\n\nSYSTEMCTL_STATUS_RC=0\nSYSTEMCTL_STATUS_BEGIN\nâ homelab-router-moscow-health-http.service - Homelab Moscow router HTTP health endpoint\n     Loaded: loaded (/etc/systemd/system/homelab-router-moscow-health-http.service; enabled; preset: enabled)\n     Active: active (running) since Sat 2026-09-19 02:11:51 MSK; 4min 9s ago\n Invocation: ce51eceb072440f2b90b98b2f2f3991e\n   Main PID: 3546764 (python3)\n      Tasks: 1 (limit: 14331)\n     Memory: 8.5M (peak: 8.7M)\n        CPU: 86ms\n     CGroup: /system.slice/homelab-router-moscow-health-http.service\n             ââ3546764 python3 /usr/local/sbin/homelab-router-moscow-health-http\n\nSep 19 02:11:51 edge-vm systemd[1]: Started homelab-router-moscow-health-http.service - Homelab Moscow router HTTP health endpoint.\n\nSYSTEMCTL_STATUS_END\nLISTEN_18091_RC=0\nLISTEN_18091_BEGIN\nLISTEN 0      5      [PRIVATE_IP]:18091 0.0.0.0:* users:((\"python3\",pid=723,fd=3))\n\nLISTEN_18091_END\nPID=3546764\nPROC_CMDLINE=python3 /usr/local/sbin/homelab-router-moscow-health-http \nPROC_EXE=/usr/bin/python3.13\nPROC_CWD=/\nLISTENER_ADDR_COUNT=1\nLISTENER_PROBE=http://[PRIVATE_IP]:18091/npmplus|RC=0|RESULT=200|[PRIVATE_IP]|http://[PRIVATE_IP]:18091/npmplus|ERR=\nLISTENER_PROBE=http://[PRIVATE_IP]:18091/router-moscow|RC=28|RESULT=000|[PRIVATE_IP]|http://[PRIVATE_IP]:18091/router-moscow|ERR=curl: (28) Operation timed out after 5002 milliseconds with 0 bytes received \nEDGE580_END\n",
   "out-truncated" : 0
}

EDGE130_END
HOME580R1_DECISION=EXECSTART_AND_LISTENER_RCA_COMPLETE
HOME580R1_NEXT_GATE=PATCH_ACTUAL_EDGE_HEALTH_EXECUTABLE_OR_VALIDATE_CORRECT_BIND
HOMELAB_RESULT_CONTRACT={"version":1,"command_id":"SUPPORT-260919-HOME-GRAM1-EDGE-HEALTH-EXECSTART-RCA-READONLY-580R1","status":"OK","changes_made":false,"rollback_started":false,"rollback_restored":null}

OUTPUT_END
CHAT_OUTPUT_END
