Skip to content

Commit 25ca9ca

Browse files
author
Adam Kraitman
committed
This commit introduces the maas_nameserver Ansible role to configure DNS domains and records in MAAS (Metal as a Service) based on an Ansible inventory. Key features include:
- Configures DNS entries for hosts (e.g., main interfaces, IPMI interfaces) using `dns_domains` and inventory variables (`ip`, `ipmi`). - Dynamically sets `maas_cluster_instance.host` via `maas_api_url` in `defaults/main.yml`, with credentials (`customer_key`, `token_key`, `token_secret`) loaded from a secrets file (`secrets/maas.yml`). - Filters inventory to process only hosts with `ip` or `ipmi` variables, excluding groups like `all` and `ungrouped`. - Cleans up unwanted DNS records and domains not in `dns_domains` or `excluded_domains`, skipping default MAAS domains. - Skips NS record creation due to module limitations, with instructions for manual creation via MAAS CLI/UI. - Includes comprehensive `README.md` with: - Inventory example with `mac`, `ip`, `ipmi`, and `bmc` attributes (e.g., `server01.example.com mac=00:1a:2b:3c:4d:5e ip=192.168.1.11 ipmi=192.168.2.11 bmc=00:1a:2b:3c:4d:5f`). - Setup instructions for inventory, secrets, and variables. - Troubleshooting for common issues (e.g., network errors, missing `dns_domains`). - Performance tips (e.g., fact caching). - Ensures idempotency and supports large inventories. Signed-off-by: Adam Kraitman <akraitma@li-8b09b2cc-35b7-11b2-a85c-cd1dbade58f9.ibm.com>
1 parent b42e556 commit 25ca9ca

File tree

4 files changed

+345
-194
lines changed

4 files changed

+345
-194
lines changed

maas_nameserver.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
2-
- name: Configure MAAS DNS
3-
hosts: maas
4-
gather_facts: false
2+
- name: Deploy MAAS DNS
3+
hosts: localhost
4+
connection: local
55
roles:
6-
- maas_nameserver
6+
- role: maas_nameserver

roles/maas_nameserver/README.md

Lines changed: 124 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@
22

33
## Overview
44

5-
The `maas_nameserver` role configures DNS domains and records in MAAS (Metal as a Service) based on an Ansible inventory. It manages DNS entries for hosts (e.g., Main interfaces, IPMI interfaces, VLAN interfaces) in specified domains, ensuring only desired records and domains exist while cleaning up unwanted ones. This role depends on a secrets file to load MAAS API credentials.
5+
The `maas_nameserver` role configures DNS domains and records in MAAS (Metal as a Service) based on an Ansible inventory. It manages DNS entries for hosts (e.g., main interfaces, IPMI interfaces) in specified domains, ensuring only desired records and domains exist while cleaning up unwanted ones. This role depends on a secrets file to load MAAS API credentials.
66

77
## Requirements
88

99
- Ansible: Version 2.9 or higher
1010
- MAAS CLI: Installed on the target MAAS server
11+
- Python: Version 3.6 or higher (for `maas.maas` collection)
1112
- Inventory: A valid Ansible inventory with `group_vars/all.yml` defining `dns_domains`
13+
- MAAS API Access: Valid credentials in a secrets file
14+
- Network: Stable connectivity to the MAAS server
1215

1316
## Role Structure
1417

@@ -26,23 +29,22 @@ roles/
2629

2730
## Dependencies
2831

29-
- **Secrets File**: A `maas.yml` file at `{{ secrets_path }}/maas.yml` provides MAAS API credentials (e.g., `maas_api_key`, `maas_api_url`). No separate secrets role is required; credentials are loaded via `include_vars`.
32+
- **Secrets File**: A `maas.yml` file at `{{ secrets_path }}/maas.yml` provides MAAS API credentials (`maas_cluster_instance` with `customer_key`, `token_key`, and `token_secret`). The `host` is set dynamically at runtime.
33+
- **maas.maas Collection**: Automatically installed by the role if not present.
3034

3135
## Usage
3236

3337
1. **Prepare Inventory**
3438

35-
Define your `maas` and target host groups:
39+
Define your `maas` group and target hosts in your inventory file (e.g., `inventory/hosts`):
3640

3741
```ini
3842
[maas]
39-
maas.internal.ceph.ibm.com ip=10.11.120.237
43+
maas-server.example.com ansible_host=192.168.1.10
4044

41-
[snipeit]
42-
snipe-it.internal.ceph.ibm.com ip=10.60.100.11
43-
44-
[machine]
45-
machine001.internal.ceph.ibm.com ip=10.18.131.100 ipmi=10.18.139.100 vlan104=10.18.144.3
45+
[servers]
46+
server01.example.com mac=00:1a:2b:3c:4d:5e ip=192.168.1.11 ipmi=192.168.2.11 bmc=00:1a:2b:3c:4d:5f
47+
server02.example.com mac=00:1a:2b:3c:4d:60 ip=192.168.1.12 ipmi=192.168.2.12 bmc=00:1a:2b:3c:4d:61
4648
```
4749

