Skip to content

Commit 84d721f

Browse files
committed
docs(roles/uptimerobot): document logging, caching, info modules, utr migration; switch sample domains to example.com
Massive expansion of the role README so it can replace the standalone `utr` CLI's docs end-to-end: - Performance / Caching section explaining the 60s on-disk read cache under ~/.cache/ansible-uptimerobot/ and how to flush it. - Debugging section now lists the correct syslog identifier (ansible-linuxfabrik.lfops.uptimerobot_<resource>, the full FQDN that Ansible uses when calling collection modules), with a journalctl --identifier recipe covering all nine UR modules at once. Also documents the `debug:` return key and the operation / reason / diff_fields values it can carry. - Migration table grew to cover the four `utr get …` -> `*_info` module pairs and the `utr set monitors --status=paused` equivalent. - Sample inventory uses example.com domains instead of real customer URLs, and the prefix-collapse rule for friendly_names is documented next to the migration table. - Inventory-running snippet drops the redundant `--limit lfops_uptimerobot` (the playbook already targets that group internally). Plus: - Top-level README gains a brief "custom modules" section listing bitwarden_item, gpg_key, ipa*, lvm_pv, nextcloud_occ_*, sqlite_query and the new uptimerobot_* family, so the modules surface from the project overview, not just the per-role README. - CHANGELOG entry updated to reflect the nine UR modules (four CRUD, four *_info, one account_info) instead of the original five.
1 parent 4b5f4dc commit 84d721f

3 files changed

Lines changed: 122 additions & 16 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2525

2626
### Added
2727

28-
* **role:uptimerobot, plugins/modules/uptimerobot_***: New role and a set of five custom modules to manage UptimeRobot resources directly from a playbook: `uptimerobot_monitor`, `uptimerobot_mwindow`, `uptimerobot_psp` (each full CRUD), `uptimerobot_alert_contact` (delete only — UptimeRobot API v2 does not expose creating contacts) and `uptimerobot_account_info` (read only). The role accepts the same YAML structure as the existing `utr` CLI's `utr.yml` / `mwindows.yml` / `psps.yml` / `alertcontacts.yml`, so existing inventories migrate by copying the lists into `uptimerobot__monitors` / `__mwindows` / `__psps` / `__alert_contacts`. API key resolution: `api_key` parameter, `api_key_file` (default `~/.uptimerobot`), or `UPTIMEROBOT_API_KEY` environment variable.
28+
* **role:uptimerobot, plugins/modules/uptimerobot_***: New role and a set of nine custom modules to manage UptimeRobot resources directly from a playbook. CRUD modules: `uptimerobot_monitor`, `uptimerobot_mwindow`, `uptimerobot_psp`, plus `uptimerobot_alert_contact` (delete only — UptimeRobot API v2 does not expose creating contacts). Read-only info modules for inspection and dynamic inventories: `uptimerobot_account_info`, `uptimerobot_monitor_info`, `uptimerobot_mwindow_info`, `uptimerobot_alert_contact_info`, `uptimerobot_psp_info` — together replacing all `utr get …` subcommands. All CRUD modules support `--check` and `--diff`, are idempotent on re-run, and translate API integer IDs to user-facing labels in both directions. The role accepts the same YAML structure as the existing `utr` CLI's `utr.yml` / `mwindows.yml` / `psps.yml` / `alertcontacts.yml`, so existing inventories migrate by copying the lists into `uptimerobot__monitors` / `__mwindows` / `__psps` / `__alert_contacts`. API key resolution: `api_key` parameter, `api_key_file` (default `~/.uptimerobot`, matching `utr` convention), or `UPTIMEROBOT_API_KEY` environment variable.
2929
* **role:at**: Add optional variable `at__service_state` (`reloaded` / `restarted` / `started` / `stopped`) to control the running state of `atd.service` independently from boot autostart. Default behaviour is unchanged: `at__service_enabled: true` keeps the service started, `false` stops it.
3030
* **role:dnf_makecache**: Add optional variables `dnf_makecache__service_state` and `dnf_makecache__timer_state` to control the running state of `dnf-makecache.service` and `dnf-makecache.timer` independently from boot autostart. Default behaviour is unchanged.
3131
* **role:open_vm_tools**: Add optional variables `open_vm_tools__service_enabled` and `open_vm_tools__service_state`. The role previously had no way to disable / stop `vmtoolsd.service`; now the service can be managed like in the other LFOps service-wrapper roles. Default behaviour is unchanged (service enabled and started).

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,18 @@ freeipa_server__ipa_admin_password:
410410

411411
See `ansible-doc -t lookup linuxfabrik.lfops.bitwarden_item` for all options.
412412

