Merge pull request #22 from SunsetDrifter/feat/safe-apply-playbook

Add safe_apply_netbird playbook for backup-preview-apply workflow
This commit is contained in:
tkloda
2026-03-31 14:21:31 +02:00
committed by GitHub
2 changed files with 179 additions and 8 deletions
+36 -8
View File
@@ -603,7 +603,9 @@ The `examples/` directory contains complete playbook examples:
This collection includes roles and playbooks for managing your entire NetBird configuration as YAML files in Git — with preview/diff, strict mode, and automatic name-to-ID resolution.
### Quick Start
### Quick Start (Safe Workflow)
The recommended workflow uses the `safe_apply_netbird` playbook, which automatically backs up the current state before making any changes:
```bash
# 1. Export current state to YAML files
@@ -611,18 +613,44 @@ ansible-playbook community.ansible_netbird.export_netbird_config \
-e "netbird_api_url=https://netbird.example.com" \
-e "netbird_api_token=your-token"
# 2. Preview changes (default — read-only, no modifications)
ansible-playbook community.ansible_netbird.configure_netbird \
-e "config_dir=/tmp/netbird_config_export" \
# 2. Preview changes (default — backup + read-only diff, no modifications)
ansible-playbook community.ansible_netbird.safe_apply_netbird \
-e "config_dir=/path/to/your/config" \
-e "netbird_api_url=https://netbird.example.com" \
-e "netbird_api_token=your-token"
# 3. Apply changes
ansible-playbook community.ansible_netbird.configure_netbird \
-e "config_dir=/tmp/netbird_config_export" \
# 3. Apply changes (backup + preview + apply)
ansible-playbook community.ansible_netbird.safe_apply_netbird \
-e "config_dir=/path/to/your/config" \
-e "netbird_api_url=https://netbird.example.com" \
-e "netbird_api_token=your-token" \
-e "commit=true"
-e "apply=true"
# 4. Apply with strict mode (also removes unmanaged resources)
ansible-playbook community.ansible_netbird.safe_apply_netbird \
-e "config_dir=/path/to/your/config" \
-e "netbird_api_url=https://netbird.example.com" \
-e "netbird_api_token=your-token" \
-e "apply=true" -e "use_strict=true"
# 5. Rollback to a backup
ansible-playbook community.ansible_netbird.safe_apply_netbird \
-e "config_dir=/path/to/backups/20260330T120000" \
-e "netbird_api_url=https://netbird.example.com" \
-e "netbird_api_token=your-token" \
-e "apply=true"
```
The `safe_apply_netbird` playbook always creates a timestamped backup in `backups/` before doing anything. You can also use the individual playbooks directly:
```bash
# Export only
ansible-playbook community.ansible_netbird.export_netbird_config \
-e "netbird_api_url=..." -e "netbird_api_token=..."
# Configure only (preview by default, add -e commit=true to apply)
ansible-playbook community.ansible_netbird.configure_netbird \
-e "config_dir=..." -e "netbird_api_url=..." -e "netbird_api_token=..."
```
### Using Roles Directly
+143
View File
@@ -0,0 +1,143 @@
---
# Playbook: Safe NetBird Configuration Pipeline
#
# Wraps the export and configure roles into a safe workflow:
# 1. BACKUP — exports current live state to a timestamped directory
# 2. PREVIEW — shows a read-only diff of what would change
# 3. APPLY — applies changes (only when explicitly requested)
#
# Preview (default — no changes):
# ansible-playbook community.ansible_netbird.safe_apply_netbird \
# -e "config_dir=/path/to/netbird_config" \
# -e "netbird_api_url=https://netbird.example.com" \
# -e "netbird_api_token=your-token"
#
# Apply:
# ... -e "apply=true"
#
# Apply + strict (remove unmanaged resources):
# ... -e "apply=true" -e "use_strict=true"
#
# Rollback to a backup:
# ... -e "config_dir=/path/to/backups/20260330T120000" -e "apply=true"
#
# Optional variables:
# - target_hosts: Host or group to run on (default: localhost)
# - backup_dir: Override backup location (default: <config_dir>/../backups/<timestamp>)
# - apply: Set to true to apply changes (default: false)
# - use_strict: Set to true to remove unmanaged resources (default: false)
- name: "NetBird Safe Apply — backup, preview, apply"
hosts: "{{ target_hosts | default('localhost') }}"
gather_facts: true
vars:
apply: false
use_strict: false
backup_dir: "{{ config_dir }}/../backups/{{ ansible_date_time.iso8601_basic_short }}"
tasks:
# ==================================================================
# Validation
# ==================================================================
- name: Validate required variables
ansible.builtin.assert:
that:
- netbird_api_url is defined and netbird_api_url | length > 0
- netbird_api_token is defined and netbird_api_token | length > 0
- config_dir is defined and config_dir | length > 0
fail_msg: >-
Missing required variables. Provide:
-e "netbird_api_url=https://..." -e "netbird_api_token=..." -e "config_dir=/path/to/config"
run_once: true
- name: Validate config directory exists
ansible.builtin.stat:
path: "{{ config_dir }}"
register: _config_check
run_once: true
- name: Fail if config directory missing
ansible.builtin.fail:
msg: "Config directory not found: {{ config_dir }}"
when: not _config_check.stat.exists
run_once: true
- name: Show operation mode
ansible.builtin.debug:
msg: |
=== NetBird Safe Apply ===
API: {{ netbird_api_url }}
Config: {{ config_dir }}
Mode: {{ 'APPLY' if apply | bool else 'PREVIEW (read-only)' }}{{ ' + STRICT' if use_strict | bool else '' }}
Backup to: {{ backup_dir }}
run_once: true
# ==================================================================
# Step 1: Backup current state
# ==================================================================
- name: "BACKUP | Export current live state"
ansible.builtin.include_role:
name: community.ansible_netbird.export
vars:
export_dir: "{{ backup_dir }}"
run_once: true
- name: "BACKUP | Verify backup"
ansible.builtin.find:
paths: "{{ backup_dir }}"
recurse: true
patterns: "*.yml"
register: _backup_files
run_once: true
- name: "BACKUP | Complete"
ansible.builtin.debug:
msg: "Backed up {{ _backup_files.matched }} files to {{ backup_dir }}"
run_once: true
# ==================================================================
# Step 2: Preview (shows diff report before any changes)
# Note: In apply mode this adds extra API calls but ensures you
# always see what's about to change. Skip with -e preview=false
# if API call volume is a concern.
# ==================================================================
- name: "PREVIEW | Show what would change"
ansible.builtin.include_role:
name: community.ansible_netbird.configure
vars:
commit: false
strict: "{{ use_strict | bool }}"
when: preview | default(true) | bool
run_once: true
# ==================================================================
# Step 3: Apply (only if apply=true)
# ==================================================================
- name: "APPLY | Apply configuration"
ansible.builtin.include_role:
name: community.ansible_netbird.configure
vars:
commit: true
strict: "{{ use_strict | bool }}"
when: apply | bool
run_once: true
# ==================================================================
# Summary
# ==================================================================
- name: "DONE | Next steps"
ansible.builtin.debug:
msg: |
{% if apply | bool %}
=== APPLY COMPLETE ===
Changes applied to {{ netbird_api_url }}.
Backup at: {{ backup_dir }}
To rollback: re-run with -e "config_dir={{ backup_dir }}" -e "apply=true"
{% else %}
=== PREVIEW COMPLETE (no changes made) ===
Review the diff report above.
Backup at: {{ backup_dir }}
To apply: re-run with -e "apply=true"
To strict: re-run with -e "apply=true" -e "use_strict=true"
{% endif %}
run_once: true