4850
2. **Set Up Inventory Variables**
@@ -52,109 +54,158 @@ roles/
5254
```yaml
5355
---
5456
dns_domains:
55-
ceph: "internal.ceph.ibm.com"
56-
ipmi: "ipmi.ceph.ibm.com"
57-
vlan104: "vlan104.internal.ceph.ibm.com"
57+
ip: "example.com"
58+
ipmi: "ipmi.example.com"
59+
```
60+
61+
Optionally, define `dns_records` in `group_vars/dns_records.yml` for additional DNS records:
62+
63+
```yaml
64+
---
65+
dns_records:
66+
- name: "api"
67+
domain: "ocp1.example.com"
68+
type: "A/AAAA"
69+
ip: "192.168.1.101"
70+
- name: "*"
71+
domain: "apps.ocp1.example.com"
72+
type: "A/AAAA"
73+
ip: "192.168.1.102"
5874
```
5975

6076
3. **Set Up Secrets**
6177

62-
Create a secrets file at `{{ secrets_path }}/maas.yml`:
78+
Create a secrets file at `{{ secrets_path }}/maas.yml` (e.g., `secrets/maas.yml`):
6379

6480
```yaml
6581
---
66-
maas_profile: "admin" # also called the maas api username
67-
maas_api_key: "XXXXXXXXXXXXXXXX" # api key of the profile defined in maas_profile
68-
maas_api_url: "http://localhost:5240/MAAS/api/2.0/"
82+
maas_cluster_instance:
83+
customer_key: "your_customer_key"
84+
token_key: "your_token_key"
85+
token_secret: "your_token_secret"
6986
```
7087

88+
**Note**: The `host` field is not included in `maas_cluster_instance` as it is set dynamically using `maas_api_url` from `defaults/main.yml` and the `maas` group in the inventory. Restrict file permissions (e.g., `chmod 600 secrets/maas.yml`) and consider using Ansible Vault for encryption.
89+
7190
4. **Run the Playbook**
7291

7392
```bash
7493
ansible-playbook maas_nameserver.yml
7594
```
7695

77-
## Variables
78-
79-
### defaults/main.yml
80-
81-
These are overridable defaults:
82-
83-
- `maas_api_url`: Default MAAS API endpoint (`http://localhost:5240/MAAS/api/2.0/`). Override in `secrets/maas.yml`.
96+
For verbose output to troubleshoot:
8497

85-
- `maas_profile`: Default MAAS profile name (`admin`). Override in `secrets/maas.yml`.
86-
87-
- `default_domains`: Domains to preserve (default: `["maas"]`). The `maas` domain is used by MAAS for internal DNS records and is excluded from cleanup.
98+
```bash
99+
ansible-playbook maas_nameserver.yml -vvvv
100+
```
88101

89-
- `target_hosts`: List of hosts for DNS records. Defaults to an empty list (`[]`), in which case the role dynamically selects all hosts from inventory groups except those in `exclude_groups`. Override in `group_vars/maas.yml`:
102+
## Variables
90103

91-
```yaml
92-
target_hosts:
93-
- machine001.internal.ceph.ibm.com
94-
- machine002.internal.ceph.ibm.com
95-
```
104+
### defaults/main.yml
96105

97-
Or via command line:
106+
Overridable defaults:
98107

99-
```bash
100-
ansible-playbook maas_nameserver.yml -e "target_hosts=['machine001.internal.ceph.ibm.com']"
101-
```
108+
- `maas_server_ip`: Derived from the first host in the `maas` group (`{{ groups.get('maas', []) | first | default('undefined_maas_server') }}`).
109+
- `maas_api_url`: MAAS API endpoint (`http://{{ maas_server_ip }}:5240/MAAS`).
110+
- `dns_ttl`: Default TTL for DNS records (`3600` seconds).
111+
- `excluded_groups`: Groups to exclude from inventory processing (`["all", "ungrouped"]`).
112+
- `excluded_domains`: Domains to preserve from cleanup (`["maas", "front.sepia.example.com"]`).
113+
- `supported_record_types`: Allowed DNS record types (`["A/AAAA", "CNAME", "MX", "NS", "SRV", "SSHFP", "TXT"]`).
102114

103-
- `exclude_groups`: List of inventory groups to exclude from `target_hosts` when `target_hosts` is empty. Defaults to `["maas", "all", "ungrouped"]`. The `all` and `ungrouped` groups must be included to prevent the automatic inclusion of all hosts (via the `all` group, which contains every host in the inventory) or ungrouped hosts (via the `ungrouped` group). Override in `group_vars/maas.yml`:
115+
Example `defaults/main.yml`:
104116

