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