diff --git a/butane/monitor.yaml b/butane/monitor.yaml index 623215b..0734782 100644 --- a/butane/monitor.yaml +++ b/butane/monitor.yaml @@ -4,8 +4,8 @@ version: 1.0.0 # Dozzle log viewer hub. # # Aggregates container logs from the dozzle agents running on the other Flatcar -# VMs (see butane/oswl_connector.yaml.tftpl) and, via the local socket, from -# this host's own containers. Reachable at http://192.168.7.63:8080. +# VMs (see the dozzle-agent units in the other butane configs) and, via the +# local socket, from this host's own containers. Reachable on :8080. # # No state is kept on disk: /data is a tmpfs, so the container is fully # disposable and there is nothing to back up. That is also why simple auth @@ -13,8 +13,9 @@ version: 1.0.0 # # Hub <-> agent traffic is TLS, using the certificate pair baked into the # dozzle image. Every hub and agent on the same image version shares it, so -# nothing needs mounting here. To move to a custom pair later, generate one -# with (do not run as root, writes into $PWD): +# nothing needs mounting here -- which is also why the agents must stay pinned +# to the same tag as the hub. To move to a custom pair later, generate one +# with (writes into $PWD): # # docker run --rm -v "$PWD":/out amir20/dozzle:v11.1.1 generate-certs \ # --cert-out /out/dozzle_cert.pem --key-out /out/dozzle_key.pem @@ -34,20 +35,69 @@ systemd: Requires=docker.service [Service] TimeoutStartSec=0 + # Kept as unit environment rather than inline -e values so that + # wait-for-agents.sh can read the agent list from the same place the + # container does. docker run forwards them by bare name below. + Environment="DOZZLE_HOSTNAME=Oswald Logs" + Environment="DOZZLE_ENABLE_MCP=true" + Environment="DOZZLE_REMOTE_AGENT=192.168.7.60:7007|oswald-runner|Goose,192.168.7.61:7007|ai|Goose,192.168.7.62:7007|oswl-connector|Goose" # Pulled up front so a slow first pull is not mistaken for a hung unit. ExecStartPre=/usr/bin/docker pull amir20/dozzle:v11.1.1 # Leading "-" so a missing container is not a failure. ExecStartPre=-/usr/bin/docker rm --force dozzle + # If the hub starts before the agents are listening, the failed initial + # handshake leaves a permanently-offline placeholder host in the UI + # alongside the real one once it connects. Bounded and "-" prefixed, so + # an agent that is genuinely gone delays the hub but never blocks it. + ExecStartPre=-/usr/bin/timeout 180 /opt/dozzle/wait-for-agents.sh # Foreground (no -d) so systemd supervises the container process. ExecStart=/usr/bin/docker run --rm --name dozzle \ -v /var/run/docker.sock:/var/run/docker.sock:ro \ --tmpfs /data \ -p 8080:8080 \ - -e "DOZZLE_HOSTNAME=Oswald Logs" \ - -e "DOZZLE_REMOTE_AGENT=192.168.7.60:7007|oswald-runner|Infra,192.168.7.61:7007|ai|Infra,192.168.7.62:7007|oswl-connector|Infra" \ + -e DOZZLE_HOSTNAME \ + -e DOZZLE_ENABLE_MCP \ + -e DOZZLE_REMOTE_AGENT \ amir20/dozzle:v11.1.1 ExecStop=/usr/bin/docker stop dozzle Restart=always RestartSec=5s [Install] WantedBy=multi-user.target + +storage: + files: + # Blocks until every agent named in DOZZLE_REMOTE_AGENT accepts a TCP + # connection. The list is read from the environment, so adding or removing + # an agent above needs no change here. + - path: /opt/dozzle/wait-for-agents.sh + mode: 0755 + contents: + inline: | + #!/usr/bin/bash + # Note: /dev/tcp is unavailable -- Flatcar's bash is built without + # net redirections -- so reachability is probed with curl. The agent + # speaks gRPC over TLS, so any completed connection answers with a + # protocol error; only exit 7 (refused) and 28 (timeout) mean the + # agent is not up yet. + if [ -z "$DOZZLE_REMOTE_AGENT" ]; then + exit 0 + fi + + for entry in $(echo "$DOZZLE_REMOTE_AGENT" | tr ',' ' '); do + # Strip the |name|group suffix; what is left is host:port. + hostport=$(echo "$entry" | cut -d'|' -f1) + while true; do + curl -sk -o /dev/null --max-time 3 "https://$hostport" + rc=$? + case "$rc" in + 7|28) + echo "waiting for dozzle agent $hostport" + sleep 2 + ;; + *) + break + ;; + esac + done + done