1#!/usr/local/bin/python3.8 2""" 3Vagrant external inventory script. Automatically finds the IP of the booted vagrant vm(s), and 4returns it under the host group 'vagrant' 5 6Example Vagrant configuration using this script: 7 8 config.vm.provision :ansible do |ansible| 9 ansible.playbook = "./provision/your_playbook.yml" 10 ansible.inventory_path = "./provision/inventory/vagrant.py" 11 ansible.verbose = true 12 end 13""" 14 15# Copyright (C) 2013 Mark Mandel <mark@compoundtheory.com> 16# 2015 Igor Khomyakov <homyakov@gmail.com> 17# 18# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 19 20from __future__ import (absolute_import, division, print_function) 21__metaclass__ = type 22 23# 24# Thanks to the spacewalk.py inventory script for giving me the basic structure 25# of this. 26# 27 28import sys 29import os.path 30import subprocess 31import re 32from paramiko import SSHConfig 33from optparse import OptionParser 34from collections import defaultdict 35import json 36 37from ansible.module_utils._text import to_text 38from ansible.module_utils.six.moves import StringIO 39 40 41_group = 'vagrant' # a default group 42_ssh_to_ansible = [('user', 'ansible_user'), 43 ('hostname', 'ansible_host'), 44 ('identityfile', 'ansible_ssh_private_key_file'), 45 ('port', 'ansible_port')] 46 47# Options 48# ------------------------------ 49 50parser = OptionParser(usage="%prog [options] --list | --host <machine>") 51parser.add_option('--list', default=False, dest="list", action="store_true", 52 help="Produce a JSON consumable grouping of Vagrant servers for Ansible") 53parser.add_option('--host', default=None, dest="host", 54 help="Generate additional host specific details for given host for Ansible") 55(options, args) = parser.parse_args() 56 57# 58# helper functions 59# 60 61 62# get all the ssh configs for all boxes in an array of dictionaries. 63def get_ssh_config(): 64 return dict((k, get_a_ssh_config(k)) for k in list_running_boxes()) 65 66 67# list all the running boxes 68def list_running_boxes(): 69 70 output = to_text(subprocess.check_output(["vagrant", "status"]), errors='surrogate_or_strict').split('\n') 71 72 boxes = [] 73 74 for line in output: 75 matcher = re.search(r"([^\s]+)[\s]+running \(.+", line) 76 if matcher: 77 boxes.append(matcher.group(1)) 78 79 return boxes 80 81 82# get the ssh config for a single box 83def get_a_ssh_config(box_name): 84 """Gives back a map of all the machine's ssh configurations""" 85 86 output = to_text(subprocess.check_output(["vagrant", "ssh-config", box_name]), errors='surrogate_or_strict') 87 config = SSHConfig() 88 config.parse(StringIO(output)) 89 host_config = config.lookup(box_name) 90 91 # man 5 ssh_config: 92 # > It is possible to have multiple identity files ... 93 # > all these identities will be tried in sequence. 94 for id in host_config['identityfile']: 95 if os.path.isfile(id): 96 host_config['identityfile'] = id 97 98 return dict((v, host_config[k]) for k, v in _ssh_to_ansible) 99 100 101# List out servers that vagrant has running 102# ------------------------------ 103if options.list: 104 ssh_config = get_ssh_config() 105 meta = defaultdict(dict) 106 107 for host in ssh_config: 108 meta['hostvars'][host] = ssh_config[host] 109 110 print(json.dumps({_group: list(ssh_config.keys()), '_meta': meta})) 111 sys.exit(0) 112 113# Get out the host details 114# ------------------------------ 115elif options.host: 116 print(json.dumps(get_a_ssh_config(options.host))) 117 sys.exit(0) 118 119# Print out help 120# ------------------------------ 121else: 122 parser.print_help() 123 sys.exit(0) 124