diff --git a/.ansible-freeipa.metadata b/.ansible-freeipa.metadata index aaec13d..c58e727 100644 --- a/.ansible-freeipa.metadata +++ b/.ansible-freeipa.metadata @@ -1 +1 @@ -a139427bb9c6fd44bd59ab258d1b17827a3dbe9a SOURCES/ansible-freeipa-0.1.10.tar.gz +5d09d3b590e8568d04edb288c9c515e308f3168f SOURCES/ansible-freeipa-0.1.12.tar.gz diff --git a/.gitignore b/.gitignore index 154e3ed..7591236 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/ansible-freeipa-0.1.10.tar.gz +SOURCES/ansible-freeipa-0.1.12.tar.gz diff --git a/SOURCES/ansible-freeipa-0.1.12-Add-suppport-for-changing-password-of-symmetric-vaults_rhbz#1839197.patch b/SOURCES/ansible-freeipa-0.1.12-Add-suppport-for-changing-password-of-symmetric-vaults_rhbz#1839197.patch new file mode 100644 index 0000000..8ff43ea --- /dev/null +++ b/SOURCES/ansible-freeipa-0.1.12-Add-suppport-for-changing-password-of-symmetric-vaults_rhbz#1839197.patch @@ -0,0 +1,435 @@ +From 78b635ae78346fdfb298dd0d0c82ae1ff34b754a Mon Sep 17 00:00:00 2001 +From: Rafael Guterres Jeffman +Date: Tue, 23 Jun 2020 17:53:47 -0300 +Subject: [PATCH] Add suppport for changing password of symmetric vaults. + +Allows changing passwords of symmetric waults, using a new variable +`new_password` (or the file-base version, `new_password_file`). The +old password must be passed using the `password` or `password_file` +variables that also received new aliases `old_password` and +`old_password_file`, respectively. + +Tests were modyfied to reflect the changes. +--- + README-vault.md | 23 +++- + .../vault/change-password-symmetric-vault.yml | 2 +- + plugins/modules/ipavault.py | 129 +++++++++++++++--- + tests/vault/test_vault_symmetric.yml | 64 +++++++++ + 4 files changed, 194 insertions(+), 24 deletions(-) + +diff --git a/README-vault.md b/README-vault.md +index c7ae6916..fa1d3e11 100644 +--- a/README-vault.md ++++ b/README-vault.md +@@ -165,6 +165,22 @@ Example playbook to make sure vault data is absent in a symmetric vault: + state: absent + ``` + ++Example playbook to change the password of a symmetric: ++ ++```yaml ++--- ++- name: Playbook to handle vaults ++ hosts: ipaserver ++ become: true ++ ++ tasks: ++ - ipavault: ++ ipaadmin_password: SomeADMINpassword ++ name: symvault ++ old_password: SomeVAULTpassword ++ new_password: SomeNEWpassword ++``` ++ + Example playbook to make sure vault is absent: + + ```yaml +@@ -197,8 +213,11 @@ Variable | Description | Required + `name` \| `cn` | The list of vault name strings. | yes + `description` | The vault description string. | no + `nomembers` | Suppress processing of membership attributes. (bool) | no +-`password ` \| `vault_password` \| `ipavaultpassword` | Vault password. | no +-`public_key ` \| `vault_public_key` \| `ipavaultpublickey` | Base64 encoded vault public key. | no ++`password` \| `vault_password` \| `ipavaultpassword` \| `old_password`| Vault password. | no ++`password_file` \| `vault_password_file` \| `old_password_file`| File containing Base64 encoded Vault password. | no ++`new_password` | Vault new password. | no ++`new_password_file` | File containing Base64 encoded new Vault password. | no ++`public_key ` \| `vault_public_key` \| `old_password_file` | Base64 encoded vault public key. | no + `public_key_file` \| `vault_public_key_file` | Path to file with public key. | no + `private_key `\| `vault_private_key` | Base64 encoded vault private key. Used only to retrieve data. | no + `private_key_file` \| `vault_private_key_file` | Path to file with private key. Used only to retrieve data. | no +diff --git a/playbooks/vault/change-password-symmetric-vault.yml b/playbooks/vault/change-password-symmetric-vault.yml +index 3871f45d..396a79f6 100644 +--- a/playbooks/vault/change-password-symmetric-vault.yml ++++ b/playbooks/vault/change-password-symmetric-vault.yml +@@ -10,7 +10,7 @@ + ipaadmin_password: SomeADMINpassword + name: symvault + password: SomeVAULTpassword +- - name: Change vault passord. ++ - name: Change vault password. + ipavault: + ipaadmin_password: SomeADMINpassword + name: symvault +diff --git a/plugins/modules/ipavault.py b/plugins/modules/ipavault.py +index ad5dd413..46c6fcdb 100644 +--- a/plugins/modules/ipavault.py ++++ b/plugins/modules/ipavault.py +@@ -69,12 +69,20 @@ + description: password to be used on symmetric vault. + required: false + type: string +- aliases: ["ipavaultpassword", "vault_password"] ++ aliases: ["ipavaultpassword", "vault_password", "old_password"] + password_file: + description: file with password to be used on symmetric vault. + required: false + type: string +- aliases: ["vault_password_file"] ++ aliases: ["vault_password_file", "old_password_file"] ++ new_password: ++ description: new password to be used on symmetric vault. ++ required: false ++ type: string ++ new_password_file: ++ description: file with new password to be used on symmetric vault. ++ required: false ++ type: string + salt: + description: Vault salt. + required: false +@@ -235,7 +243,15 @@ + state: retrieved + register: result + - debug: +- msg: "{{ result.data | b64decode }}" ++ msg: "{{ result.data }}" ++ ++# Change password of a symmetric vault ++- ipavault: ++ ipaadmin_password: SomeADMINpassword ++ name: symvault ++ username: admin ++ old_password: SomeVAULTpassword ++ new_password: SomeNEWpassword + + # Ensure vault symvault is absent + - ipavault: +@@ -416,18 +432,29 @@ def check_parameters(module, state, action, description, username, service, + shared, users, groups, services, owners, ownergroups, + ownerservices, vault_type, salt, password, password_file, + public_key, public_key_file, private_key, +- private_key_file, vault_data, datafile_in, datafile_out): ++ private_key_file, vault_data, datafile_in, datafile_out, ++ new_password, new_password_file): + invalid = [] + if state == "present": + invalid = ['private_key', 'private_key_file', 'datafile_out'] + ++ if all([password, password_file]) \ ++ or all([new_password, new_password_file]): ++ module.fail_json(msg="Password specified multiple times.") ++ ++ if any([new_password, new_password_file]) \ ++ and not any([password, password_file]): ++ module.fail_json( ++ msg="Either `password` or `password_file` must be provided to " ++ "change symmetric vault password.") ++ + if action == "member": + invalid.extend(['description']) + + elif state == "absent": + invalid = ['description', 'salt', 'vault_type', 'private_key', + 'private_key_file', 'datafile_in', 'datafile_out', +- 'vault_data'] ++ 'vault_data', 'new_password', 'new_password_file'] + + if action == "vault": + invalid.extend(['users', 'groups', 'services', 'owners', +@@ -437,7 +464,7 @@ def check_parameters(module, state, action, description, username, service, + elif state == "retrieved": + invalid = ['description', 'salt', 'datafile_in', 'users', 'groups', + 'owners', 'ownergroups', 'public_key', 'public_key_file', +- 'vault_data'] ++ 'vault_data', 'new_password', 'new_password_file'] + if action == 'member': + module.fail_json( + msg="State `retrieved` do not support action `member`.") +@@ -458,11 +485,17 @@ def check_parameters(module, state, action, description, username, service, + def check_encryption_params(module, state, action, vault_type, salt, + password, password_file, public_key, + public_key_file, private_key, private_key_file, +- vault_data, datafile_in, datafile_out, res_find): ++ vault_data, datafile_in, datafile_out, ++ new_password, new_password_file, res_find): + vault_type_invalid = [] ++ ++ if res_find is not None: ++ vault_type = res_find['ipavaulttype'] ++ + if vault_type == "standard": + vault_type_invalid = ['public_key', 'public_key_file', 'password', +- 'password_file', 'salt'] ++ 'password_file', 'salt', 'new_password', ++ 'new_password_file'] + + if vault_type is None or vault_type == "symmetric": + vault_type_invalid = ['public_key', 'public_key_file', +@@ -473,8 +506,14 @@ def check_encryption_params(module, state, action, vault_type, salt, + msg="Symmetric vault requires password or password_file " + "to store data or change `salt`.") + ++ if any([new_password, new_password_file]) and res_find is None: ++ module.fail_json( ++ msg="Cannot modify password of inexistent vault.") ++ + if vault_type == "asymmetric": +- vault_type_invalid = ['password', 'password_file'] ++ vault_type_invalid = [ ++ 'password', 'password_file', 'new_password', 'new_password_file' ++ ] + if not any([public_key, public_key_file]) and res_find is None: + module.fail_json( + msg="Assymmetric vault requires public_key " +@@ -487,6 +526,43 @@ def check_encryption_params(module, state, action, vault_type, salt, + (param, vault_type or 'symmetric')) + + ++def change_password(module, res_find, password, password_file, new_password, ++ new_password_file): ++ """ ++ Change the password of a symmetric vault. ++ ++ To change the password of a vault, it is needed to retrieve the stored ++ data with the current password, and store the data again, with the new ++ password, forcing it to override the old one. ++ """ ++ # verify parameters. ++ if not any([new_password, new_password_file]): ++ return [] ++ if res_find["ipavaulttype"][0] != "symmetric": ++ module.fail_json(msg="Cannot change password of `%s` vault." ++ % res_find["ipavaulttype"]) ++ ++ # prepare arguments to retrieve data. ++ name = res_find["cn"][0] ++ args = {} ++ if password: ++ args["password"] = password ++ if password_file: ++ args["password"] = password_file ++ # retrieve current stored data ++ result = api_command(module, 'vault_retrieve', name, args) ++ args['data'] = result['result']['data'] ++ ++ # modify arguments to store data with new password. ++ if password: ++ args["password"] = new_password ++ if password_file: ++ args["password"] = new_password_file ++ args["override_password"] = True ++ # return the command to store data with the new password. ++ return [(name, "vault_archive", args)] ++ ++ + def main(): + ansible_module = AnsibleModule( + argument_spec=dict( +@@ -533,10 +609,18 @@ def main(): + datafile_out=dict(type="str", required=False, default=None, + aliases=['out']), + vault_password=dict(type="str", required=False, default=None, +- aliases=['ipavaultpassword', 'password'], +- no_log=True), ++ no_log=True, ++ aliases=['ipavaultpassword', 'password', ++ "old_password"]), + vault_password_file=dict(type="str", required=False, default=None, +- no_log=False, aliases=['password_file']), ++ no_log=False, ++ aliases=[ ++ 'password_file', "old_password_file" ++ ]), ++ new_password=dict(type="str", required=False, default=None, ++ no_log=True), ++ new_password_file=dict(type="str", required=False, default=None, ++ no_log=False), + # state + action=dict(type="str", default="vault", + choices=["vault", "data", "member"]), +@@ -546,6 +630,7 @@ def main(): + supports_check_mode=True, + mutually_exclusive=[['username', 'service', 'shared'], + ['datafile_in', 'vault_data'], ++ ['new_password', 'new_password_file'], + ['vault_password', 'vault_password_file'], + ['vault_public_key', 'vault_public_key_file']], + ) +@@ -576,6 +661,8 @@ def main(): + salt = module_params_get(ansible_module, "vault_salt") + password = module_params_get(ansible_module, "vault_password") + password_file = module_params_get(ansible_module, "vault_password_file") ++ new_password = module_params_get(ansible_module, "new_password") ++ new_password_file = module_params_get(ansible_module, "new_password_file") + public_key = module_params_get(ansible_module, "vault_public_key") + public_key_file = module_params_get(ansible_module, + "vault_public_key_file") +@@ -614,7 +701,8 @@ def main(): + service, shared, users, groups, services, owners, + ownergroups, ownerservices, vault_type, salt, password, + password_file, public_key, public_key_file, private_key, +- private_key_file, vault_data, datafile_in, datafile_out) ++ private_key_file, vault_data, datafile_in, datafile_out, ++ new_password, new_password_file) + # Init + + changed = False +@@ -660,7 +748,7 @@ def main(): + ansible_module, state, action, vault_type, salt, password, + password_file, public_key, public_key_file, private_key, + private_key_file, vault_data, datafile_in, datafile_out, +- res_find) ++ new_password, new_password_file, res_find) + + # Found the vault + if action == "vault": +@@ -721,7 +809,6 @@ def main(): + owner_add_args = gen_member_args( + args, owner_add, ownergroups_add, ownerservice_add) + if owner_add_args is not None: +- # ansible_module.warn("OWNER ADD: %s" % owner_add_args) + commands.append( + [name, 'vault_add_owner', owner_add_args]) + +@@ -729,7 +816,6 @@ def main(): + owner_del_args = gen_member_args( + args, owner_del, ownergroups_del, ownerservice_del) + if owner_del_args is not None: +- # ansible_module.warn("OWNER DEL: %s" % owner_del_args) + commands.append( + [name, 'vault_remove_owner', owner_del_args]) + +@@ -758,19 +844,22 @@ def main(): + if any([vault_data, datafile_in]): + commands.append([name, "vault_archive", pwdargs]) + ++ cmds = change_password( ++ ansible_module, res_find, password, password_file, ++ new_password, new_password_file) ++ commands.extend(cmds) ++ + elif state == "retrieved": + if res_find is None: + ansible_module.fail_json( + msg="Vault `%s` not found to retrieve data." % name) + +- vault_type = res_find['cn'] +- + # verify data encription args + check_encryption_params( + ansible_module, state, action, vault_type, salt, password, + password_file, public_key, public_key_file, private_key, + private_key_file, vault_data, datafile_in, datafile_out, +- res_find) ++ new_password, new_password_file, res_find) + + pwdargs = data_storage_args( + args, vault_data, password, password_file, private_key, +@@ -813,7 +902,6 @@ def main(): + errors = [] + for name, command, args in commands: + try: +- # ansible_module.warn("RUN: %s %s %s" % (command, name, args)) + result = api_command(ansible_module, command, name, args) + + if command == 'vault_archive': +@@ -829,7 +917,6 @@ def main(): + raise Exception("No data retrieved.") + changed = False + else: +- # ansible_module.warn("RESULT: %s" % (result)) + if "completed" in result: + if result["completed"] > 0: + changed = True +diff --git a/tests/vault/test_vault_symmetric.yml b/tests/vault/test_vault_symmetric.yml +index c9429f4f..a6072d88 100644 +--- a/tests/vault/test_vault_symmetric.yml ++++ b/tests/vault/test_vault_symmetric.yml +@@ -178,6 +178,61 @@ + register: result + failed_when: result.data != 'Hello World.' or result.changed + ++ - name: Change vault password. ++ ipavault: ++ ipaadmin_password: SomeADMINpassword ++ name: symvault ++ password: SomeVAULTpassword ++ new_password: SomeNEWpassword ++ register: result ++ failed_when: not result.changed ++ ++ - name: Retrieve data from symmetric vault, with wrong password. ++ ipavault: ++ ipaadmin_password: SomeADMINpassword ++ name: symvault ++ password: SomeVAULTpassword ++ state: retrieved ++ register: result ++ failed_when: not result.failed or "Invalid credentials" not in result.msg ++ ++ - name: Change vault password, with wrong `old_password`. ++ ipavault: ++ ipaadmin_password: SomeADMINpassword ++ name: symvault ++ password: SomeVAULTpassword ++ new_password: SomeNEWpassword ++ register: result ++ failed_when: not result.failed or "Invalid credentials" not in result.msg ++ ++ - name: Retrieve data from symmetric vault, with new password. ++ ipavault: ++ ipaadmin_password: SomeADMINpassword ++ name: symvault ++ password: SomeNEWpassword ++ state: retrieved ++ register: result ++ failed_when: result.data != 'Hello World.' or result.changed ++ ++ - name: Try to add vault with multiple passwords. ++ ipavault: ++ ipaadmin_password: SomeADMINpassword ++ name: inexistentvault ++ password: SomeVAULTpassword ++ password_file: "{{ ansible_env.HOME }}/password.txt" ++ register: result ++ failed_when: not result.failed or "parameters are mutually exclusive" not in result.msg ++ ++ - name: Try to add vault with multiple new passwords. ++ ipavault: ++ ipaadmin_password: SomeADMINpassword ++ name: inexistentvault ++ password: SomeVAULTpassword ++ new_password: SomeVAULTpassword ++ new_password_file: "{{ ansible_env.HOME }}/password.txt" ++ register: result ++ failed_when: not result.failed or "parameters are mutually exclusive" not in result.msg ++ + - name: Ensure symmetric vault is absent + ipavault: + ipaadmin_password: SomeADMINpassword +@@ -194,5 +249,14 @@ + register: result + failed_when: result.changed + ++ - name: Try to change password of inexistent vault. ++ ipavault: ++ ipaadmin_password: SomeADMINpassword ++ name: inexistentvault ++ password: SomeVAULTpassword ++ new_password: SomeNEWpassword ++ register: result ++ failed_when: not result.failed or "Cannot modify password of inexistent vault" not in result.msg ++ + - name: Cleanup testing environment. + import_tasks: env_cleanup.yml diff --git a/SOURCES/ansible-freeipa-0.1.12-Fix-forwardzone-issues_rhbz#1843826,1843828,1843829,1843830,1843831.patch b/SOURCES/ansible-freeipa-0.1.12-Fix-forwardzone-issues_rhbz#1843826,1843828,1843829,1843830,1843831.patch new file mode 100644 index 0000000..5470d06 --- /dev/null +++ b/SOURCES/ansible-freeipa-0.1.12-Fix-forwardzone-issues_rhbz#1843826,1843828,1843829,1843830,1843831.patch @@ -0,0 +1,1447 @@ +From f0f933b4630bce810475a519e295828013d301d6 Mon Sep 17 00:00:00 2001 +From: Rafael Guterres Jeffman +Date: Wed, 10 Jun 2020 20:40:45 -0300 +Subject: [PATCH] Changed admin password on tests to match other modules. + +Use of the same password on all module tests ease test automation, +and this change ensure that dnsforwardzone use the same password as +other modules. +--- + tests/dnsforwardzone/test_dnsforwardzone.yml | 42 ++++++++++---------- + 1 file changed, 21 insertions(+), 21 deletions(-) + +diff --git a/tests/dnsforwardzone/test_dnsforwardzone.yml b/tests/dnsforwardzone/test_dnsforwardzone.yml +index 1a45e826..ac08a48f 100644 +--- a/tests/dnsforwardzone/test_dnsforwardzone.yml ++++ b/tests/dnsforwardzone/test_dnsforwardzone.yml +@@ -7,13 +7,13 @@ + tasks: + - name: ensure forwardzone example.com is absent - prep + ipadnsforwardzone: +- ipaadmin_password: password01 ++ ipaadmin_password: SomeADMINpassword + name: example.com + state: absent + + - name: ensure forwardzone example.com is created + ipadnsforwardzone: +- ipaadmin_password: password01 ++ ipaadmin_password: SomeADMINpassword + state: present + name: example.com + forwarders: +@@ -25,7 +25,7 @@ + + - name: ensure forwardzone example.com is present again + ipadnsforwardzone: +- ipaadmin_password: password01 ++ ipaadmin_password: SomeADMINpassword + state: present + name: example.com + forwarders: +@@ -37,7 +37,7 @@ + + - name: ensure forwardzone example.com has two forwarders + ipadnsforwardzone: +- ipaadmin_password: password01 ++ ipaadmin_password: SomeADMINpassword + state: present + name: example.com + forwarders: +@@ -50,7 +50,7 @@ + + - name: ensure forwardzone example.com has one forwarder again + ipadnsforwardzone: +- ipaadmin_password: password01 ++ ipaadmin_password: SomeADMINpassword + name: example.com + forwarders: + - 8.8.8.8 +@@ -62,7 +62,7 @@ + + - name: skip_overlap_check can only be set on creation so change nothing + ipadnsforwardzone: +- ipaadmin_password: password01 ++ ipaadmin_password: SomeADMINpassword + name: example.com + forwarders: + - 8.8.8.8 +@@ -74,7 +74,7 @@ + + - name: change all the things at once + ipadnsforwardzone: +- ipaadmin_password: password01 ++ ipaadmin_password: SomeADMINpassword + state: present + name: example.com + forwarders: +@@ -87,13 +87,13 @@ + + - name: ensure forwardzone example.com is absent for next testset + ipadnsforwardzone: +- ipaadmin_password: password01 ++ ipaadmin_password: SomeADMINpassword + name: example.com + state: absent + + - name: ensure forwardzone example.com is created with minimal args + ipadnsforwardzone: +- ipaadmin_password: password01 ++ ipaadmin_password: SomeADMINpassword + state: present + name: example.com + skip_overlap_check: true +@@ -104,7 +104,7 @@ + + - name: add a forwarder to any existing ones + ipadnsforwardzone: +- ipaadmin_password: password01 ++ ipaadmin_password: SomeADMINpassword + state: present + name: example.com + forwarders: +@@ -115,7 +115,7 @@ + + - name: check the list of forwarders is what we expect + ipadnsforwardzone: +- ipaadmin_password: password01 ++ ipaadmin_password: SomeADMINpassword + state: present + name: example.com + forwarders: +@@ -127,7 +127,7 @@ + + - name: remove a single forwarder + ipadnsforwardzone: +- ipaadmin_password: password01 ++ ipaadmin_password: SomeADMINpassword + state: absent + name: example.com + forwarders: +@@ -138,7 +138,7 @@ + + - name: check the list of forwarders is what we expect now + ipadnsforwardzone: +- ipaadmin_password: password01 ++ ipaadmin_password: SomeADMINpassword + state: present + name: example.com + forwarders: +@@ -149,13 +149,13 @@ + + - name: ensure forwardzone example.com is absent again + ipadnsforwardzone: +- ipaadmin_password: password01 ++ ipaadmin_password: SomeADMINpassword + name: example.com + state: absent + + - name: try to create a new forwarder with action=member + ipadnsforwardzone: +- ipaadmin_password: password01 ++ ipaadmin_password: SomeADMINpassword + state: present + name: example.com + forwarders: +@@ -167,13 +167,13 @@ + + - name: ensure forwardzone example.com is absent - tidy up + ipadnsforwardzone: +- ipaadmin_password: password01 ++ ipaadmin_password: SomeADMINpassword + name: example.com + state: absent + + - name: try to create a new forwarder is disabled state + ipadnsforwardzone: +- ipaadmin_password: password01 ++ ipaadmin_password: SomeADMINpassword + state: disabled + name: example.com + forwarders: +@@ -184,7 +184,7 @@ + + - name: enable the forwarder + ipadnsforwardzone: +- ipaadmin_password: password01 ++ ipaadmin_password: SomeADMINpassword + name: example.com + state: enabled + register: result +@@ -192,7 +192,7 @@ + + - name: disable the forwarder again + ipadnsforwardzone: +- ipaadmin_password: password01 ++ ipaadmin_password: SomeADMINpassword + name: example.com + state: disabled + action: member +@@ -201,7 +201,7 @@ + + - name: ensure it stays disabled + ipadnsforwardzone: +- ipaadmin_password: password01 ++ ipaadmin_password: SomeADMINpassword + name: example.com + state: disabled + register: result +@@ -209,6 +209,6 @@ + + - name: ensure forwardzone example.com is absent - tidy up + ipadnsforwardzone: +- ipaadmin_password: password01 ++ ipaadmin_password: SomeADMINpassword + name: example.com + state: absent +From f8ebca760dbaaf38c7b74b0c855b05d26e9cb812 Mon Sep 17 00:00:00 2001 +From: Rafael Guterres Jeffman +Date: Wed, 10 Jun 2020 22:14:27 -0300 +Subject: [PATCH] Allow processing of multiple names for deleting + dnsforwardzones. + +--- + plugins/modules/ipadnsforwardzone.py | 189 ++++++++++++++------------- + 1 file changed, 98 insertions(+), 91 deletions(-) + +diff --git a/plugins/modules/ipadnsforwardzone.py b/plugins/modules/ipadnsforwardzone.py +index 90bd3876..b28f28db 100644 +--- a/plugins/modules/ipadnsforwardzone.py ++++ b/plugins/modules/ipadnsforwardzone.py +@@ -134,7 +134,7 @@ def main(): + # general + ipaadmin_principal=dict(type="str", default="admin"), + ipaadmin_password=dict(type="str", required=False, no_log=True), +- name=dict(type="str", aliases=["cn"], default=None, ++ name=dict(type="list", aliases=["cn"], default=None, + required=True), + forwarders=dict(type='list', aliases=["idnsforwarders"], + required=False), +@@ -158,7 +158,7 @@ def main(): + "ipaadmin_principal") + ipaadmin_password = module_params_get(ansible_module, + "ipaadmin_password") +- name = module_params_get(ansible_module, "name") ++ names = module_params_get(ansible_module, "name") + action = module_params_get(ansible_module, "action") + forwarders = module_params_get(ansible_module, "forwarders") + forwardpolicy = module_params_get(ansible_module, "forwardpolicy") +@@ -166,6 +166,12 @@ def main(): + "skip_overlap_check") + state = module_params_get(ansible_module, "state") + ++ if state == 'present' and len(names) != 1: ++ ansible_module.fail_json( ++ msg="Only one dnsforwardzone can be added at a time.") ++ if state == 'absent' and len(names) < 1: ++ ansible_module.fail_json(msg="No name given.") ++ + # absent stae means delete if the action is NOT member but update if it is + # if action is member then update an exisiting resource + # and if action is not member then create a resource +@@ -207,101 +213,102 @@ def main(): + ipaadmin_password) + api_connect() + +- # Make sure forwardzone exists +- existing_resource = find_dnsforwardzone(ansible_module, name) +- +- if existing_resource is None and operation == "update": +- # does not exist and is updating +- # trying to update something that doesn't exist, so error +- ansible_module.fail_json(msg="""dnsforwardzone '%s' is not +- valid""" % (name)) +- elif existing_resource is None and operation == "del": +- # does not exists and should be absent +- # set command +- command = None +- # enabled or disabled? +- is_enabled = "IGNORE" +- elif existing_resource is not None and operation == "del": +- # exists but should be absent +- # set command +- command = "dnsforwardzone_del" +- # enabled or disabled? +- is_enabled = "IGNORE" +- elif forwarders is None: +- # forwarders are not defined its not a delete, update state? +- # set command +- command = None +- # enabled or disabled? +- if existing_resource is not None: +- is_enabled = existing_resource["idnszoneactive"][0] +- else: +- is_enabled = "IGNORE" +- elif existing_resource is not None and operation == "update": +- # exists and is updating +- # calculate the new forwarders and mod +- # determine args +- if state != "absent": +- forwarders = list(set(existing_resource["idnsforwarders"] +- + forwarders)) +- else: +- forwarders = list(set(existing_resource["idnsforwarders"]) +- - set(forwarders)) +- args = gen_args(forwarders, forwardpolicy, +- skip_overlap_check) +- if skip_overlap_check is not None: +- del args['skip_overlap_check'] +- +- # command +- if not compare_args_ipa(ansible_module, args, existing_resource): +- command = "dnsforwardzone_mod" +- else: ++ for name in names: ++ # Make sure forwardzone exists ++ existing_resource = find_dnsforwardzone(ansible_module, name) ++ ++ if existing_resource is None and operation == "update": ++ # does not exist and is updating ++ # trying to update something that doesn't exist, so error ++ ansible_module.fail_json(msg="""dnsforwardzone '%s' is not ++ valid""" % (name)) ++ elif existing_resource is None and operation == "del": ++ # does not exists and should be absent ++ # set command + command = None +- +- # enabled or disabled? +- is_enabled = existing_resource["idnszoneactive"][0] +- +- elif existing_resource is None and operation == "add": +- # does not exist but should be present +- # determine args +- args = gen_args(forwarders, forwardpolicy, +- skip_overlap_check) +- # set command +- command = "dnsforwardzone_add" +- # enabled or disabled? +- is_enabled = "TRUE" +- +- elif existing_resource is not None and operation == "add": +- # exists and should be present, has it changed? +- # determine args +- args = gen_args(forwarders, forwardpolicy, skip_overlap_check) +- if skip_overlap_check is not None: +- del args['skip_overlap_check'] +- +- # set command +- if not compare_args_ipa(ansible_module, args, existing_resource): +- command = "dnsforwardzone_mod" +- else: ++ # enabled or disabled? ++ is_enabled = "IGNORE" ++ elif existing_resource is not None and operation == "del": ++ # exists but should be absent ++ # set command ++ command = "dnsforwardzone_del" ++ # enabled or disabled? ++ is_enabled = "IGNORE" ++ elif forwarders is None: ++ # forwarders are not defined its not a delete, update state? ++ # set command + command = None ++ # enabled or disabled? ++ if existing_resource is not None: ++ is_enabled = existing_resource["idnszoneactive"][0] ++ else: ++ is_enabled = "IGNORE" ++ elif existing_resource is not None and operation == "update": ++ # exists and is updating ++ # calculate the new forwarders and mod ++ # determine args ++ if state != "absent": ++ forwarders = list(set(existing_resource["idnsforwarders"] ++ + forwarders)) ++ else: ++ forwarders = list(set(existing_resource["idnsforwarders"]) ++ - set(forwarders)) ++ args = gen_args(forwarders, forwardpolicy, ++ skip_overlap_check) ++ if skip_overlap_check is not None: ++ del args['skip_overlap_check'] ++ ++ # command ++ if not compare_args_ipa(ansible_module, args, existing_resource): ++ command = "dnsforwardzone_mod" ++ else: ++ command = None ++ ++ # enabled or disabled? ++ is_enabled = existing_resource["idnszoneactive"][0] + +- # enabled or disabled? +- is_enabled = existing_resource["idnszoneactive"][0] +- +- # if command is set then run it with the args +- if command is not None: +- api_command(ansible_module, command, name, args) +- changed = True ++ elif existing_resource is None and operation == "add": ++ # does not exist but should be present ++ # determine args ++ args = gen_args(forwarders, forwardpolicy, ++ skip_overlap_check) ++ # set command ++ command = "dnsforwardzone_add" ++ # enabled or disabled? ++ is_enabled = "TRUE" ++ ++ elif existing_resource is not None and operation == "add": ++ # exists and should be present, has it changed? ++ # determine args ++ args = gen_args(forwarders, forwardpolicy, skip_overlap_check) ++ if skip_overlap_check is not None: ++ del args['skip_overlap_check'] ++ ++ # set command ++ if not compare_args_ipa(ansible_module, args, existing_resource): ++ command = "dnsforwardzone_mod" ++ else: ++ command = None ++ ++ # enabled or disabled? ++ is_enabled = existing_resource["idnszoneactive"][0] + +- # does the enabled state match what we want (if we care) +- if is_enabled != "IGNORE": +- if wants_enable and is_enabled != "TRUE": +- api_command(ansible_module, "dnsforwardzone_enable", +- name, {}) +- changed = True +- elif not wants_enable and is_enabled != "FALSE": +- api_command(ansible_module, "dnsforwardzone_disable", +- name, {}) ++ # if command is set then run it with the args ++ if command is not None: ++ api_command(ansible_module, command, name, args) + changed = True + ++ # does the enabled state match what we want (if we care) ++ if is_enabled != "IGNORE": ++ if wants_enable and is_enabled != "TRUE": ++ api_command(ansible_module, "dnsforwardzone_enable", ++ name, {}) ++ changed = True ++ elif not wants_enable and is_enabled != "FALSE": ++ api_command(ansible_module, "dnsforwardzone_disable", ++ name, {}) ++ changed = True ++ + except Exception as e: + ansible_module.fail_json(msg=str(e)) + +From 3f785bc0e9fe1ab3ad874ce4f26e6897189db8aa Mon Sep 17 00:00:00 2001 +From: Rafael Guterres Jeffman +Date: Wed, 10 Jun 2020 22:20:20 -0300 +Subject: [PATCH] Fix error message when adding dnsforwardzone without + forwarders. + +--- + plugins/modules/ipadnsforwardzone.py | 5 +++++ + tests/dnsforwardzone/test_dnsforwardzone.yml | 13 +++++++++++-- + 2 files changed, 16 insertions(+), 2 deletions(-) + +diff --git a/plugins/modules/ipadnsforwardzone.py b/plugins/modules/ipadnsforwardzone.py +index b28f28db..3968e6a1 100644 +--- a/plugins/modules/ipadnsforwardzone.py ++++ b/plugins/modules/ipadnsforwardzone.py +@@ -217,6 +217,11 @@ def main(): + # Make sure forwardzone exists + existing_resource = find_dnsforwardzone(ansible_module, name) + ++ # validate parameters ++ if state == 'present': ++ if existing_resource is None and not forwarders: ++ ansible_module.fail_json(msg='No forwarders specified.') ++ + if existing_resource is None and operation == "update": + # does not exist and is updating + # trying to update something that doesn't exist, so error +diff --git a/tests/dnsforwardzone/test_dnsforwardzone.yml b/tests/dnsforwardzone/test_dnsforwardzone.yml +index ac08a48f..d94db9e5 100644 +--- a/tests/dnsforwardzone/test_dnsforwardzone.yml ++++ b/tests/dnsforwardzone/test_dnsforwardzone.yml +@@ -5,10 +5,12 @@ + gather_facts: false + + tasks: +- - name: ensure forwardzone example.com is absent - prep ++ - name: ensure test forwardzones are absent - prep + ipadnsforwardzone: + ipaadmin_password: SomeADMINpassword +- name: example.com ++ name: ++ - example.com ++ - newfailzone.com + state: absent + + - name: ensure forwardzone example.com is created +@@ -207,6 +209,13 @@ + register: result + failed_when: result.changed + ++ - name: Ensure forwardzone is not added without forwarders, with correct message. ++ ipadnsforwardzone: ++ ipaadmin_password: SomeADMINpassword ++ name: newfailzone.com ++ register: result ++ failed_when: not result.failed or "No forwarders specified" not in result.msg ++ + - name: ensure forwardzone example.com is absent - tidy up + ipadnsforwardzone: + ipaadmin_password: SomeADMINpassword +From 1d223c2b63634abe86f7702a64dd83c4fbc272ce Mon Sep 17 00:00:00 2001 +From: Rafael Guterres Jeffman +Date: Mon, 15 Jun 2020 16:14:25 -0300 +Subject: [PATCH] Add support for attributes `ip_address` and `port` to + `forwarders`. + +This patch modify the was forwarders are configured, using two attributes, +`ip_address` and `port`, instead of IPA API internal string representation +of `IP port PORT`. +--- + README-dnsforwardzone.md | 6 ++- + plugins/modules/ipadnsforwardzone.py | 37 ++++++++++++++--- + tests/dnsforwardzone/test_dnsforwardzone.yml | 43 ++++++++++++-------- + 3 files changed, 62 insertions(+), 24 deletions(-) + +diff --git a/README-dnsforwardzone.md b/README-dnsforwardzone.md +index 81919295..15b2b574 100644 +--- a/README-dnsforwardzone.md ++++ b/README-dnsforwardzone.md +@@ -99,8 +99,10 @@ Variable | Description | Required + `ipaadmin_principal` | The admin principal is a string and defaults to `admin` | no + `ipaadmin_password` | The admin password is a string and is required if there is no admin ticket available on the node | no + `name` \| `cn` | Zone name (FQDN). | yes if `state` == `present` +-`forwarders` \| `idnsforwarders` | Per-zone conditional forwarding policy. Possible values are `only`, `first`, `none`) | no +-`forwardpolicy` \| `idnsforwardpolicy` | Per-zone conditional forwarding policy. Set to "none" to disable forwarding to global forwarder for this zone. In that case, conditional zone forwarders are disregarded. | no ++`forwarders` \| `idnsforwarders` | Per-zone forwarders. A custom port can be specified for each forwarder. Options | no ++  | `ip_address`: The forwarder IP address. | yes ++  | `port`: The forwarder IP port. | no ++`forwardpolicy` \| `idnsforwardpolicy` | Per-zone conditional forwarding policy. Possible values are `only`, `first`, `none`. Set to "none" to disable forwarding to global forwarder for this zone. In that case, conditional zone forwarders are disregarded. | no + `skip_overlap_check` | Force DNS zone creation even if it will overlap with an existing zone. Defaults to False. | no + `action` | Work on group or member level. It can be on of `member` or `dnsforwardzone` and defaults to `dnsforwardzone`. | no + `state` | The state to ensure. It can be one of `present`, `absent`, `enabled` or `disabled`, default: `present`. | yes +diff --git a/plugins/modules/ipadnsforwardzone.py b/plugins/modules/ipadnsforwardzone.py +index 3968e6a1..8e5c3464 100644 +--- a/plugins/modules/ipadnsforwardzone.py ++++ b/plugins/modules/ipadnsforwardzone.py +@@ -54,9 +54,16 @@ + forwarders: + description: + - List of the DNS servers to forward to +- required: true +- type: list + aliases: ["idnsforwarders"] ++ options: ++ ip_address: ++ description: Forwarder IP address (either IPv4 or IPv6). ++ required: false ++ type: string ++ port: ++ description: Forwarder port. ++ required: false ++ type: int + forwardpolicy: + description: Per-zone conditional forwarding policy + required: false +@@ -128,6 +135,20 @@ def gen_args(forwarders, forwardpolicy, skip_overlap_check): + return _args + + ++def forwarder_list(forwarders): ++ """Convert the forwarder dict into a list compatible with IPA API.""" ++ if forwarders is None: ++ return None ++ fwd_list = [] ++ for forwarder in forwarders: ++ if forwarder.get('port', None) is not None: ++ formatter = "{ip_address} port {port}" ++ else: ++ formatter = "{ip_address}" ++ fwd_list.append(formatter.format(**forwarder)) ++ return fwd_list ++ ++ + def main(): + ansible_module = AnsibleModule( + argument_spec=dict( +@@ -136,8 +157,13 @@ def main(): + ipaadmin_password=dict(type="str", required=False, no_log=True), + name=dict(type="list", aliases=["cn"], default=None, + required=True), +- forwarders=dict(type='list', aliases=["idnsforwarders"], +- required=False), ++ forwarders=dict(type="list", default=None, required=False, ++ aliases=["idnsforwarders"], elements='dict', ++ options=dict( ++ ip_address=dict(type='str', required=True), ++ port=dict(type='int', required=False, ++ default=None), ++ )), + forwardpolicy=dict(type='str', aliases=["idnsforwardpolicy"], + required=False, + choices=['only', 'first', 'none']), +@@ -160,7 +186,8 @@ def main(): + "ipaadmin_password") + names = module_params_get(ansible_module, "name") + action = module_params_get(ansible_module, "action") +- forwarders = module_params_get(ansible_module, "forwarders") ++ forwarders = forwarder_list( ++ module_params_get(ansible_module, "forwarders")) + forwardpolicy = module_params_get(ansible_module, "forwardpolicy") + skip_overlap_check = module_params_get(ansible_module, + "skip_overlap_check") +diff --git a/tests/dnsforwardzone/test_dnsforwardzone.yml b/tests/dnsforwardzone/test_dnsforwardzone.yml +index d94db9e5..468cd4ce 100644 +--- a/tests/dnsforwardzone/test_dnsforwardzone.yml ++++ b/tests/dnsforwardzone/test_dnsforwardzone.yml +@@ -5,7 +5,7 @@ + gather_facts: false + + tasks: +- - name: ensure test forwardzones are absent - prep ++ - name: ensure test forwardzones are absent + ipadnsforwardzone: + ipaadmin_password: SomeADMINpassword + name: +@@ -19,7 +19,7 @@ + state: present + name: example.com + forwarders: +- - 8.8.8.8 ++ - ip_address: 8.8.8.8 + forwardpolicy: first + skip_overlap_check: true + register: result +@@ -31,7 +31,7 @@ + state: present + name: example.com + forwarders: +- - 8.8.8.8 ++ - ip_address: 8.8.8.8 + forwardpolicy: first + skip_overlap_check: true + register: result +@@ -43,19 +43,22 @@ + state: present + name: example.com + forwarders: +- - 8.8.8.8 +- - 4.4.4.4 ++ - ip_address: 8.8.8.8 ++ - ip_address: 4.4.4.4 ++ port: 8053 + forwardpolicy: first + skip_overlap_check: true + register: result + failed_when: not result.changed + ++ - pause: ++ + - name: ensure forwardzone example.com has one forwarder again + ipadnsforwardzone: + ipaadmin_password: SomeADMINpassword + name: example.com + forwarders: +- - 8.8.8.8 ++ - ip_address: 8.8.8.8 + forwardpolicy: first + skip_overlap_check: true + state: present +@@ -67,7 +70,7 @@ + ipaadmin_password: SomeADMINpassword + name: example.com + forwarders: +- - 8.8.8.8 ++ - ip_address: 8.8.8.8 + forwardpolicy: first + skip_overlap_check: false + state: present +@@ -80,8 +83,9 @@ + state: present + name: example.com + forwarders: +- - 8.8.8.8 +- - 4.4.4.4 ++ - ip_address: 8.8.8.8 ++ - ip_address: 4.4.4.4 ++ port: 8053 + forwardpolicy: only + skip_overlap_check: false + register: result +@@ -100,7 +104,7 @@ + name: example.com + skip_overlap_check: true + forwarders: +- - 8.8.8.8 ++ - ip_address: 8.8.8.8 + register: result + failed_when: not result.changed + +@@ -110,7 +114,8 @@ + state: present + name: example.com + forwarders: +- - 4.4.4.4 ++ - ip_address: 4.4.4.4 ++ port: 8053 + action: member + register: result + failed_when: not result.changed +@@ -121,8 +126,9 @@ + state: present + name: example.com + forwarders: +- - 4.4.4.4 +- - 8.8.8.8 ++ - ip_address: 4.4.4.4 ++ port: 8053 ++ - ip_address: 8.8.8.8 + action: member + register: result + failed_when: result.changed +@@ -133,7 +139,7 @@ + state: absent + name: example.com + forwarders: +- - 8.8.8.8 ++ - ip_address: 8.8.8.8 + action: member + register: result + failed_when: not result.changed +@@ -144,7 +150,8 @@ + state: present + name: example.com + forwarders: +- - 4.4.4.4 ++ - ip_address: 4.4.4.4 ++ port: 8053 + action: member + register: result + failed_when: result.changed +@@ -161,7 +168,8 @@ + state: present + name: example.com + forwarders: +- - 4.4.4.4 ++ - ip_address: 4.4.4.4 ++ port: 8053 + action: member + skip_overlap_check: true + register: result +@@ -179,7 +187,8 @@ + state: disabled + name: example.com + forwarders: +- - 4.4.4.4 ++ - ip_address: 4.4.4.4 ++ port: 8053 + skip_overlap_check: true + register: result + failed_when: not result.changed +From bf864469a1da81c6b23e9726562b21408764ac8f Mon Sep 17 00:00:00 2001 +From: Rafael Guterres Jeffman +Date: Mon, 15 Jun 2020 20:42:23 -0300 +Subject: [PATCH] Add support for attribute `permission` on dnsforwardzone + module. + +Adds missing attribute `permission to dnsforwardzone module, that +enable setting `manageby` for the DNS Forwar Zone. +--- + README-dnsforwardzone.md | 1 + + plugins/modules/ipadnsforwardzone.py | 71 ++++++++---- + tests/dnsforwardzone/test_dnsforwardzone.yml | 110 +++++++++++++++---- + 3 files changed, 136 insertions(+), 46 deletions(-) + +diff --git a/README-dnsforwardzone.md b/README-dnsforwardzone.md +index 15b2b574..175e6f8b 100644 +--- a/README-dnsforwardzone.md ++++ b/README-dnsforwardzone.md +@@ -104,6 +104,7 @@ Variable | Description | Required +   | `port`: The forwarder IP port. | no + `forwardpolicy` \| `idnsforwardpolicy` | Per-zone conditional forwarding policy. Possible values are `only`, `first`, `none`. Set to "none" to disable forwarding to global forwarder for this zone. In that case, conditional zone forwarders are disregarded. | no + `skip_overlap_check` | Force DNS zone creation even if it will overlap with an existing zone. Defaults to False. | no ++`permission` | Allow DNS Forward Zone to be managed. (bool) | no + `action` | Work on group or member level. It can be on of `member` or `dnsforwardzone` and defaults to `dnsforwardzone`. | no + `state` | The state to ensure. It can be one of `present`, `absent`, `enabled` or `disabled`, default: `present`. | yes + +diff --git a/plugins/modules/ipadnsforwardzone.py b/plugins/modules/ipadnsforwardzone.py +index 8e5c3464..a729197b 100644 +--- a/plugins/modules/ipadnsforwardzone.py ++++ b/plugins/modules/ipadnsforwardzone.py +@@ -75,6 +75,11 @@ + - Force DNS zone creation even if it will overlap with an existing zone. + required: false + default: false ++ permission: ++ description: ++ - Allow DNS Forward Zone to be managed. ++ required: false ++ type: bool + ''' + + EXAMPLES = ''' +@@ -168,6 +173,8 @@ def main(): + required=False, + choices=['only', 'first', 'none']), + skip_overlap_check=dict(type='bool', required=False), ++ permission=dict(type='bool', required=False, ++ aliases=['managedby']), + action=dict(type="str", default="dnsforwardzone", + choices=["member", "dnsforwardzone"]), + # state +@@ -191,6 +198,7 @@ def main(): + forwardpolicy = module_params_get(ansible_module, "forwardpolicy") + skip_overlap_check = module_params_get(ansible_module, + "skip_overlap_check") ++ permission = module_params_get(ansible_module, "permission") + state = module_params_get(ansible_module, "state") + + if state == 'present' and len(names) != 1: +@@ -215,7 +223,9 @@ def main(): + wants_enable = True + + if operation == "del": +- invalid = ["forwarders", "forwardpolicy", "skip_overlap_check"] ++ invalid = [ ++ "forwarders", "forwardpolicy", "skip_overlap_check", "permission" ++ ] + for x in invalid: + if vars()[x] is not None: + ansible_module.fail_json( +@@ -241,6 +251,9 @@ def main(): + api_connect() + + for name in names: ++ commands = [] ++ command = None ++ + # Make sure forwardzone exists + existing_resource = find_dnsforwardzone(ansible_module, name) + +@@ -249,6 +262,18 @@ def main(): + if existing_resource is None and not forwarders: + ansible_module.fail_json(msg='No forwarders specified.') + ++ if existing_resource is not None: ++ if state != "absent": ++ if forwarders: ++ forwarders = list( ++ set(existing_resource["idnsforwarders"] ++ + forwarders)) ++ else: ++ if forwarders: ++ forwarders = list( ++ set(existing_resource["idnsforwarders"]) ++ - set(forwarders)) ++ + if existing_resource is None and operation == "update": + # does not exist and is updating + # trying to update something that doesn't exist, so error +@@ -256,20 +281,17 @@ def main(): + valid""" % (name)) + elif existing_resource is None and operation == "del": + # does not exists and should be absent +- # set command +- command = None + # enabled or disabled? + is_enabled = "IGNORE" + elif existing_resource is not None and operation == "del": + # exists but should be absent + # set command + command = "dnsforwardzone_del" ++ args = {} + # enabled or disabled? + is_enabled = "IGNORE" + elif forwarders is None: + # forwarders are not defined its not a delete, update state? +- # set command +- command = None + # enabled or disabled? + if existing_resource is not None: + is_enabled = existing_resource["idnszoneactive"][0] +@@ -278,23 +300,13 @@ def main(): + elif existing_resource is not None and operation == "update": + # exists and is updating + # calculate the new forwarders and mod +- # determine args +- if state != "absent": +- forwarders = list(set(existing_resource["idnsforwarders"] +- + forwarders)) +- else: +- forwarders = list(set(existing_resource["idnsforwarders"]) +- - set(forwarders)) +- args = gen_args(forwarders, forwardpolicy, +- skip_overlap_check) +- if skip_overlap_check is not None: ++ args = gen_args(forwarders, forwardpolicy, skip_overlap_check) ++ if "skip_overlap_check" in args: + del args['skip_overlap_check'] + + # command + if not compare_args_ipa(ansible_module, args, existing_resource): + command = "dnsforwardzone_mod" +- else: +- command = None + + # enabled or disabled? + is_enabled = existing_resource["idnszoneactive"][0] +@@ -313,21 +325,36 @@ def main(): + # exists and should be present, has it changed? + # determine args + args = gen_args(forwarders, forwardpolicy, skip_overlap_check) +- if skip_overlap_check is not None: ++ if 'skip_overlap_check' in args: + del args['skip_overlap_check'] + + # set command + if not compare_args_ipa(ansible_module, args, existing_resource): + command = "dnsforwardzone_mod" +- else: +- command = None + + # enabled or disabled? + is_enabled = existing_resource["idnszoneactive"][0] + +- # if command is set then run it with the args ++ # if command is set... + if command is not None: +- api_command(ansible_module, command, name, args) ++ commands.append([name, command, args]) ++ ++ if permission is not None: ++ if existing_resource is None: ++ managedby = None ++ else: ++ managedby = existing_resource.get('managedby', None) ++ if permission and managedby is None: ++ commands.append( ++ [name, 'dnsforwardzone_add_permission', {}] ++ ) ++ elif not permission and managedby is not None: ++ commands.append( ++ [name, 'dnsforwardzone_remove_permission', {}] ++ ) ++ ++ for name, command, args in commands: ++ result = api_command(ansible_module, command, name, args) + changed = True + + # does the enabled state match what we want (if we care) +diff --git a/tests/dnsforwardzone/test_dnsforwardzone.yml b/tests/dnsforwardzone/test_dnsforwardzone.yml +index 468cd4ce..0386bd48 100644 +--- a/tests/dnsforwardzone/test_dnsforwardzone.yml ++++ b/tests/dnsforwardzone/test_dnsforwardzone.yml +@@ -51,8 +51,6 @@ + register: result + failed_when: not result.changed + +- - pause: +- + - name: ensure forwardzone example.com has one forwarder again + ipadnsforwardzone: + ipaadmin_password: SomeADMINpassword +@@ -63,7 +61,7 @@ + skip_overlap_check: true + state: present + register: result +- failed_when: not result.changed ++ failed_when: result.changed + + - name: skip_overlap_check can only be set on creation so change nothing + ipadnsforwardzone: +@@ -77,6 +75,22 @@ + register: result + failed_when: result.changed + ++ - name: ensure forwardzone example.com is absent. ++ ipadnsforwardzone: ++ ipaadmin_password: SomeADMINpassword ++ name: example.com ++ state: absent ++ register: result ++ failed_when: not result.changed ++ ++ - name: ensure forwardzone example.com is absent, again. ++ ipadnsforwardzone: ++ ipaadmin_password: SomeADMINpassword ++ name: example.com ++ state: absent ++ register: result ++ failed_when: result.changed ++ + - name: change all the things at once + ipadnsforwardzone: + ipaadmin_password: SomeADMINpassword +@@ -87,11 +101,12 @@ + - ip_address: 4.4.4.4 + port: 8053 + forwardpolicy: only +- skip_overlap_check: false ++ skip_overlap_check: true ++ permission: yes + register: result + failed_when: not result.changed + +- - name: ensure forwardzone example.com is absent for next testset ++ - name: ensure forwardzone example.com is absent. + ipadnsforwardzone: + ipaadmin_password: SomeADMINpassword + name: example.com +@@ -156,43 +171,58 @@ + register: result + failed_when: result.changed + +- - name: ensure forwardzone example.com is absent again ++ - name: Add a permission for per-forward zone access delegation. + ipadnsforwardzone: + ipaadmin_password: SomeADMINpassword + name: example.com +- state: absent ++ permission: yes ++ action: member ++ register: result ++ failed_when: not result.changed + +- - name: try to create a new forwarder with action=member ++ - name: Add a permission for per-forward zone access delegation, again. + ipadnsforwardzone: + ipaadmin_password: SomeADMINpassword +- state: present + name: example.com +- forwarders: +- - ip_address: 4.4.4.4 +- port: 8053 ++ permission: yes + action: member +- skip_overlap_check: true + register: result + failed_when: result.changed + +- - name: ensure forwardzone example.com is absent - tidy up ++ - name: Remove a permission for per-forward zone access delegation. + ipadnsforwardzone: + ipaadmin_password: SomeADMINpassword + name: example.com +- state: absent ++ permission: no ++ action: member ++ register: result ++ failed_when: not result.changed + +- - name: try to create a new forwarder is disabled state ++ - name: Remove a permission for per-forward zone access delegation, again. + ipadnsforwardzone: + ipaadmin_password: SomeADMINpassword +- state: disabled + name: example.com +- forwarders: +- - ip_address: 4.4.4.4 +- port: 8053 +- skip_overlap_check: true ++ permission: no ++ action: member ++ register: result ++ failed_when: result.changed ++ ++ - name: disable the forwarder ++ ipadnsforwardzone: ++ ipaadmin_password: SomeADMINpassword ++ name: example.com ++ state: disabled + register: result + failed_when: not result.changed + ++ - name: disable the forwarder again ++ ipadnsforwardzone: ++ ipaadmin_password: SomeADMINpassword ++ name: example.com ++ state: disabled ++ register: result ++ failed_when: result.changed ++ + - name: enable the forwarder + ipadnsforwardzone: + ipaadmin_password: SomeADMINpassword +@@ -201,12 +231,42 @@ + register: result + failed_when: not result.changed + +- - name: disable the forwarder again ++ - name: enable the forwarder, again + ipadnsforwardzone: + ipaadmin_password: SomeADMINpassword + name: example.com +- state: disabled ++ state: enabled ++ register: result ++ failed_when: result.changed ++ ++ - name: ensure forwardzone example.com is absent again ++ ipadnsforwardzone: ++ ipaadmin_password: SomeADMINpassword ++ name: example.com ++ state: absent ++ ++ - name: try to create a new forwarder with action=member ++ ipadnsforwardzone: ++ ipaadmin_password: SomeADMINpassword ++ state: present ++ name: example.com ++ forwarders: ++ - ip_address: 4.4.4.4 ++ port: 8053 + action: member ++ skip_overlap_check: true ++ register: result ++ failed_when: result.changed ++ ++ - name: try to create a new forwarder with disabled state ++ ipadnsforwardzone: ++ ipaadmin_password: SomeADMINpassword ++ state: disabled ++ name: example.com ++ forwarders: ++ - ip_address: 4.4.4.4 ++ port: 8053 ++ skip_overlap_check: yes + register: result + failed_when: not result.changed + +@@ -228,5 +288,7 @@ + - name: ensure forwardzone example.com is absent - tidy up + ipadnsforwardzone: + ipaadmin_password: SomeADMINpassword +- name: example.com ++ name: ++ - example.com ++ - newfailzone.com + state: absent +From 857fb82eb9141a44ffb91331653e1c30b43f671e Mon Sep 17 00:00:00 2001 +From: Rafael Guterres Jeffman +Date: Mon, 15 Jun 2020 23:40:35 -0300 +Subject: [PATCH] Allows modification of forward policy in existing DNS Forward + Zone. + +This patch allows the modification of the forward zone policy in +an existing DNS Forward Zone, and fixes some issues with `enable` +and `disable` state that prevented correct behavior of `forwardpolicy`. +--- + plugins/modules/ipadnsforwardzone.py | 154 ++++++++++--------- + tests/dnsforwardzone/test_dnsforwardzone.yml | 32 ++-- + 2 files changed, 97 insertions(+), 89 deletions(-) + +diff --git a/plugins/modules/ipadnsforwardzone.py b/plugins/modules/ipadnsforwardzone.py +index a729197b..1f1e85ec 100644 +--- a/plugins/modules/ipadnsforwardzone.py ++++ b/plugins/modules/ipadnsforwardzone.py +@@ -217,10 +217,20 @@ def main(): + else: + operation = "add" + +- if state == "disabled": +- wants_enable = False +- else: +- wants_enable = True ++ if state in ["enabled", "disabled"]: ++ if action == "member": ++ ansible_module.fail_json( ++ msg="Action `member` cannot be used with state `%s`" ++ % (state)) ++ invalid = [ ++ "forwarders", "forwardpolicy", "skip_overlap_check", "permission" ++ ] ++ for x in invalid: ++ if vars()[x] is not None: ++ ansible_module.fail_json( ++ msg="Argument '%s' can not be used with action " ++ "'%s', state `%s`" % (x, action, state)) ++ wants_enable = (state == "enabled") + + if operation == "del": + invalid = [ +@@ -230,7 +240,7 @@ def main(): + if vars()[x] is not None: + ansible_module.fail_json( + msg="Argument '%s' can not be used with action " +- "'%s'" % (x, action)) ++ "'%s', state `%s`" % (x, action, state)) + + changed = False + exit_args = {} +@@ -262,7 +272,27 @@ def main(): + if existing_resource is None and not forwarders: + ansible_module.fail_json(msg='No forwarders specified.') + +- if existing_resource is not None: ++ if existing_resource is None: ++ if operation == "add": ++ # does not exist but should be present ++ # determine args ++ args = gen_args(forwarders, forwardpolicy, ++ skip_overlap_check) ++ # set command ++ command = "dnsforwardzone_add" ++ # enabled or disabled? ++ ++ elif operation == "update": ++ # does not exist and is updating ++ # trying to update something that doesn't exist, so error ++ ansible_module.fail_json( ++ msg="dnsforwardzone '%s' not found." % (name)) ++ ++ elif operation == "del": ++ # there's nothnig to do. ++ continue ++ ++ else: # existing_resource is not None + if state != "absent": + if forwarders: + forwarders = list( +@@ -274,66 +304,51 @@ def main(): + set(existing_resource["idnsforwarders"]) + - set(forwarders)) + +- if existing_resource is None and operation == "update": +- # does not exist and is updating +- # trying to update something that doesn't exist, so error +- ansible_module.fail_json(msg="""dnsforwardzone '%s' is not +- valid""" % (name)) +- elif existing_resource is None and operation == "del": +- # does not exists and should be absent +- # enabled or disabled? +- is_enabled = "IGNORE" +- elif existing_resource is not None and operation == "del": +- # exists but should be absent +- # set command +- command = "dnsforwardzone_del" +- args = {} +- # enabled or disabled? +- is_enabled = "IGNORE" +- elif forwarders is None: +- # forwarders are not defined its not a delete, update state? +- # enabled or disabled? ++ if operation == "add": ++ # exists and should be present, has it changed? ++ # determine args ++ args = gen_args( ++ forwarders, forwardpolicy, skip_overlap_check) ++ if 'skip_overlap_check' in args: ++ del args['skip_overlap_check'] ++ ++ # set command ++ if not compare_args_ipa( ++ ansible_module, args, existing_resource): ++ command = "dnsforwardzone_mod" ++ ++ elif operation == "del": ++ # exists but should be absent ++ # set command ++ command = "dnsforwardzone_del" ++ args = {} ++ ++ elif operation == "update": ++ # exists and is updating ++ # calculate the new forwarders and mod ++ args = gen_args( ++ forwarders, forwardpolicy, skip_overlap_check) ++ if "skip_overlap_check" in args: ++ del args['skip_overlap_check'] ++ ++ # command ++ if not compare_args_ipa( ++ ansible_module, args, existing_resource): ++ command = "dnsforwardzone_mod" ++ ++ if state in ['enabled', 'disabled']: + if existing_resource is not None: + is_enabled = existing_resource["idnszoneactive"][0] + else: +- is_enabled = "IGNORE" +- elif existing_resource is not None and operation == "update": +- # exists and is updating +- # calculate the new forwarders and mod +- args = gen_args(forwarders, forwardpolicy, skip_overlap_check) +- if "skip_overlap_check" in args: +- del args['skip_overlap_check'] +- +- # command +- if not compare_args_ipa(ansible_module, args, existing_resource): +- command = "dnsforwardzone_mod" +- +- # enabled or disabled? +- is_enabled = existing_resource["idnszoneactive"][0] +- +- elif existing_resource is None and operation == "add": +- # does not exist but should be present +- # determine args +- args = gen_args(forwarders, forwardpolicy, +- skip_overlap_check) +- # set command +- command = "dnsforwardzone_add" +- # enabled or disabled? +- is_enabled = "TRUE" +- +- elif existing_resource is not None and operation == "add": +- # exists and should be present, has it changed? +- # determine args +- args = gen_args(forwarders, forwardpolicy, skip_overlap_check) +- if 'skip_overlap_check' in args: +- del args['skip_overlap_check'] +- +- # set command +- if not compare_args_ipa(ansible_module, args, existing_resource): +- command = "dnsforwardzone_mod" +- +- # enabled or disabled? +- is_enabled = existing_resource["idnszoneactive"][0] ++ ansible_module.fail_json( ++ msg="dnsforwardzone '%s' not found." % (name)) ++ ++ # does the enabled state match what we want (if we care) ++ if is_enabled != "IGNORE": ++ if wants_enable and is_enabled != "TRUE": ++ commands.append([name, "dnsforwardzone_enable", {}]) ++ elif not wants_enable and is_enabled != "FALSE": ++ commands.append([name, "dnsforwardzone_disable", {}]) + + # if command is set... + if command is not None: +@@ -354,20 +369,9 @@ def main(): + ) + + for name, command, args in commands: +- result = api_command(ansible_module, command, name, args) ++ api_command(ansible_module, command, name, args) + changed = True + +- # does the enabled state match what we want (if we care) +- if is_enabled != "IGNORE": +- if wants_enable and is_enabled != "TRUE": +- api_command(ansible_module, "dnsforwardzone_enable", +- name, {}) +- changed = True +- elif not wants_enable and is_enabled != "FALSE": +- api_command(ansible_module, "dnsforwardzone_disable", +- name, {}) +- changed = True +- + except Exception as e: + ansible_module.fail_json(msg=str(e)) + +diff --git a/tests/dnsforwardzone/test_dnsforwardzone.yml b/tests/dnsforwardzone/test_dnsforwardzone.yml +index 0386bd48..223cf3d0 100644 +--- a/tests/dnsforwardzone/test_dnsforwardzone.yml ++++ b/tests/dnsforwardzone/test_dnsforwardzone.yml +@@ -106,6 +106,22 @@ + register: result + failed_when: not result.changed + ++ - name: change zone forward policy ++ ipadnsforwardzone: ++ ipaadmin_password: SomeADMINpassword ++ name: example.com ++ forwardpolicy: first ++ register: result ++ failed_when: not result.changed ++ ++ - name: change zone forward policy, again ++ ipadnsforwardzone: ++ ipaadmin_password: SomeADMINpassword ++ name: example.com ++ forwardpolicy: first ++ register: result ++ failed_when: result.changed ++ + - name: ensure forwardzone example.com is absent. + ipadnsforwardzone: + ipaadmin_password: SomeADMINpassword +@@ -256,27 +272,15 @@ + action: member + skip_overlap_check: true + register: result +- failed_when: result.changed ++ failed_when: not result.failed or "not found" not in result.msg + + - name: try to create a new forwarder with disabled state +- ipadnsforwardzone: +- ipaadmin_password: SomeADMINpassword +- state: disabled +- name: example.com +- forwarders: +- - ip_address: 4.4.4.4 +- port: 8053 +- skip_overlap_check: yes +- register: result +- failed_when: not result.changed +- +- - name: ensure it stays disabled + ipadnsforwardzone: + ipaadmin_password: SomeADMINpassword + name: example.com + state: disabled + register: result +- failed_when: result.changed ++ failed_when: not result.failed or "not found" not in result.msg + + - name: Ensure forwardzone is not added without forwarders, with correct message. + ipadnsforwardzone: +From 8da6a6937919d0c390b870113fb557649c39c815 Mon Sep 17 00:00:00 2001 +From: Rafael Guterres Jeffman +Date: Fri, 26 Jun 2020 11:28:15 -0300 +Subject: [PATCH] Change password values in README to keep consistency with + other modules. + +--- + README-dnsforwardzone.md | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/README-dnsforwardzone.md b/README-dnsforwardzone.md +index 175e6f8b..32de7bfe 100644 +--- a/README-dnsforwardzone.md ++++ b/README-dnsforwardzone.md +@@ -49,7 +49,7 @@ Example playbook to ensure presence of a forwardzone to ipa DNS: + tasks: + - name: ensure presence of forwardzone for DNS requests for example.com to 8.8.8.8 + ipadnsforwardzone: +- ipaadmin_password: password01 ++ ipaadmin_password: SomeADMINpassword + state: present + name: example.com + forwarders: +@@ -59,13 +59,13 @@ Example playbook to ensure presence of a forwardzone to ipa DNS: + + - name: ensure the forward zone is disabled + ipadnsforwardzone: +- ipaadmin_password: password01 ++ ipaadmin_password: SomeADMINpassword + name: example.com + state: disabled + + - name: ensure presence of multiple upstream DNS servers for example.com + ipadnsforwardzone: +- ipaadmin_password: password01 ++ ipaadmin_password: SomeADMINpassword + state: present + name: example.com + forwarders: +@@ -74,7 +74,7 @@ Example playbook to ensure presence of a forwardzone to ipa DNS: + + - name: ensure presence of another forwarder to any existing ones for example.com + ipadnsforwardzone: +- ipaadmin_password: password01 ++ ipaadmin_password: SomeADMINpassword + state: present + name: example.com + forwarders: +@@ -83,7 +83,7 @@ Example playbook to ensure presence of a forwardzone to ipa DNS: + + - name: ensure the forwarder for example.com does not exists (delete it if needed) + ipadnsforwardzone: +- ipaadmin_password: password01 ++ ipaadmin_password: SomeADMINpassword + name: example.com + state: absent + ``` diff --git a/SOURCES/ansible-freeipa-0.1.12-Fixes-service-disable-when-service-has-no-certificates-attached_rhbz#1836294.patch b/SOURCES/ansible-freeipa-0.1.12-Fixes-service-disable-when-service-has-no-certificates-attached_rhbz#1836294.patch new file mode 100644 index 0000000..b4b8e6e --- /dev/null +++ b/SOURCES/ansible-freeipa-0.1.12-Fixes-service-disable-when-service-has-no-certificates-attached_rhbz#1836294.patch @@ -0,0 +1,112 @@ +From e57e4908f936c524085fb5853fe4493c7711ab3f Mon Sep 17 00:00:00 2001 +From: Rafael Guterres Jeffman +Date: Thu, 25 Jun 2020 16:26:30 -0300 +Subject: [PATCH] Fixes service disable when service has no certificates + attached. + +Services without certificates, but with keytabs were not being +disabled. This change allows execution of service_disable if +there is a certificate or if has_keytab is true. + +A new test was added to verify the issue: + + tests/service/test_service_disable.yml +--- + plugins/modules/ipaservice.py | 8 +-- + tests/service/test_service_disable.yml | 68 ++++++++++++++++++++++++++ + 2 files changed, 73 insertions(+), 3 deletions(-) + create mode 100644 tests/service/test_service_disable.yml + +diff --git a/plugins/modules/ipaservice.py b/plugins/modules/ipaservice.py +index 23a0d6b3..b0d25355 100644 +--- a/plugins/modules/ipaservice.py ++++ b/plugins/modules/ipaservice.py +@@ -812,9 +812,11 @@ def main(): + + elif state == "disabled": + if action == "service": +- if res_find is not None and \ +- len(res_find.get('usercertificate', [])) > 0: +- commands.append([name, 'service_disable', {}]) ++ if res_find is not None: ++ has_cert = bool(res_find.get('usercertificate')) ++ has_keytab = res_find.get('has_keytab', False) ++ if has_cert or has_keytab: ++ commands.append([name, 'service_disable', {}]) + else: + ansible_module.fail_json( + msg="Invalid action '%s' for state '%s'" % +diff --git a/tests/service/test_service_disable.yml b/tests/service/test_service_disable.yml +new file mode 100644 +index 00000000..3b4a88fb +--- /dev/null ++++ b/tests/service/test_service_disable.yml +@@ -0,0 +1,68 @@ ++--- ++- name: Playbook to manage IPA service. ++ hosts: ipaserver ++ become: yes ++ gather_facts: yes ++ ++ tasks: ++ - name: Ensure service is absent ++ ipaservice: ++ ipaadmin_password: SomeADMINpassword ++ name: "mysvc1/{{ ansible_fqdn }}" ++ ++ - name: Ensure service is present ++ ipaservice: ++ ipaadmin_password: SomeADMINpassword ++ name: "mysvc1/{{ ansible_fqdn }}" ++ certificate: ++ - MIIC/zCCAeegAwIBAgIUMNHIbn+hhrOVew/2WbkteisV29QwDQYJKoZIhvcNAQELBQAwDzENMAsGA1UEAwwEdGVzdDAeFw0yMDAyMDQxNDQxMDhaFw0zMDAyMDExNDQxMDhaMA8xDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC+XVVGFYpHVkcDfVnNInE1Y/pFciegdzqTjMwUWlRL4Zt3u96GhaMLRbtk+OfEkzLUAhWBOwEraELJzMLJOMvjYF3C+TiGO7dStFLikZmccuSsSIXjnzIPwBXa8KvgRVRyGLoVvGbLJvmjfMXp0nIToTx/i74KF9S++WEes9H5ErJ99CDhLKFgq0amnvsgparYXhypHaRLnikn0vQINt55YoEd1s4KrvEcD2VdZkIMPbLRu2zFvMprF3cjQQG4LT9ggfEXNIPZ1nQWAnAsu7OJEkNF+E4Mkmpcxj9aGUVt5bsq1D+Tzj3GsidSX0nSNcZ2JltXRnL/5v63g5cZyE+nAgMBAAGjUzBRMB0GA1UdDgQWBBRV0j7JYukuH/r/t9+QeNlRLXDlEDAfBgNVHSMEGDAWgBRV0j7JYukuH/r/t9+QeNlRLXDlEDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCgVy1+1kNwHs5y1Zp0WjMWGCJC6/zw7FDG4OW5r2GJiCXZYdJ0UonY9ZtoVLJPrp2/DAv1m5DtnDhBYqicuPgLzEkOS1KdTi20Otm/J4yxLLrZC5W4x0XOeSVPXOJuQWfwQ5pPvKkn6WxYUYkGwIt1OH2nSMngkbami3CbSmKZOCpgQIiSlQeDJ8oGjWFMLDymYSHoVOIXHwNoooyEiaio3693l6noobyGv49zyCVLVR1DC7i6RJ186ql0av+D4vPoiF5mX7+sKC2E8xEj9uKQ5GTWRh59VnRBVC/SiMJ/H78tJnBAvoBwXxSEvj8Z3Kjm/BQqZfv4IBsA5yqV7MVq ++ force: no ++ register: result ++ failed_when: not result.changed ++ ++ - name: Obtain keytab ++ shell: ipa-getkeytab -s "{{ ansible_fqdn }}" -p "mysvc1/{{ ansible_fqdn }}" -k mysvc1.keytab ++ ++ - name: Verify keytab ++ shell: ipa service-find "mysvc1/{{ ansible_fqdn }}" ++ register: result ++ failed_when: result.failed or result.stdout | regex_search(" Keytab. true") ++ ++ - name: Ensure service is disabled ++ ipaservice: ++ ipaadmin_password: SomeADMINpassword ++ name: "mysvc1/{{ ansible_fqdn }}" ++ state: disabled ++ register: result ++ failed_when: not result.changed ++ ++ - name: Verify keytab ++ shell: ipa service-find "mysvc1/{{ ansible_fqdn }}" ++ register: result ++ failed_when: result.failed or result.stdout | regex_search(" Keytab. true") ++ ++ - name: Obtain keytab ++ shell: ipa-getkeytab -s "{{ ansible_fqdn }}" -p "mysvc1/{{ ansible_fqdn }}" -k mysvc1.keytab ++ ++ - name: Verify keytab ++ shell: ipa service-find "mysvc1/{{ ansible_fqdn }}" ++ register: result ++ failed_when: result.failed or result.stdout | regex_search(" Keytab. true") ++ ++ - name: Ensure service is disabled ++ ipaservice: ++ ipaadmin_password: SomeADMINpassword ++ name: "mysvc1/{{ ansible_fqdn }}" ++ state: disabled ++ register: result ++ failed_when: not result.changed ++ ++ - name: Verify keytab ++ shell: ipa service-find "mysvc1/{{ ansible_fqdn }}" ++ register: result ++ failed_when: result.failed or result.stdout | regex_search(" Keytab. true") ++ ++ - name: Ensure service is absent ++ ipaservice: ++ ipaadmin_password: SomeADMINpassword ++ name: "mysvc1/{{ ansible_fqdn }}" diff --git a/SOURCES/ansible-freeipa-0.1.12-action_plugins-ipaclient_get_otp-Discovered-python-n_rhbz#1852714.patch b/SOURCES/ansible-freeipa-0.1.12-action_plugins-ipaclient_get_otp-Discovered-python-n_rhbz#1852714.patch new file mode 100644 index 0000000..14dbf4e --- /dev/null +++ b/SOURCES/ansible-freeipa-0.1.12-action_plugins-ipaclient_get_otp-Discovered-python-n_rhbz#1852714.patch @@ -0,0 +1,49 @@ +From 80aac15de9026055ae2b9972859939cf7925b813 Mon Sep 17 00:00:00 2001 +From: Thomas Woerner +Date: Tue, 30 Jun 2020 17:32:19 +0200 +Subject: [PATCH] action_plugins/ipaclient_get_otp: Discovered python needed in + task_vars + +Ansible is now also supporting discovered_python_interpreter for +action_plugins. task_vars needs to be non Null and contain a setting for +discovered_python_interpreter. The ipaclient_get_otp action_plugin +therefore needed to be adapted. +--- + roles/ipaclient/action_plugins/ipaclient_get_otp.py | 4 ++-- + roles/ipaclient/tasks/install.yml | 1 - + 2 files changed, 2 insertions(+), 3 deletions(-) + +diff --git a/roles/ipaclient/action_plugins/ipaclient_get_otp.py b/roles/ipaclient/action_plugins/ipaclient_get_otp.py +index dcddc0a..8e04ad9 100644 +--- a/roles/ipaclient/action_plugins/ipaclient_get_otp.py ++++ b/roles/ipaclient/action_plugins/ipaclient_get_otp.py +@@ -164,7 +164,8 @@ class ActionModule(ActionBase): + return result + + data = self._execute_module(module_name='ipaclient_get_facts', +- module_args=dict(), task_vars=None) ++ module_args=dict(), task_vars=task_vars) ++ + try: + domain = data['ansible_facts']['ipa']['domain'] + realm = data['ansible_facts']['ipa']['realm'] +@@ -245,4 +246,3 @@ class ActionModule(ActionBase): + finally: + # delete the local temp directory + shutil.rmtree(local_temp_dir, ignore_errors=True) +- run_cmd(['/usr/bin/kdestroy', '-c', tmp_ccache]) +diff --git a/roles/ipaclient/tasks/install.yml b/roles/ipaclient/tasks/install.yml +index 0de3dea..4421f0c 100644 +--- a/roles/ipaclient/tasks/install.yml ++++ b/roles/ipaclient/tasks/install.yml +@@ -134,7 +134,6 @@ + "Password cannot be set on enrolled host" not + in result_ipaclient_get_otp.msg + delegate_to: "{{ result_ipaclient_test.servers[0] }}" +- delegate_facts: yes + ignore_errors: yes + + - name: Install - Report error for OTP generation +-- +2.26.2 + diff --git a/SOURCES/ansible-freeipa-0.1.12-ipa-host-group-Fix-membermanager-unknow-user-issue_rhbz#1848426.patch b/SOURCES/ansible-freeipa-0.1.12-ipa-host-group-Fix-membermanager-unknow-user-issue_rhbz#1848426.patch new file mode 100644 index 0000000..69069b2 --- /dev/null +++ b/SOURCES/ansible-freeipa-0.1.12-ipa-host-group-Fix-membermanager-unknow-user-issue_rhbz#1848426.patch @@ -0,0 +1,132 @@ +From 6132a947e65fb9c3a1ec5c059aed34afb06a67df Mon Sep 17 00:00:00 2001 +From: Thomas Woerner +Date: Mon, 29 Jun 2020 13:12:12 +0200 +Subject: [PATCH] ipa[host]group: Fix membermanager unknow user issue + +If a unknown membermanager user presence will be ensured, the unknown user +error was ignored. This has been fixed in ipagroup. The code for the error +handling in ipagroup and ipahostgroup has been adapted because of this. + +New tests for tests/[host]group/test_[host]group_membermnager.yml have been +added. +--- + plugins/modules/ipagroup.py | 19 +++++++++---------- + plugins/modules/ipahostgroup.py | 13 +++++++------ + tests/group/test_group_membermanager.yml | 11 ++++++++++- + .../test_hostgroup_membermanager.yml | 11 ++++++++++- + 4 files changed, 36 insertions(+), 18 deletions(-) + +diff --git a/plugins/modules/ipagroup.py b/plugins/modules/ipagroup.py +index 915bc499..903c256d 100644 +--- a/plugins/modules/ipagroup.py ++++ b/plugins/modules/ipagroup.py +@@ -507,16 +507,15 @@ def main(): + # All "already a member" and "not a member" failures in the + # result are ignored. All others are reported. + errors = [] +- if "failed" in result and len(result["failed"]) > 0: +- for item in result["failed"]: +- failed_item = result["failed"][item] +- for member_type in failed_item: +- for member, failure in failed_item[member_type]: +- if "already a member" in failure \ +- or "not a member" in failure: +- continue +- errors.append("%s: %s %s: %s" % ( +- command, member_type, member, failure)) ++ for failed_item in result.get("failed", []): ++ failed = result["failed"][failed_item] ++ for member_type in failed: ++ for member, failure in failed[member_type]: ++ if "already a member" in failure \ ++ or "not a member" in failure: ++ continue ++ errors.append("%s: %s %s: %s" % ( ++ command, member_type, member, failure)) + if len(errors) > 0: + ansible_module.fail_json(msg=", ".join(errors)) + +diff --git a/plugins/modules/ipahostgroup.py b/plugins/modules/ipahostgroup.py +index 4c18e940..5f615160 100644 +--- a/plugins/modules/ipahostgroup.py ++++ b/plugins/modules/ipahostgroup.py +@@ -423,14 +423,15 @@ def main(): + # All "already a member" and "not a member" failures in the + # result are ignored. All others are reported. + errors = [] +- if "failed" in result and "member" in result["failed"]: +- failed = result["failed"]["member"] ++ for failed_item in result.get("failed", []): ++ failed = result["failed"][failed_item] + for member_type in failed: + for member, failure in failed[member_type]: +- if "already a member" not in failure \ +- and "not a member" not in failure: +- errors.append("%s: %s %s: %s" % ( +- command, member_type, member, failure)) ++ if "already a member" in failure \ ++ or "not a member" in failure: ++ continue ++ errors.append("%s: %s %s: %s" % ( ++ command, member_type, member, failure)) + if len(errors) > 0: + ansible_module.fail_json(msg=", ".join(errors)) + +diff --git a/tests/group/test_group_membermanager.yml b/tests/group/test_group_membermanager.yml +index 1d38654f..661f26d6 100644 +--- a/tests/group/test_group_membermanager.yml ++++ b/tests/group/test_group_membermanager.yml +@@ -8,7 +8,7 @@ + - name: Ensure user manangeruser1 and manageruser2 is absent + ipauser: + ipaadmin_password: SomeADMINpassword +- name: manageruser1,manageruser2 ++ name: manageruser1,manageruser2,unknown_user + state: absent + + - name: Ensure group testgroup, managergroup1 and managergroup2 are absent +@@ -185,6 +185,15 @@ + register: result + failed_when: not result.changed + ++ - name: Ensure unknown membermanager_user member failure ++ ipagroup: ++ ipaadmin_password: SomeADMINpassword ++ name: testgroup ++ membermanager_user: unknown_user ++ action: member ++ register: result ++ failed_when: result.changed or "no such entry" not in result.msg ++ + - name: Ensure group testgroup, managergroup1 and managergroup2 are absent + ipagroup: + ipaadmin_password: SomeADMINpassword +diff --git a/tests/hostgroup/test_hostgroup_membermanager.yml b/tests/hostgroup/test_hostgroup_membermanager.yml +index c32d1088..c0f65460 100644 +--- a/tests/hostgroup/test_hostgroup_membermanager.yml ++++ b/tests/hostgroup/test_hostgroup_membermanager.yml +@@ -15,7 +15,7 @@ + - name: Ensure user manangeruser1 and manageruser2 is absent + ipauser: + ipaadmin_password: SomeADMINpassword +- name: manageruser1,manageruser2 ++ name: manageruser1,manageruser2,unknown_user + state: absent + + - name: Ensure group managergroup1 and managergroup2 are absent +@@ -200,6 +200,15 @@ + register: result + failed_when: not result.changed + ++ - name: Ensure unknown membermanager_user member failure ++ ipahostgroup: ++ ipaadmin_password: SomeADMINpassword ++ name: testhostgroup ++ membermanager_user: unknown_user ++ action: member ++ register: result ++ failed_when: result.changed or "no such entry" not in result.msg ++ + - name: Ensure host-group testhostgroup is absent + ipahostgroup: + ipaadmin_password: SomeADMINpassword diff --git a/SOURCES/ansible-freeipa-0.1.12-ipa-server-replica-Fix-pkcs12-info-regressions-intro_rhbz#1853284.patch b/SOURCES/ansible-freeipa-0.1.12-ipa-server-replica-Fix-pkcs12-info-regressions-intro_rhbz#1853284.patch new file mode 100644 index 0000000..ab45af0 --- /dev/null +++ b/SOURCES/ansible-freeipa-0.1.12-ipa-server-replica-Fix-pkcs12-info-regressions-intro_rhbz#1853284.patch @@ -0,0 +1,150 @@ +From 8ce5fd147aafc34e43dbe4246565c48eace2e115 Mon Sep 17 00:00:00 2001 +From: Thomas Woerner +Date: Thu, 2 Jul 2020 12:02:33 +0200 +Subject: [PATCH] ipa[server,replica]: Fix pkcs12 info regressions introduced + with CA-less + +With the CA-less patches the types for the pkcs12 infos have been changed +to lists in the modules. This is resulting in a bad conversion from None +to [''] for the parameters. Because of this a normal replica deployment is +failing as [''] is not a valid value. + +The install.yml files for ipareplica and also ipaserver have been changed +in the way that the pkcs12 values are checked if they are None. The +parameter will simply be omitted in this case and the parameter in the +module will become None by default. +--- + roles/ipareplica/tasks/install.yml | 18 +++++++++--------- + roles/ipaserver/tasks/install.yml | 10 +++++----- + 2 files changed, 14 insertions(+), 14 deletions(-) + +diff --git a/roles/ipareplica/tasks/install.yml b/roles/ipareplica/tasks/install.yml +index fc7f83e..c2a6222 100644 +--- a/roles/ipareplica/tasks/install.yml ++++ b/roles/ipareplica/tasks/install.yml +@@ -281,7 +281,7 @@ + ccache: "{{ result_ipareplica_prepare.ccache }}" + installer_ccache: "{{ result_ipareplica_prepare.installer_ccache }}" + _ca_enabled: "{{ result_ipareplica_prepare._ca_enabled }}" +- _dirsrv_pkcs12_info: "{{ result_ipareplica_prepare._dirsrv_pkcs12_info }}" ++ _dirsrv_pkcs12_info: "{{ result_ipareplica_prepare._dirsrv_pkcs12_info if result_ipareplica_prepare._dirsrv_pkcs12_info != None else omit }}" + subject_base: "{{ result_ipareplica_prepare.subject_base }}" + _top_dir: "{{ result_ipareplica_prepare._top_dir }}" + _add_to_ipaservers: "{{ result_ipareplica_prepare._add_to_ipaservers }}" +@@ -345,7 +345,7 @@ + config_master_host_name: + "{{ result_ipareplica_install_ca_certs.config_master_host_name }}" + ccache: "{{ result_ipareplica_prepare.ccache }}" +- _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info }}" ++ _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info if result_ipareplica_prepare._pkinit_pkcs12_info != None else omit }}" + _top_dir: "{{ result_ipareplica_prepare._top_dir }}" + + # We need to point to the master in ipa default conf when certmonger +@@ -407,8 +407,8 @@ + ccache: "{{ result_ipareplica_prepare.ccache }}" + _ca_enabled: "{{ result_ipareplica_prepare._ca_enabled }}" + _ca_file: "{{ result_ipareplica_prepare._ca_file }}" +- _dirsrv_pkcs12_info: "{{ result_ipareplica_prepare._dirsrv_pkcs12_info }}" +- _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info }}" ++ _dirsrv_pkcs12_info: "{{ result_ipareplica_prepare._dirsrv_pkcs12_info if result_ipareplica_prepare._dirsrv_pkcs12_info != None else omit }}" ++ _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info if result_ipareplica_prepare._pkinit_pkcs12_info != None else omit }}" + _top_dir: "{{ result_ipareplica_prepare._top_dir }}" + dirman_password: "{{ ipareplica_dirman_password }}" + ds_ca_subject: "{{ result_ipareplica_setup_ds.ds_ca_subject }}" +@@ -429,7 +429,7 @@ + ccache: "{{ result_ipareplica_prepare.ccache }}" + _ca_enabled: "{{ result_ipareplica_prepare._ca_enabled }}" + _ca_file: "{{ result_ipareplica_prepare._ca_file }}" +- _http_pkcs12_info: "{{ result_ipareplica_prepare._http_pkcs12_info }}" ++ _http_pkcs12_info: "{{ result_ipareplica_prepare._http_pkcs12_info if result_ipareplica_prepare._http_pkcs12_info != None else omit }}" + _top_dir: "{{ result_ipareplica_prepare._top_dir }}" + dirman_password: "{{ ipareplica_dirman_password }}" + +@@ -507,7 +507,7 @@ + _kra_enabled: "{{ result_ipareplica_prepare._kra_enabled }}" + _kra_host_name: "{{ result_ipareplica_prepare.config_kra_host_name }}" + _ca_file: "{{ result_ipareplica_prepare._ca_file }}" +- _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info }}" ++ _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info if result_ipareplica_prepare._pkinit_pkcs12_info != None else omit }}" + _top_dir: "{{ result_ipareplica_prepare._top_dir }}" + dirman_password: "{{ ipareplica_dirman_password }}" + +@@ -529,7 +529,7 @@ + _kra_enabled: "{{ result_ipareplica_prepare._kra_enabled }}" + _kra_host_name: "{{ result_ipareplica_prepare.config_kra_host_name }}" + _subject_base: "{{ result_ipareplica_prepare._subject_base }}" +- _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info }}" ++ _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info if result_ipareplica_prepare._pkinit_pkcs12_info != None else omit }}" + _top_dir: "{{ result_ipareplica_prepare._top_dir }}" + dirman_password: "{{ ipareplica_dirman_password }}" + config_setup_ca: "{{ result_ipareplica_prepare.config_setup_ca }}" +@@ -554,7 +554,7 @@ + ccache: "{{ result_ipareplica_prepare.ccache }}" + _ca_enabled: "{{ result_ipareplica_prepare._ca_enabled }}" + _ca_file: "{{ result_ipareplica_prepare._ca_file }}" +- _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info }}" ++ _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info if result_ipareplica_prepare._pkinit_pkcs12_info != None else omit }}" + _top_dir: "{{ result_ipareplica_prepare._top_dir }}" + dirman_password: "{{ ipareplica_dirman_password }}" + +@@ -574,7 +574,7 @@ + ccache: "{{ result_ipareplica_prepare.ccache }}" + _ca_enabled: "{{ result_ipareplica_prepare._ca_enabled }}" + _ca_file: "{{ result_ipareplica_prepare._ca_file }}" +- _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info }}" ++ _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info if result_ipareplica_prepare._pkinit_pkcs12_info != None else omit }}" + _top_dir: "{{ result_ipareplica_prepare._top_dir }}" + dirman_password: "{{ ipareplica_dirman_password }}" + ds_ca_subject: "{{ result_ipareplica_setup_ds.ds_ca_subject }}" +diff --git a/roles/ipaserver/tasks/install.yml b/roles/ipaserver/tasks/install.yml +index 30f9da2..687f72d 100644 +--- a/roles/ipaserver/tasks/install.yml ++++ b/roles/ipaserver/tasks/install.yml +@@ -203,7 +203,7 @@ + # no_host_dns: "{{ result_ipaserver_test.no_host_dns }}" + dirsrv_config_file: "{{ ipaserver_dirsrv_config_file | default(omit) }}" + dirsrv_cert_files: "{{ ipaserver_dirsrv_cert_files | default(omit) }}" +- _dirsrv_pkcs12_info: "{{ result_ipaserver_test._dirsrv_pkcs12_info }}" ++ _dirsrv_pkcs12_info: "{{ result_ipaserver_test._dirsrv_pkcs12_info if result_ipaserver_test._dirsrv_pkcs12_info != None else omit }}" + external_cert_files: + "{{ ipaserver_external_cert_files | default(omit) }}" + subject_base: "{{ result_ipaserver_prepare.subject_base }}" +@@ -240,7 +240,7 @@ + no_hbac_allow: "{{ ipaserver_no_hbac_allow }}" + idstart: "{{ result_ipaserver_test.idstart }}" + idmax: "{{ result_ipaserver_test.idmax }}" +- _pkinit_pkcs12_info: "{{ result_ipaserver_test._pkinit_pkcs12_info }}" ++ _pkinit_pkcs12_info: "{{ result_ipaserver_test._pkinit_pkcs12_info if result_ipaserver_test._pkinit_pkcs12_info != None else omit }}" + + - name: Install - Setup custodia + ipaserver_setup_custodia: +@@ -270,7 +270,7 @@ + no_pkinit: "{{ result_ipaserver_test.no_pkinit }}" + dirsrv_config_file: "{{ ipaserver_dirsrv_config_file | default(omit) }}" + dirsrv_cert_files: "{{ ipaserver_dirsrv_cert_files | default([]) }}" +- _dirsrv_pkcs12_info: "{{ result_ipaserver_test._dirsrv_pkcs12_info }}" ++ _dirsrv_pkcs12_info: "{{ result_ipaserver_test._dirsrv_pkcs12_info if result_ipaserver_test._dirsrv_pkcs12_info != None else omit }}" + external_ca: "{{ ipaserver_external_ca }}" + external_ca_type: "{{ ipaserver_external_ca_type | default(omit) }}" + external_ca_profile: +@@ -334,7 +334,7 @@ + idmax: "{{ result_ipaserver_test.idmax }}" + http_cert_files: "{{ ipaserver_http_cert_files | default([]) }}" + no_ui_redirect: "{{ ipaserver_no_ui_redirect }}" +- _http_pkcs12_info: "{{ result_ipaserver_test._http_pkcs12_info }}" ++ _http_pkcs12_info: "{{ result_ipaserver_test._http_pkcs12_info if result_ipaserver_test._http_pkcs12_info != None else omit }}" + + - name: Install - Setup KRA + ipaserver_setup_kra: +@@ -394,7 +394,7 @@ + idstart: "{{ result_ipaserver_test.idstart }}" + idmax: "{{ result_ipaserver_test.idmax }}" + dirsrv_config_file: "{{ ipaserver_dirsrv_config_file | default(omit) }}" +- _dirsrv_pkcs12_info: "{{ result_ipaserver_test._dirsrv_pkcs12_info }}" ++ _dirsrv_pkcs12_info: "{{ result_ipaserver_test._dirsrv_pkcs12_info if result_ipaserver_test._dirsrv_pkcs12_info != None else omit }}" + + - name: Install - Setup client + include_role: +-- +2.26.2 + diff --git a/SOURCES/ansible-freeipa-0.1.12-ipa-user,host-Fail-on-duplucate-names-in-the-users-and-hosts-lists_rhbz#1822683.patch b/SOURCES/ansible-freeipa-0.1.12-ipa-user,host-Fail-on-duplucate-names-in-the-users-and-hosts-lists_rhbz#1822683.patch new file mode 100644 index 0000000..1bf52b7 --- /dev/null +++ b/SOURCES/ansible-freeipa-0.1.12-ipa-user,host-Fail-on-duplucate-names-in-the-users-and-hosts-lists_rhbz#1822683.patch @@ -0,0 +1,132 @@ +From 1d7fb31b8bfa00babd7c753b354d7344b531cd77 Mon Sep 17 00:00:00 2001 +From: Thomas Woerner +Date: Mon, 29 Jun 2020 14:50:56 +0200 +Subject: [PATCH] ipa[user,host]: Fail on duplucate names in the users and + hosts lists + +It was possible to have several entries for names with the hosts and users +lists. This resulted sometimes in errors but also unexpected changes. A new +check has been added to make sure that the names in the users and hosts +lists are unique. + +New tests have been added to verify this in the existing files: +- tests/host/test_hosts.yml +- tests/user/test_users.yml +--- + plugins/modules/ipahost.py | 7 +++++++ + plugins/modules/ipauser.py | 7 +++++++ + tests/host/test_hosts.yml | 15 +++++++++++++++ + tests/user/test_users.yml | 19 +++++++++++++++++++ + 4 files changed, 48 insertions(+) + +diff --git a/plugins/modules/ipahost.py b/plugins/modules/ipahost.py +index 7a981f16..1fe11dc5 100644 +--- a/plugins/modules/ipahost.py ++++ b/plugins/modules/ipahost.py +@@ -799,10 +799,15 @@ def main(): + server_realm = api_get_realm() + + commands = [] ++ host_set = set() + + for host in names: + if isinstance(host, dict): + name = host.get("name") ++ if name in host_set: ++ ansible_module.fail_json( ++ msg="host '%s' is used more than once" % name) ++ host_set.add(name) + description = host.get("description") + locality = host.get("locality") + location = host.get("location") +@@ -1337,6 +1342,8 @@ def main(): + else: + ansible_module.fail_json(msg="Unkown state '%s'" % state) + ++ del host_set ++ + # Execute commands + + errors = [] +diff --git a/plugins/modules/ipauser.py b/plugins/modules/ipauser.py +index b8152ee4..03713a41 100644 +--- a/plugins/modules/ipauser.py ++++ b/plugins/modules/ipauser.py +@@ -958,10 +958,15 @@ def main(): + # commands + + commands = [] ++ user_set = set() + + for user in names: + if isinstance(user, dict): + name = user.get("name") ++ if name in user_set: ++ ansible_module.fail_json( ++ msg="user '%s' is used more than once" % name) ++ user_set.add(name) + # present + first = user.get("first") + last = user.get("last") +@@ -1370,6 +1375,8 @@ def main(): + else: + ansible_module.fail_json(msg="Unkown state '%s'" % state) + ++ del user_set ++ + # Execute commands + + errors = [] +diff --git a/tests/host/test_hosts.yml b/tests/host/test_hosts.yml +index 30fd6538..f82cc612 100644 +--- a/tests/host/test_hosts.yml ++++ b/tests/host/test_hosts.yml +@@ -96,3 +96,18 @@ + state: absent + register: result + failed_when: result.changed ++ ++ - name: Duplicate names in hosts failure test ++ ipahost: ++ ipaadmin_password: SomeADMINpassword ++ hosts: ++ - name: "{{ host1_fqdn }}" ++ force: yes ++ - name: "{{ host2_fqdn }}" ++ force: yes ++ - name: "{{ host3_fqdn }}" ++ force: yes ++ - name: "{{ host3_fqdn }}" ++ force: yes ++ register: result ++ failed_when: result.changed or "is used more than once" not in result.msg +diff --git a/tests/user/test_users.yml b/tests/user/test_users.yml +index 5b5d4538..81c7b608 100644 +--- a/tests/user/test_users.yml ++++ b/tests/user/test_users.yml +@@ -85,6 +85,25 @@ + register: result + failed_when: result.changed + ++ - name: Duplicate names in users failure test ++ ipauser: ++ ipaadmin_password: SomeADMINpassword ++ users: ++ - name: user1 ++ givenname: user1 ++ last: Last ++ - name: user2 ++ first: user2 ++ last: Last ++ - name: user3 ++ first: user3 ++ last: Last ++ - name: user3 ++ first: user3 ++ last: Last ++ register: result ++ failed_when: result.changed or "is used more than once" not in result.msg ++ + - name: Remove test users + ipauser: + ipaadmin_password: SomeADMINpassword diff --git a/SPECS/ansible-freeipa.spec b/SPECS/ansible-freeipa.spec index 9ef5da6..c7862d2 100644 --- a/SPECS/ansible-freeipa.spec +++ b/SPECS/ansible-freeipa.spec @@ -5,11 +5,18 @@ Summary: Roles and playbooks to deploy FreeIPA servers, replicas and clients Name: ansible-freeipa -Version: 0.1.10 -Release: 1%{?dist} +Version: 0.1.12 +Release: 4%{?dist} URL: https://github.com/freeipa/ansible-freeipa License: GPLv3+ Source: https://github.com/freeipa/ansible-freeipa/archive/v%{version}.tar.gz#/%{name}-%{version}.tar.gz +Patch1: ansible-freeipa-0.1.12-Fixes-service-disable-when-service-has-no-certificates-attached_rhbz#1836294.patch +Patch2: ansible-freeipa-0.1.12-Add-suppport-for-changing-password-of-symmetric-vaults_rhbz#1839197.patch +Patch3: ansible-freeipa-0.1.12-Fix-forwardzone-issues_rhbz#1843826,1843828,1843829,1843830,1843831.patch +Patch4: ansible-freeipa-0.1.12-ipa-host-group-Fix-membermanager-unknow-user-issue_rhbz#1848426.patch +Patch5: ansible-freeipa-0.1.12-ipa-user,host-Fail-on-duplucate-names-in-the-users-and-hosts-lists_rhbz#1822683.patch +Patch6: ansible-freeipa-0.1.12-action_plugins-ipaclient_get_otp-Discovered-python-n_rhbz#1852714.patch +Patch7: ansible-freeipa-0.1.12-ipa-server-replica-Fix-pkcs12-info-regressions-intro_rhbz#1853284.patch BuildArch: noarch #Requires: ansible @@ -30,6 +37,7 @@ Features - One-time-password (OTP) support for client installation - Repair mode for clients - Modules for dns forwarder management +- Modules for dns record management - Modules for dns zone management - Modules for group management - Modules for hbacrule management @@ -87,6 +95,13 @@ a separate step before starting the server installation. %prep %setup -q # Do not create backup files with patches +%patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%patch5 -p1 +%patch6 -p1 +%patch7 -p1 # Fix python modules and module utils: # - Remove shebang # - Remove execute flag @@ -121,6 +136,38 @@ cp -rp plugins/* %{buildroot}%{_datadir}/ansible/plugins/ %doc playbooks %changelog +* Thu Jul 02 2020 Thomas Woerner - 0.1.12-4 +- ipa[server,replica]: Fix pkcs12 info regressions introduced with CA-less + Resolves: RHBZ#1853284 + +* Wed Jul 01 2020 Thomas Woerner - 0.1.12-3 +- action_plugins/ipaclient_get_otp: Discovered python needed in task_vars + Resolves: RHBZ#1852714 + +* Mon Jun 29 2020 Thomas Woerner - 0.1.12-2 +- Fixes service disable when service has no certificates attached + Resolves: RHBZ#1836294 +- Add suppport for changing password of symmetric vaults + Resolves: RHBZ#1839197 +- Fix forwardzone issues + Resolves: RHBZ#1843826 + Resolves: RHBZ#1843828 + Resolves: RHBZ#1843829 + Resolves: RHBZ#1843830 + Resolves: RHBZ#1843831 +- ipa[host]group: Fix membermanager unknow user issue + Resolves: RHBZ#1848426 +- ipa[user,host]: Fail on duplucate names in the users and hosts lists + Resolves: RHBZ#1822683 + +* Mon Jun 15 2020 Thomas Woerner - 0.1.12-1 +- Update to version 0.1.12 bug fix only release + Related: RHBZ#1818768 + +* Thu Jun 11 2020 Thomas Woerner - 0.1.11-1 +- Update to version 0.1.11 + Related: RHBZ#1818768 + * Mon Apr 27 2020 Thomas Woerner - 0.1.10-1 - Update to version 0.1.10: - ipaclient: Not delete keytab when ipaclient_on_master is true