105-
```yaml
106-
exclude_groups: ["maas", "all", "ungrouped", "other_group"]
107-
```
117+
```yaml
118+
---
119+
maas_server_ip: "{{ groups.get('maas', []) | first | default('undefined_maas_server') }}"
120+
maas_api_url: "http://{{ maas_server_ip }}:5240/MAAS"
121+
dns_ttl: 3600
122+
excluded_groups: ["all", "ungrouped"]
123+
excluded_domains: ["maas", "front.sepia.example.com"]
124+
supported_record_types: ["A/AAAA", "CNAME", "MX", "NS", "SRV", "SSHFP", "TXT"]
125+
```
108126

109127
### vars/main.yml
110128

111129
No mandatory, non-overridable variables are defined. Environment-specific variables like `dns_domains` must be set in `inventory/group_vars/all.yml`.
112130

113131
### secrets/maas.yml
114132

115-
Provides MAAS API credentials and optional overrides:
116-
117-
1. `maas_api_key`: MAAS API key for authentication.
118-
2. `maas_api_url`: MAAS API endpoint (e.g., `http://127.0.0.1:5240/MAAS/api/2.0/`).
133+
Provides MAAS API credentials:
119134

120-
`maas_profile`: MAAS CLI profile name (e.g., `admin`).
121-
122-
1. `target_hosts` (optional): Override the default `target_hosts` list.
123-
2. `exclude_groups` (optional): Override the default `exclude_groups` list.
135+
- `maas_cluster_instance.customer_key`: MAAS API customer key.
136+
- `maas_cluster_instance.token_key`: MAAS API token key.
137+
- `maas_cluster_instance.token_secret`: MAAS API token secret.
124138

125139
**Example**:
126140

127141
```yaml
128-
maas_api_key: "XXXXXXXXXXXXXXXX"
129-
maas_api_url: "http://127.0.0.1:5240/MAAS/api/2.0/"
130-
maas_profile: "admin"
131-
# Optional overrides
132-
target_hosts:
133-
- machine001.internal.ceph.ibm.com
134-
exclude_groups:
135-
- maas
136-
- all
137-
- ungrouped
142+
---
143+
maas_cluster_instance:
144+
customer_key: "your_customer_key"
145+
token_key: "your_token_key"
146+
token_secret: "your_token_secret"
138147
```
139148

140-
**Notes**:
141-
142-
- **Security**: Ensure file permissions are restricted (e.g., `chmod 600 maas.yml`).
143-
- **Vault**: If encrypted, provide the vault password (e.g., via `--vault-password-file ~/.vault_pass.txt`).
144-
145149
## Behavior
146150

147-
- **DNS Records**: Creates A records for hosts based on `dns_domains` and inventory variables (e.g., `ip`, `ipmi`, `vlan104`). Example:
148-
- `machine001.internal.ceph.ibm.com` → `10.18.131.100`
149-
- `machine001.ipmi.ceph.ibm.com` → `10.18.139.100`
150-
- `machine001.vlan104.internal.ceph.ibm.com` → `10.18.144.3`
151-
- **Cleanup**: Deletes DNS records and domains not in `dns_domains` or `default_domains`.
151+
- **DNS Records**: Creates A/AAAA records for hosts based on `dns_domains` and inventory variables (e.g., `ip`, `ipmi`). Example:
152+
- `server01.example.com` → `192.168.1.11`
153+
- `server01.ipmi.example.com` → `192.168.2.11`
154+
- Additional records from `dns_records` (e.g., `api.ocp1.example.com` → `192.168.1.101`).
155+
- **Cleanup**: Deletes DNS records and domains not in `dns_domains` or `excluded_domains`, skipping default MAAS domains.
156+
- **NS Records**: Skipped due to module limitations; create manually via MAAS CLI or UI.
152157
- **Idempotency**: Skips actions if the desired state is already met.
158+
- **Retries**: Removal tasks include retries (`retries: 3`, `delay: 5`) to handle transient network issues.
153159

154160
## Troubleshooting
155161