413+
LFOps also ships a small set of custom modules for resource types that are not covered by Ansible core:
414+
415+
* **`bitwarden_item`** — create / update / fetch Bitwarden items.
416+
* **`gpg_key`** — manage GPG keys.
417+
* **`ipa*`** (`ipagroup`, `ipahbacrule`, `ipasudorule`, ...) — FreeIPA resource management.
418+
* **`lvm_pv`** — manage LVM physical volumes.
419+
* **`nextcloud_occ_app`**, **`nextcloud_occ_app_config`**, **`nextcloud_occ_system_config`** — drive Nextcloud `occ` from a playbook.
420+
* **`sqlite_query`** — run SQLite queries.
421+
* **`uptimerobot_*`** — manage UptimeRobot monitors, maintenance windows, public status pages and alert contacts; covers everything the standalone `utr` CLI does, with full idempotency, `--check`, `--diff` and a parallel set of `*_info` modules for read-only inspection. See the [`uptimerobot` role README](roles/uptimerobot/) for the full reference.
422+
423+
Each custom module ships its own `DOCUMENTATION`, `EXAMPLES` and `RETURN` blocks; browse them with `ansible-doc linuxfabrik.lfops.<module>`.
424+
413425

414426
## Documentation
415427

roles/uptimerobot/README.md

Lines changed: 109 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ The role does not deploy any software on the target hosts. It runs on the Ansibl
1212

1313
## Concepts
1414

15-
The role works with five concepts that map 1:1 to UptimeRobot's data model and to one Ansible module each:
15+
The role works with five concepts that map 1:1 to UptimeRobot's data model and to one Ansible CRUD module each (plus a parallel set of read-only `*_info` modules — see the migration section below):
1616

1717
* **Monitor** (`linuxfabrik.lfops.uptimerobot_monitor`) — a single check (URL, host, heartbeat). Carries its own interval, timeout, HTTP method, optional auth, optional keyword search, and references to alert contacts and maintenance windows.
1818
* **Maintenance window** (`linuxfabrik.lfops.uptimerobot_mwindow`) — a recurring or one-off time slot in which monitors that reference it stop alerting. `daily`, `weekly`, `monthly`, or `once`.
@@ -329,26 +329,26 @@ uptimerobot__mwindows:
329329

330330
uptimerobot__monitors:
331331
- prefix: '001'
332-
url: 'https://cloud.linuxfabrik.io/index.php/login'
332+
url: 'https://www.example.com/index.php/login'
333333
interval: 120
334334
http_method: 'get'
335335
alert_contacts:
336-
- friendly_name: 'root@linuxfabrik.ch'
336+
- friendly_name: 'monitoring@example.com'
337337
threshold: 1
338338
recurrence: 0
339339
mwindows:
340340
- friendly_name: 'weekly mon 03:30-05:30'
341341
state: 'present'
342342

343343
- prefix: '001'
344-
url: 'https://old-host.linuxfabrik.ch'
344+
url: 'https://legacy.example.com'
345345
state: 'absent'
346346

347347
uptimerobot__psps:
348-
- friendly_name: 'Status - linuxfabrik.io'
349-
custom_url: 'status.linuxfabrik.io'
348+
- friendly_name: 'Status - example.com'
349+
custom_url: 'status.example.com'
350350
monitors:
351-
- friendly_name: '001 cloud.linuxfabrik.io/index.php/login'
351+
- friendly_name: '001 www.example.com/index.php/login'
352352
sort: 'a-z'
353353
status: 'active'
354354
state: 'present'
@@ -361,14 +361,16 @@ uptimerobot__alert_contacts:
361361
362362
## Running the Role
363363
364+
The shipped playbook already targets `hosts: lfops_uptimerobot` internally, so put `localhost` (or wherever you keep your API key) into that group and run:
365+
364366
```bash
365-
ansible-playbook --inventory path/to/inventory linuxfabrik.lfops.uptimerobot --limit lfops_uptimerobot
367+
ansible-playbook --inventory path/to/inventory linuxfabrik.lfops.uptimerobot
366368
367369
# Only push maintenance windows:
368-
ansible-playbook ... linuxfabrik.lfops.uptimerobot --tags uptimerobot:mwindow
370+
ansible-playbook --inventory path/to/inventory linuxfabrik.lfops.uptimerobot --tags uptimerobot:mwindow
369371
370-
# Dry-run with diff output:
371-
ansible-playbook ... linuxfabrik.lfops.uptimerobot --check --diff
372+
# Dry-run with per-resource diff output:
373+
ansible-playbook --inventory path/to/inventory linuxfabrik.lfops.uptimerobot --check --diff
372374
```
373375

