Daemon for Cloud VMs. Watches a metadata key containing an Ansible playbook (YAML) and runs it whenever the value changes, using the wait_for_change long-polling API.
- On start, fetches the current metadata value and runs the playbook if it differs from saved state.
- Enters a long-poll loop — the metadata server holds the connection until the value changes.
- On change, writes the YAML to a temp file and calls
ansible-playbook. - Saves state (value + ETag) to disk so restarts don't re-run an unchanged playbook.
cargo install cargo-deb
cargo build --release
cargo deb
dpkg -i target/debian/metadata-watcher_*.debUsage: metadata-watcher [OPTIONS]
Options:
-k, --metadata-key <METADATA_KEY> Metadata key path to watch (relative to /computeMetadata/v1/). The value must be a valid Ansible playbook YAML [env: WATCHER_KEY=] [default: instance/attributes/playbook]
-t, --timeout <TIMEOUT> Timeout in seconds: used both for the HTTP socket and as wait_for_change timeout_sec [env: WATCHER_TIMEOUT=] [default: 60]
--ansible-bin <ANSIBLE_BIN> Path to ansible-playbook binary [env: WATCHER_ANSIBLE_BIN=] [default: ansible-playbook]
-i, --inventory <INVENTORY> Ansible inventory passed via -i (optional) [env: WATCHER_INVENTORY=]
--ansible-args <ANSIBLE_ARGS> Extra arguments forwarded to ansible-playbook verbatim [env: WATCHER_ANSIBLE_ARGS=]
--state-dir <STATE_DIR> Directory for the state file. Defaults to platform-appropriate location [env: WATCHER_STATE_DIR=]
--once Fetch once and exit without entering the watch loop
--dry-run Print what would be run without actually running ansible-playbook
--log-format <LOG_FORMAT> Log format: pretty | compact | json [env: WATCHER_LOG_FORMAT=] [default: pretty]
--log-level <LOG_LEVEL> Log level: trace | debug | info | warn | error [env: RUST_LOG=] [default: info]
-h, --help Print help
-V, --version Print version```
All options are also available as env variables (WATCHER_KEY, WATCHER_TIMEOUT, WATCHER_INVENTORY, etc.).
# Optional: override settings before enabling
systemctl edit metadata-watcher
# [Service]
# Environment=WATCHER_INVENTORY=/etc/ansible/hosts
# Environment=WATCHER_ANSIBLE_ARGS=--tags deploy
systemctl enable --now metadata-watcher| Context | Path |
|---|---|
| System daemon / root | /var/lib/metadata-watcher/ |
| User session (XDG) | ~/.local/state/metadata-watcher/ |
| macOS | ~/Library/Application Support/metadata-watcher/ |
gcloud compute instances add-metadata my-vm \
--metadata-from-file playbook=/path/to/playbook.yml