moose-inventory is a command-line tool for managing dynamic inventories for Ansible. This package is the Python implementation of the original Ruby moose-inventory tool, with the same basic job: keep hosts, groups, variables, and inventory metadata in a database and expose them through a CLI that Ansible can consume.
If you are here to use the tool, start with installation, configuration, and the examples below. Development, release, and maintenance notes live in the docs/ directory where they belong, safely away from the front desk.
Install the base package from PyPI:
python -m pip install moose-inventoryThis installs the moose-inventory command and includes SQLite support.
For MySQL/MariaDB or PostgreSQL database support, install the matching extra:
python -m pip install 'moose-inventory[mysql]'
python -m pip install 'moose-inventory[postgresql]'Check that the command is available:
moose-inventory version
moose-inventory helpmoose-inventory uses a YAML configuration file. The configuration has a required general section and one or more environment sections.
A minimal SQLite configuration looks like this:
general:
defaultenv: dev
dev:
db:
adapter: sqlite3
file: ./inventory.dbA configuration with multiple environments might look like this:
general:
defaultenv: dev
dev:
db:
adapter: sqlite3
file: ./inventory-dev.db
ops_mysql:
db:
adapter: mysql
host: localhost
database: inventory
user: inventory_user
password_env: MOOSE_INVENTORY_MYSQL_PASSWORD
ops_postgres:
db:
adapter: postgresql
host: localhost
database: inventory
user: inventory_user
password_env: MOOSE_INVENTORY_POSTGRES_PASSWORDPrefer password_env for MySQL/MariaDB and PostgreSQL passwords. It keeps reusable configuration files from containing plaintext secrets:
export MOOSE_INVENTORY_MYSQL_PASSWORD='use-a-real-secret-here'
moose-inventory --config ./config.yml --env ops_mysql host listThe configuration file can be supplied explicitly:
moose-inventory --config ./config.yml host listIf --config is not supplied, the command searches the standard Moose Tools configuration locations, including project-local, user-local, and system-level paths.
Use --env to select an environment section. If --env is omitted, the section named by general.defaultenv is used:
moose-inventory --config ./config.yml --env dev host listCreate and inspect inventory records:
moose-inventory --config ./config.yml database migrate
moose-inventory --config ./config.yml host add web01 --groups web
moose-inventory --config ./config.yml host addvar web01 os=fedora
moose-inventory --config ./config.yml group addvar web role=frontend
moose-inventory --config ./config.yml host list
moose-inventory --config ./config.yml host get web01
moose-inventory --config ./config.yml group list
moose-inventory --config ./config.yml group get webAsk the command for help when you forget the shape of a subcommand, as all civilized people do constantly:
moose-inventory help
moose-inventory help host
moose-inventory host help add
moose-inventory help groupMany read operations support --format:
moose-inventory --config ./config.yml --format json host list
moose-inventory --config ./config.yml --format pjson host list
moose-inventory --config ./config.yml --format yaml group listSupported formats are:
json— compact JSONpjson— pretty-printed JSONyaml— YAML
Mutating commands support --dry-run so you can preview changes before writing them:
moose-inventory --config ./config.yml host add web02 --groups web --dry-run
moose-inventory --config ./config.yml group rm old-web --dry-runFor automation and review workflows, combine --dry-run with --plan-format:
moose-inventory --config ./config.yml host add web02 --groups web --dry-run --plan-format pjsonDestructive commands require explicit confirmation with --yes unless you are only doing a dry run:
moose-inventory --config ./config.yml host rm old-web01 --dry-run
moose-inventory --config ./config.yml host rm old-web01 --yesHosts can belong to one or more groups. New hosts start in the automatic ungrouped group unless you place them elsewhere. When a host gains a real group association, ungrouped is removed automatically. When its last real group association is removed, ungrouped is added back.
moose-inventory --config ./config.yml host add web01
moose-inventory --config ./config.yml group add web
moose-inventory --config ./config.yml group add api --hosts api01 api02
moose-inventory --config ./config.yml host addgroup web01 web
moose-inventory --config ./config.yml group addhost web web02
moose-inventory --config ./config.yml host rmgroup web01 web --yes
moose-inventory --config ./config.yml group rmhost web web02 --yesGroups can also have child groups. This lets you model nested inventory structure without flattening everything into a sad pile of names.
moose-inventory --config ./config.yml group add region-east web
moose-inventory --config ./config.yml group addchild region-east web
moose-inventory --config ./config.yml group rmchild region-east web --yesUse --recursive when deleting a group and you intentionally want orphaned child groups removed too. Use --delete-orphans with group rmchild when removing a parent-child relationship should also delete child subtrees that become orphaned by that removal.
moose-inventory --config ./config.yml group rm old-parent --recursive --yes
moose-inventory --config ./config.yml group rmchild parent child --delete-orphans --yesHost and group variables are exposed to inventory consumers. Use them for data Ansible should see:
moose-inventory --config ./config.yml host addvar web01 os=fedora owner=platform
moose-inventory --config ./config.yml group addvar web role=frontend
moose-inventory --config ./config.yml host listvars web01
moose-inventory --config ./config.yml group listvars web
moose-inventory --config ./config.yml host rmvar web01 owner --yes
moose-inventory --config ./config.yml group rmvar web role --yesMetadata tags are separate from Ansible variables. Use them for operational labels such as environment, owner, lifecycle, location, role, or criticality when you want searchable inventory metadata without exposing it as host/group vars.
moose-inventory --config ./config.yml host addtag web01 prod critical owner-platform
moose-inventory --config ./config.yml host listtags web01
moose-inventory --config ./config.yml host rmtag web01 critical --yes
moose-inventory --config ./config.yml group addtag web frontend public-edge
moose-inventory --config ./config.yml group listtags web --format json
moose-inventory --config ./config.yml group rmtag web public-edge --yesTag names are normalized to lowercase and deduplicated.
Host listings can be filtered by group, tag, and variable. Multiple filters are treated as an AND: the host must match all requested groups, tags, and variable key/value pairs.
moose-inventory --config ./config.yml host list --group web --tag prod --var os=fedora --format yamlSuccessful mutating commands are recorded in a small append-only audit log. Dry runs are not recorded, because they did not change anything. Shocking restraint, really.
moose-inventory --config ./config.yml audit list
moose-inventory --config ./config.yml audit list --limit 100
moose-inventory --config ./config.yml audit list --format pjsonDatabase lifecycle commands live under database; db is an alias.
moose-inventory --config ./config.yml db status
moose-inventory --config ./config.yml db doctor
moose-inventory --config ./config.yml db migrate
moose-inventory --config ./config.yml db backup ./backup/moose-inventory.sqlite3db migrate creates missing schema tables and records the current schema version. db backup is supported for SQLite databases only; for MySQL/MariaDB and PostgreSQL, use native database backup tools such as mysqldump, mariadb-dump, pg_dump, or managed-service snapshots.
Export the full inventory as a portable YAML or JSON snapshot:
moose-inventory --config ./config.yml --format yaml export ./inventory.yml
moose-inventory --config ./config.yml --format pjson exportPreview an import before writing anything:
moose-inventory --config ./config.yml import ./inventory.yml --preview
moose-inventory --config ./config.yml import ./inventory.yml --preview --preview-format pjsonApply the import:
moose-inventory --config ./config.yml import ./inventory.ymlImports are additive and update-oriented: they create missing hosts and groups, add missing associations and tags, and create or update variables from the snapshot. They do not delete existing inventory records that are absent from the file.
Run doctor to check inventory health:
moose-inventory --config ./config.yml doctorUse a machine-readable format in CI or automation:
moose-inventory --config ./config.yml --format pjson doctorThe doctor command checks configuration, password hygiene, hosts only in ungrouped, orphan or empty groups, suspicious duplicate-ish names, invalid variable rows, and group cycles.
moose-inventory can be used as an Ansible dynamic inventory source.
List the inventory:
moose-inventory --config ./config.yml --listGet host variables for one host:
moose-inventory --config ./config.yml --host web01You can also call the underlying Ansible-oriented commands explicitly:
moose-inventory --config ./config.yml --ansible group list
moose-inventory --config ./config.yml --ansible host listvars web01To persist data from an Ansible run back into the inventory, call moose-inventory from a local task or from your inventory shim. For example:
- set_fact:
discovered_role: frontend
- name: Record discovered host role in Moose Inventory
delegate_to: localhost
ansible.builtin.command:
argv:
- moose-inventory
- --config
- ./config.yml
- host
- addvar
- "{{ inventory_hostname }}"
- "role={{ discovered_role }}"If you wrap moose-inventory in a shell shim, pass Ansible's arguments through as quoted "$@" so names and values containing spaces survive the trip through the shell-shaped cheese grater.
For manual browsing, open the read-only console:
moose-inventory --config ./config.yml consoleUseful console commands include:
hosts
groups
host web01
group web
tags host web01
tags group web
audit 20
help
quit
The Python package is intended as a replacement for the Ruby moose-inventory CLI. Before switching production automation, export from the Ruby-backed inventory and import into a test Python-backed database:
ruby-moose-inventory --config ./ruby-config.yml export ./moose-snapshot.yml
moose-inventory --config ./python-test.yml import ./moose-snapshot.yml --preview
moose-inventory --config ./python-test.yml import ./moose-snapshot.yml
moose-inventory --config ./python-test.yml doctor
moose-inventory --config ./python-test.yml export ./roundtrip.ymlCompare the round-tripped snapshot and run your Ansible inventory checks before pointing automation at the new database.
- User guide:
docs/user-guide.md - Database backend notes:
docs/backend-adapters.md - Release/package operations:
docs/release.md - Ruby compatibility notes:
docs/compatibility/
For contributors working from a checkout:
python -m pip install -e '.[dev,postgresql,mysql]'
./scripts/check.shThe check script runs tests, linting, type checking, package build, and package metadata validation.