374376
For ad-hoc / read-only queries against UptimeRobot, the modules can be invoked directly without the role:
@@ -388,13 +390,82 @@ For ad-hoc / read-only queries against UptimeRobot, the modules can be invoked d
388390
```
389391

390392

393+
## Performance / Caching
394+
395+
To keep the per-item API cost down when the role loops a CRUD module over a long list, `module_utils.uptimerobot` writes the four heavy `getX` responses (`getMonitors`, `getAlertContacts`, `getMWindows`, `getPSPs`) to a short-lived on-disk cache under `~/.cache/ansible-uptimerobot/` with a 60-second TTL. Cache files are mode `0600` because they hold the full resource list returned by the API.
396+
397+
* **Read calls** check the cache first; a hit replaces the (paginated) HTTP request entirely. Logged as `cache HIT <endpoint> (...)` in syslog.
398+
* **Mutating calls** (`newX` / `editX` / `deleteX`) succeed against the API and then invalidate the matching `getX` cache so the next read sees the post-write state.
399+
* Cache files are per-engineer (the path is in your `$HOME`), so different engineers running against the same UptimeRobot account don't share state.
400+
* If you need to force a fresh read, delete the directory:
401+
402+
```
403+
rm -rf ~/.cache/ansible-uptimerobot/
404+
```
405+
406+
Typical impact: a `--check` run over 56 monitors goes from ~56× 4 page `getMonitors` + 56× `getAlertContacts` + 56× `getMWindows` to one of each (the rest hit cache). Idempotent re-runs of the same playbook within a minute are nearly free.
407+
408+
391409
## Debugging / Verbose Output
392410

393-
The five modules emit verbose output through three channels — useful when iterating against a live API:
411+
The CRUD modules emit verbose output through three channels — useful when iterating against a live API:
394412

395-
* **`module.log()`** lines go to syslog under the tag `ansible-uptimerobot_<resource>`. They cover: API-key resolution source, lookup result (existing monitor / window / PSP found or not), every HTTP POST (endpoint plus sanitised key list — API key and passwords are masked), pagination page count, response status, diff field list. Tail with `journalctl -t ansible-uptimerobot_monitor -f`.
413+
* **`module.log()`** lines go to syslog under the tag `ansible-linuxfabrik.lfops.uptimerobot_<resource>` (the full collection FQDN; that's the identifier Ansible uses when calling modules through a collection). They cover: API-key resolution source, lookup result (existing monitor / window / PSP found or not), every HTTP POST (endpoint plus sanitised key list — API key and passwords are masked), pagination page count, response status, diff field list.
396414
* **`module.warn()`** is used on rate-limit retries (HTTP 429) so the playbook output shows how often the modules had to back off.
397-
* The **`debug`** key in every module's return value carries a structured summary (`operation`, `friendly_name`, resource id, `diff_fields` or `sent_keys`). `register:` it and `ansible.builtin.debug var=ur_result.debug` to inspect what the module decided to do, especially when investigating false-positive `changed: true`.
415+
* The **`debug`** key in every module's return value carries a structured summary (`operation`, `friendly_name`, resource id, `diff_fields` or `sent_keys`).
416+
417+
### Tailing the syslog channel
418+
419+
The syslog tag is `ansible-linuxfabrik.lfops.uptimerobot_<resource>` (one tag per resource type). On a controller running systemd / journald:
420+
421+
```
422+
# Live tail while a playbook runs:
423+
journalctl --identifier ansible-linuxfabrik.lfops.uptimerobot_monitor --follow
424+
425+
# Everything from the last run, all UR resources at once:
426+
journalctl --since '5 minutes ago' \
427+
--identifier ansible-linuxfabrik.lfops.uptimerobot_account_info \
428+
--identifier ansible-linuxfabrik.lfops.uptimerobot_alert_contact \
429+
--identifier ansible-linuxfabrik.lfops.uptimerobot_alert_contact_info \
430+
--identifier ansible-linuxfabrik.lfops.uptimerobot_monitor \
431+
--identifier ansible-linuxfabrik.lfops.uptimerobot_monitor_info \
432+
--identifier ansible-linuxfabrik.lfops.uptimerobot_mwindow \
433+
--identifier ansible-linuxfabrik.lfops.uptimerobot_mwindow_info \
434+
--identifier ansible-linuxfabrik.lfops.uptimerobot_psp \
435+
--identifier ansible-linuxfabrik.lfops.uptimerobot_psp_info
436+
```
437+
438+
On a sysv / non-journald host, the same lines land in `/var/log/messages` (Red Hat-family) or `/var/log/syslog` (Debian-family). Filter with `grep ansible-uptimerobot_`.
439+
440+
The tag prefix is fixed in `module_utils/uptimerobot.py`; it does not change with `--verbose` and does not need any extra configuration on the controller.
441+
442+
### Reading the debug dict from the playbook side
443+
444+
Every CRUD and info module returns a `debug:` key alongside the resource payload. Capture it with `register:` and inspect it directly — much more compact than `-vvv`-level Ansible chatter:
445+
446+
```yaml
447+
- linuxfabrik.lfops.uptimerobot_monitor:
448+
friendly_name: '001 www.example.com'
449+
url: 'https://www.example.com'
450+
type: 'http'
451+
interval: 30
452+
state: 'present'
453+
register: 'ur_result'
454+
455+
- ansible.builtin.debug:
456+
var: 'ur_result.debug'
457+
```
458+
459+
Typical values you will see:
460+
461+
* `operation`: `'noop'`, `'create'`, `'create (check_mode)'`, `'update'`, `'update (check_mode)'`, `'delete'`, `'delete (check_mode)'`, `'list'`, `'read'`.
462+
* `reason`: only set for `noop`, e.g. `'no diff'` or `'monitor not present'`.
463+
* `friendly_name`, `monitor_id` / `mwindow_id` / `psp_id`: identifiers of the resource the module touched.
464+
* `diff_fields`: list of field names that actually differ between current and desired state — what an `update` will send to the API, or what a `--check` `update (check_mode)` would send.
465+
* `sent_keys`: list of field names included in a `create`'s body.
466+
* `count`: number of items returned (info modules only).
467+
468+
Combined with `--check --diff`, the `debug` dict makes it cheap to investigate false-positive `changed: true` (typically a missing read-side translation or a desired-vs-current normalisation gap).
398469

399470

400471
## Migrating from the `utr` CLI
@@ -408,7 +479,30 @@ Linuxfabrik used to drive the same configuration through the standalone `utr` CL
408479
| `psps.yml` (top-level `psps:` list) | `uptimerobot__psps` |
409480
| `alertcontacts.yml` (top-level `alert_contacts:` list) | `uptimerobot__alert_contacts` |
410481

411-
The list items use the same field names — drop them into your inventory's `group_vars/lfops_uptimerobot.yml` (or wherever) and run the playbook. The auto-generated `friendly_name` follows the same `'<prefix> <url-without-protocol>'` (monitors) and `'<type> [<value>] <start_time>-<end_time>'` (mwindows) conventions.
482+
The list items use the same field names — drop them into your inventory's `group_vars/lfops_uptimerobot.yml` (or wherever) and run the playbook. The auto-generated `friendly_name` follows the same `'<prefix> <url-without-protocol>'` (monitors) and `'<type> [<value>] <start_time>-<end_time>'` (mwindows) conventions, including the same prefix-collapse rule for URLs whose host already starts with the prefix (e.g. `prefix: '038'` plus URL `https://038-p-mon61…/icingaweb2/` becomes friendly_name `038-p-mon61…/icingaweb2/`).
483+
484+
Read-side parity with `utr get …` is provided by four read-only modules — useful for ad-hoc inspection, dynamic inventories, or driving downstream tasks:
485+
486+
| `utr` command | Ansible module |
487+
|---|---|
488+
| `utr get account` | `linuxfabrik.lfops.uptimerobot_account_info` |
489+
| `utr get monitors` | `linuxfabrik.lfops.uptimerobot_monitor_info` |
490+
| `utr get mwindows` | `linuxfabrik.lfops.uptimerobot_mwindow_info` |
491+
| `utr get alert_contacts` | `linuxfabrik.lfops.uptimerobot_alert_contact_info` |
492+
| `utr get psps` | `linuxfabrik.lfops.uptimerobot_psp_info` |
493+
494+
All info modules accept `friendly_name:` to filter to a single resource and (where supported by the API) `search:` for a server-side substring filter. Enum-style fields are returned as labels (e.g. `http_method: 'get'`, `status: 'up'`), matching the user-facing parameter values you write in your inventory.
495+
496+
```yaml
497+
- linuxfabrik.lfops.uptimerobot_monitor_info:
498+
friendly_name: '001 www.example.com'
499+
register: ur_monitor
500+
501+
- ansible.builtin.debug:
502+
var: ur_monitor.monitors[0].interval
503+
```
504+
505+
For the equivalent of `utr set monitors --status=paused`, loop the regular `uptimerobot_monitor` module with `state: 'present'` and `status: 'paused'` over the result of `uptimerobot_monitor_info`.
412506

413507

414508
## License

0 commit comments

Comments
 (0)