1#!/usr/bin/env python 2# Copyright (c) 2017 Ansible Project 3# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 4 5import argparse 6from distutils.version import LooseVersion 7import json 8import os 9import sys 10from ipalib import api, errors, __version__ as IPA_VERSION 11from ansible.module_utils.six import u 12 13 14def initialize(): 15 ''' 16 This function initializes the FreeIPA/IPA API. This function requires 17 no arguments. A kerberos key must be present in the users keyring in 18 order for this to work. IPA default configuration directory is /etc/ipa, 19 this path could be overridden with IPA_CONFDIR environment variable. 20 ''' 21 22 api.bootstrap(context='cli') 23 24 if not os.path.isdir(api.env.confdir): 25 print("WARNING: IPA configuration directory (%s) is missing. " 26 "Environment variable IPA_CONFDIR could be used to override " 27 "default path." % api.env.confdir) 28 29 if LooseVersion(IPA_VERSION) >= LooseVersion('4.6.2'): 30 # With ipalib < 4.6.0 'server' and 'domain' have default values 31 # ('localhost:8888', 'example.com'), newer versions don't and 32 # DNS autodiscovery is broken, then one of jsonrpc_uri / xmlrpc_uri is 33 # required. 34 # ipalib 4.6.0 is unusable (https://pagure.io/freeipa/issue/7132) 35 # that's why 4.6.2 is explicitely tested. 36 if 'server' not in api.env or 'domain' not in api.env: 37 sys.exit("ERROR: ('jsonrpc_uri' or 'xmlrpc_uri') or 'domain' are not " 38 "defined in '[global]' section of '%s' nor in '%s'." % 39 (api.env.conf, api.env.conf_default)) 40 41 api.finalize() 42 try: 43 api.Backend.rpcclient.connect() 44 except AttributeError: 45 # FreeIPA < 4.0 compatibility 46 api.Backend.xmlclient.connect() 47 48 return api 49 50 51def list_groups(api): 52 ''' 53 This function prints a list of all host groups. This function requires 54 one argument, the FreeIPA/IPA API object. 55 ''' 56 57 inventory = {} 58 hostvars = {} 59 60 result = api.Command.hostgroup_find(all=True)['result'] 61 62 for hostgroup in result: 63 # Get direct and indirect members (nested hostgroups) of hostgroup 64 members = [] 65 66 if 'member_host' in hostgroup: 67 members = [host for host in hostgroup['member_host']] 68 if 'memberindirect_host' in hostgroup: 69 members += (host for host in hostgroup['memberindirect_host']) 70 inventory[hostgroup['cn'][0]] = {'hosts': [host for host in members]} 71 72 for member in members: 73 hostvars[member] = {} 74 75 inventory['_meta'] = {'hostvars': hostvars} 76 inv_string = json.dumps(inventory, indent=1, sort_keys=True) 77 print(inv_string) 78 79 return None 80 81 82def parse_args(): 83 ''' 84 This function parses the arguments that were passed in via the command line. 85 This function expects no arguments. 86 ''' 87 88 parser = argparse.ArgumentParser(description='Ansible FreeIPA/IPA ' 89 'inventory module') 90 group = parser.add_mutually_exclusive_group(required=True) 91 group.add_argument('--list', action='store_true', 92 help='List active servers') 93 group.add_argument('--host', help='List details about the specified host') 94 95 return parser.parse_args() 96 97 98def get_host_attributes(api, host): 99 """ 100 This function expects one string, this hostname to lookup variables for. 101 Args: 102 api: FreeIPA API Object 103 host: Name of Hostname 104 105 Returns: Dict of Host vars if found else None 106 """ 107 try: 108 result = api.Command.host_show(u(host))['result'] 109 if 'usercertificate' in result: 110 del result['usercertificate'] 111 return json.dumps(result, indent=1) 112 except errors.NotFound as e: 113 return {} 114 115 116if __name__ == '__main__': 117 args = parse_args() 118 api = initialize() 119 120 if args.host: 121 print(get_host_attributes(api, args.host)) 122 elif args.list: 123 list_groups(api) 124