https://github.com/aioue/ansible-unifi-inventory
Dynamic Ansible inventory plugin for UniFi OS controllers
https://github.com/aioue/ansible-unifi-inventory
ansible ansible-galaxy-collections ansible-inventory unifi
Last synced: 3 months ago
JSON representation
Dynamic Ansible inventory plugin for UniFi OS controllers
- Host: GitHub
- URL: https://github.com/aioue/ansible-unifi-inventory
- Owner: aioue
- License: gpl-3.0
- Created: 2025-10-09T19:58:57.000Z (9 months ago)
- Default Branch: main
- Last Pushed: 2026-03-22T18:04:03.000Z (3 months ago)
- Last Synced: 2026-03-23T09:07:21.826Z (3 months ago)
- Topics: ansible, ansible-galaxy-collections, ansible-inventory, unifi
- Language: Python
- Homepage: https://aioue.net/2026/03/22/ansible-unifi-inventory-plugin/
- Size: 60.5 KB
- Stars: 10
- Watchers: 0
- Forks: 3
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# aioue.network
Dynamic inventory plugin for Ansible that discovers hosts from a UniFi OS controller (UDM, UCG, etc.). Built on top of [aiounifi](https://github.com/Kane610/aiounifi).
```shell
$ ansible-inventory -i inventory/unifi.yaml all --graph
@all:
|--@ungrouped:
|--@unifi_clients:
| |--phone
| |--laptop
| |--Kitchen Echo
| |--pc
| |--console
| |--nas
|--@unifi_wireless_clients:
| |--phone
|--@network_default:
| |--laptop
|--@network_iot:
| |--Kitchen Echo
|--@vlan_30:
| |--Kitchen Echo
|--@vlan_iot:
| |--Kitchen Echo
|--@unifi_wired_clients:
| |--pc
| |--console
| |--nas
|--@ssid_iot:
| |--Kitchen Echo
```
## What This Is
- **Dynamic inventory plugin** for Ansible that fetches UniFi network clients as inventory hosts.
- **Supports UniFi OS controllers** (modern UniFi Dream Machine, Cloud Gateway, etc.).
- **Discovers clients** connected to your network (wired and wireless).
- **Optionally includes UniFi devices** (access points, switches, gateways).
## What This Is Not
- Not a UniFi controller configuration tool.
- Not compatible with legacy UniFi controllers (pre-UniFi OS) without modification.
## Prerequisites
- **Python 3.12+** (newer `aiounifi` releases may require 3.13+; check `pip install` output)
- **Ansible 2.15+**
- **UniFi OS controller** accessible via network (UDM, UCG, etc.).
- **API credentials**: A dedicated local admin user/password (2FA not supported) or an API token.
- **Python dependencies**: Install in the same Python environment as Ansible:
```bash
pip install aiounifi aiohttp PyYAML
```
## Installation
You can install the `aioue.network` collection from this GitHub repository using the Ansible Galaxy CLI:
```shell
ansible-galaxy collection install git+https://github.com/aioue/ansible-unifi-inventory.git
```
You can also include it in a `requirements.yml` file:
```yaml
---
collections:
- name: aioue.network
source: https://github.com/aioue/ansible-unifi-inventory.git
type: git
# If you need a specific version, you can specify a branch or tag:
# version: main
```
Then, install it with `ansible-galaxy collection install -r requirements.yml`.
## Configuration
This is an Ansible inventory plugin. Configuration is done via a YAML inventory file that uses the plugin.
### Create an Inventory File
Create a new inventory file (e.g., `unifi_inventory.yml`) with your settings.
**Important:** You must use the Fully Qualified Collection Name (FQCN) `aioue.network.unifi` for the `plugin` key.
```yaml
# Example: unifi_inventory.yml
# Use the FQCN for the plugin
plugin: aioue.network.unifi
# UniFi controller URL (required)
url: "https://192.168.1.1"
# --- Authentication ---
# Provide EITHER token OR username/password
# API Token (Preferred method)
# Leave empty to use username/password
token: "your-api-token-here"
# Username/Password (Alternative)
# Must be a LOCAL admin account without 2FA
username: "ansible-admin"
password: "your-password"
# ---------------------
# UniFi site name
site: "default"
# Set to false for self-signed certificates
verify_ssl: false
# Set to true to include APs, switches, etc.
include_devices: false
# Only include clients seen in the last 30 minutes
last_seen_minutes: 30
# Cache API results for 30 seconds
cache_ttl: 30
```
### Environment Variables
You can also provide configuration via environment variables, which will override settings in the YAML file.
```bash
export UNIFI_URL=https://192.168.1.1
export UNIFI_TOKEN=your-api-token-here
export UNIFI_SITE=default
export UNIFI_VERIFY_SSL=false
```
## Usage
Once your collection is installed and your `unifi_inventory.yml` file is created, you can use it like any other Ansible inventory source.
### Use With ansible-inventory
```bash
# View full inventory as JSON
ansible-inventory -i unifi_inventory.yml --list
# Show hosts in a specific group
ansible-inventory -i unifi_inventory.yml --graph unifi_wired_clients
# See graph of all groups
ansible-inventory -i unifi_inventory.yml --graph
```
### Use With Ansible Ad-Hoc Commands
```bash
# Ping all discovered hosts
ansible -i unifi_inventory.yml all -m ping
# Target only wireless clients
ansible -i unifi_inventory.yml unifi_wireless_clients -m shell -a "uptime"
# Target a specific SSID group
ansible -i unifi_inventory.yml ssid_guest_wifi -m shell -a "uptime"
```
### Use With Ansible Playbooks
```bash
# Run a playbook against your UniFi inventory
ansible-playbook -i unifi_inventory.yml site.yml
# Limit the playbook to a dynamic group
ansible-playbook -i unifi_inventory.yml site.yml --limit unifi_clients
```
### Using Multiple Inventory Sources
Ansible can merge multiple inventory sources.
```bash
ansible-playbook -i static_hosts.yml -i unifi_inventory.yml site.yml
```
## Authentication
Two authentication methods are supported.
### API Token (Preferred)
1. Log in to your UniFi controller as a **local** admin user.
2. Go to `Settings > Network > Control Plane > Integrations > Network API` (or similar path).
3. Create a new token.
4. Use this token for the `token` config option or the `UNIFI_TOKEN` environment variable.
### Username/Password
You must use a **local admin account** (not a ui.com SSO account) and **2FA must be disabled** for this account.
1. Go to `UniFi OS Settings > Admins & Users`.
2. Create a new user.
3. Select "Admin" role.
4. **Crucially, select "Restrict to Local Access Only"**.
5. Do **NOT** enable 2FA for this account.
6. Use these credentials for the `username`/`password` config options or the `UNIFI_USERNAME`/`UNIFI_PASSWORD` environment variables.
**Note:** If both token and username/password are provided, the **token takes precedence**.
## Inventory Schema
### Groups
The plugin creates these dynamic groups:
**For clients:**
- `unifi_clients` - all discovered clients
- `unifi_wireless_clients` - wireless clients only
- `unifi_wired_clients` - wired clients only
- `ssid_` - clients on specific SSID (e.g., `ssid_guest_wifi`)
- `vlan_` - clients on specific VLAN ID (e.g., `vlan_10`)
- `vlan_` - clients on specific VLAN name (e.g., `vlan_guest_network`)
- `network_` - clients on specific network (e.g., `network_iot`)
**For devices (when `include_devices: true`):**
- `unifi_devices` - all UniFi devices
- `unifi_uap` - UniFi access points
- `unifi_usw` - UniFi switches
- `unifi_ugw` / `unifi_uxg` / `unifi_ucg` - UniFi gateways
### Host Variables (Clients)
Each client host includes:
- `ansible_host` - IP address (IPv4 preferred, IPv6 fallback)
- `mac` - MAC address
- `ip` / `ipv4` - IPv4 address (if available)
- `ipv6` - IPv6 address (if available)
- `ipv6_addresses` - All IPv6 addresses (if multiple)
- `is_wired` - boolean, true if wired connection
- `site` - UniFi site name
- `last_seen_unix` - Unix timestamp of last seen
- `last_seen_iso` - ISO 8601 timestamp of last seen
- `ssid` - SSID name (wireless only)
- `ap_mac` - AP MAC address (wireless only)
- `sw_mac` - Switch MAC address (wired only)
- `port` - Switch port number (wired only)
- `vlan` - VLAN ID (if available)
- `vlan_name` - VLAN name (if available)
- `network` - Network name (if available)
- `network_id` - Network ID (if available)
- `oui` - Device manufacturer OUI (if available)
### Host Variables (Devices)
Each device host includes:
- `ansible_host` - Management IP address
- `mac` - MAC address
- `ip` - IP address
- `model` - Device model
- `type` - Device type (uap, usw, ugw, etc.)
- `firmware_version` - Current firmware version
- `site` - UniFi site name
- `adopted` - boolean, adoption status
- `state` - Device state
## Configuration Options Reference
| Option | Env Var | Config Key | Default |
|--------|---------|------------|---------|
| Controller URL | `UNIFI_URL` | `url` | (required) |
| Username | `UNIFI_USERNAME` | `username` | "" |
| Password | `UNIFI_PASSWORD` | `password` | "" |
| API Token | `UNIFI_TOKEN` | `token` | "" |
| Site Name | `UNIFI_SITE` | `site` | `default` |
| Verify SSL | `UNIFI_VERIFY_SSL` | `verify_ssl` | `true` |
| Include Devices | `UNIFI_INCLUDE_DEVICES` | `include_devices` | `false` |
| Last Seen Minutes | `UNIFI_LAST_SEEN_MINUTES` | `last_seen_minutes` | `30` |
| Cache TTL | `UNIFI_CACHE_TTL` | `cache_ttl` | `30` |
| Cache Path | `UNIFI_CACHE_PATH` | `cache_path` | `./.cache/unifi_inventory.json` |
## Security Best Practices
### Don't Commit Secrets
- **Never commit** your `unifi_inventory.yml` file with real credentials.
- Use a local file and add it to `.gitignore`.
- Use Ansible Vault to encrypt the inventory file.
### Use Ansible Vault
Encrypt your sensitive inventory file:
```bash
# Encrypt config file
ansible-vault encrypt unifi_inventory.yml
# Use with inventory
ansible-playbook -i unifi_inventory.yml site.yml --ask-vault-pass
```
### Use Environment Variables
For CI/CD pipelines, use environment variables to inject secrets.
```bash
export UNIFI_URL=https://192.168.1.1
export UNIFI_TOKEN=$VAULT_UNIFI_TOKEN
ansible-playbook -i unifi_inventory.yml site.yml
```
### Token vs Password
- Prefer **API tokens** over username/password.
- Tokens can be easily revoked without changing account credentials.
## Troubleshooting
### SSL Certificate Errors
**Symptom:** `SSL: CERTIFICATE_VERIFY_FAILED` errors
**Solution:** Self-signed certificates are common on UniFi controllers.
- Set `verify_ssl: false` in your inventory config file (easiest, but less secure).
- Add your controller's certificate to your system trust store.
### Authentication Failures
**Symptom:** "Authentication failed" or 403/401 errors
**Causes:**
- Incorrect username/password or token.
- Token expired or revoked.
- **Two-Factor Authentication (2FA) is enabled on the account.** This plugin does not support 2FA.
- Using a ui.com SSO account instead of a local admin account.
**Solution:**
- Verify credentials.
- **You MUST use a local admin account with 2FA disabled.** See the "Authentication" section for instructions on how to create one.
- Regenerate your API token.
### No Hosts Returned
**Symptom:** Empty inventory
**Causes:**
- `last_seen_minutes` threshold is too low.
- No clients have been active recently.
- Wrong `site` name specified.
**Solution:**
- Increase `last_seen_minutes` to `1440` (24 hours) to see if stale clients appear.
- Verify your `site` name in the UniFi controller (it's often `default`).
- Enable devices to see your infrastructure: `include_devices: true`.
### Stale Cache Data
**Symptom:** Inventory doesn't reflect recent changes (new clients, IP changes).
**Solution:**
- Clear the cache file: `rm ./.cache/unifi_inventory.json` (or the path set in `cache_path`).
- Reduce `cache_ttl` for more frequent updates.
- Set `cache_ttl: 0` to disable caching entirely (not recommended for frequent runs).
### Network Timeouts
**Symptom:** Network request errors, "Connection refused".
**Causes:**
- Controller URL is incorrect or unreachable from where Ansible is running.
- Firewall is blocking HTTPS (port 443) access to the controller.
**Solution:**
- Verify controller URL.
- Test connectivity: `curl -k https://192.168.1.1` (replace with your URL).
- Check firewall rules.
## Advanced Usage
### Filter by Last Seen Time
Only include clients seen in the last 5 minutes:
```yaml
plugin: aioue.network.unifi
url: "https://192.168.1.1"
token: "your-token"
last_seen_minutes: 5
```
### Include Infrastructure Devices
Include APs, switches, and gateways in the inventory:
```yaml
plugin: aioue.network.unifi
url: "https://192.168.1.1"
token: "your-token"
include_devices: true
```
### Disable Caching
For real-time inventory without caching (will be slower and cause more API load):
```yaml
plugin: aioue.network.unifi
url: "https://192.168.1.1"
token: "your-token"
cache_ttl: 0
```
### Multiple Sites
For multi-site controllers, create separate inventory files for each site you want to query.
**`site_default.yml`:**
```yaml
plugin: aioue.network.unifi
url: "https://192.168.1.1"
token: "your-token"
site: "default"
```
**`site_branch.yml`:**
```yaml
plugin: aioue.network.unifi
url: "https://192.168.1.1"
token: "your-token"
site: "branch-office"
```
## Performance Notes
- **Caching is enabled by default** (`cache_ttl: 30` seconds) to reduce API calls.
- The first run will be slower (2-10 seconds) as it fetches data from the API.
- Subsequent runs within the TTL window will be very fast (< 100ms) as they read from the cache file.
## Upgrading from pre-collection versions
If you were using the plugin directly (copying `unifi.py` to your plugins directory), 1.0.0 has breaking changes:
1. **Install the collection:** `ansible-galaxy collection install git+https://github.com/aioue/ansible-unifi-inventory.git`
2. **Update inventory files:** change `plugin: unifi` to `plugin: aioue.network.unifi`
3. **Update ansible.cfg:** remove `unifi` from `enable_plugins` (the collection is auto-discovered). If you had `inventory_plugins = ./plugins/inventory`, that line can also be removed
4. **Remove the old plugin file** from `~/.ansible/plugins/inventory/` or your custom path
5. **Python 3.12+** is now required (was 3.11+)
## Releasing a New Version
1. Bump `version:` in `galaxy.yml`
2. Update `CHANGELOG.md`
3. Commit, tag, and push:
```bash
git tag v1.x.x
git push origin v1.x.x
```
The GitHub Actions workflow will build the collection, publish it to Ansible Galaxy, and create a GitHub Release automatically.
## Contributing
For issues or enhancements, please ensure:
- Python 3.12+ compatibility
- Type hints for all functions
- PEP 8 code style
## License
GNU General Public License v3.0 or later (GPL-3.0+)
See [LICENSE](LICENSE) file for full text.
Copyright (c) 2025 Tom Paine (https://github.com/aioue)