From charlesreid1

(Created page with "==Example executable dynamic inventory script== Let's walk through an example. '''List of hosts:''' For vagrant machines, vagrant status gives output about which machines a...")
 
Line 1: Line 1:
==Example executable dynamic inventory script==
==How to use dynamic inventory script==


Let's walk through an example.
The dynamic inventory script should


'''List of hosts:'''
The dynamic inventory script must accept to command line flags, for the two ways Ansible will call this dynamic inventory script:


For vagrant machines, vagrant status gives output about which machines are running. This is information we want to provide to the dynamic inventory file to create a list of hosts.
<pre>
--host=<hostname>  show host details
--list              list groups
</pre>
 
For example, Ansible will call the inventory script like so:
 
<pre>
$ ./dynamic.py --host=vagrant2
</pre>
 
 
 
=Example executable dynamic inventory script=
 
Let's walk through an example script with Vagrant.
 
This example script is written in Python. It takes two input arguments, <code>--host=X</code> and <code>--list</code>, and interacts with Vagrant to return the requested information.
 
==Vagrant==
 
===Getting List of Hosts===
 
Start with how to get a list of hosts for the <code>--list</code> flag.
 
Vagrant provides a command to show info about all running vagrant machines:
 
<pre>
vagrant status
</pre>
 
This info can be used to create the list of hosts for the dynamic inventory file. A more convenient format for parsing is:


<pre>
<pre>
Line 11: Line 42:
</pre>
</pre>


which is a lot of info in CSV format that can be parsed.
which prints everything in CSV format. The code:
 
<pre>
 
def list_running_hosts():
    cmd = "vagrant status --machine-readable"
    status = subprocess.check_output(cmd.split()).rstrip()
    hosts = []
    for line in status.split('\n'):
        (_, host, key, value) = line.split(',')[:4]
        if key == 'state' and value == 'running':
            hosts.append(host)
    return hosts
</pre>
 
===Getting Machine Configuration Details===
 
Now we need to get host-specific details for the <code>--host=X</code> flag.


Next, we can use the <code>vagrant ssh-config</code> command, which outputs information that is formatted for an SSH config file, and parse it using pamiko (a Python library for doing SSH-related things - in this case, parsing an SSH config file and turning it into a python dictionary).
Next we can use the <code>vagrant ssh-config</code> command to get info about the machine-specific configuration details of each machine, which is necessary for Ansible to connect to them. To parse SSH config files, we can use a Python library called pamiko.
 
<pre>
def get_host_details(host):
    cmd = "vagrant ssh-config {}".format(host)
    p = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
    config = paramiko.SSHConfig()
    config.parse(p.stdout)
    c = config.lookup(host)
    return {'ansible_host': c['hostname'],
            'ansible_port': c['port'],
            'ansible_user': c['user'],
            'ansible_private_key_file': c['identityfile'][0]}
</pre>
 
===Parsing user arguments===
 
A quick argparser tutorial for the flags we're interested in parsing:
 
<pre>
def parse_args():
    parser = argparse.ArgumentParser(description="Vagrant inventory script")
    group = parser.add_mutually_exclusive_group(required=True)
    group.add_argument('--list', action='store_true')
    group.add_argument('--host')
    return parser.parse_args()
</pre>
 
Now we can call this function and use args.list or args.host to access the values of the flags.
 
===Putting it all together===
 
Here is the final dynamic inventory script:
 
'''dynamic_vagrant.py''':


<pre>
<pre>
Line 71: Line 153:
</pre>
</pre>


===Running the dynamic inventory script===
Once we've written the dynamic inventory script and we're ready to run Ansible using it, we can pass the inventory script using the -i flag:
<pre>
ansible -i dynamic_vagrant.py -u ubuntu myvagrantbox -m ping
</pre>


==Flags==
==Flags==

Revision as of 18:46, 10 November 2018

How to use dynamic inventory script

The dynamic inventory script should

