diff --git a/plugins/modules/ipaservice.py b/plugins/modules/ipaservice.py index bc7377126..5444f2a62 100644 --- a/plugins/modules/ipaservice.py +++ b/plugins/modules/ipaservice.py @@ -148,6 +148,9 @@ required: false default: True type: bool + fetch_param: + description: The fields to fetch with state=fetched + required: false action: description: Work on service or member level default: service @@ -155,7 +158,7 @@ state: description: State to ensure default: present - choices: ["present", "absent", "disabled"] + choices: ["present", "absent", "disabled", "fetched"] author: - Rafael Jeffman """ @@ -303,7 +306,12 @@ def check_parameters(module, state, action, names): 'allow_retrieve_keytab_group', 'allow_retrieve_keytab_host', 'allow_retrieve_keytab_hostgroup'] - if state == 'present': + if state == 'fetched': + if action != 'service': + module.fail_json(msg="Can only fetch if action is 'service'.") + invalid = ['delete_continue'] + + elif state == 'present': if len(names) != 1: module.fail_json(msg="Only one service can be added at a time.") @@ -347,7 +355,7 @@ def init_ansible_module(): argument_spec=dict( # general name=dict(type="list", aliases=["service"], default=None, - required=True), + required=False), # service attributesstr certificate=dict(type="list", aliases=['usercertificate'], default=None, required=False), @@ -392,6 +400,11 @@ def init_ansible_module(): allow_retrieve_keytab_hostgroup=dict( type="list", required=False, aliases=['ipaallowedtoperform_read_keys_hostgroup']), + # fetched + fetch_param=dict(type="list", default=None, + choices=["all"].extend(ipa_param_mapping.keys()), + required=False), + # absent delete_continue=dict(type="bool", required=False, aliases=['continue']), # action @@ -399,7 +412,7 @@ def init_ansible_module(): choices=["member", "service"]), # state state=dict(type="str", default="present", - choices=["present", "absent", "disabled"]), + choices=["present", "absent", "disabled", "fetched"]), ), supports_check_mode=True, ) @@ -409,6 +422,20 @@ def init_ansible_module(): return ansible_module +ipa_param_mapping = { + "principal": "krbprincipalname", + "certificate": "usercertificate", + "pac_type": "ipakrbauthzdata", + "auth_ind": "krbprincipalauthind", + "requires_pre_auth": "ipakrbrequirespreauth", + "ok_as_delegate": "ipakrbokasdelegate", + "ok_to_auth_as_delegate": "ipakrboktoauthasdelegate", + "netbiosname": "ipantflatname", + "host": "managedby_host", + "service": "krbcanonicalname", +} + + def main(): ansible_module = init_ansible_module() @@ -461,6 +488,35 @@ def main(): commands = [] keytab_members = ["user", "group", "host", "hostgroup"] + if state == "fetched": + encoding_fn = { + "usercertificate": encode_certificate + } + # set filter based on "name" + if names: + names = [ + p.lower() if "@" in p + else "%s@%s".lower() % (p.lower(), api_get_realm().lower()) + for p in names + ] + + def object_filter(res): + return any( + ( + to_text(svc).lower().startswith(n) + for svc in res["krbcanonicalname"] for n in names + ) + ) + + # fetch objects + fetched = ansible_module.fetch_objects( + "service", ["service"], ipa_param_mapping, + object_filter, encoding_fn=encoding_fn + ) + exit_args["services"] = fetched + ansible_module.exit_json(changed=False, service=exit_args) + names = [] + for name in names: res_find = find_service(ansible_module, name) res_principals = [] diff --git a/tests/service/test_service_fetched.yml b/tests/service/test_service_fetched.yml new file mode 100644 index 000000000..312aa70f3 --- /dev/null +++ b/tests/service/test_service_fetched.yml @@ -0,0 +1,112 @@ +--- +- name: Test ipaservice fetch + hosts: ipaserver + become: true + + tasks: + - include_tasks: ../env_freeipa_facts.yml + + - when: ipa_version is version('4.7.0', '>=') + block: + # SETUP + - name: Generate self-signed certificates. + shell: + cmd: | + openssl req -x509 -newkey rsa:2048 -days 365 -nodes -keyout "private{{ item }}.key" -out "cert{{ item }}.pem" -subj '/CN=test' + openssl x509 -outform der -in "cert{{ item }}.pem" -out "cert{{ item }}.der" + base64 "cert{{ item }}.der" -w5000 > "cert{{ item }}.b64" + with_items: [1, 2] + become: no + delegate_to: localhost + + - name: Setup test environment + include_tasks: env_setup.yml + + - name: Ensure service is present + ipaservice: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" + name: "HTTP/{{ svc_fqdn }}" + pac_type: + - MS-PAC + - PAD + auth_ind: otp + skip_host_check: no + force: yes + requires_pre_auth: yes + ok_as_delegate: no + ok_to_auth_as_delegate: no + certificate: + - "{{ lookup('file', 'cert1.b64') }}" + register: result + failed_when: not result.changed or result.failed + + # TESTS + - name: Fetch service information + ipaservice: + ipaadmin_password: SomeADMINpassword + name: + - DNS/fedsrv.ipa.test + fetch_param: all + state: fetched + register: result + failed_when: result.changed or result.failed + + - name: Print fetched information + debug: + var: result + + - name: Fetch service information + ipaservice: + ipaadmin_password: SomeADMINpassword + fetch_param: + - host + - principal + state: fetched + register: result + failed_when: result.changed or result.failed + + - name: Print fetched information + debug: + var: result + + - name: Fetch service information + ipaservice: + ipaadmin_password: SomeADMINpassword + state: fetched + register: result + failed_when: result.changed or result.failed + + - name: Print fetched information + debug: + var: result + + - name: Fetch service information + ipaservice: + ipaadmin_password: SomeADMINpassword + name: + - DNS/fedsrv.ipa.test + - http/fedsrv.ipa.test + - mysvc/fedsrv.ipa.test + fetch_param: all + state: fetched + register: result + failed_when: result.changed or result.failed + + - name: Print fetched information + debug: + var: result + + always: + # CLEANUP + - name: Cleanup test environment + include_tasks: env_cleanup.yml + + - name: Remove certificate files. + shell: + cmd: rm -f "private{{ item }}.key" "cert{{ item }}.pem" "cert{{ item }}.der" "cert{{ item }}.b64" + with_items: [1, 2] + become: no + delegate_to: localhost + args: + warn: no # suppres warning for not using the `file` module.