With this inventory script, when Ansible starts, it will execute the script once with --list to gather the group data. Then, Ansible will execute the script again with --host <hostname> for each host it discovered in the first call. With our script, this takes very little time, as there are very few hosts, and our execution is very fast. However, in an environment with a large number of hosts or a plugin that takes a while to run, gathering the inventory data can be a lengthy process. Fortunately, there is an optimization that can be made in the return data from a --list call that will prevent Ansible from rerunning the script for every host. The host-specific data can be returned all at once inside the group data return, inside a top-level key named _meta, which has a subkey named hostvars that contains a hash of all the hosts that have host variables and the variable data itself. When Ansible encounters a _meta key in the --list return, it'll skip the --host calls and assume that all of the host-specific data was already returned, potentially saving a significant amount of time! Let's modify our inventory script to return host variables inside _meta, and create an error condition inside the --host option to show that --host is not being called:
- First, we'll add the _meta key to the inventory dictionary after all of the hostvars have been built up using the same algorithm as before, and just before argument parsing:
hostvars['scsihost'] = {'ansible_ssh_user': 'jfreeman'}
agghostvars = dict()
for outergroup in inventory:
for grouphost in inventory[outergroup].get('hosts', {}):
agghostvars[grouphost] = allgroupvars.copy()
for group in inventory:
if grouphost in inventory[group].get('hosts', {}):
for childgroup in inventory:
if group in inventory[childgroup].get('children', {}):
agghostvars[grouphost].update(inventory[childgroup].get('vars', {}))
for group in inventory:
if grouphost in inventory[group].get('hosts', {}):
agghostvars[grouphost].update(inventory[group].get('vars', {}))
agghostvars[grouphost].update(hostvars.get(grouphost, {}))
inventory['_meta'] = {'hostvars': agghostvars}
parser = argparse.ArgumentParser(description='Simple Inventory')
Next, we'll change the --host handling to raise an exception:
elif args.host:
raise StandardError("You've been a bad boy")
-
- Now, we'll rerun the inventory_test.yaml playbook to ensure that we're still getting the right data:
- Just to be sure, we'll manually run the inventory plugin with the --hosts argument to show the exception:
With this optimization, our simple playbook using our inventory module now runs nearly twice as fast, just because of the gained efficiency in inventory parsing.