The dynamic inventory script must accept to command line flags, for the two ways Ansible will call this dynamic inventory script:

--host=<hostname>   show host details
--list              list groups

For example, Ansible will call the inventory script like so:

$ ./dynamic.py --host=vagrant2


Example executable dynamic inventory script

Let's walk through an example script with Vagrant.

This example script is written in Python. It takes two input arguments, --host=X and --list, and interacts with Vagrant to return the requested information.

Vagrant

Getting List of Hosts

Start with how to get a list of hosts for the --list flag.

Vagrant provides a command to show info about all running vagrant machines:

vagrant status

This info can be used to create the list of hosts for the dynamic inventory file. A more convenient format for parsing is:

vagrant status --machine-readable

which prints everything in CSV format. The code:


def list_running_hosts():
    cmd = "vagrant status --machine-readable"
    status = subprocess.check_output(cmd.split()).rstrip()
    hosts = []
    for line in status.split('\n'):
        (_, host, key, value) = line.split(',')[:4]
        if key == 'state' and value == 'running':
            hosts.append(host)
    return hosts

Getting Machine Configuration Details

Now we need to get host-specific details for the --host=X flag.

Next we can use the vagrant ssh-config command to get info about the machine-specific configuration details of each machine, which is necessary for Ansible to connect to them. To parse SSH config files, we can use a Python library called pamiko.

def get_host_details(host):
    cmd = "vagrant ssh-config {}".format(host)
    p = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
    config = paramiko.SSHConfig()
    config.parse(p.stdout)
    c = config.lookup(host)
    return {'ansible_host': c['hostname'],
            'ansible_port': c['port'],
            'ansible_user': c['user'],
            'ansible_private_key_file': c['identityfile'][0]}

Parsing user arguments

A quick argparser tutorial for the flags we're interested in parsing:

def parse_args():
    parser = argparse.ArgumentParser(description="Vagrant inventory script")
    group = parser.add_mutually_exclusive_group(required=True)
    group.add_argument('--list', action='store_true')
    group.add_argument('--host')
    return parser.parse_args()

Now we can call this function and use args.list or args.host to access the values of the flags.

Putting it all together

Here is the final dynamic inventory script:

dynamic_vagrant.py:

#!/usr/bin/env python
# Adapted from Mark Mandel's implementation
# https://github.com/ansible/ansible/blob/stable-2.1/contrib/inventory/vagrant.py
# License: GNU General Public License, Version 3 <http://www.gnu.org/licenses/>
import argparse
import json
import paramiko
import subprocess
import sys


def parse_args():
    parser = argparse.ArgumentParser(description="Vagrant inventory script")
    group = parser.add_mutually_exclusive_group(required=True)
    group.add_argument('--list', action='store_true')
    group.add_argument('--host')
    return parser.parse_args()


def list_running_hosts():
    cmd = "vagrant status --machine-readable"
    status = subprocess.check_output(cmd.split()).rstrip()
    hosts = []
    for line in status.split('\n'):
        (_, host, key, value) = line.split(',')[:4]
        if key == 'state' and value == 'running':
            hosts.append(host)
    return hosts


def get_host_details(host):
    cmd = "vagrant ssh-config {}".format(host)
    p = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
    config = paramiko.SSHConfig()
    config.parse(p.stdout)
    c = config.lookup(host)
    return {'ansible_host': c['hostname'],
            'ansible_port': c['port'],
            'ansible_user': c['user'],
            'ansible_private_key_file': c['identityfile'][0]}


def main():
    args = parse_args()
    if args.list:
        hosts = list_running_hosts()
        json.dump({'vagrant': hosts}, sys.stdout)
    else:
        details = get_host_details(args.host)
        json.dump(details, sys.stdout)

if __name__ == '__main__':
    main()

Running the dynamic inventory script

Once we've written the dynamic inventory script and we're ready to run Ansible using it, we can pass the inventory script using the -i flag:

ansible -i dynamic_vagrant.py -u ubuntu myvagrantbox -m ping

Flags