Dynamic Inventories & Data¶
One of the biggest features of pyinfra is that it's configured in regular Python. This means inventory, data and deploy files can use Python code and modules. As a result it is possible to generate inventory and group data for a deploy.
For example, here we fetch the list of target hosts from some internal inventory API:
# inventory.py
import requests
def get_servers():
db = []
web = []
servers = requests.get('inventory.mycompany.net/api/v1/app_servers').json()
for server in servers:
if server['group'] == 'db':
db.append(server['hostname'])
elif server['group'] == 'web':
web.append(server['hostname'])
return db, web
db_servers, web_servers = get_servers()
Like the dynamic inventory, we can use Python inside group data. It is also possible to access the initial inventory (without group data):
Test Inventories with Fake Data¶
For tests, demos and screenshots you often want a whole inventory of hosts
without any real target to connect to. The built-in @fake connector
simulates command execution locally without running anything, and pairs nicely
with a function-based inventory
to generate any number of fake hosts and data in plain Python:
# inventory.py
def make_test(web_count=2, db_count=1):
web_hosts = [f'@fake/web-{i}' for i in range(1, web_count + 1)]
db_hosts = [f'@fake/db-{i}' for i in range(1, db_count + 1)]
# Any host can script specific command results (including failures) via
# `fake_responses`; anything unmatched just succeeds with no output.
web_hosts[0] = (
'@fake/web-1',
{
'fake_responses': {
'git --version': 'git version 2.40.0',
'pip install': {
'success': False,
'stderr': 'error: externally-managed-environment',
},
},
},
)
return {
'web': (web_hosts, {'role': 'web', 'port': 80}),
'db': (db_hosts, {'role': 'db', 'port': 5432}),
}
Point pyinfra at the function on the command line as module.attribute:
# Inspect the generated hosts and data
pyinfra inventory:make_test debug-inventory
# Run any command or operation against the fake hosts
pyinfra inventory:make_test exec -- echo "hello world"
# `@fake/web-1` reports the scripted failure, the rest succeed
pyinfra inventory:make_test server.shell "pip install requests"
See the @fake connector documentation for the full
fake_responses format (substring and regular-expression matchers), simulated
command timing and other available data.