156-
- **Missing** `dns_domains`: Ensure `dns_domains` is defined in `inventory/group_vars/all.yml`. The playbook will fail if undefined.
157-
- **Secrets Not Loading**: Verify `secrets_path` points to the correct directory and `maas.yml` contains valid credentials.
158-
- **MAAS CLI Errors**: Confirm the MAAS CLI is installed on the target server and the API key is valid.
159-
- **Failed Deletions**: Check playbook output for errors during DNS record or domain deletions (e.g., permissions, network issues, or records that do not exist).
160-
- **Unwanted DNS Records**: If DNS records are created for unintended hosts, verify `exclude_groups` includes `all` and `ungrouped` to prevent the inclusion of all inventory hosts or ungrouped hosts. Check for overrides in `secrets/maas.yml` or extra vars that modify `target_hosts` or `exclude_groups`.
162+
- **Network Issues**: If you see `[Errno -2] Name or service not known`, verify the MAAS server hostname (e.g., `maas-server.example.com`) resolves correctly:
163+
```bash
164+
ping maas-server.example.com
165+
curl http://maas-server.example.com:5240/MAAS/api/2.0/version/
166+
```
167+
Add to `/etc/hosts` if needed (e.g., `192.168.1.10 maas-server.example.com`).
168+
169+
- **Missing dns_domains**: Ensure `dns_domains` is defined in `inventory/group_vars/all.yml`.
170+
171+
- **Secrets Not Loading**: Verify `secrets_path` points to the correct directory and `maas.yml` contains valid credentials. If using Ansible Vault, provide the vault password:
172+
```bash
173+
ansible-playbook maas_nameserver.yml --vault-password-file ~/.vault_pass.txt
174+
```
175+
176+
- **MAAS API Errors**: Confirm the MAAS CLI is installed and the API credentials are valid. Test with:
177+
```bash
178+
maas login <profile> http://maas-server.example.com:5240/MAAS <api-key>
179+
maas <profile> domains read
180+
```
181+
182+
- **Unwanted DNS Records**: Verify `excluded_groups` includes `all` and `ungrouped` in `defaults/main.yml` to prevent unintended host inclusion.
183+
184+
- **NS Record Skipped**: Manually create NS records in MAAS UI or CLI:
185+
```bash
186+
maas login <profile> http://maas-server.example.com:5240/MAAS <api-key>
187+
maas <profile> dnsresource create domain=example.com name=ns1 type=NS data=ns1.example.com ttl=3600
188+
```
189+
190+
- **Slow Execution**: Enable profiling to identify bottlenecks:
191+
```bash
192+
ansible-playbook maas_nameserver.yml -v
193+
```
194+
Adjust `ansible.cfg` for higher parallelism:
195+
```ini
196+
[defaults]
197+
forks = 20
198+
```
199+
200+
## Performance Optimizations
201+
202+
- **Inventory Filtering**: Only hosts with `ip` or `ipmi` variables are processed, reducing unnecessary iterations.
203+
- **Retries for Reliability**: Removal tasks use retries to handle transient network issues, improving robustness for large inventories (e.g., 48 hosts).
204+
205+
For further optimization, consider enabling fact caching in `ansible.cfg` to reduce API calls in subsequent runs:
206+
```ini
207+
[defaults]
208+
fact_caching = jsonfile
209+
fact_caching_timeout = 86400
210+
fact_caching_connection = /tmp/ansible_cache
211+
```
Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
---
2-
maas_api_url: "http://localhost:5240/MAAS/api/2.0/" # Default, overridden by secrets
3-
maas_profile: "admin" # Default, overridden by secrets
4-
default_domains:
5-
- "maas"
6-
7-
# List of target hosts for DNS records, excluding the 'maas' group by default.
8-
# Can be overridden in secrets/maas.yml (e.g., target_hosts: ['host1.example.com', 'host2.example.com'])
9-
# If not set, defaults to all hosts in inventory groups except those in exclude_groups.
10-
target_hosts: []
11-
12-
# List of inventory groups to exclude from target_hosts.
13-
# Includes 'all' and 'ungrouped' to prevent automatic inclusion of all hosts or ungrouped hosts,
14-
# as 'all' contains every host in the inventory and 'ungrouped' includes hosts not assigned to any group.
15-
exclude_groups: ["maas", "all", "ungrouped"]
16-
17-
# Note: dns_domains should be defined in the inventory's group_vars/all.yml
2+
inventory_path: "{{ lookup('env', 'ANSIBLE_INVENTORY_PATH') | default('/etc/ansible/hosts', true) }}"
3+
# MAAS server IP address
4+
maas_server_ip: "{{ groups.get('maas', []) | first | default('undefined_maas_server') }}"
5+
# MAAS API URL
6+
maas_api_url: "http://{{ maas_server_ip }}:5240/MAAS"
7+
# Default TTL for DNS records
8+
dns_ttl: 3600
9+
# Groups to exclude from inventory processing
10+
excluded_groups: ['all', 'ungrouped']
11+
# Domains to exclude from management
12+
excluded_domains: ['maas', 'front.sepia.ceph.com']
13+
# Supported DNS record types
14+
supported_record_types: ['A/AAAA', 'CNAME', 'MX', 'NS', 'SRV', 'SSHFP', 'TXT']

0 commit comments

Comments
 (0)