From 19da03c485f64e49840e635c7570c4117f7e3a97 Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Sun, 28 Jan 2018 20:12:58 +0530 Subject: [PATCH] Add random password generation logic in host_add (#30380) Fix adds ipa host_add functionality of generating random passwords for host enrollement. This fix also preserves the idempotency of host_add and host_mod IPA APIs. Fixes: #30328 Signed-off-by: Abhijeet Kasurde --- lib/ansible/modules/identity/ipa/ipa_host.py | 43 +++++++++++++++++--- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/lib/ansible/modules/identity/ipa/ipa_host.py b/lib/ansible/modules/identity/ipa/ipa_host.py index c24caeea576..4c626f85d75 100644 --- a/lib/ansible/modules/identity/ipa/ipa_host.py +++ b/lib/ansible/modules/identity/ipa/ipa_host.py @@ -71,6 +71,11 @@ options: - This option has no effect for states other than "absent". default: false version_added: "2.5" + random_password: + description: Generate a random password to be used in bulk enrollment + default: False + type: bool + version_added: '2.5' extends_documentation_fragment: ipa.documentation version_added: "2.3" ''' @@ -92,6 +97,18 @@ EXAMPLES = ''' ipa_user: admin ipa_pass: topsecret +# Generate a random password for bulk enrolment +- ipa_host: + name: host01.example.com + description: Example host + ip_address: 192.168.0.123 + state: present + ipa_host: ipa.example.com + ipa_user: admin + ipa_pass: topsecret + validate_certs: False + random_password: True + # Ensure host is disabled - ipa_host: name: host01.example.com @@ -148,6 +165,9 @@ class HostIPAClient(IPAClient): def __init__(self, module, host, port, protocol): super(HostIPAClient, self).__init__(module, host, port, protocol) + def host_show(self, name): + return self._post_json(method='host_show', name=name) + def host_find(self, name): return self._post_json(method='host_find', name=None, item={'all': True, 'fqdn': name}) @@ -165,7 +185,7 @@ class HostIPAClient(IPAClient): def get_host_dict(description=None, force=None, ip_address=None, ns_host_location=None, ns_hardware_platform=None, - ns_os_version=None, user_certificate=None, mac_address=None): + ns_os_version=None, user_certificate=None, mac_address=None, random_password=None): data = {} if description is not None: data['description'] = description @@ -183,11 +203,15 @@ def get_host_dict(description=None, force=None, ip_address=None, ns_host_locatio data['usercertificate'] = [{"__base64__": item} for item in user_certificate] if mac_address is not None: data['macaddress'] = mac_address + if random_password is not None: + data['random'] = random_password return data def get_host_diff(client, ipa_host, module_host): non_updateable_keys = ['force', 'ip_address'] + if not module_host.get('random'): + non_updateable_keys.append('random') for key in non_updateable_keys: if key in module_host: del module_host[key] @@ -206,13 +230,17 @@ def ensure(module, client): ns_hardware_platform=module.params['ns_hardware_platform'], ns_os_version=module.params['ns_os_version'], user_certificate=module.params['user_certificate'], - mac_address=module.params['mac_address']) + mac_address=module.params['mac_address'], + random_password=module.params.get('random_password'), + ) changed = False if state in ['present', 'enabled', 'disabled']: if not ipa_host: changed = True if not module.check_mode: - client.host_add(name=name, host=module_host) + # OTP password generated by FreeIPA is visible only for host_add command + # so, return directly from here. + return changed, client.host_add(name=name, host=module_host) else: diff = get_host_diff(client, ipa_host, module_host) if len(diff) > 0: @@ -221,7 +249,10 @@ def ensure(module, client): data = {} for key in diff: data[key] = module_host.get(key) - client.host_mod(name=name, host=data) + ipa_host_show = client.host_show(name=name) + if ipa_host_show.get('has_keytab', False) and module.params.get('random_password'): + client.host_disable(name=name) + return changed, client.host_mod(name=name, host=data) else: if ipa_host: @@ -245,7 +276,8 @@ def main(): user_certificate=dict(type='list', aliases=['usercertificate']), mac_address=dict(type='list', aliases=['macaddress']), update_dns=dict(type='bool'), - state=dict(type='str', default='present', choices=['present', 'absent', 'enabled', 'disabled'])) + state=dict(type='str', default='present', choices=['present', 'absent', 'enabled', 'disabled']), + random_password=dict(type='bool'),) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) @@ -263,5 +295,6 @@ def main(): except Exception as e: module.fail_json(msg=to_native(e), exception=traceback.format_exc()) + if __name__ == '__main__': main()