mirror of
https://github.com/netbirdio/ansible-netbird.git
synced 2026-05-22 18:43:36 -07:00
- Add (items or []) to all find_*_by_* functions across 12 modules.
The NetBird API returns null for empty collections, causing TypeError
when iterating. Affects find_group_by_name, find_policy_by_name,
find_setup_key_by_name, find_user_by_email, find_user_by_name,
find_network_by_name, find_route_by_network_id, find_nsgroup_by_name,
find_zone_by_name, find_posture_check_by_name, find_idp_by_name,
find_invite_by_email, find_token_by_name.
- Add (or []) to sync_routers and sync_resources in netbird_network
for the same reason (new networks have null router/resource lists).
- Fix export role network enrichment: .get('json', []) does not work
on Ansible uri module results. Changed to .json | default([]).
- Fix set_fact parsing in export and configure roles: {{ result | to_json }}
produces a JSON string, not a list. Added | from_json so downstream
loop directives receive proper lists (3 occurrences in configure,
1 in export).
- Use urllib.parse.urlencode for query parameter encoding instead of
raw f-string interpolation to prevent URL breakage with special chars.
358 lines
13 KiB
YAML
358 lines
13 KiB
YAML
---
|
|
# Role: community.ansible_netbird.export
|
|
#
|
|
# Captures the current NetBird API state and produces clean, ready-to-use
|
|
# config files that can be used directly with the configure role/playbook.
|
|
# Also saves raw API data in a raw/ subdirectory for debugging.
|
|
#
|
|
# Required variables:
|
|
# - netbird_api_url: NetBird API URL (e.g., https://netbird.example.com)
|
|
# - netbird_api_token: NetBird API token
|
|
#
|
|
# Optional variables:
|
|
# - export_dir: Output directory (default: /tmp/netbird_config_export)
|
|
# - netbird_validate_certs: Validate API TLS certs (default: true)
|
|
#
|
|
# Note: This role uses ansible_date_time — ensure gather_facts is enabled
|
|
# in your playbook (gather_facts: true).
|
|
|
|
# =========================================================================
|
|
# Validation
|
|
# =========================================================================
|
|
- name: Validate API configuration
|
|
ansible.builtin.assert:
|
|
that:
|
|
- netbird_api_url is defined
|
|
- netbird_api_url | length > 0
|
|
- netbird_api_token is defined
|
|
- netbird_api_token | length > 0
|
|
fail_msg: |
|
|
NetBird API configuration is missing!
|
|
Required variables:
|
|
netbird_api_url: "https://netbird.example.com"
|
|
netbird_api_token: "your-api-token"
|
|
|
|
- name: Gather facts if needed
|
|
ansible.builtin.setup:
|
|
when: ansible_date_time is not defined
|
|
|
|
- name: Create export directories
|
|
ansible.builtin.file:
|
|
path: "{{ item }}"
|
|
state: directory
|
|
mode: "0755"
|
|
loop:
|
|
- "{{ export_dir }}"
|
|
- "{{ export_dir }}/access_control"
|
|
- "{{ export_dir }}/dns"
|
|
- "{{ export_dir }}/raw"
|
|
|
|
# =========================================================================
|
|
# All API-calling tasks wrapped in a block with module_defaults
|
|
# =========================================================================
|
|
- name: Export NetBird configuration
|
|
block:
|
|
# =====================================================================
|
|
# Fetch all resources from the NetBird API
|
|
# =====================================================================
|
|
- name: Fetch account settings
|
|
community.ansible_netbird.netbird_info:
|
|
resource: accounts
|
|
register: accounts_data
|
|
|
|
- name: Fetch groups
|
|
community.ansible_netbird.netbird_info:
|
|
resource: groups
|
|
register: groups_data
|
|
|
|
- name: Fetch posture checks
|
|
community.ansible_netbird.netbird_info:
|
|
resource: posture_checks
|
|
register: posture_checks_data
|
|
|
|
- name: Fetch setup keys
|
|
community.ansible_netbird.netbird_info:
|
|
resource: setup_keys
|
|
register: setup_keys_data
|
|
|
|
- name: Fetch DNS nameserver groups
|
|
community.ansible_netbird.netbird_info:
|
|
resource: dns_nameservers
|
|
register: dns_nameservers_data
|
|
|
|
- name: Fetch DNS settings
|
|
community.ansible_netbird.netbird_info:
|
|
resource: dns_settings
|
|
register: dns_settings_data
|
|
|
|
- name: Fetch DNS zones
|
|
community.ansible_netbird.netbird_info:
|
|
resource: dns_zones
|
|
register: dns_zones_data
|
|
|
|
- name: Fetch routes (deprecated API)
|
|
community.ansible_netbird.netbird_info:
|
|
resource: routes
|
|
register: routes_data
|
|
|
|
- name: Fetch networks
|
|
community.ansible_netbird.netbird_info:
|
|
resource: networks
|
|
register: networks_data
|
|
|
|
- name: Fetch routers for each network
|
|
ansible.builtin.uri:
|
|
url: "{{ netbird_api_url }}/api/networks/{{ item.id }}/routers"
|
|
method: GET
|
|
headers:
|
|
Authorization: "Token {{ netbird_api_token }}"
|
|
Accept: "application/json"
|
|
validate_certs: "{{ netbird_validate_certs }}"
|
|
return_content: true
|
|
loop: "{{ networks_data.data }}"
|
|
loop_control:
|
|
label: "{{ item.name }}"
|
|
register: networks_routers_raw
|
|
when: networks_data.data | length > 0
|
|
|
|
- name: Fetch resources for each network
|
|
ansible.builtin.uri:
|
|
url: "{{ netbird_api_url }}/api/networks/{{ item.id }}/resources"
|
|
method: GET
|
|
headers:
|
|
Authorization: "Token {{ netbird_api_token }}"
|
|
Accept: "application/json"
|
|
validate_certs: "{{ netbird_validate_certs }}"
|
|
return_content: true
|
|
loop: "{{ networks_data.data }}"
|
|
loop_control:
|
|
label: "{{ item.name }}"
|
|
register: networks_resources_raw
|
|
when: networks_data.data | length > 0
|
|
|
|
- name: Enrich networks with routers and resources
|
|
ansible.builtin.set_fact:
|
|
networks_enriched: >-
|
|
{% set result = [] -%}
|
|
{% for net in networks_data.data -%}
|
|
{% set routers = networks_routers_raw.results[loop.index0].json | default([]) -%}
|
|
{% set resources = networks_resources_raw.results[loop.index0].json | default([]) -%}
|
|
{% set _ = result.append(net | combine({'routers': routers, 'resources': resources})) -%}
|
|
{% endfor -%}
|
|
{{ result | to_json | from_json }}
|
|
when: networks_data.data | length > 0
|
|
|
|
- name: Set empty enriched networks when none exist
|
|
ansible.builtin.set_fact:
|
|
networks_enriched: []
|
|
when: networks_data.data | length == 0
|
|
|
|
- name: Fetch policies
|
|
community.ansible_netbird.netbird_info:
|
|
resource: policies
|
|
register: policies_data
|
|
|
|
- name: Fetch users
|
|
community.ansible_netbird.netbird_info:
|
|
resource: users
|
|
register: users_data
|
|
|
|
- name: Fetch peers
|
|
community.ansible_netbird.netbird_info:
|
|
resource: peers
|
|
register: peers_data
|
|
|
|
# =====================================================================
|
|
# Build ID-to-name lookup maps
|
|
# =====================================================================
|
|
- name: Initialize lookup maps
|
|
ansible.builtin.set_fact:
|
|
group_id_map: {}
|
|
posture_check_id_map: {}
|
|
peer_id_map: {}
|
|
|
|
- name: Build ID-to-name maps
|
|
ansible.builtin.set_fact:
|
|
group_id_map: "{{ dict(groups_data.data | map(attribute='id') | zip(groups_data.data | map(attribute='name'))) }}"
|
|
posture_check_id_map: "{{ dict(posture_checks_data.data | map(attribute='id') | zip(posture_checks_data.data | map(attribute='name'))) }}"
|
|
peer_id_map: "{{ dict(peers_data.data | map(attribute='id') | zip(peers_data.data | map(attribute='name'))) }}"
|
|
|
|
# =====================================================================
|
|
# Write clean config files (ready to use with configure role)
|
|
# =====================================================================
|
|
- name: Export clean settings
|
|
ansible.builtin.template:
|
|
src: export/settings.yml.j2
|
|
dest: "{{ export_dir }}/settings.yml"
|
|
mode: "0644"
|
|
|
|
- name: Export clean groups
|
|
ansible.builtin.template:
|
|
src: export/access_control/groups.yml.j2
|
|
dest: "{{ export_dir }}/access_control/groups.yml"
|
|
mode: "0644"
|
|
|
|
- name: Export clean posture checks
|
|
ansible.builtin.template:
|
|
src: export/access_control/posture_checks.yml.j2
|
|
dest: "{{ export_dir }}/access_control/posture_checks.yml"
|
|
mode: "0644"
|
|
|
|
- name: Export clean policies
|
|
ansible.builtin.template:
|
|
src: export/access_control/policies.yml.j2
|
|
dest: "{{ export_dir }}/access_control/policies.yml"
|
|
mode: "0644"
|
|
|
|
- name: Export clean setup keys
|
|
ansible.builtin.template:
|
|
src: export/setup_keys.yml.j2
|
|
dest: "{{ export_dir }}/setup_keys.yml"
|
|
mode: "0644"
|
|
|
|
- name: Export clean DNS nameservers
|
|
ansible.builtin.template:
|
|
src: export/dns/nameservers.yml.j2
|
|
dest: "{{ export_dir }}/dns/nameservers.yml"
|
|
mode: "0644"
|
|
|
|
- name: Export clean DNS zones
|
|
ansible.builtin.template:
|
|
src: export/dns/zones.yml.j2
|
|
dest: "{{ export_dir }}/dns/zones.yml"
|
|
mode: "0644"
|
|
|
|
- name: Export clean DNS settings
|
|
ansible.builtin.template:
|
|
src: export/dns/settings.yml.j2
|
|
dest: "{{ export_dir }}/dns/settings.yml"
|
|
mode: "0644"
|
|
|
|
- name: Export clean networks
|
|
ansible.builtin.template:
|
|
src: export/networks.yml.j2
|
|
dest: "{{ export_dir }}/networks.yml"
|
|
mode: "0644"
|
|
|
|
- name: Export clean routes (deprecated API)
|
|
ansible.builtin.template:
|
|
src: export/routes.yml.j2
|
|
dest: "{{ export_dir }}/routes.yml"
|
|
mode: "0644"
|
|
|
|
# =====================================================================
|
|
# Write raw API data (for debugging/reference)
|
|
# =====================================================================
|
|
- name: Export raw account settings
|
|
ansible.builtin.copy:
|
|
content: "{{ accounts_data.data | to_nice_yaml(indent=2) }}"
|
|
dest: "{{ export_dir }}/raw/account_settings_raw.yml"
|
|
mode: "0644"
|
|
|
|
- name: Export raw groups
|
|
ansible.builtin.copy:
|
|
content: "{{ groups_data.data | to_nice_yaml(indent=2) }}"
|
|
dest: "{{ export_dir }}/raw/groups_raw.yml"
|
|
mode: "0644"
|
|
|
|
- name: Export raw posture checks
|
|
ansible.builtin.copy:
|
|
content: "{{ posture_checks_data.data | to_nice_yaml(indent=2) }}"
|
|
dest: "{{ export_dir }}/raw/posture_checks_raw.yml"
|
|
mode: "0644"
|
|
|
|
- name: Export raw setup keys
|
|
ansible.builtin.copy:
|
|
content: "{{ setup_keys_data.data | to_nice_yaml(indent=2) }}"
|
|
dest: "{{ export_dir }}/raw/setup_keys_raw.yml"
|
|
mode: "0644"
|
|
|
|
- name: Export raw DNS
|
|
ansible.builtin.copy:
|
|
content: "{{ dns_nameservers_data.data | to_nice_yaml(indent=2) }}"
|
|
dest: "{{ export_dir }}/raw/dns_nameservers_raw.yml"
|
|
mode: "0644"
|
|
|
|
- name: Export raw DNS zones
|
|
ansible.builtin.copy:
|
|
content: "{{ dns_zones_data.data | to_nice_yaml(indent=2) }}"
|
|
dest: "{{ export_dir }}/raw/dns_zones_raw.yml"
|
|
mode: "0644"
|
|
|
|
- name: Export raw networks
|
|
ansible.builtin.copy:
|
|
content: "{{ networks_data.data | to_nice_yaml(indent=2) }}"
|
|
dest: "{{ export_dir }}/raw/networks_raw.yml"
|
|
mode: "0644"
|
|
|
|
- name: Export raw routes
|
|
ansible.builtin.copy:
|
|
content: "{{ routes_data.data | to_nice_yaml(indent=2) }}"
|
|
dest: "{{ export_dir }}/raw/routes_raw.yml"
|
|
mode: "0644"
|
|
|
|
- name: Export raw policies
|
|
ansible.builtin.copy:
|
|
content: "{{ policies_data.data | to_nice_yaml(indent=2) }}"
|
|
dest: "{{ export_dir }}/raw/policies_raw.yml"
|
|
mode: "0644"
|
|
|
|
- name: Export users reference
|
|
ansible.builtin.copy:
|
|
content: |
|
|
---
|
|
# NetBird Users Reference ({{ users_data.data | length }} users)
|
|
# Exported on {{ ansible_date_time.date }}
|
|
# Users are managed via IdP sync, not via config-as-code.
|
|
{{ users_data.data | to_nice_yaml(indent=2) }}
|
|
dest: "{{ export_dir }}/raw/users_reference.yml"
|
|
mode: "0644"
|
|
|
|
- name: Export peers reference
|
|
ansible.builtin.copy:
|
|
content: |
|
|
---
|
|
# NetBird Peers Reference ({{ peers_data.data | length }} peers)
|
|
# Exported on {{ ansible_date_time.date }}
|
|
# Peers register via setup keys — not managed via config-as-code.
|
|
# Use peer IDs from this file for network router configuration.
|
|
{{ peers_data.data | to_nice_yaml(indent=2) }}
|
|
dest: "{{ export_dir }}/raw/peers_reference.yml"
|
|
mode: "0644"
|
|
|
|
# =====================================================================
|
|
# Summary
|
|
# =====================================================================
|
|
- name: Display export summary
|
|
ansible.builtin.debug:
|
|
msg:
|
|
- "Export complete! Files written to: {{ export_dir }}/"
|
|
- ""
|
|
- "Clean config files (ready to use with configure role):"
|
|
- " - settings.yml (account settings)"
|
|
- " - access_control/"
|
|
- " groups.yml ({{ groups_data.data | rejectattr('name', 'equalto', 'All') | rejectattr('issued', 'equalto', 'jwt') | list | length }} groups)"
|
|
- " posture_checks.yml ({{ posture_checks_data.data | length }} posture checks)"
|
|
- " policies.yml ({{ policies_data.data | length }} policies)"
|
|
- " - setup_keys.yml ({{ setup_keys_data.data | length }} setup keys — read-only reference)"
|
|
- " - dns/"
|
|
- " nameservers.yml ({{ dns_nameservers_data.data | length }} nameserver groups)"
|
|
- " zones.yml ({{ dns_zones_data.data | length }} zones)"
|
|
- " settings.yml (DNS settings)"
|
|
- " - networks.yml ({{ networks_data.data | length }} networks)"
|
|
- " - routes.yml ({{ routes_data.data | length }} routes — deprecated API)"
|
|
- ""
|
|
- "Raw API data (for debugging):"
|
|
- " raw/ (account, groups, posture_checks, setup_keys, dns, routes, networks, policies, users, peers)"
|
|
- ""
|
|
- "Next steps:"
|
|
- " 1. Review the clean config files"
|
|
- " 2. Copy them to your config directory (preserving directory structure)"
|
|
- " 3. Run the configure role/playbook to preview"
|
|
|
|
module_defaults:
|
|
group/community.ansible_netbird.netbird:
|
|
api_url: "{{ netbird_api_url }}"
|
|
api_token: "{{ netbird_api_token }}"
|
|
validate_certs: "{{ netbird_validate_certs }}"
|