Metadata-Version: 2.4
Name: invgen
Version: 1.1.12
Summary: Dynamic Ansible Inventory Generator
License: MIT License
        
        Copyright (c) 2024 Florian
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
        
Requires-Python: >=3.11
Description-Content-Type: text/markdown
Requires-Dist: jinja2
Requires-Dist: pyyaml>=6.0.2
Requires-Dist: typer>=0.13.1
Requires-Dist: watchdog

# Dynamic Ansible Inventory

[![CI](https://github.com/rwxd/invgen/actions/workflows/ci.yml/badge.svg)](https://github.com/rwxd/invgen/actions/workflows/ci.yml)
[![codecov](https://codecov.io/gh/rwxd/invgen/branch/main/graph/badge.svg)](https://codecov.io/gh/rwxd/invgen)

This is a dynamic inventory script for Ansible that reads the inventory from a
directory. A list of hosts is managed by the user. Each host has metadata that is used to gather variables.

## Directory Structure

The structure of the inventory directory is as follows:

```tree
hosts/
  host1.yaml
  host2.yaml
  host3.yaml
generated/
  host1.yaml
  host2.yaml
  host3.yaml
metadata/
  tags/
    tag1.yaml
    tag2.yaml
  platform/
    platform1.yaml
    platform2.yaml
  my_custom_metadata/
    my_custom_metadata1.yaml
    my_custom_metadata2.yaml
```

- The `hosts` directory contains host files that define the hosts.
- The `generated` directory contains generated host files that are created by the script and used as an inventory.
- The `metadata` directory contains metadata files that can be used to give hosts variables.

## Host Configuration

To use the metadata, the host file must have a `metadata` key that contains a list of metadata files:

```yaml
metadata:
  tags:
    - tag1
    - tag2
  platform: platform1
  my_custom_metadata: my_custom_metadata1
```

Under [example/](./example/) you can find an example of how to build an inventory.

## Variable Templating

Jinja2 can be used inside of variables, because it is parsed by Ansible at runtime:

```yaml
domain_name: example.com
hostname: ap01

ansible_host: "{{ hostname }}.{{ domain_name }}"

dns_servers:
  - 1.1.1.1
  - 8.8.8.8

network_interfaces:
  - name: eth0
    type: ethernet
    state: up
    ip: 192.168.1.100
    netmask: 255.255.255.0
    gateway: 192.168.1.1
    dns: "{{ dns_servers }}"
```

## Installation

Install with `pip install -U invgen` or `uv tool install -U invgen`.

## Usage

### Generate Inventory

```bash
# set the environment variable INVGEN_SOURCE to the path of the inventory directory
export INVGEN_SOURCE="$PWD/example/"

# generate the host files
invgen generate --verbose

# clean and regenerate host files
invgen generate --verbose --clean

# regenerate on file change
invgen generate --verbose --watch
```

### Create New Hosts and Metadata

```bash
# Create a new host from a template
invgen new host -t example/templates/host.yaml -d example/hosts --name "ap02.test.local" -o "platform=raspberry-pi-4 provider=self-hosted services=pihole,dnsmasq"

# Create a new metadata file
invgen new metadata --metadata-type platform --name "raspberry-pi-5" -s example/
```

### Validate Inventory

```bash
# Validate all host files
invgen validate hosts
```

### Use with Ansible

```bash
# set the environment variable INVGEN_SOURCE to the path of the inventory directory
export INVGEN_SOURCE="$PWD/example/"

# run playbook with the inventory
ansible-playbook -i $(which invgen-ansible) playbook.yaml

# explore the inventory
❯ ansible-inventory -i $(which invgen-ansible) --graph
@all:
  |--@ungrouped:
  |--@environment_production:
  |  |--ap01.test.local
  |--@provider_self-hosted:
  |  |--ap01.test.local
  |--@hardware_raspberry-pi-4:
  |  |--ap01.test.local
  |--@os_rhel-9:
  |  |--ap01.test.local
  |--@services_podman-rootless:
  |  |--ap01.test.local
  |--@tags_selinux-deactivated:
  |  |--ap01.test.local
```

## Variable Merging

When multiple metadata sources define the same variable:

- For dictionaries: Keys are merged with host-specific values taking precedence
- For lists: Items are combined with duplicates removed
- For scalar values: The last processed value (host-specific) takes precedence

## Advanced Features

### Templating

You can use Jinja2 templates to generate host files:

```yaml
---
metadata:
    platform: {{ platform }}
    provider: {{ provider }}
    services: {{ services }}

ansible_host: {{ name }}
```

### Watching for Changes

The `--watch` flag allows the tool to automatically regenerate the inventory when files change:

```bash
invgen generate --verbose --watch
```
