Skip to content

Instantly share code, notes, and snippets.

@timfoster
Created July 16, 2020 14:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save timfoster/d4303cdc6221bd9523b5a71c665930b6 to your computer and use it in GitHub Desktop.
Save timfoster/d4303cdc6221bd9523b5a71c665930b6 to your computer and use it in GitHub Desktop.
An Ansible plugin that builds an inventory from the output of 'getent hosts' on a remote machine
#!/usr/bin/python
# -*- coding: utf-8 -*-
import socket
import subprocess
from ansible.plugins.inventory import BaseInventoryPlugin
DOCUMENTATION = r'''
name: remote_hosts
plugin_type: inventory
short_description: Returns an Ansible inventory from 'getent hosts'
description:
- Generate an inventory by connecting to a remote machine using ssh
- and running 'getent hosts'.
- The returned inventory is grouped into a 'xxx_hosts' group, where xxx
- is the remote_hostname. We assume that 'ssh' is on the path, and
- the system is able to connect using passwordless auth.
options:
plugin:
description: getent hosts inventory
required: true
remote_hostname:
description: The remote machine on which to run 'getent hosts'.
required: true
remote_user:
description:
- The user to connect to the remote machine as.
- If left empty, we connect as the current user.
required: false
author: Tim Foster @timfoster
'''
#
# For example:
# $ /bin/ls ~/.ansible/plugins/inventory/remote_hosts.py
# /Users/timf/.ansible/plugins/inventory/remote_hosts.py
#
# $ cat remote_inv.yml
# plugin: remote_hosts
# remote_hostname: puroto
#
# $ ansible-inventory -i remote_inv.yml --graph
# @all:
# |--@puroto_hosts:
# | |--LB2120.mhs
# | |--aeris
# | |--amiorangi
# | |--ampache
# | |--aratuku
# etc.
#
class InventoryModule(BaseInventoryPlugin):
NAME = 'remote_hosts'
def verify_file(self, path):
# This is really basic
if path.endswith(".yaml") or path.endswith(".yml"):
return True
return False
def parse(self, inventory, loader, path, cache=True):
super(InventoryModule, self).parse(inventory, loader, path, cache)
self.inventory = inventory
self.loader = loader
self.path = path
self.cache = cache
config = self._read_config_data(path)
remote_host = config.get("remote_hostname")
remote_user = config.get("remote_user")
if not remote_host:
raise Exception("Missing 'remote_hostname' configuration")
try:
socket.gethostbyname(remote_host)
except Exception as e:
raise Exception("Unable to reach %s: %s" % (s, e))
group = "%s_hosts" % remote_host
self.inventory.add_group(group)
if remote_user:
ssh_cmd = "ssh -l %s %s getent hosts" % (remote_user, remote_host)
else:
ssh_cmd = "ssh %s getent hosts" % remote_host
completed = subprocess.run(ssh_cmd.split(), capture_output=True)
if completed.returncode != 0:
raise Exception("Unable to run command: %s" % ssh_cmd)
for line in completed.stdout.decode().split('\n'):
if not line:
continue
address, hosts = line.split(maxsplit=1)
for host in hosts.split():
self.inventory.add_host(host.strip(), group)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment