{"id":34837263,"url":"https://github.com/arenadata/ad-status-sender","last_synced_at":"2026-05-24T17:05:33.197Z","repository":{"id":323547440,"uuid":"1093694605","full_name":"arenadata/ad-status-sender","owner":"arenadata","description":null,"archived":false,"fork":false,"pushed_at":"2025-11-10T18:32:25.000Z","size":32,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-11-10T20:26:28.312Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/arenadata.png","metadata":{"files":{"readme":"README.MD","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-11-10T18:01:02.000Z","updated_at":"2025-11-10T18:32:29.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/arenadata/ad-status-sender","commit_stats":null,"previous_names":["arenadata/ad-status-sender"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/arenadata/ad-status-sender","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arenadata%2Fad-status-sender","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arenadata%2Fad-status-sender/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arenadata%2Fad-status-sender/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arenadata%2Fad-status-sender/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/arenadata","download_url":"https://codeload.github.com/arenadata/ad-status-sender/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arenadata%2Fad-status-sender/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28032396,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-25T02:00:05.988Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-12-25T16:08:39.382Z","updated_at":"2025-12-25T16:10:18.274Z","avatar_url":"https://github.com/arenadata.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ad-status-sender\n\nA lightweight Go agent that runs **on every host**, collects local statuses (systemd units and Docker container groups), and **asynchronously posts** them to an ADCM-compatible endpoint. It also sends a host heartbeat. Supports **1→m** (one unit → many components) and **m↔n** (a component can be reported by multiple rules).\n\n---\n\n## Features\n\n- Single `config.yaml` + single `rules.yaml`.\n- **Hot reload** of rules via `fsnotify` (no restart or signals).\n- **Hot reload** of config on **SIGHUP**.\n- **Status cache** + **forced re-send** at configurable interval (`force_send_after`, default **120s**) so the ADCM doesn’t mark entities as stale.\n- **TLS/HTTPS**: custom CA, mTLS (client cert/key), `server_name` override, `insecure_skip_verify`.\n- Token from YAML, **token file**, or **systemd credentials**.\n- Worker pool, stable HTTP timeouts.\n\n---\n\n## Requirements\n\n- Go **≥ 1.24**\n- systemd **with D-Bus available** (for systemd checks)\n- Docker (for Docker checks)\n\n---\n\n## Run (manually)\n\n```bash\nad-status-sender -config /etc/ad-status-sender/config.yaml\n```\n\n---\n\n## Configuration (`config.yaml`)\n\n```yaml\nadcm_url: \"https://adcm.example.com\"\nhost_id: 101\n\n# token (prefer file or systemd-credentials)\ntoken_file: \"/etc/secure/adcm.token\"\n\n# path to rules (auto hot-reload)\nrules_path: \"/etc/ad-status-sender/rules.yaml\"\n\n# intervals \u0026 timeouts\ninterval: \"5s\"            # how often to probe local system\nhttp_timeout: \"5s\"        # HTTP client timeout\nforce_send_after: \"120s\"  # re-send even if unchanged\n\n# performance\nconcurrency: 0            # 0 = NumCPU\n\n# log server response bodies (useful for debugging)\nlog_bodies: false\n\n# TLS (only if adcm_url is https://)\ntls:\n  ca_file: \"/etc/pki/ca-trust/source/anchors/adcm-root.pem\"  # optional\n  cert_file: \"/etc/ad-status-sender/client.crt\"               # optional (mTLS)\n  key_file: \"/etc/ad-status-sender/client.key\"                # optional (mTLS)\n  server_name: \"adcm.internal\"                                # optional (SNI/verify override)\n  insecure_skip_verify: false                                 \n```\n\n\u003e You can put the token directly in YAML (`token:`), but **using `token_file` or systemd credentials is recommended**.\n\n---\n\n## Rules (`rules.yaml`)\n\nDescribe what to check locally and which **component_id(s)** to report.\n\n```yaml\nsystemd:\n  - unit: \"nginx.service\"\n    components: [\"501\",\"502\"]                 # one unit → many components\n  - unit_glob: \"hbase-regionserver@*.service\" # glob expansion\n    components: [\"202\",\"203\"]\n\ndocker:\n  - name: \"webstack\"                          # group name (arbitrary)\n    components: [\"201\",\"202\"]\n    containers:\n      names: [\"nginx\",\"redis:cluster-a\"]      # explicit container names\n\n  - name: \"etl-by-labels\"\n    components: [\"301\"]\n    containers:\n      labels: [\"app=etl\",\"stage=prod\"]        # label selector\n```\n\n### Status semantics\n\n- **systemd**: queried via systemd **D-Bus** (`go-systemd/dbus`).  \n  Returns **0** if the unit’s `ActiveState == \"active\"`, otherwise **1** (including “unit not found”).\n  \n- **docker**:\n  - `names`: **0** if **all** listed containers are `running`, else **1**.\n  - `labels`: **0** if it finds **at least one** container by labels **and all found** are `running`, else **1**.\n\n- **host heartbeat**: POST `/status/api/v1/host/{host_id}/` with `{\"status\":0}` each cycle.\n\n### Guaranteed resends\n\nThe agent caches last sent status per key:\n- `host:{host_id}`\n- `comp:{host_id}:{component_id}`\n\nIt sends **only if**:\n- status **changed**, or\n- at least `force_send_after` elapsed since last send (default 120s).\n\nThis prevents the receiver from marking entities stale when nothing changes.\n\n---\n\n## How it works\n\nEach `interval`:\n1) Expands `unit_glob` via systemd **D-Bus** (`ListUnitsByPatterns`) and checks each unit’s `ActiveState`.\n2) Checks Docker groups (by `names` or `labels`).\n3) Sends host heartbeat.\n\n**Hot reload**:\n- `rules.yaml` is automatically reloaded via `fsnotify`.\n- `config.yaml` is reloaded on **SIGHUP** (e.g., `systemctl reload ad-status-sender`).\n\nHTTP client:\n- Connection pool, timeouts, TLS 1.2+, optional custom CA \u0026 mTLS.\n\n\n---\n\n## Logging\n\nStructured logs via `log/slog` to stdout.  \nIf `log_bodies: true`, the agent logs server response bodies (useful for debugging).\n\n---\n\n## Build\n\nLocal (snapshot) build:\n```bash\ngoreleaser release --snapshot --clean\n```\n\n---\n\n## Lint\n\nWe target strict settings:\n\n```bash\ngolangci-lint run\n```\n\n---\n\n## Tips\n\n- For self-signed ADCM certs, use `tls.ca_file`.\n- For mTLS, set both `tls.cert_file` and `tls.key_file`.\n- If Docker label selection finds **no** containers, status is **1** (not OK).\n- A component can appear in multiple rules — the agent will post all related statuses.\n\n---\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farenadata%2Fad-status-sender","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Farenadata%2Fad-status-sender","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farenadata%2Fad-status-sender/lists"}