Advanced: drive a playbook from a custom field¶
A per-device custom field can act as a feature flag your runner reads straight out of Danbyte's Ansible inventory. Flip a boolean on a device in the UI, and the next playbook run does (or skips) the work — no playbook edit, no inventory file change.
The worked example: a boolean custom field install_btop. Set it true on
a device and a runner installs btop; set
it back to false (or never set it) and the device is left alone.
Same rules as the rest of config drift
Danbyte stores only the flag. The runner holds the device credentials and does the install — Danbyte never touches the device. See the config-drift guide for the full model.
1 — define the custom field¶
Customize → Custom fields → Add:
| Field | Value |
|---|---|
| Name | install_btop |
| Type | Boolean |
| Applies to | Device |
| Label | Install btop (optional, friendlier UI label) |
The name (install_btop) is the key you'll read in the playbook — keep it
lowercase with underscores so it's a clean Ansible variable and group name.
2 — set it on a device¶
Open a device → edit → toggle Install btop on → save. (Or bulk-set it on
many devices at once, or via PATCH /api/devices/<id>/
{"custom_fields": {"install_btop": true}}.)
3 — it shows up in the inventory¶
GET /api/inventory/ansible/ now carries the flag two ways for the devices you
set it on:
{
"cf_install_btop": { "hosts": ["sw1", "edge-fw-demo"] }, // ← a ready-made group
"_meta": {
"hostvars": {
"sw1": {
"ansible_host": "10.0.0.5",
"danbyte": {
"id": "…",
"role": "leaf",
"custom_fields": { "install_btop": true } // ← and a hostvar
}
}
}
}
}
- Every boolean custom field that's on becomes a
cf_<name>group — so you can targethosts: cf_install_btopdirectly. - All custom fields (any type) are also readable per host at
danbyte.custom_fields.<name>.
4 — the playbook¶
Two equivalent styles — pick one.
a) Target the group (cleanest when the flag is the audience):
# install_btop.yml
- hosts: cf_install_btop
become: true
tasks:
- name: Install btop
ansible.builtin.package:
name: btop
state: present
Only devices with the flag on are in cf_install_btop, so the play simply has
nothing to do elsewhere.
b) Run everywhere, gate per host (handy when one play handles several flags, or you also want the off case to actively uninstall):
- hosts: all
become: true
tasks:
- name: Ensure btop matches the Danbyte flag
ansible.builtin.package:
name: btop
state: "{{ 'present' if danbyte.custom_fields.install_btop | default(false) else 'absent' }}"
Because the task is idempotent (state: present), re-running is safe — it only
acts on devices that have drifted from the flag.
5 — run it¶
Same three options as any runner work (Danbyte never schedules it):
- Cron / systemd timer on the runner host — converge the fleet every N minutes.
- On demand —
ansible-playbook …by hand or from CI after you flip a flag. - Danbyte "Deploy" — register an automation target (AWX job template or webhook) and hit a device's Deploy button; Danbyte tells that system to launch the run.
Why this is nice¶
- Self-service — a non-Ansible operator flips a checkbox in Danbyte; the automation owner never edits inventory or playbooks.
- Auditable — the flag change is in Danbyte's change log: who turned btop on, and when.
- Composable — add
enable_netdata,harden_ssh,monitoring_agent… each a boolean CF and acf_<name>group. One inventory, many feature flags.
Beyond booleans
Non-boolean custom fields don't create groups but are still readable as
hostvars — e.g. a text CF syslog_profile at
danbyte.custom_fields.syslog_profile can select which template a play
applies. Reach for a config context instead when the
value is shared network-wide policy data rather than a per-device toggle.