Compare commits

...

88 Commits

Author SHA1 Message Date
Thomas Woerner
ba3fe74b60 Merge pull request #487 from rjeffman/ipagroup_add_idoverrideuser
Add support for managing idoverrideusers in ipagroup.
2022-04-29 13:39:33 +02:00
Thomas Woerner
b9151f3069 Merge pull request #813 from rjeffman/idrange
New idrange management module
2022-04-29 13:35:32 +02:00
Thomas Woerner
6085fbf77d Merge pull request #820 from rjeffman/ipaautomountmap_mapname_required
ipaautomountmap: Fix parameter evaluation.
2022-04-29 13:16:37 +02:00
Rafael Guterres Jeffman
603bd61845 New idrange management module
There is a new idrange management module placed in the plugins folder:

    plugins/modules/ipaidrange.py

The idrange module allows to ensure presence and absence of idranges.

Here is the documentation of the module:

    README-idrange.md

New example playbooks have been added:

    playbooks/idrange/idrange-absent.yml
    playbooks/idrange/idrange-ad-posix-present.yml
    playbooks/idrange/idrange-ad-present.yml
    playbooks/idrange/idrange-present.yml

New tests for the module can be found at:

    tests/idrange/test_idrange.yml
    tests/idrange/test_idrange_client_context.yml
2022-04-28 11:54:41 -03:00
Rafael Guterres Jeffman
1a31f62a6f ipaautomountmap: Fix error messages for invalid 'name' sizes.
This patch fixes the error messages when an invalid number of 'mapname'
are provided for states 'present' or 'absent'.
2022-04-27 11:26:32 -03:00
Rafael Guterres Jeffman
23e07a9a17 ipaautomountmap: Force setting automountmapname in IPA API calls.
The usage of 'automountmapname' is required in all automount map IPA
API calls, and this change ensures that the value is always set as
an argument.
2022-04-27 11:25:39 -03:00
Thomas Woerner
bd084ad37b Merge pull request #810 from rjeffman/ipatrust_fix_range_type
ipatrust: fix range_type and test enhancement.
2022-04-27 15:36:16 +02:00
Rafael Guterres Jeffman
099eb96b58 Add support for managing idoverrideusers in ipagroup.
The group CLI option `idoverrideusers` was not supported by
ansible-freeipa, and this patch adds support to it.

Tests require an AD trust, and a user `aduser@ad.ipa.test` to exist, or
the user name must be provided (variable, CLI)  through `test_ad_user`.

A new test playbook was added:

    tests/group/test_group_idoverrideuser.yml
2022-04-27 07:41:47 -03:00
Thomas Woerner
1276e38895 Merge pull request #780 from rjeffman/module_utils_empty_strings_and_inexistent_attributes
module_utils: Fix comparison of elements not in IPA object.
2022-04-27 08:29:38 +02:00
Thomas Woerner
2fa9ed9127 Merge pull request #808 from rjeffman/ipatrust_type_choices
ipatrust: Set valid choices for trust_type.
2022-04-27 08:28:20 +02:00
Rafael Guterres Jeffman
766cf5a285 ipatrust: Fix support for range_type.
The ipatrust module was ignoring the value of `range_type`, which is
required to allow for different types of idranges.
2022-04-26 14:43:05 -03:00
Rafael Guterres Jeffman
3ea452ef6f tests/trust: Improved test coverage and execution.
This patch applies several changes to the ipatrust test playbook:

* Add externally defined parameters so execution in local trust
  environments can be configured. The available parameters are:
    * winserver_admin_password: the Administrator password for the AD
      server (default: 'SomeW1Npassword')
    * winserver_domain: the AD server domain (default: 'windows.local')
    * winserver realm: the AD server realm (by default, the uppercase
      version of winserver_domain)
    * ipaserver_domain: the FreeIPA server domain (default: 'ipa.test')
    * ipaserver_realm: the FreeIPA server realm (by default, the
      uppercase version of ipaserver_domain

* Modify trust verification to check for the existence of the trust as
  it the output of `ipa trust-find`, instead of cheking for the number
  of items returned, as the number might vary.

* Add idempotency tests by re-executing tasks and verifying that no
  change was performed.

* Added tests to verify creation of trusts with different 'range_type'.

* Use a Kerberos cache for shell scripts, and destroy it on exit.

* Properly remove all `idrange` that might be created upon setting up a
  trust.
2022-04-26 14:43:05 -03:00
Rafael Guterres Jeffman
50b16cb33f tests/ipatrust: Modify AD realm name to an invalid name.
As the task is expected to fail, the AD realm name was modified to show
the expected behavior more clearly.
2022-04-26 14:42:40 -03:00
Thomas Woerner
9b0558a953 Merge pull request #807 from rjeffman/zone_forwarder_consistency
DNS forward policy: ensure consistency between module parameters.
2022-04-26 17:17:26 +02:00
Rafael Guterres Jeffman
6124dc0cf1 ipatrust: Updated ipatrust documentation.
This patch updates the ipatrust documentation about the 'trust_type'
parameter, and changes one password to be similar to the standard
passwords used in other modules.
2022-04-26 11:12:55 -03:00
Rafael Guterres Jeffman
423a6b0e12 ipatrust: Set valid choices for trust_type.
Ensure only valid choices for trust_type ('ad')  are available for the
module parameter.
2022-04-26 11:12:55 -03:00
Rafael Guterres Jeffman
a83bab9425 ipaautomountmap: Allows clearing description attribute with "".
This change allows clearing automountmap 'description' attribute by
passing an empty string ("") as the playbook parameter.

New test cases were added to check this behavior.
2022-04-26 09:58:01 -03:00
Rafael Guterres Jeffman
70f4b7d646 ipauser: Refactor module due to fix on arguments comparison.
Due to a change in 'ansible_freeipa_module.compare_args_ipa', playbook
parameters using empty strings are correctly evaluated, and do not need
to be removed before comparison is performed.

A new test playbook, with tests for clearing attributes with an empty
string ("") is available at:

    tests/user/test_user_empty_lists.yml
2022-04-26 09:58:01 -03:00
Rafael Guterres Jeffman
f2865efb1a module_utils: Fix comparison of elements not in IPA object.
This change modifies the comparison of the retrieved IPA object and the
provided arguments on ansible_freeipa_module.compare_args_ipa when the
provider argument is an empty string.

If an attribute is not available in 'ipa', its value is considered to be
a list with an empty string (['']), possibly forcing the conversion of
the 'args' attribute to a list for comparison. This allows, for example,
the usage of empty strings which should compare as equals to inexistent
attributes (None), as is done in IPA API.
2022-04-26 09:58:01 -03:00
Thomas Woerner
ce143bad52 Merge pull request #805 from rjeffman/templates_add_password_example_playbooks
utils/new_module templates: Add missing password to example playbooks.
2022-04-26 12:39:18 +02:00
Thomas Woerner
928fdf4b2d Merge pull request #757 from rjeffman/templates_refactor
Update module templates to current practices.
2022-04-26 12:36:46 +02:00
Thomas Woerner
0d95b8ebcb Merge pull request #818 from rjeffman/ansible_lint_tasks
ansible-lint: Identify env_*.yml and tasks_*.yml as task files.
2022-04-26 12:28:43 +02:00
Rafael Guterres Jeffman
0efe2c30d2 ansible-lint: Identify env_*.yml and tasks_*.yml as task files.
Failing to identify task files included by playbooks raised false
positives when runnnig ansible lint. This change force ansible-lint to
correctly identify YAML files named "env_*.yml" or "tasks_*.yml" as task
files that are imported by other playbooks, and treat them accordingly.
2022-04-25 10:58:16 -03:00
Rafael Guterres Jeffman
10e9c30af6 DNS forward policy: ensure consistency between module parameters.
Modules ipadnsconfig and ipadnsforwardzone allow the setting of forward
policy for zone forwarders, but the parameter names differ between the
modules.

This patch ensures that the same parameter names can be used in each
module. To keep backwar compatibility in both modules, both
`forward_policy` and `forwardpolicy` are now supported.
2022-04-12 15:53:33 -03:00
Rafael Guterres Jeffman
f770b5d581 utils/new_module templates: Add missing password to example playbooks.
Add missing ipaadmin_password to example playbooks so new modules have
all necessary fields set on basic files.
2022-04-11 18:06:57 -03:00
Rafael Guterres Jeffman
9b020a56f3 Merge pull request #799 from vjs2174/master
Update README-group.md
2022-04-06 21:02:26 -03:00
vjs2174
09a0077b77 Update README-group.md
Fixed issue #790 changed line 103 to be more accurate.
2022-04-06 14:08:58 -04:00
Thomas Woerner
3779698e0a Merge pull request #793 from rjeffman/playbooks_minor_fixes
Ensure example playbooks have ipaadmin_password and it is the standard one.
2022-04-05 13:20:27 +02:00
Thomas Woerner
65adc7860e Merge pull request #791 from rjeffman/pylint_update_2_12_2
Update pylint to version 2.12.2
2022-04-05 13:19:28 +02:00
Rafael Guterres Jeffman
df87ff464a example playbooks: ipaadmin_password is used and consistent.
Some example playbooks do not had the parameter `ipaadmin_password`
set, and some had a different value than the standard value
"SomeADMINpassword".

This patch fixes this difference in all example playbooks.
2022-03-30 08:45:05 -03:00
Rafael Guterres Jeffman
4b8358b897 Removed vim swap file from the repository. 2022-03-30 08:44:58 -03:00
Rafael Guterres Jeffman
68661d6922 pylint: Bump version to 2.12.2.
Update pylint version to the latest supported by Fedora 36.
2022-03-22 12:03:20 -03:00
Rafael Guterres Jeffman
461bd8b15b pylint: Ignore global-variable-not-assigned 2022-03-22 12:03:20 -03:00
Rafael Guterres Jeffman
ef0e368741 pylint: Ignore consider-using-f-string.
Newer versions of pylint warns about not using f-strings, but those are
not supported in Python 2, which ansible-freeipa still need to support.
2022-03-22 11:25:13 -03:00
Varun Mylaraiah
f0a71eda84 Merge pull request #779 from t-woerner/module_params_get_fail_empty_str_in_list
module_params_get*: Fail on empty string in string list parameters
2022-03-03 18:36:53 +05:30
Rafael Guterres Jeffman
d0402d7905 Merge pull request #783 from t-woerner/automember_remove_debug_warn
automember: Remove debug output
2022-02-28 12:49:22 -03:00
Thomas Woerner
eebfdbca7a automember: Remove debug output
The warn debug line was added with "Add automember default group
handling" d2648b142a
2022-02-28 13:16:22 +01:00
Thomas Woerner
e30bcfd876 ipaconfig: Set allow_empty_string for user_auth_type, pac_type, configstring
The parameters user_auth_type, pac_type and configstring are allowing to
use "" to reset to the default value or for configstring to set an empty
list.

The new check in params_get is not allowing to use empty strings in lists,
therefore allow_empty_string=True had to be added to the call.

A test has been added to verify that the empty strings are supported and
working.

Additionally empty pac_type, user_auth_type and domain_resolution_order
have been added to exit_args as if they have not been set.
2022-02-28 13:12:41 +01:00
Thomas Woerner
abf0cc3251 ipahost: Set allow_empty_string for auth_ind
The parameter auth_ind is allowing to use "" to reset to the default
value.

The new check in params_get is not allowing to use empty strings in lists,
therefore allow_empty_string=True had to be added to the call.

A test has been added to verify that the empty strings are supported and
working.
2022-02-25 18:42:25 +01:00
Thomas Woerner
9decad4e4f ipaservice: Set allow_empty_string for auth_ind and pac_type
The parameters auth_ind and pac_type are allowing to use "" to reset to
the default value.

The new check in params_get is not allowing to use empty strings in lists,
therefore allow_empty_string=True had to be added to the call.

A test has been added to verify that the empty strings are supported and
working. An idempotency issue with pac_type has been found with the test
and fixed additionally.
2022-02-25 18:42:07 +01:00
Thomas Woerner
03098c218d ipauser: Set allow_empty_string for userauthtype and sshpubkey
The parameters userauthtype and sshpubkey allowing to use "" to reset to
the default value.

The new check in params_get is not allowing to use empty strings in lists,
therefore allow_empty_string=True had to be added to the call.

A test has been added to verify that the empty strings are supported and
working. An idempotency issue with sshpubkey has been found with the test
and fixed additionally.
2022-02-24 12:37:55 +01:00
Thomas Woerner
d05ad6b1f2 module_params_get*: Fail on empty string in string list parameters
So far it is possible to pass list parameters with empty strings to the
modules. The use of empty strings in list does not make a lot of sense,
though. The simple solution is to add a check to module_params_get for
empty strings in returned lists.

The option allow_empty_string can be set to True to allow an empty string
in the list with a list len of 1. The option defaults to False. It is
needed for some parameters the modules, like for example userauthtype in
the user module. It is using "" to reset to the default value.

module_params_get_lowercase has been changed to use module_params_get to
have one place to add the check.

Due to an issue in Ansible it is possible to use the empty string "" for
lists with choices, even if the empty list is not part of the choices.
Ansible issue https://github.com/ansible/ansible/issues/77108
2022-02-24 12:37:42 +01:00
Thomas Woerner
9981e5f84b Merge pull request #752 from rjeffman/hbacrule_allow_clearing_members
hbacrule: Allow clearing members with empty lists.
2022-02-21 15:01:29 +01:00
Rafael Guterres Jeffman
4df2cab42a module templates: Add delete_commit code template.
This patch add the lines necessary to allow the use of the attribute
`delete_continue`, as it is a commom attribute, and if newer commom
attributes are added to IPAAnsibleModule in the future, the usage will
be similar.
2022-02-17 15:22:18 -03:00
Rafael Guterres Jeffman
5d6324e2da module templates: Add example and note for case insensitive members.
Some modules should be compared in a case insensitive manner, and this
patch adds an example of a call to IPAAnsibleModule.params_get_lowercase
and a note on its usage.
2022-02-17 14:31:48 -03:00
Rafael Guterres Jeffman
8772379dcc module templates: Refactor member management.
This patch refactors the module template for modules with member
management, in a way that the addition of member management command
logic is not duplicated in different states or actions.

This idiom has been applied recently along with other fixes to modules
with idempotence issues reducing the modules code size and centering
code logic in specific blocks.
2022-02-17 14:31:48 -03:00
Thomas Woerner
29badaecca Merge pull request #761 from rjeffman/delete_continue_module_utils
IPAAnsibleModule: Provide base configuration for delete_continue.
2022-02-17 16:01:12 +01:00
Rafael Guterres Jeffman
e88aaaf95a IPAAnsibleModule: Provide base configuration for delete_continue.
Allows the creation of IPAAnsibleModule objects with specific
`ipa_arguments` which are defined in a dictionary of argumets in
the base class.

Every module using `delete_continue` should provide the proper behavior
and the module must be instantiated with:

  ansible_module = IPAAnsibleModule(
      ...,
      ipa_arguments=["delete_continue"]
  )

The plugin documentation must be extended with
'ipamodule_arguments.delete_continue'.
2022-02-17 08:20:57 -03:00
Thomas Woerner
b54333358d Merge pull request #777 from rjeffman/ci_fix_c8s_usage
upstream ci: Fix scenario for Centos 8 Stream with Ansible 2.11.
2022-02-16 22:13:09 +01:00
Thomas Woerner
c16ceac892 Merge pull request #770 from rjeffman/ci_rename_c9s_pipelines
upstream ci: Rename CentOS 9 pipelines jobs to c9s.
2022-02-16 20:39:31 +01:00
Rafael Guterres Jeffman
d303a81e4c upstream ci: Fix scenario for Centos 8 Stream with Ansible 2.11.
Changed scenario from old CentOS 8 (centos-8) to current Centos 8
Stream (c8s).
2022-02-16 14:50:48 -03:00
Rafael Guterres Jeffman
d561d8f372 upstream ci: Rename CentOS 9 pipelines jobs to c9s.
The correct name for upcoming release of CentOS is CentOS 9 Stream,
usually abbreviated to 'c9s'. As we need to differentiate from the
stream and the standard versions, this patch modifies the Azure
piipelines to use 'c9s' instead of 'CentOS 9'.
2022-02-16 14:48:58 -03:00
Thomas Woerner
33c571ebb6 Merge pull request #776 from rjeffman/ci_fix_ansible_lint_dnsrecord
ansible-lint: Remove warning on 'ignore_errors'.
2022-02-16 16:10:01 +01:00
Thomas Woerner
81d1896f0f Merge pull request #775 from rjeffman/ci_build_container_python_version
upstream CI: Fix container builds in face of Ansible and CentOS changes.
2022-02-16 16:08:36 +01:00
Thomas Woerner
75f5082ad0 Merge pull request #732 from rjeffman/ci_enable_c8s
upstream CI: Enable CentOS 8 Stream for PR and nightly tests.
2022-02-16 12:05:22 +01:00
Thomas Woerner
a05eed6a4b Merge pull request #758 from rjeffman/ci_centos9_ansible_2_12
upstream ci: enable ansible-core 2.12 for CentOS 9 Stream.
2022-02-16 09:52:46 +01:00
Rafael Guterres Jeffman
cddb861fd9 ansible-lint: Remove warning on 'ignore_errors'.
The test for dnsrecord creates a DNSSEC zone, and was forcing the task
to ignore errors using `ignore_errors: true`. The test environment
should be clean at that point, and without the zone, tests would fail,
so there is no need to keep the attribute set. If the task fails, it
should be fixed.
2022-02-15 17:04:09 -03:00
Rafael Guterres Jeffman
15d3123ed3 Merge pull request #774 from t-woerner/no_molecule_prerun
molecule: Disable prerun for normal tests
2022-02-15 14:56:22 -03:00
Rafael Guterres Jeffman
7a1bf986a8 upstream CI: Use fedora-latest as default test container.
With the removal of CentOS 8 container, the available Fedora latest
image will be used for tests, if a specific container is not given.
2022-02-15 13:24:34 -03:00
Rafael Guterres Jeffman
c89f6624b5 upstream CI: Update Python version when building containers.
Newer Ansible versions will require at least Python 3.8 to be used,
and the build containers pipeline was requiring Python 3.6, which is
EOL.

This patch requests the latest Python version available for the
controller, and allows it to be configured to a specific version if,
and when, needed.
2022-02-15 13:19:39 -03:00
Rafael Guterres Jeffman
998a141482 upstream CI: Enable CentOS 8 Stream for PR and nightly tests.
Add configuration to build a testing CentOS 8 stream image and to
execute upstream tests using that image in pull requests (Ansible
2.9) and on the nightly tests (all supported Ansible versions).
2022-02-15 13:19:39 -03:00
Rafael Guterres Jeffman
d111f0d92b ci images: Fix creation of CentOS 9 stream test container.
CentOS 9 Stream package pytho3-devel was not installable, and as it is
not required for the testing container, it was removed from the
Dockerfile used to create the image.
2022-02-15 12:16:09 -03:00
Rafael Guterres Jeffman
5ab9ae21ad molecule: Disable prerun for build containers.
This disables the generation of the collection using the default
galaxy.yml. The installation of the generated collection fails with
invalid version A.B.C.

The collection is not used when building containers and the generated
collection is not using proper name and namespace in the collection files.
2022-02-15 10:11:00 -03:00
Rafael Guterres Jeffman
3c130795e3 build containers: Allow setting of Python version used.
Currently the pipeline used to create test containers is using Python
3.6.15, and Ansible 2.12 requires, at least, Python 3.8.

This change adds a new parameter to build container template,
`python_version`, which is set by default to '3.x', meaning it will use
the latest Python version available (for version 3) if the parameter is
not explicitly set.
2022-02-15 09:12:26 -03:00
Thomas Woerner
954c911a85 molecule: Disable prerun for normal tests
This disables the generation of the collection using the default
galaxy.yml. The installation of the generated collection fails with
invalid version A.B.C.

The collection is not used in the tests and the generated collection
is not using proper name and namespace in the collection files.

Note: utils/build-galaxy-releasesh needs to be used to generate the correct
collection.
2022-02-15 12:46:29 +01:00
Rafael Guterres Jeffman
e681f25e5c Merge pull request #773 from t-woerner/servicedelegation_do_no_fail_on_not_existing_members_with_state_absent
servicedelegation: Do not fail for not existing members with state absent
2022-02-14 18:10:46 -03:00
Thomas Woerner
8010d19be9 servicedelegation: Do not fail for not existing members with state absent
Ensuring absence of members (services and targets) that do not exist may
not fail as they are not members for servicedelegationtarget and
servicedelegationrule.

servicedelegation_normalize_principals in ansible_freeipa_module has
been extended with a check_exists argument that defaults to False. state
== "present" is now given as this argument to turn on the element exists
check only if elements should be added.
2022-02-14 18:16:29 +01:00
Rafael Guterres Jeffman
892cb037eb Merge pull request #771 from t-woerner/build-galaxy-release_fix_refs_for_all_doc_fragments
build-galaxy-release: Fix refs for all doc_fragments in plugins/doc_fragments
2022-02-14 11:50:58 -03:00
Rafael Guterres Jeffman
40d4150590 Merge pull request #772 from t-woerner/fix_new_ansible-lint_findings
Fix new ansible-lint findings
2022-02-14 11:50:25 -03:00
Thomas Woerner
bc72bbd92e tests/vault/test_vault_change_type.yml: Use lower case var names
The upper case name has been reported as issues by new ansible-lint.
2022-02-14 13:42:56 +01:00
Thomas Woerner
ae9c81139b tests/role/test_role_lists_handling.yml: Use lower case var names
The upper case name has been reported as issues by new ansible-lint.
2022-02-14 13:39:36 +01:00
Thomas Woerner
d5fdaaf444 tests/env_freeipa_facts.yml: Use lower case var names
The upper case name has been reported as issues by new ansible-lint.
2022-02-14 13:37:54 +01:00
Thomas Woerner
fdd4b19b18 tests/config/test_config.yml: Use named tasks
The unnamed tasks have been reported as issues by new ansible-lint.
2022-02-14 12:57:32 +01:00
Thomas Woerner
dc62744f6a ipaclient install.yml: Use named tasks
The unnamed tasks have been reported as issues by new ansible-lint.
2022-02-14 12:56:08 +01:00
Thomas Woerner
2af7602a8c build-galaxy-release: Fix refs for all doc_fragments in plugins/doc_fragments
The script now fixes the references for all doc_fragments in the
plugins/doc_fragments folder. So far it was only fixing the references
for ipamodule_base_docs.

PR #762 (automount location: add support for delete_continue) added an
other doc_fragment and the references have not been fixes as needed.
2022-02-14 10:51:20 +01:00
Rafael Guterres Jeffman
1b74cf1692 Merge pull request #769 from t-woerner/servicedelegationtarget_list_tests
test_servicedelegationtarget.yml: Added list tests
2022-02-11 08:24:47 -03:00
Rafael Guterres Jeffman
19fc21cd1b hbacrule: Allow clearing members with empty lists.
If a hbacrule member has any value, the only way to clear it is by
creating a task with 'state: absent' and 'action: member' and provide
a list with all the values for that member.

This patch allows the use of '<member>: []' with 'action: hbacrule'
to clear a hbacrule member.

A new test playbook can be found at:

    tests/hbacrule/test_hbacrule_member_empty.yml
2022-02-10 19:08:59 -03:00
Thomas Woerner
804e633f13 test_servicedelegationtarget.yml: Added list tests
List tests, also an empty list test has been added.
2022-02-10 14:00:10 +01:00
Thomas Woerner
ad37bed37b Merge pull request #755 from austlane/master
Fixes `no_log` warning for `ipahost` module
2022-02-09 11:04:23 +01:00
Rafael Guterres Jeffman
b00dc5daa5 Merge pull request #766 from t-woerner/servicedelegationrule
New servicedelegationrule management module
2022-02-08 15:55:43 -03:00
Thomas Woerner
2c278ab39d New servicedelegationrule management module
There is a new servicedelegationrule management module placed in the plugins
folder:

    plugins/modules/ipaservicedelegationrule.py

The servicedelegationrule module allows to ensure presence and absence of
servicedelegationrules and servicedelegationrule members.

Here is the documentation of the module:

    README-servicedelegationrule.md

New example playbooks have been added:

    playbooks/servicedelegationrule/servicedelegationrule-absent.yml
    playbooks/servicedelegationrule/servicedelegationrule-principal-member-absent.yml
    playbooks/servicedelegationrule/servicedelegationrule-principal-member-present.yml
    playbooks/servicedelegationrule/servicedelegationrule-target-member-absent.yml
    playbooks/servicedelegationrule/servicedelegationrule-target-member-present.yml
    playbooks/servicedelegationrule/servicedelegationrule-present.yml

New tests for the module:

    tests/servicedelegationrule/test_servicedelegationrule.yml
    tests/servicedelegationrule/test_servicedelegationrule_client_context.yml
    tests/servicedelegationrule/test_servicedelegationrule_hostprincipal.yml
2022-02-08 14:19:16 +01:00
Rafael Guterres Jeffman
ef2adf54b4 Merge pull request #756 from t-woerner/servicedelegationtarget
New servicedelegationtarget management module
2022-02-07 11:09:10 -03:00
Thomas Woerner
a61c046abe New servicedelegationtarget management module
There is a new servicedelegationtarget management module placed in the plugins
folder:

    plugins/modules/ipaservicedelegationtarget.py

The servicedelegationtarget module allows to ensure presence and absence of
servicedelegationtargets and servicedelegationtarget members.

Here is the documentation of the module:

    README-servicedelegationtarget.md

New example playbooks have been added:

    playbooks/servicedelegationtarget/servicedelegationtarget-absent.yml
    playbooks/servicedelegationtarget/servicedelegationtarget-member-absent.yml
    playbooks/servicedelegationtarget/servicedelegationtarget-member-present.yml
    playbooks/servicedelegationtarget/servicedelegationtarget-present.yml

New tests for the module:

    tests/servicedelegationtarget/test_servicedelegationtarget.yml
    tests/servicedelegationtarget/test_servicedelegationtarget_client_context.yml
    tests/servicedelegationtarget/test_servicedelegationtarget_hostprincipal.yml
2022-02-07 13:00:38 +01:00
Rafael Guterres Jeffman
1fee891aa4 upstream ci: enable ansible-core 2.12 for CentOS 9 Stream.
Enables ansible-core 2.12 for CentOS 9 stream on nightly tests.
2022-02-03 16:05:19 -03:00
Thomas Woerner
1aca0c1304 ansible_freeipa_module: New function servicedelegation_normalize_principals
This function will be used in servicedelegation target and rule modules
to normalize principals given in the tasks. These can be service and host
principals and also aliases.

Note: The use of host principals requires IPA 4.9.0 or later. fail_json
is called if the version is lower.

servicedelegation_normalize_principals contains two embedded fuctions.
One is normalize_principal_name that has been copied from
ipaserver/plugins/servicedelegation.py, the other is the generic
function _check_exists to be able to check if a host or service exists.
2022-02-03 15:40:37 +01:00
Austin
60fd87c567 Fixes no_log warning for ipahost module
Similar to PR 286
This PR explicitly sets `no_log` option for `update_password` attribute to `False`, so that the warning on `no_log` not being set is not issued anymore. Ansible incorrectly issued the warning, as `update_password` does not carry sensitive information.
2022-01-31 13:09:31 -05:00
Rafael Guterres Jeffman
4aab1599bd Merge pull request #753 from t-woerner/group_test_fix_services
group test: Enable ansible_facts, fix service hostname
2022-01-27 10:05:04 -03:00
Thomas Woerner
0c36194038 group test: Enable ansible_facts, fix service hostname
The service hostname needs to be gathered from ansibe_facts as it might
not be "ipaserver". ansible_facts['fqdn'] is now used as the service
hostname, therefore gather_facts had to be turned on.
2022-01-27 11:35:52 +01:00
116 changed files with 4728 additions and 377 deletions

View File

@@ -14,6 +14,8 @@ exclude_paths:
kinds:
- playbook: '**/tests/**/test_*.yml'
- playbook: '**/playbooks/**/*.yml'
- tasks: '**/tasks_*.yml'
- tasks: '**/env_*.yml'
parseable: true

View File

@@ -68,7 +68,7 @@ jobs:
python-version: "3.x"
- name: Run pylint
run: |
pip install pylint==2.10.2
pip install pylint==2.12.2
pylint plugins roles --disable=import-error
shellcheck:

View File

@@ -24,7 +24,7 @@ repos:
hooks:
- id: pydocstyle
- repo: https://github.com/pycqa/pylint
rev: v2.10.2
rev: v2.12.2
hooks:
- id: pylint
args:

View File

@@ -129,7 +129,7 @@ Variable | Description | Required
`forwarders` | The list of forwarders dicts. Each `forwarders` dict entry has:| no
&nbsp; | `ip_address` - The IPv4 or IPv6 address of the DNS server. | yes
&nbsp; | `port` - The custom port that should be used on this server. | no
`forward_policy` | The global forwarding policy. It can be one of `only`, `first`, or `none`. | no
`forward_policy` \| `forwardpolicy` | The global forwarding policy. It can be one of `only`, `first`, or `none`. | no
`allow_sync_ptr` | Allow synchronization of forward (A, AAAA) and reverse (PTR) records (bool). | yes
`action` | Work on dnsconfig or member level. It can be one of `member` or `dnsconfig` and defaults to `dnsconfig`. Only `forwarders` can be managed with `action: member`. | no
`state` | The state to ensure. It can be one of `present` or `absent`, default: `present`. `absent` can only be used with `action: member` and `forwarders`. | yes

View File

@@ -110,7 +110,7 @@ Variable | Description | Required
`forwarders` \| `idnsforwarders` | Per-zone forwarders. A custom port can be specified for each forwarder. Options | no
&nbsp; | `ip_address`: The forwarder IP address. | yes
&nbsp; | `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
`forwardpolicy` \| `idnsforwardpolicy` \| `forward_policy` | 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

View File

@@ -100,7 +100,7 @@ Example playbook to add group members to a group:
become: true
tasks:
# Add group members sysops and appops to group sysops
# Add group members sysops and appops to group ops
- ipagroup:
ipaadmin_password: SomeADMINpassword
name: ops
@@ -166,6 +166,7 @@ Variable | Description | Required
`membermanager_user` | List of member manager users assigned to this group. Only usable with IPA versions 4.8.4 and up. | no
`membermanager_group` | List of member manager groups assigned to this group. Only usable with IPA versions 4.8.4 and up. | no
`externalmember` \| `ipaexternalmember` \| `external_member`| List of members of a trusted domain in DOM\\name or name@domain form. | no
`idoverrideuser` | List of user ID overrides to manage. Only usable with IPA versions 4.8.7 and up.| no
`action` | Work on group or member level. It can be on of `member` or `group` and defaults to `group`. | no
`state` | The state to ensure. It can be one of `present` or `absent`, default: `present`. | yes

196
README-idrange.md Normal file
View File

@@ -0,0 +1,196 @@
Idrange module
============
Description
-----------
The idrange module allows the management of ID ranges.
In general it is not necessary to modify or delete ID ranges. If there is no other way to achieve a certain configuration than to modify or delete an ID range it should be done with great care. Because UIDs are stored in the file system and are used for access control it might be possible that users are allowed to access files of other users if an ID range got deleted and reused for a different domain.
Use cases
---------
* Add an ID range from a transitively trusted domain
If the trusted domain (A) trusts another domain (B) as well and this trust is transitive 'ipa trust-add domain-A' will only create a range for domain A. The ID range for domain B must be added manually.
* Add an additional ID range for the local domain
If the ID range of the local domain is exhausted, i.e. no new IDs can be assigned to Posix users or groups by the DNA plugin, a new range has to be created to allow new users and groups to be added. (Currently there is no connection between this range CLI and the DNA plugin, but a future version might be able to modify the configuration of the DNS plugin as well).
Features
--------
* ID Range management
Supported FreeIPA Versions
--------------------------
FreeIPA versions 4.4.0 and up are supported by the ipaidrange module.
Requirements
------------
**Controller**
* Ansible version: 2.8+
**Node**
* Supported FreeIPA version (see above)
Usage
=====
Example inventory file
```ini
[ipaserver]
ipaserver.test.local
```
Example playbook to ensure a local domain idrange is present:
```yaml
---
- name: Playbook to manage IPA idrange.
hosts: ipaserver
become: no
tasks:
- name: Ensure an ID Range for the local domain is present.
ipaidrange:
ipaadmin_password: SomeADMINpassword
name: local_domain_id_range
base_id: 150000
range_size: 200000
```
Example playbook to ensure a local domain idrange is present, with RID and secondary RID base values:
```yaml
---
- name: Playbook to manage IPA idrange.
hosts: ipaserver
become: no
tasks:
- name: Ensure local idrange is present
ipaidrange:
ipaadmin_password: SomeADMINpassword
name: local_domain_id_range
base_id: 150000000
range_size: 200000
rid_base: 1000000
secondary_rid_base: 200000000
```
Example playbook to ensure an AD-trust idrange is present, with range type 'trust-ad' and using domain SID:
```yaml
---
- name: Playbook to manage IPA idrange.
hosts: ipaserver
become: no
tasks:
- name: Ensure AD-trust idrange is present
ipaidrange:
ipaadmin_password: SomeADMINpassword
name: ad_id_range
base_id: 150000000
range_size: 200000
idrange_type: ipa-ad-trust
dom_sid: S-1-5-21-2870384104-3340008087-3140804251
```
Example playbook to ensure an AD-trust idrange is present, with range type 'trust-ad-posix' and using domain SID:
```yaml
---
- name: Playbook to manage IPA idrange.
hosts: ipaserver
become: no
tasks:
- name: Ensure AD-trust idrange is present
ipaidrange:
name: ad_posix_id_range
base_id: 150000000
range_size: 200000
idrange_type: ipa-ad-trust-posix
dom_name: ad.ipa.test
```
Example playbook to ensure an AD-trust idrange has auto creation of groups set to 'hybrid':
```yaml
---
- name: Playbook to manage IPA idrange.
hosts: ipaserver
become: no
tasks:
- name: Modify AD-trust idrange 'auto_private_groups'
ipaidrange:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: ad_id_range
auto_private_groups: "hybrid"
```
Example playbook to make sure an idrange is absent:
```yaml
---
- name: Playbook to manage IPA idrange.
hosts: ipaserver
become: no
tasks:
- name: Ensure ID range 'ad_id_range' is absent.
ipaidrange:
ipaadmin_password: SomeADMINpassword
name: ad_id_range
state: absent
```
Variables
---------
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
`ipaapi_context` | The context in which the module will execute. Executing in a server context is preferred. If not provided context will be determined by the execution environment. Valid values are `server` and `client`. | no
`ipaapi_ldap_cache` | Use LDAP cache for IPA connection. The bool setting defaults to yes. (bool) | no
`name` \| `cn` | The list of idrange name strings. | yes
`base_id` \| `ipabaseid` | First Posix ID of the range. (int) | yes, if `state: present`
`range_size` \| `ipaidrangesize` | Number of IDs in the range. (int) | yes, if `state: present`
`rid_base` \| `ipabaserid` | First RID of the corresponding RID range. (int) | no
`secondary_rid_base` \| `ipasecondarybaserid` | First RID of the secondary RID range. (int) | no
`dom_sid` \| `ipanttrusteddomainsid` | Domain SID of the trusted domain. | no
`dom_name` \| `ipanttrusteddomainname` | Name of the trusted domain. | no
`idrange_type` \| `iparangetype` | ID range type, one of `ipa-ad-trust`, `ipa-ad-trust-posix`, `ipa-local`. Only valid if idrange does not exist. | no
`auto_private_groups` \| `ipaautoprivategroups` | Auto creation of private groups, one of `true`, `false`, `hybrid`. | no
`delete_continue` \| `continue` | Continuous mode: don't stop on errors. Valid only if `state` is `absent`. Default: `no` (bool) | no
`state` | The state to ensure. It can be one of `present`, `absent`, default: `present`. | no
Notes
=====
DNA plugin in 389-ds will allocate IDs based on the ranges configured for the local domain. Currently the DNA plugin *cannot* be reconfigured itself based on the local ranges set via this family of commands.
Manual configuration change has to be done in the DNA plugin configuration for the new local range. Specifically, The dnaNextRange attribute of 'cn=Posix IDs,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config' has to be modified to match the new range.
Authors
=======
Rafael Guterres Jeffman

View File

@@ -293,8 +293,8 @@ Variable | Description | Required
`ipaapi_ldap_cache` | Use LDAP cache for IPA connection. The bool setting defaults to yes. (bool) | no
`name` \| `service` | The list of service name strings. | yes
`certificate` \| `usercertificate` | Base-64 encoded service certificate. | no
`pac_type` \| `ipakrbauthzdata` | Supported PAC type. It can be one of `MS-PAC`, `PAD`, or `NONE`. | no
`auth_ind` \| `krbprincipalauthind` | Defines an allow list for Authentication Indicators. It can be any of `otp`, `radius`, `pkinit`, or `hardened`. | no
`pac_type` \| `ipakrbauthzdata` | Supported PAC type. It can be one of `MS-PAC`, `PAD`, or `NONE`. Use empty string to reset pac_type to the initial value. | no
`auth_ind` \| `krbprincipalauthind` | Defines an allow list for Authentication Indicators. It can be any of `otp`, `radius`, `pkinit` or `hardened`. Use empty string to reset auth_ind to the initial value. | no
`requires_pre_auth` \| `ipakrbrequirespreauth` | Pre-authentication is required for the service. Default to true. (bool) | no
`ok_as_delegate` \| `ipakrbokasdelegate` | Client credentials may be delegated to the service. Default to false. (bool) | no
`ok_to_auth_as_delegate` \| `ipakrboktoauthasdelegate` | The service is allowed to authenticate on behalf of a client. Default to false. (bool) | no

View File

@@ -0,0 +1,172 @@
Servicedelegationrule module
============
Description
-----------
The servicedelegationrule module allows to ensure presence and absence of servicedelegationrules and servicedelegationrule members.
Features
--------
* Servicedelegationrule management
Supported FreeIPA Versions
--------------------------
FreeIPA versions 4.4.0 and up are supported by the ipaservicedelegationrule module.
Host princpals are only usable with IPA versions 4.9.0 and up.
Requirements
------------
**Controller**
* Ansible version: 2.8+
**Node**
* Supported FreeIPA version (see above)
Usage
=====
Example inventory file
```ini
[ipaserver]
ipaserver.test.local
```
Example playbook to make sure servicedelegationrule delegation-rule is present:
```yaml
---
- name: Playbook to manage IPA servicedelegationrule
hosts: ipaserver
become: no
tasks:
- name: Ensure servicedelegationrule delegation-rule is present
ipaservicedelegationrule:
ipaadmin_password: SomeADMINpassword
name: delegation-rule
```
Example playbook to make sure servicedelegationrule delegation-rule member principal test/example.com is present:
```yaml
---
- name: Playbook to manage IPA servicedelegationrule
hosts: ipaserver
become: no
tasks:
- name: Ensure servicedelegationrule delegation-rule member principal test/example.com is present
ipaservicedelegationrule:
ipaadmin_password: SomeADMINpassword
name: delegation-rule
principal: test/example.com
action: member
```
Example playbook to make sure servicedelegationrule delegation-rule member principal test/example.com is absent:
```yaml
---
- name: Playbook to manage IPA servicedelegationrule
hosts: ipaserver
become: no
tasks:
- name: Ensure servicedelegationrule delegation-rule member principal test/example.com is absent
ipaservicedelegationrule:
ipaadmin_password: SomeADMINpassword
name: delegation-rule
principal: test/example.com
action: member
state: absent
state: absent
```
Example playbook to make sure servicedelegationrule delegation-rule member target delegation-target is present:
```yaml
---
- name: Playbook to manage IPA servicedelegationrule
hosts: ipaserver
become: no
tasks:
- name: Ensure servicedelegationrule delegation-rule member target delegation-target is present
ipaservicedelegationrule:
ipaadmin_password: SomeADMINpassword
name: delegation-rule
target: delegation-target
action: member
```
Example playbook to make sure servicedelegationrule delegation-rule member target delegation-target is absent:
```yaml
---
- name: Playbook to manage IPA servicedelegationrule
hosts: ipaserver
become: no
tasks:
- name: Ensure servicedelegationrule delegation-rule member target delegation-target is absent
ipaservicedelegationrule:
ipaadmin_password: SomeADMINpassword
name: delegation-rule
target: delegation-target
action: member
state: absent
state: absent
```
Example playbook to make sure servicedelegationrule delegation-rule is absent:
```yaml
---
- name: Playbook to manage IPA servicedelegationrule
hosts: ipaserver
become: no
tasks:
- name: Ensure servicedelegationrule delegation-rule is absent
ipaservicedelegationrule:
ipaadmin_password: SomeADMINpassword
name: delegation-rule
state: absent
```
Variables
---------
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
`ipaapi_context` | The context in which the module will execute. Executing in a server context is preferred. If not provided context will be determined by the execution environment. Valid values are `server` and `client`. | no
`ipaapi_ldap_cache` | Use LDAP cache for IPA connection. The bool setting defaults to yes. (bool) | no
`name` \| `cn` | The list of servicedelegationrule name strings. | yes
`principal` | The list of principals. A principal can be of the format: fqdn, fqdn@REALM, service/fqdn, service/fqdn@REALM, host/fqdn, host/fqdn@REALM, alias$, alias$@REALM, where fqdn and fqdn@REALM are host principals and the same as host/fqdn and host/fqdn@REALM. Host princpals are only usable with IPA versions 4.9.0 and up. | no
`target` \| `servicedelegationtarget` | The list of service delegation targets. | no
`action` | Work on servicedelegationrule or member level. It can be on of `member` or `servicedelegationrule` and defaults to `servicedelegationrule`. | no
`state` | The state to ensure. It can be one of `present`, `absent`, default: `present`. | no
Authors
=======
Thomas Woerner

View File

@@ -0,0 +1,133 @@
Servicedelegationtarget module
============
Description
-----------
The servicedelegationtarget module allows to ensure presence and absence of servicedelegationtargets and servicedelegationtarget members.
Features
--------
* Servicedelegationtarget management
Supported FreeIPA Versions
--------------------------
FreeIPA versions 4.4.0 and up are supported by the ipaservicedelegationtarget module.
Host princpals are only usable with IPA versions 4.9.0 and up.
Requirements
------------
**Controller**
* Ansible version: 2.8+
**Node**
* Supported FreeIPA version (see above)
Usage
=====
Example inventory file
```ini
[ipaserver]
ipaserver.test.local
```
Example playbook to make sure servicedelegationtarget delegation-target is present:
```yaml
---
- name: Playbook to manage IPA servicedelegationtarget
hosts: ipaserver
become: no
tasks:
- name: Ensure servicedelegationtarget delegation-target is present
ipaservicedelegationtarget:
ipaadmin_password: SomeADMINpassword
name: delegation-target
```
Example playbook to make sure servicedelegationtarget delegation-target member principal test/example.com is present:
```yaml
---
- name: Playbook to manage IPA servicedelegationtarget
hosts: ipaserver
become: no
tasks:
- name: Ensure servicedelegationtarget delegation-target member principal test/example.com is present
ipaservicedelegationtarget:
ipaadmin_password: SomeADMINpassword
name: delegation-target
principal: test/example.com
action: member
```
Example playbook to make sure servicedelegationtarget delegation-target member principal test/example.com is absent:
```yaml
---
- name: Playbook to manage IPA servicedelegationtarget
hosts: ipaserver
become: no
tasks:
- name: Ensure servicedelegationtarget delegation-target member principal test/example.com is absent
ipaservicedelegationtarget:
ipaadmin_password: SomeADMINpassword
name: delegation-target
principal: test/example.com
action: member
state: absent
state: absent
```
Example playbook to make sure servicedelegationtarget delegation-target is absent:
```yaml
---
- name: Playbook to manage IPA servicedelegationtarget
hosts: ipaserver
become: no
tasks:
- name: Ensure servicedelegationtarget delegation-target is absent
ipaservicedelegationtarget:
ipaadmin_password: SomeADMINpassword
name: delegation-target
state: absent
```
Variables
---------
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
`ipaapi_context` | The context in which the module will execute. Executing in a server context is preferred. If not provided context will be determined by the execution environment. Valid values are `server` and `client`. | no
`ipaapi_ldap_cache` | Use LDAP cache for IPA connection. The bool setting defaults to yes. (bool) | no
`name` \| `cn` | The list of servicedelegationtarget name strings. | yes
`principal` | The list of principals. A principal can be of the format: fqdn, fqdn@REALM, service/fqdn, service/fqdn@REALM, host/fqdn, host/fqdn@REALM, alias$, alias$@REALM, where fqdn and fqdn@REALM are host principals and the same as host/fqdn and host/fqdn@REALM. Host princpals are only usable with IPA versions 4.9.0 and up. | no
`action` | Work on servicedelegationtarget or member level. It can be on of `member` or `servicedelegationtarget` and defaults to `servicedelegationtarget`. | no
`state` | The state to ensure. It can be one of `present`, `absent`, default: `present`. | no
Authors
=======
Thomas Woerner

View File

@@ -105,6 +105,7 @@ Variable | Description | Required
`password` | Active Directory domain administrator's password string. | no
`server` | Domain controller for the Active Directory domain string. | no
`trust_secret` | Shared secret for the trust string. | no
`trust_type` | Trust type. Currently, only 'ad' for Active Directory is supported. | no
`base_id` | First posix id for the trusted domain integer. | no
`range_size` | Size of the ID range reserved for the trusted domain integer. | no
`range_type` | Type of trusted domain ID range, It can be one of `ipa-ad-trust` or `ipa-ad-trust-posix`and defaults to `ipa-ad-trust`. | no

View File

@@ -28,6 +28,7 @@ Features
* Modules for hbacsvcgroup management
* Modules for host management
* Modules for hostgroup management
* Modules for idrange management
* Modules for location management
* Modules for permission management
* Modules for privilege management
@@ -36,6 +37,8 @@ Features
* Modules for self service management
* Modules for server management
* Modules for service management
* Modules for service delegation rule management
* Modules for service delegation target management
* Modules for sudocmd management
* Modules for sudocmdgroup management
* Modules for sudorule management
@@ -442,6 +445,7 @@ Modules in plugin/modules
* [ipahbacsvcgroup](README-hbacsvcgroup.md)
* [ipahost](README-host.md)
* [ipahostgroup](README-hostgroup.md)
* [idrange](README-idrange.md)
* [ipalocation](README-location.md)
* [ipapermission](README-permission.md)
* [ipaprivilege](README-privilege.md)
@@ -450,6 +454,8 @@ Modules in plugin/modules
* [ipaselfservice](README-selfservice.md)
* [ipaserver](README-server.md)
* [ipaservice](README-service.md)
* [ipaservicedelegationrule](README-servicedelegationrule.md)
* [ipaservicedelegationtarget](README-servicedelegationtarget.md)
* [ipasudocmd](README-sudocmd.md)
* [ipasudocmdgroup](README-sudocmdgroup.md)
* [ipasudorule](README-sudorule.md)

View File

@@ -0,0 +1,30 @@
FROM quay.io/centos/centos:stream8
ENV container=docker
RUN rm -fv /var/cache/dnf/metadata_lock.pid; \
dnf makecache; \
dnf --assumeyes install \
/usr/bin/python3 \
/usr/bin/python3-config \
/usr/bin/dnf-3 \
sudo \
bash \
systemd \
procps-ng \
iproute && \
dnf clean all; \
(cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*;\
rm -f /etc/systemd/system/*.wants/*;\
rm -f /lib/systemd/system/local-fs.target.wants/*; \
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
rm -f /lib/systemd/system/basic.target.wants/*;\
rm -f /lib/systemd/system/anaconda.target.wants/*; \
rm -rf /var/cache/dnf/;
STOPSIGNAL RTMIN+3
VOLUME ["/sys/fs/cgroup"]
CMD ["/usr/sbin/init"]

View File

@@ -0,0 +1,19 @@
---
driver:
name: docker
platforms:
- name: c8s-build
image: "quay.io/centos/centos:stream8"
dockerfile: Dockerfile
hostname: ipaserver.test.local
dns_servers:
- 8.8.8.8
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:ro
command: /usr/sbin/init
privileged: true
provisioner:
name: ansible
playbooks:
prepare: ../resources/playbooks/prepare-build.yml
prerun: false

View File

@@ -2,8 +2,8 @@
driver:
name: docker
platforms:
- name: centos-9
image: quay.io/ansible-freeipa/upstream-tests:centos-9
- name: c8s
image: quay.io/ansible-freeipa/upstream-tests:c8s
pre_build_image: true
hostname: ipaserver.test.local
dns_servers:
@@ -16,3 +16,4 @@ provisioner:
name: ansible
playbooks:
prepare: ../resources/playbooks/prepare.yml
prerun: false

View File

@@ -5,7 +5,6 @@ RUN rm -fv /var/cache/dnf/metadata_lock.pid; \
dnf makecache; \
dnf --assumeyes install \
/usr/bin/python3 \
/usr/bin/python3-config \
/usr/bin/dnf-3 \
sudo \
bash \

View File

@@ -2,7 +2,7 @@
driver:
name: docker
platforms:
- name: centos-9-build
- name: c9s-build
image: "quay.io/centos/centos:stream9"
dockerfile: Dockerfile
hostname: ipaserver.test.local
@@ -16,3 +16,4 @@ provisioner:
name: ansible
playbooks:
prepare: ../resources/playbooks/prepare-build.yml
prerun: false

19
molecule/c9s/molecule.yml Normal file
View File

@@ -0,0 +1,19 @@
---
driver:
name: docker
platforms:
- name: c9s
image: quay.io/ansible-freeipa/upstream-tests:c9s
pre_build_image: true
hostname: ipaserver.test.local
dns_servers:
- 127.0.0.1
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:ro
command: /usr/sbin/init
privileged: true
provisioner:
name: ansible
playbooks:
prepare: ../resources/playbooks/prepare.yml
prerun: false

View File

@@ -16,3 +16,4 @@ provisioner:
name: ansible
playbooks:
prepare: ../resources/playbooks/prepare-build.yml
prerun: false

View File

@@ -16,3 +16,4 @@ provisioner:
name: ansible
playbooks:
prepare: ../resources/playbooks/prepare.yml
prerun: false

View File

@@ -16,3 +16,4 @@ provisioner:
name: ansible
playbooks:
prepare: ../resources/playbooks/prepare-build.yml
prerun: false

View File

@@ -16,3 +16,4 @@ provisioner:
name: ansible
playbooks:
prepare: ../resources/playbooks/prepare.yml
prerun: false

View File

@@ -16,3 +16,4 @@ provisioner:
name: ansible
playbooks:
prepare: ../resources/playbooks/prepare-build.yml
prerun: false

View File

@@ -16,3 +16,4 @@ provisioner:
name: ansible
playbooks:
prepare: ../resources/playbooks/prepare.yml
prerun: false

View File

@@ -5,7 +5,7 @@
tasks:
- name: Ensure aumount key TestKey is renamed to NewKeyName
ipaautomountkey:
ipaadmin_password: password01
ipaadmin_password: SomeADMINpassword
automountlocationcn: TestLocation
automountmapname: TestMap
automountkey: TestKey

View File

@@ -6,4 +6,5 @@
tasks:
- name: Disable global forwarders.
ipadnsconfig:
ipaadmin_password: SomeADMINpassword
forward_policy: none

View File

@@ -6,4 +6,5 @@
tasks:
- name: Disallow reverse record synchronization.
ipadnsconfig:
ipaadmin_password: SomeADMINpassword
allow_sync_ptr: no

View File

@@ -6,6 +6,7 @@
tasks:
- name: Set dnsconfig forwarders.
ipadnsconfig:
ipaadmin_password: SomeADMINpassword
forwarders:
- ip_address: 8.8.4.4
- ip_address: 2001:4860:4860::8888

View File

@@ -6,6 +6,7 @@
tasks:
- name: Set dnsconfig forwarders.
ipadnsconfig:
ipaadmin_password: SomeADMINpassword
forwarders:
- ip_address: 8.8.4.4
- ip_address: 2001:4860:4860::8888

View File

@@ -6,6 +6,7 @@
tasks:
- name: Set dnsconfig.
ipadnsconfig:
ipaadmin_password: SomeADMINpassword
forwarders:
- ip_address: 8.8.4.4
- ip_address: 2001:4860:4860::8888

View File

@@ -7,6 +7,7 @@
tasks:
- name: Ensure that 'host04' has CNAME, with cname_hostname, is absent
ipadnsrecord:
ipaadmin_password: SomeADMINpassword
zone_name: example.com
name: host04
cname_hostname: host04.example.com

View File

@@ -7,6 +7,7 @@
tasks:
- name: Ensure that 'host04' has CNAME, with cname_hostname, is present
ipadnsrecord:
ipaadmin_password: SomeADMINpassword
zone_name: example.com
name: host04
cname_hostname: host04.example.com

View File

@@ -0,0 +1,11 @@
---
- name: Idrange absent example
hosts: ipaserver
become: no
tasks:
- name: Ensure idrange is absent
ipaidrange:
ipaadmin_password: SomeADMINpassword
name: id_range
state: absent

View File

@@ -0,0 +1,15 @@
---
- name: Playbook to manage idrange
hosts: ipaserver
become: no
tasks:
- name: Ensure AD-trust idrange is present
ipaidrange:
name: id_range
base_id: 150000000
range_size: 200000
rid_base: 1000000
idrange_type: ipa-ad-trust-posix
dom_name: ad.ipa.test
auto_private_groups: "false"

View File

@@ -0,0 +1,16 @@
---
- name: Playbook to manage idrange
hosts: ipaserver
become: no
tasks:
- name: Ensure AD-trust idrange is present
ipaidrange:
ipaadmin_password: SomeADMINpassword
name: ad_id_range
base_id: 150000000
range_size: 200000
rid_base: 1000000
idrange_type: ipa-ad-trust
dom_sid: S-1-5-21-2870384104-3340008087-3140804251
auto_private_groups: "true"

View File

@@ -0,0 +1,14 @@
---
- name: Playbook to manage idrange
hosts: ipaserver
become: no
tasks:
- name: Ensure local idrange is present
ipaidrange:
ipaadmin_password: SomeADMINpassword
name: id_range
base_id: 150000000
range_size: 200000
rid_base: 1000000
secondary_rid_base: 200000000

View File

@@ -6,5 +6,6 @@
tasks:
- name: Ensure privilege "Broad Privilege" is absent
ipaprivilege:
ipaadmin_password: SomeADMINpassword
name: Broad Privilege
state: absent

View File

@@ -0,0 +1,11 @@
---
- name: Servicedelegationrule absent example
hosts: ipaserver
become: no
tasks:
- name: Ensure servicedelegationrule test-delegation-rule is absent
ipaservicedelegationrule:
ipaadmin_password: SomeADMINpassword
name: test-delegation-rule
state: absent

View File

@@ -0,0 +1,10 @@
---
- name: Servicedelegationrule present example
hosts: ipaserver
become: no
tasks:
- name: Ensure servicedelegationrule test-delegation-rule is present
ipaservicedelegationrule:
ipaadmin_password: SomeADMINpassword
name: test-delegation-rule

View File

@@ -0,0 +1,13 @@
---
- name: Servicedelegationrule principal member absent example
hosts: ipaserver
become: no
tasks:
- name: Ensure principal member test/example.com is absent in servicedelegationrule test-delegation-rule
ipaservicedelegationrule:
ipaadmin_password: SomeADMINpassword
name: test-delegation-rule
principal: test/example.com
action: member
state: absent

View File

@@ -0,0 +1,12 @@
---
- name: Servicedelegationrule principal member present example
hosts: ipaserver
become: no
tasks:
- name: Ensure principal member test/example.com is present in servicedelegationrule test-delegation-rule
ipaservicedelegationrule:
ipaadmin_password: SomeADMINpassword
name: test-delegation-rule
principal: test/example.com
action: member

View File

@@ -0,0 +1,13 @@
---
- name: Servicedelegationrule absent example
hosts: ipaserver
become: no
tasks:
- name: Ensure member test/example.com is absent in servicedelegationrule test-delegation-rule
ipaservicedelegationrule:
ipaadmin_password: SomeADMINpassword
name: test-delegation-rule
principal: test/example.com
action: member
state: absent

View File

@@ -0,0 +1,12 @@
---
- name: Servicedelegationrule member present example
hosts: ipaserver
become: no
tasks:
- name: Ensure member test/example.com is present in servicedelegationrule test-delegation-rule
ipaservicedelegationrule:
ipaadmin_password: SomeADMINpassword
name: test-delegation-rule
principal: test/example.com
action: member

View File

@@ -0,0 +1,11 @@
---
- name: Servicedelegationtarget absent example
hosts: ipaserver
become: no
tasks:
- name: Ensure servicedelegationtarget test-delegation-target is absent
ipaservicedelegationtarget:
ipaadmin_password: SomeADMINpassword
name: test-delegation-target
state: absent

View File

@@ -0,0 +1,13 @@
---
- name: Servicedelegationtarget absent example
hosts: ipaserver
become: no
tasks:
- name: Ensure member test/example.com is absent in servicedelegationtarget test-delegation-target
ipaservicedelegationtarget:
ipaadmin_password: SomeADMINpassword
name: test-delegation-target
principal: test/example.com
action: member
state: absent

View File

@@ -0,0 +1,12 @@
---
- name: Servicedelegationtarget member present example
hosts: ipaserver
become: no
tasks:
- name: Ensure member test/example.com is present in servicedelegationtarget test-delegation-target
ipaservicedelegationtarget:
ipaadmin_password: SomeADMINpassword
name: test-delegation-target
principal: test/example.com
action: member

View File

@@ -0,0 +1,10 @@
---
- name: Servicedelegationtarget present example
hosts: ipaserver
become: no
tasks:
- name: Ensure servicedelegationtarget test-delegation-target is present
ipaservicedelegationtarget:
ipaadmin_password: SomeADMINpassword
name: test-delegation-target

View File

@@ -6,7 +6,7 @@
tasks:
- name: Ensure sudocmdgroup is absent
ipasudocmdgroup:
ipaadmin_password: pass1234
ipaadmin_password: SomeADMINpassword
name: network
state: absent
action: sudocmdgroup

View File

@@ -6,7 +6,7 @@
tasks:
- name: Ensure sudocmdgroup sudocmds are present
ipasudocmdgroup:
ipaadmin_password: pass1234
ipaadmin_password: SomeADMINpassword
name: network
description: Group of important commands.
sudocmd:

View File

@@ -6,6 +6,6 @@
tasks:
- name: Ensure sudorule command is absent
ipasudorule:
ipaadmin_password: pass1234
ipaadmin_password: SomeADMINpassword
name: testrule1
state: absent

View File

@@ -14,7 +14,7 @@
tasks:
- name: Add topology segment
ipatopologysegment:
ipaadmin_password: "{{ ipaadmin_password }}"
ipaadmin_password: SomeADMINpassword
suffix: "{{ item.suffix }}"
name: "{{ item.name | default(omit) }}"
left: "{{ item.left }}"

View File

@@ -14,7 +14,7 @@
tasks:
- name: Add topology segment
ipatopologysegment:
ipaadmin_password: "{{ ipaadmin_password }}"
ipaadmin_password: SomeADMINpassword
suffix: "{{ item.suffix }}"
name: "{{ item.name | default(omit) }}"
left: "{{ item.left }}"

View File

@@ -14,7 +14,7 @@
tasks:
- name: Add topology segment
ipatopologysegment:
ipaadmin_password: "{{ ipaadmin_password }}"
ipaadmin_password: SomeADMINpassword
suffix: "{{ item.suffix }}"
name: "{{ item.name | default(omit) }}"
left: "{{ item.left }}"

View File

@@ -6,6 +6,7 @@
tasks:
- name: ensure the trust is present
ipatrust:
ipaadmin_password: SomeADMINpassword
realm: windows.local
admin: Administrator
password: secret_password

View File

@@ -6,5 +6,6 @@
tasks:
- name: ensure the trust is absent
ipatrust:
ipaadmin_password: SomeADMINpassword
realm: windows.local
state: absent

View File

@@ -45,3 +45,13 @@ options:
type: bool
default: true
"""
DELETE_CONTINUE = r"""
options:
delete_continue:
description: |
Continuous mode. Don't stop on errors. Valid only if `state` is `absent`.
aliases: ["continue"]
type: bool
default: True
"""

View File

@@ -86,6 +86,7 @@ else:
from ipaplatform.paths import paths
from ipalib.krb_utils import get_credentials_if_valid
from ipapython.dnsutil import DNSName
from ipapython import kerberos
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_text
from ansible.module_utils.common.text.converters import jsonify
@@ -309,15 +310,49 @@ else:
raise ValueError("Invalid date '%s'" % value)
def compare_args_ipa(module, args, ipa, ignore=None): # noqa
"""Compare IPA obj attrs with the command args.
"""Compare IPA object attributes against command arguments.
This function compares IPA objects attributes with the args the
module is intending to use to call a command. ignore can be a list
of attributes, that should be ignored in the comparison.
This is useful to know if a call to IPA server will be needed or not.
In order to compare we have to perform slight changes in data formats.
This function compares 'ipa' attributes with the 'args' the module
is intending to use as parameters to an IPA API command. A list of
attribute names that should be ignored during comparison may be
provided.
Returns True if they are the same and False otherwise.
The comparison will be performed on every attribute provided in
'args'. If the attribute in 'args' or 'ipa' is not a scalar value
(including strings) the comparison will be performed as if the
attribute is a set of values, so duplicate values will count as a
single one. If both values are scalar values, then a direct
comparison is performed.
If an attribute is not available in 'ipa', its value is considered
to be a list with an empty string (['']), possibly forcing the
conversion of the 'args' attribute to a list for comparison. This
allows, for example, the usage of empty strings which should compare
as equals to inexistent attributes (None), as is done in IPA API.
This function is mostly useful to evaluate the need of a call to
IPA server when provided arguments are equivalent to the existing
values for a given IPA object.
Parameters
----------
module: AnsibleModule
The AnsibleModule used to log debug messages.
args: dict
The set of attributes provided by the playbook task.
ipa: dict
The set of attributes from the IPA object retrieved.
ignore: list
An optional list of attribute names that should be ignored and
not evaluated.
Return
------
True is returned if all attribute values in 'args' are
equivalent to the corresponding attribute value in 'ipa'.
"""
base_debug_msg = "Ansible arguments and IPA commands differed. "
@@ -337,52 +372,45 @@ else:
filtered_args = [key for key in args if key not in ignore]
for key in filtered_args:
if key not in ipa: # pylint: disable=no-else-return
module.debug(
base_debug_msg + "Command key not present in IPA: %s" % key
)
return False
arg = args[key]
ipa_arg = ipa.get(key, [""])
# If ipa_arg is a list and arg is not, replace arg
# with list containing arg. Most args in a find result
# are lists, but not all.
if isinstance(ipa_arg, (list, tuple)):
if not isinstance(arg, list):
arg = [arg]
if len(ipa_arg) != len(arg):
module.debug(
base_debug_msg
+ "List length doesn't match for key %s: %d %d"
% (key, len(arg), len(ipa_arg),)
)
return False
# ensure list elements types are the same.
if not (
isinstance(ipa_arg[0], type(arg[0]))
or isinstance(arg[0], type(ipa_arg[0]))
):
arg = [to_text(_arg) for _arg in arg]
try:
arg_set = set(arg)
ipa_arg_set = set(ipa_arg)
except TypeError:
if arg != ipa_arg:
module.debug(
base_debug_msg
+ "Different values: %s %s" % (arg, ipa_arg)
)
return False
else:
arg = args[key]
ipa_arg = ipa[key]
# If ipa_arg is a list and arg is not, replace arg
# with list containing arg. Most args in a find result
# are lists, but not all.
if isinstance(ipa_arg, tuple):
ipa_arg = list(ipa_arg)
if isinstance(ipa_arg, list):
if not isinstance(arg, list):
arg = [arg]
if len(ipa_arg) != len(arg):
module.debug(
base_debug_msg
+ "List length doesn't match for key %s: %d %d"
% (key, len(arg), len(ipa_arg),)
)
return False
if isinstance(ipa_arg[0], str) and isinstance(arg[0], int):
arg = [to_text(_arg) for _arg in arg]
if isinstance(ipa_arg[0], unicode) \
and isinstance(arg[0], int):
arg = [to_text(_arg) for _arg in arg]
try:
arg_set = set(arg)
ipa_arg_set = set(ipa_arg)
except TypeError:
if arg != ipa_arg:
module.debug(
base_debug_msg
+ "Different values: %s %s" % (arg, ipa_arg)
)
return False
else:
if arg_set != ipa_arg_set:
module.debug(
base_debug_msg
+ "Different set content: %s %s"
% (arg_set, ipa_arg_set,)
)
return False
if arg_set != ipa_arg_set:
module.debug(
base_debug_msg
+ "Different set content: %s %s"
% (arg_set, ipa_arg_set,)
)
return False
return True
def _afm_convert(value):
@@ -397,11 +425,32 @@ else:
return value
def module_params_get(module, name):
return _afm_convert(module.params.get(name))
def module_params_get_lowercase(module, name):
def module_params_get(module, name, allow_empty_string=False):
value = _afm_convert(module.params.get(name))
# Fail on empty strings in the list or if allow_empty_string is True
# if there is another entry in the list together with the empty
# string.
# Due to an issue in Ansible it is possible to use the empty string
# "" for lists with choices, even if the empty list is not part of
# the choices.
# Ansible issue https://github.com/ansible/ansible/issues/77108
if isinstance(value, list):
for val in value:
if isinstance(val, (str, unicode)) and not val:
if not allow_empty_string:
module.fail_json(
msg="Parameter '%s' contains an empty string" %
name)
elif len(value) > 1:
module.fail_json(
msg="Parameter '%s' may not contain another "
"entry together with an empty string" % name)
return value
def module_params_get_lowercase(module, name, allow_empty_string=False):
value = module_params_get(module, name, allow_empty_string)
if isinstance(value, list):
value = [v.lower() for v in value]
if isinstance(value, (str, unicode)):
@@ -550,6 +599,89 @@ else:
return False
return True
def servicedelegation_normalize_principals(module, principal,
check_exists=False):
"""
Normalize servicedelegation principals.
The principals can be service and with IPA 4.9.0+ also host principals.
"""
def _normalize_principal_name(name, realm):
# Normalize principal name
# Copied from ipaserver/plugins/servicedelegation.py
try:
princ = kerberos.Principal(name, realm=realm)
except ValueError as _err:
raise ipalib_errors.ValidationError(
name='principal',
reason="Malformed principal: %s" % str(_err))
if len(princ.components) == 1 and \
not princ.components[0].endswith('$'):
nprinc = 'host/' + unicode(princ)
else:
nprinc = unicode(princ)
return nprinc
def _check_exists(module, _type, name):
# Check if item of type _type exists using the show command
try:
module.ipa_command("%s_show" % _type, name, {})
except ipalib_errors.NotFound as e:
msg = str(e)
if "%s not found" % _type in msg:
return False
module.fail_json(msg="%s_show failed: %s" % (_type, msg))
return True
ipa_realm = module.ipa_get_realm()
_principal = []
for _princ in principal:
princ = _princ
realm = ipa_realm
# Get principal and realm from _princ if there is a realm
if '@' in _princ:
princ, realm = _princ.rsplit('@', 1)
# Lowercase principal
princ = princ.lower()
# Normalize principal
try:
nprinc = _normalize_principal_name(princ, realm)
except ipalib_errors.ValidationError as err:
module.fail_json(msg="%s: %s" % (_princ, str(err)))
princ = unicode(nprinc)
# Check that host principal exists
if princ.startswith("host/"):
if module.ipa_check_version("<", "4.9.0"):
module.fail_json(
msg="The use of host principals is not supported "
"by your IPA version")
# Get host FQDN (no leading 'host/' and no trailing realm)
# (There is no removeprefix and removesuffix in Python2)
_host = princ[5:]
if _host.endswith("@%s" % realm):
_host = _host[:-len(realm) - 1]
# Seach for host
if check_exists and not _check_exists(module, "host", _host):
module.fail_json(msg="Host '%s' does not exist" % _host)
# Check the service principal exists
else:
if check_exists and \
not _check_exists(module, "service", princ):
module.fail_json(msg="Service %s does not exist" % princ)
_principal.append(princ)
return _principal
def exit_raw_json(module, **kwargs):
"""
Print the raw parameters in JSON format, without masking.
@@ -742,6 +874,12 @@ else:
ipaapi_ldap_cache=dict(type="bool", default="True"),
)
ipa_module_options_spec = dict(
delete_continue=dict(
type="bool", default=True, aliases=["continue"]
)
)
def __init__(self, *args, **kwargs):
# Extend argument_spec with ipa_module_base_spec
if "argument_spec" in kwargs:
@@ -749,6 +887,16 @@ else:
_spec.update(self.ipa_module_base_spec)
kwargs["argument_spec"] = _spec
if "ipa_module_options" in kwargs:
_update = {
k: self.ipa_module_options_spec[k]
for k in kwargs["ipa_module_options"]
}
_spec = kwargs.get("argument_spec", {})
_spec.update(_update)
kwargs["argument_spec"] = _spec
del kwargs["ipa_module_options"]
# pylint: disable=super-with-arguments
super(IPAAnsibleModule, self).__init__(*args, **kwargs)
@@ -797,7 +945,7 @@ else:
finally:
temp_kdestroy(ccache_dir, ccache_name)
def params_get(self, name):
def params_get(self, name, allow_empty_string=False):
"""
Retrieve value set for module parameter.
@@ -805,11 +953,13 @@ else:
----------
name: string
The name of the parameter to retrieve.
allow_empty_string: bool
The parameter allowes to have empty strings in a list
"""
return module_params_get(self, name)
return module_params_get(self, name, allow_empty_string)
def params_get_lowercase(self, name):
def params_get_lowercase(self, name, allow_empty_string=False):
"""
Retrieve value set for module parameter as lowercase, if not None.
@@ -817,9 +967,11 @@ else:
----------
name: string
The name of the parameter to retrieve.
allow_empty_string: bool
The parameter allowes to have empty strings in a list
"""
return module_params_get_lowercase(self, name)
return module_params_get_lowercase(self, name, allow_empty_string)
def params_fail_used_invalid(self, invalid_params, state, action=None):
"""

View File

@@ -587,7 +587,6 @@ def main():
commands.append([None,
'automember_default_group_remove',
{'type': automember_type}])
ansible_module.warn("commands: %s" % repr(commands))
else:
dn_default_group = [DN(('cn', default_group),

View File

@@ -112,21 +112,23 @@ class AutomountMap(IPAAnsibleModule):
state = self.params_get("state")
if state == "present":
if len(name) != 1:
self.fail_json(msg="Exactly one name must be provided \
for state=present.")
self.fail_json(msg="Exactly one name must be provided for"
" 'state: present'.")
if state == "absent":
if len(name) == 0:
self.fail_json(msg="Argument 'map_type' can not be used with "
"state 'absent'")
self.fail_json(msg="At least one 'name' must be provided for"
" 'state: absent'")
invalid = ["desc"]
self.params_fail_used_invalid(invalid, state)
def get_args(self, mapname, desc): # pylint: disable=no-self-use
_args = {}
if mapname:
_args["automountmapname"] = mapname
if desc:
# automountmapname is required for all automountmap operations.
if not mapname:
self.fail_json(msg="automountmapname cannot be None or empty.")
_args = {"automountmapname": mapname}
# An empty string is valid and will clear the attribute.
if desc is not None:
_args["description"] = desc
return _args

View File

@@ -346,11 +346,13 @@ def main():
"ca_renewal_master_server": "ca_renewal_master_server",
"domain_resolution_order": "ipadomainresolutionorder"
}
allow_empty_string = ["pac_type", "user_auth_type", "configstring"]
reverse_field_map = {v: k for k, v in field_map.items()}
params = {}
for x in field_map:
val = ansible_module.params_get(x)
val = ansible_module.params_get(
x, allow_empty_string=(x in allow_empty_string))
if val is not None:
params[field_map.get(x, x)] = val
@@ -401,6 +403,10 @@ def main():
k: v for k, v in params.items()
if k not in result or result[k] != v
}
# Remove empty string args from params if result arg is not set
for k in ["ipakrbauthzdata", "ipauserauthtype", "ipaconfigstring"]:
if k not in result and k in params and params[k] == [""]:
del params[k]
if params \
and not compare_args_ipa(ansible_module, params, result):
changed = True
@@ -441,6 +447,13 @@ def main():
raise ValueError(
"Unexpected attribute type: %s" % arg_type)
exit_args[k] = type_map[arg_type](value)
# Add empty pac_type and user_auth_type if they are not set
for key in ["pac_type", "user_auth_type"]:
if key not in exit_args:
exit_args[key] = ""
# Add empty domain_resolution_order if it is not set
if "domain_resolution_order" not in exit_args:
exit_args["domain_resolution_order"] = []
# Done
ansible_module.exit_json(changed=changed, config=exit_args)

View File

@@ -54,6 +54,7 @@ options:
global forwarders.
required: false
choices: ['only', 'first', 'none']
alias: ["forwardpolicy"]
allow_sync_ptr:
description:
Allow synchronization of forward (A, AAAA) and reverse (PTR) records.
@@ -189,7 +190,8 @@ def main():
forwarders=dict(type='list', default=None, required=False,
options=dict(**forwarder_spec)),
forward_policy=dict(type='str', required=False, default=None,
choices=['only', 'first', 'none']),
choices=['only', 'first', 'none'],
aliases=["forwardpolicy"]),
allow_sync_ptr=dict(type='bool', required=False, default=None),
# general

View File

@@ -68,7 +68,7 @@ options:
required: false
default: only
choices: ["only", "first", "none"]
aliases: ["idnsforwarders"]
aliases: ["idnsforwarders", "forward_policy"]
skip_overlap_check:
description:
- Force DNS zone creation even if it will overlap with an existing zone.
@@ -189,7 +189,8 @@ def main():
port=dict(type='int', required=False,
default=None),
)),
forwardpolicy=dict(type='str', aliases=["idnsforwardpolicy"],
forwardpolicy=dict(type='str',
aliases=["idnsforwardpolicy", "forward_policy"],
required=False,
choices=['only', 'first', 'none']),
skip_overlap_check=dict(type='bool', required=False),

View File

@@ -97,6 +97,11 @@ options:
required: false
type: list
ailases: ["ipaexternalmember", "external_member"]
idoverrideuser:
description:
- User ID overrides to add
required: false
type: list
action:
description: Work on group or member level
default: group
@@ -184,7 +189,7 @@ RETURN = """
from ansible.module_utils._text import to_text
from ansible.module_utils.ansible_freeipa_module import \
IPAAnsibleModule, compare_args_ipa, gen_add_del_lists, \
gen_add_list, gen_intersection_list
gen_add_list, gen_intersection_list, api_check_param
def find_group(module, name):
@@ -223,7 +228,7 @@ def gen_args(description, gid, nomembers):
return _args
def gen_member_args(user, group, service, externalmember):
def gen_member_args(user, group, service, externalmember, idoverrideuser):
_args = {}
if user is not None:
_args["member_user"] = user
@@ -233,6 +238,8 @@ def gen_member_args(user, group, service, externalmember):
_args["member_service"] = service
if externalmember is not None:
_args["member_external"] = externalmember
if idoverrideuser is not None:
_args["member_idoverrideuser"] = idoverrideuser
return _args
@@ -280,6 +287,7 @@ def main():
user=dict(required=False, type='list', default=None),
group=dict(required=False, type='list', default=None),
service=dict(required=False, type='list', default=None),
idoverrideuser=dict(required=False, type='list', default=None),
membermanager_user=dict(required=False, type='list', default=None),
membermanager_group=dict(required=False, type='list',
default=None),
@@ -312,6 +320,7 @@ def main():
gid = ansible_module.params_get("gid")
nonposix = ansible_module.params_get("nonposix")
external = ansible_module.params_get("external")
idoverrideuser = ansible_module.params_get("idoverrideuser")
posix = ansible_module.params_get("posix")
nomembers = ansible_module.params_get("nomembers")
user = ansible_module.params_get("user")
@@ -379,6 +388,13 @@ def main():
"by your IPA version"
)
has_idoverrideuser = api_check_param(
"group_add_member", "idoverrideuser")
if idoverrideuser is not None and not has_idoverrideuser:
ansible_module.fail_json(
msg="Managing a idoverrideuser as part of a group is not "
"supported by your IPA version")
commands = []
for name in names:
@@ -389,6 +405,7 @@ def main():
group_add, group_del = [], []
service_add, service_del = [], []
externalmember_add, externalmember_del = [], []
idoverrides_add, idoverrides_del = [], []
membermanager_user_add, membermanager_user_del = [], []
membermanager_group_add, membermanager_group_del = [], []
@@ -438,7 +455,7 @@ def main():
res_find["objectclass"].append("posixgroup")
member_args = gen_member_args(
user, group, service, externalmember
user, group, service, externalmember, idoverrideuser
)
if not compare_args_ipa(ansible_module, member_args,
res_find):
@@ -456,6 +473,12 @@ def main():
externalmember_del) = gen_add_del_lists(
externalmember, res_find.get("member_external"))
(idoverrides_add,
idoverrides_del) = gen_add_del_lists(
idoverrideuser,
res_find.get("member_idoverrideuser")
)
membermanager_user_add, membermanager_user_del = \
gen_add_del_lists(
membermanager_user,
@@ -483,6 +506,8 @@ def main():
service, res_find.get("member_service"))
externalmember_add = gen_add_list(
externalmember, res_find.get("member_external"))
idoverrides_add = gen_add_list(
idoverrideuser, res_find.get("member_idoverrideuser"))
membermanager_user_add = gen_add_list(
membermanager_user,
@@ -516,6 +541,8 @@ def main():
service, res_find.get("member_service"))
externalmember_del = gen_intersection_list(
externalmember, res_find.get("member_external"))
idoverrides_del = gen_intersection_list(
idoverrideuser, res_find.get("member_idoverrideuser"))
membermanager_user_del = gen_intersection_list(
membermanager_user, res_find.get("membermanager_user"))
@@ -532,10 +559,16 @@ def main():
"user": user_add,
"group": group_add,
}
del_member_args = {
"user": user_del,
"group": group_del,
}
if has_idoverrideuser:
add_member_args["idoverrideuser"] = idoverrides_add
del_member_args["idoverrideuser"] = idoverrides_del
if has_add_member_service:
add_member_args["service"] = service_add
del_member_args["service"] = service_del
@@ -550,15 +583,16 @@ def main():
msg="Cannot add external members to a "
"non-external group."
)
# Add members
add_members = any([user_add, group_add,
add_members = any([user_add, group_add, idoverrides_add,
service_add, externalmember_add])
if add_members:
commands.append(
[name, "group_add_member", add_member_args]
)
# Remove members
remove_members = any([user_del, group_del,
remove_members = any([user_del, group_del, idoverrides_del,
service_del, externalmember_del])
if remove_members:
commands.append(

View File

@@ -360,28 +360,28 @@ def main():
res_find = {}
# Generate addition and removal lists
if host:
if host is not None:
host_add, host_del = gen_add_del_lists(
host, res_find.get("memberhost_host"))
if hostgroup:
if hostgroup is not None:
hostgroup_add, hostgroup_del = gen_add_del_lists(
hostgroup, res_find.get("memberhost_hostgroup"))
if hbacsvc:
if hbacsvc is not None:
hbacsvc_add, hbacsvc_del = gen_add_del_lists(
hbacsvc, res_find.get("memberservice_hbacsvc"))
if hbacsvcgroup:
if hbacsvcgroup is not None:
hbacsvcgroup_add, hbacsvcgroup_del = gen_add_del_lists(
hbacsvcgroup,
res_find.get("memberservice_hbacsvcgroup"))
if user:
if user is not None:
user_add, user_del = gen_add_del_lists(
user, res_find.get("memberuser_user"))
if group:
if group is not None:
group_add, group_del = gen_add_del_lists(
group, res_find.get("memberuser_group"))
@@ -395,7 +395,7 @@ def main():
if host:
host_add = gen_add_list(
host, res_find.get("memberhost_host"))
if hostgroup is not None:
if hostgroup:
hostgroup_add = gen_add_list(
hostgroup, res_find.get("memberhost_hostgroup"))

View File

@@ -709,7 +709,7 @@ def main():
elements='dict', required=False),
# mod
update_password=dict(type='str', default=None,
update_password=dict(type='str', default=None, no_log=False,
choices=['always', 'on_create']),
# general
@@ -764,7 +764,7 @@ def main():
mac_address = ansible_module.params_get("mac_address")
sshpubkey = ansible_module.params_get("sshpubkey")
userclass = ansible_module.params_get("userclass")
auth_ind = ansible_module.params_get("auth_ind")
auth_ind = ansible_module.params_get("auth_ind", allow_empty_string=True)
requires_pre_auth = ansible_module.params_get("requires_pre_auth")
ok_as_delegate = ansible_module.params_get("ok_as_delegate")
ok_to_auth_as_delegate = ansible_module.params_get(

View File

@@ -0,0 +1,332 @@
# -*- coding: utf-8 -*-
# Authors:
# Rafael Guterres Jeffman <rjeffman@redhat.com>
#
# Copyright (C) 2022 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
ANSIBLE_METADATA = {
"metadata_version": "1.0",
"supported_by": "community",
"status": ["preview"],
}
DOCUMENTATION = """
---
module: ipaidrange
short description: Manage FreeIPA idrange
description: Manage FreeIPA idrange
extends_documentation_fragment:
- ipamodule_base_docs
- ipamodule_base_docs.delete_continue
options:
name:
description: The list of idrange name strings.
required: true
aliases: ["cn"]
base_id:
description: First Posix ID of the range.
type: int
required: false
aliases: ["ipabaseid"]
range_size:
description: Number of IDs in the range.
type: int
required: false
aliases: ["ipaidrangesize"]
rid_base:
description: First RID of the corresponding RID range.
type: int
required: false
aliases: ["ipabaserid"]
secondary_rid_base:
description: First RID of the secondary RID range.
type: int
required: false
aliases: ["ipasecondarybaserid"]
idrange_type:
description: ID range type.
type: string
required: false
choices: ["ipa-ad-trust", "ipa-ad-trust-posix", "ipa-local"]
aliases: ["iparangetype"]
dom_sid:
description: Domain SID of the trusted domain.
type: string
required: false
aliases: ["ipanttrusteddomainsid"]
dom_name:
description: Domain name of the trusted domain.
type: string
required: false
aliases: ["ipanttrusteddomainname"]
auto_private_groups:
description: Auto creation of private groups.
type: string
required: false
choices: ["true", "false", "hybrid"]
aliases: ["ipaautoprivategroups"]
state:
description: The state to ensure.
choices: ["present", "absent"]
default: present
required: true
"""
EXAMPLES = """
# Ensure local domain idrange is present
- ipaidrange:
ipaadmin_password: SomeADMINpassword
name: id_range
base_id: 150000000
range_size: 200000
rid_base: 1000000
secondary_rid_base: 200000000
# Ensure local domain idrange is absent
- ipaidrange:
ipaadmin_password: SomeADMINpassword
name: id_range
state: absent
# Ensure AD-trust idrange is present
- ipaidrange:
name: id_range
base_id: 150000000
range_size: 200000
rid_base: 1000000
idrange_type: ipa-ad-trust
dom_sid: S-1-5-21-2870384104-3340008087-3140804251
auto_private_groups: "false"
# Ensure AD-trust idrange is present, with range type ad-trust-posix,
# and using domain name
- ipaidrange:
name: id_range
base_id: 150000000
range_size: 200000
rid_base: 1000000
idrange_type: ipa-ad-trust-posix
dom_name: ad.ipa.test
auto_private_groups: "hybrid"
"""
RETURN = """
"""
from ansible.module_utils.ansible_freeipa_module import \
IPAAnsibleModule, compare_args_ipa
from ansible.module_utils import six
if six.PY3:
unicode = str
def find_idrange(module, name):
"""Find if a idrange with the given name already exist."""
try:
_result = module.ipa_command("idrange_show", name, {"all": True})
except Exception: # pylint: disable=broad-except
# An exception is raised if idrange name is not found.
return None
else:
return _result["result"]
def gen_args(
base_id, range_size, rid_base, secondary_rid_base, idrange_type, dom_sid,
auto_private_groups
):
_args = {}
# Integer parameters are stored as strings.
# Converting them here allows the proper use of compare_args_ipa.
if base_id is not None:
_args["ipabaseid"] = base_id
if range_size is not None:
_args["ipaidrangesize"] = range_size
if rid_base is not None:
_args["ipabaserid"] = rid_base
if secondary_rid_base is not None:
_args["ipasecondarybaserid"] = secondary_rid_base
if idrange_type is not None:
_args["iparangetype"] = idrange_type
if dom_sid is not None:
_args["ipanttrusteddomainsid"] = dom_sid
if auto_private_groups is not None:
_args["ipaautoprivategroups"] = auto_private_groups
return _args
def main():
ansible_module = IPAAnsibleModule(
argument_spec=dict(
# general
name=dict(type="list", aliases=["cn"],
default=None, required=True),
# present
base_id=dict(required=False, type='int',
aliases=["ipabaseid"], default=None),
range_size=dict(required=False, type='int',
aliases=["ipaidrangesize"], default=None),
rid_base=dict(required=False, type='int',
aliases=["ipabaserid"], default=None),
secondary_rid_base=dict(required=False, type='int', default=None,
aliases=["ipasecondarybaserid"]),
idrange_type=dict(required=False, aliases=["iparangetype"],
type="str", default=None,
choices=["ipa-ad-trust", "ipa-ad-trust-posix",
"ipa-local"]),
dom_sid=dict(required=False, type='str', default=None,
aliases=["ipanttrusteddomainsid"]),
dom_name=dict(required=False, type='str', default=None,
aliases=["ipanttrusteddomainname"]),
auto_private_groups=dict(required=False, type='str', default=None,
aliases=["ipaautoprivategroups"],
choices=['true', 'false', 'hybrid']),
# state
state=dict(type="str", default="present",
choices=["present", "absent"]),
),
mutually_exclusive=[
["dom_sid", "secondary_rid_base"],
["dom_name", "secondary_rid_base"],
["dom_sid", "dom_name"],
],
supports_check_mode=True,
ipa_module_options=["delete_continue"],
)
ansible_module._ansible_debug = True
# Get parameters
# general
names = ansible_module.params_get("name")
delete_continue = ansible_module.params_get("delete_continue")
# present
base_id = ansible_module.params_get("base_id")
range_size = ansible_module.params_get("range_size")
rid_base = ansible_module.params_get("rid_base")
secondary_rid_base = ansible_module.params_get("secondary_rid_base")
idrange_type = ansible_module.params_get("idrange_type")
dom_sid = ansible_module.params_get("dom_sid")
auto_private_groups = \
ansible_module.params_get_lowercase("auto_private_groups")
# state
state = ansible_module.params_get("state")
# Check parameters
invalid = []
if state == "present":
if len(names) != 1:
ansible_module.fail_json(
msg="Only one idrange can be added at a time.")
if state == "absent":
if len(names) < 1:
ansible_module.fail_json(msg="No name given.")
invalid = ["base_id", "range_size", "idrange_type", "dom_sid"]
ansible_module.params_fail_used_invalid(invalid, state)
# Init
changed = False
exit_args = {}
range_types = {
"Active Directory domain range": "ipa-ad-trust",
"Active Directory trust range with POSIX attributes":
"ipa-ad-trust-posix",
"local domain range": "ipa-local",
}
# Connect to IPA API
with ansible_module.ipa_connect():
commands = []
for name in names:
# Make sure idrange exists
res_find = find_idrange(ansible_module, name)
# Create command
if state == "present":
# Generate args
args = gen_args(
base_id, range_size, rid_base, secondary_rid_base,
idrange_type, dom_sid, auto_private_groups
)
# Found the idrange
if res_find is not None:
# For all settings is args, check if there are
# different settings in the find result.
# If yes: modify
if not compare_args_ipa(
ansible_module, args, res_find, ignore=["iparangetype"]
):
res_type = range_types.get(
res_find.get("iparangetype")[0]
)
if res_type == "local_id_range":
ansible_module.fail_json(
"Cannot modify local IPA domain idrange."
)
arg_type = args.get("iparangetype")
if arg_type:
if arg_type != res_type:
ansible_module.fail_json(
"Cannot modify idrange type."
)
del args["iparangetype"]
commands.append([name, "idrange_mod", args])
else:
commands.append([name, "idrange_add", args])
elif state == "absent":
if res_find is not None:
commands.append([
name,
"idrange_del",
{"continue": delete_continue or False}
])
else:
ansible_module.fail_json(msg="Unkown state '%s'" % state)
# Execute commands
changed = ansible_module.execute_ipa_commands(commands)
# Done
ansible_module.exit_json(changed=changed, **exit_args)
if __name__ == "__main__":
main()

View File

@@ -50,13 +50,13 @@ options:
pac_type:
description: Supported PAC type.
required: false
choices: ["MS-PAC", "PAD", "NONE"]
choices: ["MS-PAC", "PAD", "NONE", ""]
type: list
aliases: ["pac_type", "ipakrbauthzdata"]
auth_ind:
description: Defines a whitelist for Authentication Indicators.
required: false
choices: ["otp", "radius", "pkinit", "hardened"]
choices: ["otp", "radius", "pkinit", "hardened", ""]
aliases: ["krbprincipalauthind"]
skip_host_check:
description: Skip checking if host object exists.
@@ -356,7 +356,7 @@ def init_ansible_module():
smb=dict(type="bool", required=False),
netbiosname=dict(type="str", required=False),
pac_type=dict(type="list", aliases=["ipakrbauthzdata"],
choices=["MS-PAC", "PAD", "NONE"]),
choices=["MS-PAC", "PAD", "NONE", ""]),
auth_ind=dict(type="list",
aliases=["krbprincipalauthind"],
choices=["otp", "radius", "pkinit", "hardened", ""]),
@@ -420,8 +420,8 @@ def main():
# service attributes
principal = ansible_module.params_get("principal")
certificate = ansible_module.params_get("certificate")
pac_type = ansible_module.params_get("pac_type")
auth_ind = ansible_module.params_get("auth_ind")
pac_type = ansible_module.params_get("pac_type", allow_empty_string=True)
auth_ind = ansible_module.params_get("auth_ind", allow_empty_string=True)
skip_host_check = ansible_module.params_get("skip_host_check")
force = ansible_module.params_get("force")
requires_pre_auth = ansible_module.params_get("requires_pre_auth")
@@ -537,6 +537,15 @@ def main():
if remove in args:
del args[remove]
if (
"ipakrbauthzdata" in args
and (
args.get("ipakrbauthzdata", [""]) ==
res_find.get("ipakrbauthzdata", [""])
)
):
del args["ipakrbauthzdata"]
if (
"krbprincipalauthind" in args
and (

View File

@@ -0,0 +1,352 @@
# -*- coding: utf-8 -*-
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# Copyright (C) 2022 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
ANSIBLE_METADATA = {
"metadata_version": "1.0",
"supported_by": "community",
"status": ["preview"],
}
DOCUMENTATION = """
---
module: ipaservicedelegationrule
short description: Manage FreeIPA servicedelegationrule
description: |
Manage FreeIPA servicedelegationrule and servicedelegationrule members
extends_documentation_fragment:
- ipamodule_base_docs
options:
name:
description: The list of servicedelegationrule name strings.
required: true
aliases: ["cn"]
principal:
description: |
The list of principals. A principal can be of the format:
fqdn, fqdn@REALM, service/fqdn, service/fqdn@REALM, host/fqdn,
host/fqdn@REALM, alias$, alias$@REALM, where fqdn and fqdn@REALM
are host principals and the same as host/fqdn and host/fqd
Host princpals are only usable with IPA versions 4.9.0 and up.
required: false
target:
description: |
The list of service delegation targets.
required: false
aliases: ["servicedelegationtarget"]
action:
description: Work on servicedelegationrule or member level.
choices: ["servicedelegationrule", "member"]
default: servicedelegationrule
required: false
state:
description: The state to ensure.
choices: ["present", "absent"]
default: present
required: true
"""
EXAMPLES = """
# Ensure servicedelegationrule delegation-rule is present
- ipaservicedelegationrule:
ipaadmin_password: SomeADMINpassword
name: delegation-rule
# Ensure servicedelegationrule delegation-rule member principal
# test/example.com is present
- ipaservicedelegationrule:
ipaadmin_password: SomeADMINpassword
name: delegation-rule
principal: test/example.com
action: member
# Ensure servicedelegationrule delegation-rule member principal
# test/example.com is absent
- ipaservicedelegationrule:
ipaadmin_password: SomeADMINpassword
name: delegation-rule
principal: test/example.com
action: member
state: absent
# Ensure servicedelegationrule delegation-rule member target
# test/example.com is present
- ipaservicedelegationrule:
ipaadmin_password: SomeADMINpassword
name: delegation-rule
target: delegation-target
action: member
# Ensure servicedelegationrule delegation-rule member target
# test/example.com is absent
- ipaservicedelegationrule:
ipaadmin_password: SomeADMINpassword
name: delegation-rule
target: delegation-target
action: member
state: absent
# Ensure servicedelegationrule delegation-rule is absent
- ipaservicedelegationrule:
ipaadmin_password: SomeADMINpassword
name: delegation-rule
state: absent
"""
RETURN = """
"""
from ansible.module_utils.ansible_freeipa_module import \
IPAAnsibleModule, gen_add_del_lists, gen_add_list, gen_intersection_list, \
servicedelegation_normalize_principals, ipalib_errors
from ansible.module_utils import six
if six.PY3:
unicode = str
def find_servicedelegationrule(module, name):
"""Find if a servicedelegationrule with the given name already exist."""
try:
_result = module.ipa_command("servicedelegationrule_show", name,
{"all": True})
except Exception: # pylint: disable=broad-except
# An exception is raised if servicedelegationrule name is not found.
return None
else:
return _result["result"]
def check_targets(module, targets):
def _check_exists(module, _type, name):
# Check if item of type _type exists using the show command
try:
module.ipa_command("%s_show" % _type, name, {})
except ipalib_errors.NotFound as e:
msg = str(e)
if "%s not found" % _type in msg:
return False
module.fail_json(msg="%s_show failed: %s" % (_type, msg))
return True
for _target in targets:
if not _check_exists(module, "servicedelegationtarget", _target):
module.fail_json(
msg="Service delegation target '%s' does not exist" % _target)
def main():
ansible_module = IPAAnsibleModule(
argument_spec=dict(
# general
name=dict(type="list", aliases=["cn"], default=None,
required=True),
# present
principal=dict(required=False, type='list', default=None),
target=dict(required=False, type='list',
aliases=["servicedelegationtarget"], default=None),
action=dict(type="str", default="servicedelegationrule",
choices=["member", "servicedelegationrule"]),
# state
state=dict(type="str", default="present",
choices=["present", "absent"]),
),
supports_check_mode=True,
)
ansible_module._ansible_debug = True
# Get parameters
# general
names = ansible_module.params_get("name")
# present
principal = ansible_module.params_get("principal")
target = ansible_module.params_get("target")
action = ansible_module.params_get("action")
# state
state = ansible_module.params_get("state")
# Check parameters
invalid = []
if state == "present":
if len(names) != 1:
ansible_module.fail_json(
msg="Only one servicedelegationrule can be added at a time.")
if state == "absent":
if len(names) < 1:
ansible_module.fail_json(msg="No name given.")
if action == "servicedelegationrule":
invalid = ["principal", "target"]
ansible_module.params_fail_used_invalid(invalid, state, action)
# Init
membertarget = "ipaallowedtarget_servicedelegationtarget"
changed = False
exit_args = {}
# Connect to IPA API
with ansible_module.ipa_connect():
# Normalize principals
if principal:
principal = servicedelegation_normalize_principals(
ansible_module, principal, state == "present")
if target and state == "present":
check_targets(ansible_module, target)
commands = []
principal_add = principal_del = []
target_add = target_del = []
for name in names:
# Make sure servicedelegationrule exists
res_find = find_servicedelegationrule(ansible_module, name)
# Create command
if state == "present":
if action == "servicedelegationrule":
# A servicedelegationrule does not have normal options.
# There is no servicedelegationtarget-mod command.
# Principal members are handled with the _add_member and
# _remove_member commands further down.
if res_find is None:
commands.append([name, "servicedelegationrule_add",
{}])
res_find = {}
# Generate addition and removal lists for principal
principal_add, principal_del = gen_add_del_lists(
principal, res_find.get("memberprincipal"))
# Generate addition and removal lists for target
target_add, target_del = gen_add_del_lists(
target, res_find.get(membertarget))
elif action == "member":
if res_find is None:
ansible_module.fail_json(
msg="No servicedelegationrule '%s'" % name)
# Reduce add lists for principal
# to new entries only that are not in res_find.
if principal is not None and \
"memberprincipal" in res_find:
principal_add = gen_add_list(
principal, res_find["memberprincipal"])
else:
principal_add = principal
# Reduce add lists for target
# to new entries only that are not in res_find.
if target is not None and membertarget in res_find:
target_add = gen_add_list(
target, res_find[membertarget])
else:
target_add = target
elif state == "absent":
if action == "servicedelegationrule":
if res_find is not None:
commands.append([name, "servicedelegationrule_del",
{}])
elif action == "member":
if res_find is None:
ansible_module.fail_json(
msg="No servicedelegationrule '%s'" % name)
# Reduce del lists of principals to the entries only
# that are in res_find.
if principal is not None:
principal_del = gen_intersection_list(
principal, res_find.get("memberprincipal"))
else:
principal_del = principal
# Reduce del lists of targets to the entries only
# that are in res_find.
if target is not None:
target_del = gen_intersection_list(
target, res_find.get(membertarget))
else:
target_del = target
else:
ansible_module.fail_json(msg="Unkown state '%s'" % state)
# Handle members
# Add principal members
if principal_add is not None and len(principal_add) > 0:
commands.append(
[name, "servicedelegationtarget_add_member",
{
"principal": principal_add,
}])
# Remove principal members
if principal_del is not None and len(principal_del) > 0:
commands.append(
[name, "servicedelegationtarget_remove_member",
{
"principal": principal_del,
}])
# Add target members
if target_add is not None and len(target_add) > 0:
commands.append(
[name, "servicedelegationrule_add_target",
{
"servicedelegationtarget": target_add,
}])
# Remove target members
if target_del is not None and len(target_del) > 0:
commands.append(
[name, "servicedelegationrule_remove_target",
{
"servicedelegationtarget": target_del,
}])
# Execute commands
changed = ansible_module.execute_ipa_commands(
commands, fail_on_member_errors=True)
# Done
ansible_module.exit_json(changed=changed, **exit_args)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,270 @@
# -*- coding: utf-8 -*-
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# Copyright (C) 2022 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
ANSIBLE_METADATA = {
"metadata_version": "1.0",
"supported_by": "community",
"status": ["preview"],
}
DOCUMENTATION = """
---
module: ipaservicedelegationtarget
short description: Manage FreeIPA servicedelegationtarget
description: |
Manage FreeIPA servicedelegationtarget and servicedelegationtarget members
extends_documentation_fragment:
- ipamodule_base_docs
options:
name:
description: The list of servicedelegationtarget name strings.
required: true
aliases: ["cn"]
principal:
description: |
The list of principals. A principal can be of the format:
fqdn, fqdn@REALM, service/fqdn, service/fqdn@REALM, host/fqdn,
host/fqdn@REALM, alias$, alias$@REALM, where fqdn and fqdn@REALM
are host principals and the same as host/fqdn and host/fqdn@REALM.
Host princpals are only usable with IPA versions 4.9.0 and up.
required: false
action:
description: Work on servicedelegationtarget or member level.
choices: ["servicedelegationtarget", "member"]
default: servicedelegationtarget
required: false
state:
description: The state to ensure.
choices: ["present", "absent"]
default: present
required: true
"""
EXAMPLES = """
# Ensure servicedelegationtarget delegation-target is present
- ipaservicedelegationtarget:
ipaadmin_password: SomeADMINpassword
name: delegation-target
# Ensure servicedelegationtarget delegation-target member principal
# test/example.com is present
- ipaservicedelegationtarget:
ipaadmin_password: SomeADMINpassword
name: delegation-target
principal: test/example.com
action: member
# Ensure servicedelegationtarget delegation-target member principal
# test/example.com is absent
- ipaservicedelegationtarget:
ipaadmin_password: SomeADMINpassword
name: delegation-target
principal: test/example.com
action: member
state: absent
# Ensure servicedelegationtarget delegation-target is absent
- ipaservicedelegationtarget:
ipaadmin_password: SomeADMINpassword
name: delegation-target
state: absent
"""
RETURN = """
"""
from ansible.module_utils.ansible_freeipa_module import \
IPAAnsibleModule, gen_add_del_lists, gen_add_list, gen_intersection_list, \
servicedelegation_normalize_principals
from ansible.module_utils import six
if six.PY3:
unicode = str
def find_servicedelegationtarget(module, name):
"""Find if a servicedelegationtarget with the given name already exist."""
try:
_result = module.ipa_command("servicedelegationtarget_show", name,
{"all": True})
except Exception: # pylint: disable=broad-except
# An exception is raised if servicedelegationtarget name is not found.
return None
else:
return _result["result"]
def main():
ansible_module = IPAAnsibleModule(
argument_spec=dict(
# general
name=dict(type="list", aliases=["cn"], default=None,
required=True),
# present
principal=dict(required=False, type='list', default=None),
action=dict(type="str", default="servicedelegationtarget",
choices=["member", "servicedelegationtarget"]),
# state
state=dict(type="str", default="present",
choices=["present", "absent"]),
),
supports_check_mode=True,
)
ansible_module._ansible_debug = True
# Get parameters
# general
names = ansible_module.params_get("name")
# present
principal = ansible_module.params_get("principal")
action = ansible_module.params_get("action")
# state
state = ansible_module.params_get("state")
# Check parameters
invalid = []
if state == "present":
if len(names) != 1:
ansible_module.fail_json(
msg="Only one servicedelegationtarget can be added at a time.")
if state == "absent":
if len(names) < 1:
ansible_module.fail_json(msg="No name given.")
if action == "servicedelegationtarget":
invalid.append("principal")
ansible_module.params_fail_used_invalid(invalid, state, action)
# Init
changed = False
exit_args = {}
# Connect to IPA API
with ansible_module.ipa_connect():
# Normalize principals
if principal:
principal = servicedelegation_normalize_principals(
ansible_module, principal, state == "present")
commands = []
principal_add = principal_del = []
for name in names:
# Make sure servicedelegationtarget exists
res_find = find_servicedelegationtarget(ansible_module, name)
# Create command
if state == "present":
if action == "servicedelegationtarget":
# A servicedelegationtarget does not have normal options.
# There is no servicedelegationtarget-mod command.
# Principal members are handled with the _add_member and
# _remove_member commands further down.
if res_find is None:
commands.append([name, "servicedelegationtarget_add",
{}])
res_find = {}
# Generate addition and removal lists
principal_add, principal_del = gen_add_del_lists(
principal, res_find.get("memberprincipal"))
elif action == "member":
if res_find is None:
ansible_module.fail_json(
msg="No servicedelegationtarget '%s'" % name)
# Reduce add lists for principal
# to new entries only that are not in res_find.
if principal is not None and \
"memberprincipal" in res_find:
principal_add = gen_add_list(
principal, res_find["memberprincipal"])
else:
principal_add = principal
elif state == "absent":
if action == "servicedelegationtarget":
if res_find is not None:
commands.append([name, "servicedelegationtarget_del",
{}])
elif action == "member":
if res_find is None:
ansible_module.fail_json(
msg="No servicedelegationtarget '%s'" % name)
# Reduce del lists of principal
# to the entries only that are in res_find.
if principal is not None:
principal_del = gen_intersection_list(
principal, res_find.get("memberprincipal"))
else:
principal_del = principal
else:
ansible_module.fail_json(msg="Unkown state '%s'" % state)
# Handle members
# Add principal members
if principal_add is not None and len(principal_add) > 0:
commands.append(
[name, "servicedelegationtarget_add_member",
{
"principal": principal_add,
}])
# Remove principal members
if principal_del is not None and len(principal_del) > 0:
commands.append(
[name, "servicedelegationtarget_remove_member",
{
"principal": principal_del,
}])
# Execute commands
changed = ansible_module.execute_ipa_commands(
commands, fail_on_member_errors=True)
# Done
ansible_module.exit_json(changed=changed, **exit_args)
if __name__ == "__main__":
main()

View File

@@ -44,7 +44,8 @@ options:
description:
- Trust type (ad for Active Directory, default)
default: ad
required: true
required: false
choices: ["ad"]
admin:
description:
- Active Directory domain administrator
@@ -103,7 +104,7 @@ EXAMPLES = """
realm: ad.example.test
trust_type: ad
admin: Administrator
password: Welcome2020!
password: SomeW1Npassword
state: present
# delete ad-trust
@@ -157,7 +158,7 @@ def add_trust(module, realm, args):
def gen_args(trust_type, admin, password, server, trust_secret, base_id,
range_size, _range_type, two_way, external):
range_size, range_type, two_way, external):
_args = {}
if trust_type is not None:
_args["trust_type"] = trust_type
@@ -173,6 +174,8 @@ def gen_args(trust_type, admin, password, server, trust_secret, base_id,
_args["base_id"] = base_id
if range_size is not None:
_args["range_size"] = range_size
if range_type is not None:
_args["range_type"] = range_type
if two_way is not None:
_args["bidirectional"] = two_way
if external is not None:
@@ -190,7 +193,8 @@ def main():
state=dict(type="str", default="present",
choices=["present", "absent"]),
# present
trust_type=dict(type="str", default="ad", required=False),
trust_type=dict(type="str", default="ad", required=False,
choices=["ad"]),
admin=dict(type="str", default=None, required=False),
password=dict(type="str", default=None,
required=False, no_log=True),

View File

@@ -892,8 +892,10 @@ def main():
title = ansible_module.params_get("title")
manager = ansible_module.params_get("manager")
carlicense = ansible_module.params_get("carlicense")
sshpubkey = ansible_module.params_get("sshpubkey")
userauthtype = ansible_module.params_get("userauthtype")
sshpubkey = ansible_module.params_get("sshpubkey",
allow_empty_string=True)
userauthtype = ansible_module.params_get("userauthtype",
allow_empty_string=True)
userclass = ansible_module.params_get("userclass")
radius = ansible_module.params_get("radius")
radiususer = ansible_module.params_get("radiususer")
@@ -1101,13 +1103,6 @@ def main():
if "noprivate" in args:
del args["noprivate"]
# Ignore userauthtype if it is empty (for resetting)
# and not set in for the user
if "ipauserauthtype" not in res_find and \
"ipauserauthtype" in args and \
args["ipauserauthtype"] == ['']:
del args["ipauserauthtype"]
# For all settings is args, check if there are
# different settings in the find result.
# If yes: modify

View File

@@ -2,4 +2,4 @@
ipdb
pre-commit
flake8-bugbear
pylint==2.10.2
pylint==2.12.2

View File

@@ -207,7 +207,7 @@ else:
cli_realm, cli_domain, cli_server, cli_kdc, dnsok,
filename, client_domain, client_hostname, force=False,
configure_sssd=True):
# pylint: disable=global-statement
# pylint: disable=global-variable-not-assigned
global options
options.force = force
options.sssd = configure_sssd

View File

@@ -216,15 +216,18 @@
ipaclient_force_join)
- block:
- fail:
- name: krb5 configuration not correct
fail:
msg: >
The krb5 configuration is not correct, please enable allow_repair
to fix this.
when: not result_ipaclient_test_keytab.krb5_conf_ok
- fail:
- name: IPA test failed
fail:
msg: "The IPA test failed, please enable allow_repair to fix this."
when: not result_ipaclient_test_keytab.ping_test_ok
- fail:
- name: ca.crt file is missing
fail:
msg: >
The ca.crt file is missing, please enable allow_repair to fix this.
when: not result_ipaclient_test_keytab.ca_crt_exists

View File

@@ -34,6 +34,7 @@ ignore = D1,D212,D203
[pylint.MASTER]
disable =
consider-using-f-string, # f-string is not supported on Python2
unspecified-encoding, # open() does not provide `encoding` in Python2
use-maxsplit-arg,
redundant-u-string-prefix,

View File

@@ -71,6 +71,24 @@
register: result
failed_when: result.failed or result.changed
- name: ensure map TestMap has an empty description
ipaautomountmap:
ipaadmin_password: SomeADMINpassword
name: TestMap
location: TestLocation
desc: ""
register: result
failed_when: result.failed or not result.changed
- name: ensure map TestMap has an empty description, again
ipaautomountmap:
ipaadmin_password: SomeADMINpassword
name: TestMap
location: TestLocation
desc: ""
register: result
failed_when: result.failed or result.changed
- name: ensure map TestMap is removed
ipaautomountmap:
ipaadmin_password: SomeADMINpassword

View File

@@ -18,28 +18,39 @@ stages:
scenario: fedora-latest
ansible_version: ">=2.9,<2.10"
# CentOS 9
# CentOS 9 Stream
- stage: CentOS9_Ansible_2_9
- stage: c9s_Ansible_2_9
dependsOn: []
jobs:
- template: templates/group_tests.yml
parameters:
build_number: $(Build.BuildNumber)
scenario: centos-9
scenario: c9s
ansible_version: ">=2.9,<2.10"
# CentOS 8
# CentOS 8 Stream
- stage: CentOS8_Ansible_2_9
- stage: c8s_Ansible_2_9
dependsOn: []
jobs:
- template: templates/group_tests.yml
parameters:
build_number: $(Build.BuildNumber)
scenario: centos-8
scenario: c8s
ansible_version: ">=2.9,<2.10"
# # CentOS 8
#
# - stage: CentOS8_Ansible_2_9
# dependsOn: []
# jobs:
# - template: templates/group_tests.yml
# parameters:
# build_number: $(Build.BuildNumber)
# scenario: centos-8
# ansible_version: ">=2.9,<2.10"
# CentOS 7
- stage: CentOS7_Ansible_2_9

View File

@@ -21,17 +21,23 @@ jobs:
container_name: centos-7
build_scenario_name: centos-7-build
- template: templates/build_container.yml
parameters:
job_name_suffix: Centos8
container_name: centos-8
build_scenario_name: centos-8-build
# - template: templates/build_container.yml
# parameters:
# job_name_suffix: Centos8
# container_name: centos-8
# build_scenario_name: centos-8-build
- template: templates/build_container.yml
parameters:
job_name_suffix: Centos9
container_name: centos-9
build_scenario_name: centos-9-build
job_name_suffix: C8S
container_name: c8s
build_scenario_name: c8s-build
- template: templates/build_container.yml
parameters:
job_name_suffix: C9S
container_name: c9s
build_scenario_name: c9s-build
- template: templates/build_container.yml
parameters:

View File

@@ -52,73 +52,120 @@ stages:
scenario: fedora-latest
ansible_version: ""
# CentoOS 9
# CentoOS 9 Stream
- stage: CentOS9_Ansible_2_9
- stage: c9s_Ansible_2_9
dependsOn: []
jobs:
- template: templates/group_tests.yml
parameters:
build_number: $(Build.BuildNumber)
scenario: centos-9
scenario: c9s
ansible_version: ">=2.9,<2.10"
- stage: CentOS9_Ansible_Core_2_11
- stage: c9s_Ansible_Core_2_11
dependsOn: []
jobs:
- template: templates/group_tests.yml
parameters:
build_number: $(Build.BuildNumber)
scenario: centos-9
scenario: c9s
ansible_version: "-core >=2.11,<2.12"
- stage: CentOS9_Ansible_latest
- stage: c9s_Ansible_Core_2_12
dependsOn: []
jobs:
- template: templates/group_tests.yml
parameters:
build_number: $(Build.BuildNumber)
scenario: centos-9
ansible_version: ""
# CentOS 8
- stage: CentOS8_Ansible_2_9
dependsOn: []
jobs:
- template: templates/group_tests.yml
parameters:
build_number: $(Build.BuildNumber)
scenario: centos-8
ansible_version: ">=2.9,<2.10"
- stage: CentOS8_Ansible_Core_2_11
dependsOn: []
jobs:
- template: templates/group_tests.yml
parameters:
build_number: $(Build.BuildNumber)
scenario: centos-8
ansible_version: "-core >=2.11,<2.12"
- stage: CentOS8_Ansible_Core_2_12
dependsOn: []
jobs:
- template: templates/group_tests.yml
parameters:
build_number: $(Build.BuildNumber)
scenario: centos-8
scenario: c9s
ansible_version: "-core >=2.12,<2.13"
- stage: CentOS8_Ansible_latest
- stage: c9s_Ansible_latest
dependsOn: []
jobs:
- template: templates/group_tests.yml
parameters:
build_number: $(Build.BuildNumber)
scenario: centos-8
scenario: c9s
ansible_version: ""
# CentOS 8 Stream
- stage: c8s_Ansible_2_9
dependsOn: []
jobs:
- template: templates/group_tests.yml
parameters:
build_number: $(Build.BuildNumber)
scenario: c8s
ansible_version: ">=2.9,<2.10"
- stage: c8s_Ansible_Core_2_11
dependsOn: []
jobs:
- template: templates/group_tests.yml
parameters:
build_number: $(Build.BuildNumber)
scenario: c8s
ansible_version: "-core >=2.11,<2.12"
- stage: c8s_Ansible_Core_2_12
dependsOn: []
jobs:
- template: templates/group_tests.yml
parameters:
build_number: $(Build.BuildNumber)
scenario: c8s
ansible_version: "-core >=2.12,<2.13"
- stage: c8s_Ansible_latest
dependsOn: []
jobs:
- template: templates/group_tests.yml
parameters:
build_number: $(Build.BuildNumber)
scenario: c8s
ansible_version: ""
# # CentOS 8
#
# - stage: CentOS8_Ansible_2_9
# dependsOn: []
# jobs:
# - template: templates/group_tests.yml
# parameters:
# build_number: $(Build.BuildNumber)
# scenario: centos-8
# ansible_version: ">=2.9,<2.10"
#
# - stage: CentOS8_Ansible_Core_2_11
# dependsOn: []
# jobs:
# - template: templates/group_tests.yml
# parameters:
# build_number: $(Build.BuildNumber)
# scenario: centos-8
# ansible_version: "-core >=2.11,<2.12"
#
# - stage: CentOS8_Ansible_Core_2_12
# dependsOn: []
# jobs:
# - template: templates/group_tests.yml
# parameters:
# build_number: $(Build.BuildNumber)
# scenario: centos-8
# ansible_version: "-core >=2.12,<2.13"
#
# - stage: CentOS8_Ansible_latest
# dependsOn: []
# jobs:
# - template: templates/group_tests.yml
# parameters:
# build_number: $(Build.BuildNumber)
# scenario: centos-8
# ansible_version: ""
# CentOS 7
- stage: CentOS7_Ansible_2_9

View File

@@ -6,6 +6,9 @@ parameters:
type: string
- name: build_scenario_name
type: string
- name: python_version
type: string
default: 3.x
jobs:
- job: BuildTestImage${{ parameters.job_name_suffix }}
@@ -13,7 +16,7 @@ jobs:
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '3.6'
versionSpec: '${{ parameters.python_version }}'
- script: python -m pip install --upgrade pip setuptools wheel ansible
displayName: Install tools

View File

@@ -2,7 +2,7 @@
parameters:
- name: scenario
type: string
default: centos-8
default: fedora-latest
- name: build_number
type: string
- name: ansible_version

View File

@@ -8,7 +8,7 @@ parameters:
default: 1
- name: scenario
type: string
default: centos-8
default: fedora-latest
- name: ansible_version
type: string
default: ""

View File

@@ -4,6 +4,7 @@ parameters:
type: string
- name: scenario
type: string
default: fedora-latest
- name: ansible_version
type: string
default: ""

View File

@@ -56,9 +56,9 @@
ipaapi_context: "{{ ipa_context | default(omit) }}"
pac_type: ""
- name: set maxhostname to 255
block:
- ipaconfig:
- block:
- name: set maxhostname to 255
ipaconfig:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
maxhostname: 255
@@ -221,16 +221,17 @@
register: result
failed_when: result.changed or result.failed
- name: set maxhostname to 77
block:
- ipaconfig:
- block:
- name: set maxhostname to 77
ipaconfig:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
maxhostname: 77
register: result
failed_when: not result.changed or result.failed
- ipaconfig:
- name: set maxhostname to 77, again
ipaconfig:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
maxhostname: 77
@@ -409,9 +410,9 @@
register: result
failed_when: not result.changed or result.failed
- name: reset maxhostname
block:
- ipaconfig:
- block:
- name: reset maxhostname
ipaconfig:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
maxhostname: '{{ previousconfig.config.maxhostname | default(omit) }}'
@@ -444,9 +445,9 @@
register: result
failed_when: result.changed or result.failed
- name: reset maxhostname
block:
- ipaconfig:
- block:
- name: reset maxhostname
ipaconfig:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
maxhostname: '{{ previousconfig.config.maxhostname | default(omit) }}'

View File

@@ -0,0 +1,143 @@
---
- name: Test config
hosts: "{{ ipa_test_host | default('ipaserver') }}"
become: yes
gather_facts: no
tasks:
# GET CURRENT CONFIG
- name: Return current values of the global configuration options
ipaconfig:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
register: previousconfig
- name: Ensure config with empty pac_type, user_auth_type and configstring
ipaconfig:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
pac_type: ""
user_auth_type: ""
configstring: ""
# TESTS
- name: Ensure config with pac_type "nfs:NONE" and PAD
ipaconfig:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
pac_type:
- "nfs:NONE"
- PAD
register: result
failed_when: not result.changed or result.failed
- name: Ensure config with pac_type "nfs:NONE" and PAD, again
ipaconfig:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
pac_type:
- "nfs:NONE"
- PAD
register: result
failed_when: result.changed or result.failed
- name: Ensure config with empty pac_type
ipaconfig:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
pac_type: ""
register: result
failed_when: not result.changed or result.failed
- name: Ensure config with empty pac_type, again
ipaconfig:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
pac_type: ""
register: result
failed_when: result.changed or result.failed
- name: Ensure config with user_auth_type otp and radius
ipaconfig:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
user_auth_type:
- otp
- radius
register: result
failed_when: not result.changed or result.failed
- name: Ensure config with user_auth_type otp and radius, again
ipaconfig:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
user_auth_type:
- otp
- radius
register: result
failed_when: result.changed or result.failed
- name: Ensure config with empty user_auth_type
ipaconfig:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
user_auth_type: ""
register: result
failed_when: not result.changed or result.failed
- name: Ensure config with empty user_auth_type, again
ipaconfig:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
user_auth_type: ""
register: result
failed_when: result.changed or result.failed
- name: Ensure config with configstring AllowNThash and "KDC:Disable Lockout"
ipaconfig:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
configstring:
- AllowNThash
- "KDC:Disable Lockout"
register: result
failed_when: not result.changed or result.failed
- name: Ensure config with configstring AllowNThash and "KDC:Disable Lockout", again
ipaconfig:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
configstring:
- AllowNThash
- "KDC:Disable Lockout"
register: result
failed_when: result.changed or result.failed
- name: Ensure config with empty configstring
ipaconfig:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
configstring: ""
register: result
failed_when: not result.changed or result.failed
- name: Ensure config with empty configstring, again
ipaconfig:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
configstring: ""
register: result
failed_when: result.changed or result.failed
# REVERT TO PREVIOUS CONFIG
- name: Reset to previous pac_type and user_auth_type
ipaconfig:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
pac_type: '{{ previousconfig.config.pac_type }}'
user_auth_type: '{{ previousconfig.config.user_auth_type }}'
configstring: '{{ previousconfig.config.configstring }}'

View File

@@ -31,4 +31,3 @@
dnssec: yes
skip_nameserver_check: yes
skip_overlap_check: yes
ignore_errors: yes

View File

@@ -15,12 +15,12 @@
- name: Verify if host is an IPA server or client.
shell:
cmd: |
echo SomeADMINpassword | kinit -c {{ KRB5CCNAME }} admin
RESULT=$(KRB5CCNAME={{ KRB5CCNAME }} ipa server-show `hostname` && echo SERVER || echo CLIENT)
kdestroy -A -c {{ KRB5CCNAME }}
echo SomeADMINpassword | kinit -c {{ krb5ccname }} admin
RESULT=$(KRB5CCNAME={{ krb5ccname }} ipa server-show `hostname` && echo SERVER || echo CLIENT)
kdestroy -A -c {{ krb5ccname }}
echo $RESULT
vars:
KRB5CCNAME: "__check_ipa_host_is_client_or_server__"
krb5ccname: "__check_ipa_host_is_client_or_server__"
register: output
- name: Set FreeIPA facts.

View File

@@ -2,23 +2,17 @@
- name: Test group
hosts: "{{ ipa_test_host | default('ipaserver') }}"
become: true
gather_facts: false
gather_facts: true
tasks:
# setup
- include_tasks: ../env_freeipa_facts.yml
# GET DOMAIN AND REALM
# GET FQDN_AT_DOMAIN
- name: Get Domain from server name
- name: Get fqdn_at_domain
set_fact:
ipaserver_domain: "{{ ansible_facts['fqdn'].split('.')[1:] | join ('.') }}"
when: ipaserver_domain is not defined
- name: Get Realm from server name
set_fact:
ipaserver_realm: "{{ ansible_facts['fqdn'].split('.')[1:] | join ('.') | upper }}"
when: ipaserver_realm is not defined
fqdn_at_domain: "{{ ansible_facts['fqdn'] + '@' + ipaserver_realm }}"
# CLEANUP TEST ITEMS
@@ -144,93 +138,93 @@
- block:
- name: Ensure service "{{ 'HTTP/ipaserver.' + ipaserver_domain + '@' + ipaserver_realm }}" is present in group group1
- name: Ensure service "{{ 'HTTP/' + fqdn_at_domain }}" is present in group group1
ipagroup:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: group1
service:
- "{{ 'HTTP/ipaserver.' + ipaserver_domain + '@' + ipaserver_realm }}"
- "{{ 'HTTP/' + fqdn_at_domain }}"
action: member
register: result
failed_when: not result.changed or result.failed
- name: Ensure service "{{ 'HTTP/ipaserver.' + ipaserver_domain + '@' + ipaserver_realm }}" is present in group group1, again
- name: Ensure service "{{ 'HTTP/' + fqdn_at_domain }}" is present in group group1, again
ipagroup:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: group1
service:
- "{{ 'HTTP/ipaserver.' + ipaserver_domain + '@' + ipaserver_realm }}"
- "{{ 'HTTP/' + fqdn_at_domain }}"
action: member
register: result
failed_when: result.changed or result.failed
- name: Ensure service "{{ 'ldap/ipaserver.' + ipaserver_domain + '@' + ipaserver_realm }}" is present in group group1
- name: Ensure service "{{ 'ldap/' + fqdn_at_domain }}" is present in group group1
ipagroup:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: group1
service:
- "{{ 'ldap/ipaserver.' + ipaserver_domain + '@' + ipaserver_realm }}"
- "{{ 'ldap/' + fqdn_at_domain }}"
action: member
register: result
failed_when: not result.changed or result.failed
- name: Ensure service "{{ 'ldap/ipaserver.' + ipaserver_domain + '@' + ipaserver_realm }}" is present in group group1, again
- name: Ensure service "{{ 'ldap/' + fqdn_at_domain }}" is present in group group1, again
ipagroup:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: group1
service:
- "{{ 'ldap/ipaserver.' + ipaserver_domain + '@' + ipaserver_realm }}"
- "{{ 'ldap/' + fqdn_at_domain }}"
action: member
register: result
failed_when: result.changed or result.failed
- name: Ensure service "{{ 'HTTP/ipaserver.' + ipaserver_domain + '@' + ipaserver_realm }}" is absent in group group1
- name: Ensure service "{{ 'HTTP/' + fqdn_at_domain }}" is absent in group group1
ipagroup:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: group1
service:
- "{{ 'HTTP/ipaserver.' + ipaserver_domain + '@' + ipaserver_realm }}"
- "{{ 'HTTP/' + fqdn_at_domain }}"
action: member
state: absent
register: result
failed_when: not result.changed or result.failed
- name: Ensure service "{{ 'HTTP/ipaserver.' + ipaserver_domain + '@' + ipaserver_realm }}" is absent in group group1, again
- name: Ensure service "{{ 'HTTP/' + fqdn_at_domain }}" is absent in group group1, again
ipagroup:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: group1
service:
- "{{ 'HTTP/ipaserver.' + ipaserver_domain + '@' + ipaserver_realm }}"
- "{{ 'HTTP/' + fqdn_at_domain }}"
action: member
state: absent
register: result
failed_when: result.changed or result.failed
- name: Ensure service "{{ 'ldap/ipaserver.' + ipaserver_domain + '@' + ipaserver_realm }}" is absent in group group1
- name: Ensure service "{{ 'ldap/' + fqdn_at_domain }}" is absent in group group1
ipagroup:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: group1
service:
- "{{ 'ldap/ipaserver.' + ipaserver_domain + '@' + ipaserver_realm }}"
- "{{ 'ldap/' + fqdn_at_domain }}"
action: member
state: absent
register: result
failed_when: not result.changed or result.failed
- name: Ensure service "{{ 'ldap/ipaserver.' + ipaserver_domain + '@' + ipaserver_realm }}" is absent in group group1, again
- name: Ensure service "{{ 'ldap/' + fqdn_at_domain }}" is absent in group group1, again
ipagroup:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: group1
service:
- "{{ 'ldap/ipaserver.' + ipaserver_domain + '@' + ipaserver_realm }}"
- "{{ 'ldap/' + fqdn_at_domain }}"
action: member
state: absent
register: result
@@ -242,8 +236,8 @@
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: group1
service:
- "{{ 'HTTP/ipaserver.' + ipaserver_domain + '@' + ipaserver_realm }}"
- "{{ 'ldap/ipaserver.' + ipaserver_domain + '@' + ipaserver_realm }}"
- "{{ 'HTTP/' + fqdn_at_domain }}"
- "{{ 'ldap/' + fqdn_at_domain }}"
action: member
register: result
failed_when: not result.changed or result.failed
@@ -254,8 +248,8 @@
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: group1
service:
- "{{ 'http/ipaserver.' + ipaserver_domain + '@' + ipaserver_realm }}"
- "{{ 'ldap/ipaserver.' + ipaserver_domain + '@' + ipaserver_realm }}"
- "{{ 'http/' + fqdn_at_domain }}"
- "{{ 'ldap/' + fqdn_at_domain }}"
action: member
register: result
failed_when: result.changed or result.failed
@@ -266,8 +260,8 @@
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: group1
service:
- "{{ 'HTTP/ipaserver.' + ipaserver_domain + '@' + ipaserver_realm }}"
- "{{ 'LDAP/ipaserver.' + ipaserver_domain + '@' + ipaserver_realm }}"
- "{{ 'HTTP/' + fqdn_at_domain }}"
- "{{ 'LDAP/' + fqdn_at_domain }}"
action: member
state: absent
register: result
@@ -279,8 +273,8 @@
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: group1
service:
- "{{ 'HTTP/ipaserver.' + ipaserver_domain + '@' + ipaserver_realm }}"
- "{{ 'ldap/ipaserver.' + ipaserver_domain + '@' + ipaserver_realm }}"
- "{{ 'HTTP/' + fqdn_at_domain }}"
- "{{ 'ldap/' + fqdn_at_domain }}"
action: member
state: absent
register: result

View File

@@ -0,0 +1,104 @@
---
- name: Test group
hosts: ipaserver
become: yes
gather_facts: yes
vars:
ad_user: "{{ test_ad_user | default('AD\\aduser') }}"
ad_domain: "{{ test_ad_domain | default('ad.ipa.test') }}"
tasks:
- include_tasks: ../env_freeipa_facts.yml
- block:
- name: Create idoverrideuser.
shell: |
kinit -c idoverride_cache admin <<< SomeADMINpassword
ipa idoverrideuser-add "Default Trust View" {{ ad_user }}
kdestroy -A -q -c idoverride_cache
- name: Remove testing groups.
ipagroup:
ipaadmin_password: SomeADMINpassword
name:
- idovergroup
state: absent
- name: Add group with idoverrideuser.
ipagroup:
ipaadmin_password: SomeADMINpassword
name: idovergroup
idoverrideuser: "{{ ad_user }}"
register: result
failed_when: result.failed or not result.changed
- name: Add group with idoverrideuser, again.
ipagroup:
ipaadmin_password: SomeADMINpassword
name: idovergroup
idoverrideuser: "{{ ad_user }}"
register: result
failed_when: result.failed or result.changed
- name: Remove idoverrideuser member.
ipagroup:
ipaadmin_password: SomeADMINpassword
name: idovergroup
idoverrideuser: "{{ ad_user }}"
action: member
state: absent
register: result
failed_when: result.failed or not result.changed
- name: Remove idoverrideuser member, again.
ipagroup:
ipaadmin_password: SomeADMINpassword
name: idovergroup
idoverrideuser: "{{ ad_user }}"
action: member
state: absent
register: result
failed_when: result.failed or result.changed
- name: Add idoverrideuser member.
ipagroup:
ipaadmin_password: SomeADMINpassword
name: idovergroup
idoverrideuser: "{{ ad_user }}"
action: member
register: result
failed_when: result.failed or not result.changed
- name: Add idoverrideuser member, again.
ipagroup:
ipaadmin_password: SomeADMINpassword
name: idovergroup
idoverrideuser: "{{ ad_user }}"
action: member
register: result
failed_when: result.failed or result.changed
- name: Cleanup idoverrideuser member.
ipagroup:
ipaadmin_password: SomeADMINpassword
name: idovergroup
idoverrideuser: "{{ ad_user }}"
state: absent
- name: Remove testing groups.
ipagroup:
ipaadmin_password: SomeADMINpassword
name:
- idovergroup
state: absent
always:
- name: Remove idoverrideuser.
shell: |
kinit -c idoverride_cache admin <<< SomeADMINpassword
ipa idoverrideuser-del "Default Trust View" {{ ad_user }}
kdestroy -A -q -c idoverride_cache
when:
when: ipa_version is version("4.8.7", ">=") and trust_test_is_supported | default(false)

View File

@@ -0,0 +1,296 @@
---
- name: Test hbacrule
hosts: "{{ ipa_test_host | default('ipaserver') }}"
become: true
tasks:
- name: Get Domain from server name
set_fact:
ipaserver_domain: "{{ ansible_facts['fqdn'].split('.')[1:] | join ('.') }}"
when: ipaserver_domain is not defined
- block:
# SETUP:
- name: Ensure test HBAC rule is absent
ipahbacrule:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: hbacrule01
state: absent
- name: Ensure test hosts are present
ipahost:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
hosts:
- name: "{{ 'testhost03.' + ipaserver_domain }}"
force: yes
- name: "{{ 'testhost04.' + ipaserver_domain }}"
force: yes
- name: Ensure test hostgroups are present
ipahostgroup:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: "{{ item }}"
with_items:
- testhostgroup03
- testhostgroup04
- name: Ensure test users are present
ipauser:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
users:
- name: testuser03
first: test
last: user03
- name: testuser04
first: test
last: user04
- name: Ensure test groups are present
ipagroup:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: "{{ item }}"
with_items:
- testgroup03
- testgroup04
- name: Ensure test HBAC Services are present
ipahbacsvc:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: "{{ item }}"
with_items:
- testhbacsvc03
- testhbacsvc04
- name: Ensure test HBAC Service Groups are present
ipahbacsvcgroup:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: "{{ item }}"
with_items:
- testhbacsvcgroup03
- testhbacsvcgroup04
- name: Ensure test HBAC rule hbacrule01 is absent
ipahbacrule:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: hbacrule01
state: absent
# Ensure members are empty.
- name: Ensure HBAC rule is present with known members
ipahbacrule:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: hbacrule01
host:
- "{{ 'testhost03.' + ipaserver_domain }}"
- "{{ 'testhost04.' + ipaserver_domain }}"
hostgroup: testhostgroup03,testhostgroup04
user: testuser03,testuser04
group: testgroup03,testgroup04
hbacsvc: testhbacsvc03,testhbacsvc04
hbacsvcgroup: testhbacsvcgroup03,testhbacsvcgroup04
register: result
failed_when: not result.changed or result.failed
- name: Ensure test HBAC rule host is empty
ipahbacrule:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: hbacrule01
host: []
register: result
failed_when: not result.changed or result.failed
- name: Ensure test HBAC rule host is empty, again
ipahbacrule:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: hbacrule01
host: []
register: result
failed_when: result.changed or result.failed
- name: Ensure test HBAC rule hostgroup is empty
ipahbacrule:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: hbacrule01
hostgroup: []
register: result
failed_when: not result.changed or result.failed
- name: Ensure test HBAC rule hostgroup is empty, again
ipahbacrule:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: hbacrule01
hostgroup: []
register: result
failed_when: result.changed or result.failed
- name: Ensure test HBAC rule user is empty
ipahbacrule:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: hbacrule01
user: []
register: result
failed_when: not result.changed or result.failed
- name: Ensure test HBAC rule user is empty, again
ipahbacrule:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: hbacrule01
user: []
register: result
failed_when: result.changed or result.failed
- name: Ensure test HBAC rule group is empty
ipahbacrule:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: hbacrule01
group: []
register: result
failed_when: not result.changed or result.failed
- name: Ensure test HBAC rule group is empty, again
ipahbacrule:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: hbacrule01
group: []
register: result
failed_when: result.changed or result.failed
- name: Ensure test HBAC rule hbacsvc is empty
ipahbacrule:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: hbacrule01
hbacsvc: []
register: result
failed_when: not result.changed or result.failed
- name: Ensure test HBAC rule hbacsvc is empty, again
ipahbacrule:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: hbacrule01
hbacsvc: []
register: result
failed_when: result.changed or result.failed
- name: Ensure test HBAC rule hbacsvcgroup is empty
ipahbacrule:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: hbacrule01
hbacsvcgroup: []
register: result
failed_when: not result.changed or result.failed
- name: Ensure test HBAC rule hbacsvcgroup is empty, again
ipahbacrule:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: hbacrule01
hbacsvcgroup: []
register: result
failed_when: result.changed or result.failed
- name: Verify HBAC rule is present with only members would not require changes.
ipahbacrule:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: hbacrule01
host: []
hostgroup: []
user: []
group: []
hbacsvc: []
hbacsvcgroup: []
check_mode: yes
register: result
failed_when: result.changed or result.failed
- name: Verify HBAC rule is present with known members would require changes.
ipahbacrule:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: hbacrule01
host:
- "{{ 'testhost03.' + ipaserver_domain }}"
- "{{ 'testhost04.' + ipaserver_domain }}"
hostgroup: testhostgroup03,testhostgroup04
user: testuser03,testuser04
group: testgroup03,testgroup04
hbacsvc: testhbacsvc03,testhbacsvc04
hbacsvcgroup: testhbacsvcgroup03,testhbacsvcgroup04
check_mode: yes
register: result
failed_when: not result.changed or result.failed
always:
# CLEANUP
- name: Ensure test HBAC rule is absent
ipahbacrule:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: hbacrule01
state: absent
- name: Ensure test HBAC Service Groups are absent
ipahbacsvcgroup:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: testhbacsvcgroup01,testhbacsvcgroup02,testhbacsvcgroup03,testhbacsvcgroup04
state: absent
- name: Ensure test HBAC Services are absent
ipahbacsvc:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: testhbacsvc01,testhbacsvc02,testhbacsvc03,testhbacsvc04
state: absent
- name: Ensure test hostgroups are absent
ipahostgroup:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: testhostgroup01,testhostgroup02,testhostgroup03,testhostgroup04
state: absent
- name: Ensure test hosts are absent
ipahost:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name:
- "{{ 'testhost01.' + ipaserver_domain }}"
- "{{ 'testhost02.' + ipaserver_domain }}"
- "{{ 'testhost03.' + ipaserver_domain }}"
- "{{ 'testhost04.' + ipaserver_domain }}"
state: absent
- name: Ensure test user groups are absent
ipagroup:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: testgroup01,testgroup02,testgroup03,testgroup04
state: absent
- name: Ensure test users are absent
ipauser:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: testuser01,testuser02,testuser03,testuser04
state: absent

View File

@@ -0,0 +1,86 @@
---
- name: Test host
hosts: "{{ ipa_test_host | default('ipaserver') }}"
become: yes
gather_facts: yes
tasks:
- name: Get Domain from server name
set_fact:
ipaserver_domain: "{{ ansible_facts['fqdn'].split('.')[1:] | join ('.') }}"
when: ipaserver_domain is not defined
- name: Set host1_fqdn .. host6_fqdn
set_fact:
host1_fqdn: "{{ 'host1.' + ipaserver_domain }}"
# CLEANUP TEST ITEMS
- name: Ensure host "{{ host1_fqdn }}" absent
ipahost:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: "{{ host1_fqdn }}"
state: absent
# CREATE TEST ITEMS
- name: Ensure host "{{ host1_fqdn }}" present
ipahost:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: "{{ host1_fqdn }}"
force: yes
register: result
failed_when: not result.changed or result.failed
# TESTS
- name: Ensure host "{{ host1_fqdn }}" present with auth_ind otp and radius
ipahost:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: "{{ host1_fqdn }}"
auth_ind:
- otp
- radius
register: result
failed_when: not result.changed or result.failed
- name: Ensure host "{{ host1_fqdn }}" present with auth_ind otp and radius, again
ipahost:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: "{{ host1_fqdn }}"
auth_ind:
- otp
- radius
register: result
failed_when: result.changed or result.failed
- name: Ensure host "{{ host1_fqdn }}" present with empty auth_ind
ipahost:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: "{{ host1_fqdn }}"
auth_ind: ""
register: result
failed_when: not result.changed or result.failed
- name: Ensure host "{{ host1_fqdn }}" present with empty auth_ind, again
ipahost:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: "{{ host1_fqdn }}"
auth_ind: ""
register: result
failed_when: result.changed or result.failed
# CLEANUP TEST ITEMS
- name: Ensure host "{{ host1_fqdn }}" absent
ipahost:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: "{{ host1_fqdn }}"
state: absent

View File

@@ -0,0 +1,24 @@
---
- name: Ensure testing trust is absent
ipatrust:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
realm: "{{ adserver.domain }}"
state: absent
- name: Ensure testing idranges are absent
ipaidrange:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name:
- "{{ adserver.realm }}_id_range"
continue: yes
state: absent
- name: Remove dns forward zone
ipadnsforwardzone:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: "{{ adserver.domain }}"
state: absent
when: trust_dnszone is defined and trust_dnszone.changed

View File

@@ -0,0 +1,36 @@
---
- name: Ensure DNS forward zone to Windows AD
ipadnsforwardzone:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: "{{ adserver.domain }}"
forwarders:
- ip_address: "{{ adserver.ip_address }}"
forwardpolicy: first
register: trust_dnszone
- name: Set trust to Widows AD
ipatrust:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
realm: "{{ adserver.domain }}"
admin: Administrator
password: "{{ adserver.password }}"
base_id: "{{ trust_base_id | default(omit) }}"
range_type: "{{ trust_range_type | default(omit) }}"
range_size: "{{ trust_range_size | default(omit) }}"
register: result
failed_when: result.failed
- name: Retrieve Domain Security Identifier
shell:
cmd: |
kinit -c test_krb5_cache admin <<< SomeADMINpassword > /dev/null
KRB5CCNAME=test_krb5_cache ipa trust-show {{ adserver.domain }} | sed -n "/Domain Security Identifier/s/ //gp" | cut -d":" -f2
kdestroy -c test_krb5_cache -A -q > /dev/null
register: getsid
no_log: yes
- name: Set ipa_domain_sid.
set_fact:
ipa_domain_sid: "{{ getsid.stdout }}"

View File

@@ -0,0 +1,280 @@
---
- name: Test idrange
hosts: "{{ ipa_test_host | default('ipaserver') }}"
become: no
gather_facts: no
vars:
adserver:
domain: "{{ winserver_domain | default('windows.local')}}"
realm: "{{ winserver_realm | default(winserver_domain) | default('windows.local') | upper }}"
password: "{{ winserver_admin_password | default('SomeW1Npassword') }}"
ip_address: "{{ winserver_ip | default(omit) }}"
tasks:
# CLEANUP TEST ITEMS
- name: Remove test trust.
include_tasks: tasks_remove_trust.yml
when: trust_test_is_supported | default(false)
- name: Ensure testing idranges are absent
ipaidrange:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name:
- "{{ adserver.realm }}_id_range"
- local_id_range
- ad_id_range
- ad_posix_id_range
continue: yes
state: absent
# CREATE TEST ITEMS
# TESTS
# Test local idrange, only if ipa-adtrust-install was not executed.
- block:
- name: Ensure idrange with minimal attributes is present
ipaidrange:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: local_id_range
base_id: 150000000
range_size: 200000
register: result
failed_when:
not (result.failed or result.changed) or (result.failed and 'ipa-adtrust-install has already been run' not in result.msg)
- name: Ensure idrange with minimal attributes is present, again
ipaidrange:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: local_id_range
base_id: 150000000
range_size: 200000
register: result
failed_when:
result.changed or (result.failed and 'ipa-adtrust-install has already been run' not in result.msg)
- name: Ensure idrange with minimal attributes is absent
ipaidrange:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: local_id_range
state: absent
register: range_delete
failed_when: range_delete.failed or (result.changed and not range_delete.changed)
# Test local idrange, even after ipa-adtrust-install.
- name: Ensure local idrange is present
ipaidrange:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: local_id_range
base_id: 150000000
range_size: 200000
rid_base: 1000000
secondary_rid_base: 200000000
register: result
failed_when: not result.changed or result.failed
- name: Ensure local idrange is present again
ipaidrange:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: local_id_range
base_id: 150000000
range_size: 200000
rid_base: 1000000
secondary_rid_base: 200000000
register: result
failed_when: result.changed or result.failed
- name: Ensure local idrange is absent
ipaidrange:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: local_id_range
state: absent
continue: no
register: result
failed_when: not result.changed or result.failed
- name: Ensure local idrange is absent again
ipaidrange:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: local_id_range
state: absent
continue: no
register: result
failed_when: result.changed or result.failed
rescue:
- name: Ensure local idranges is absent
ipaidrange:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: local_id_range
- block:
# Create trust with range_type: ipa-ad-trust-posix
- name: Create trust with range_type 'ipa-ad-trust'
include_tasks: tasks_set_trust.yml
vars:
trust_base_id: 10000000
trust_range_size: 200000
trust_range_type: ipa-ad-trust
# Can't user secondary_rid_base with dom_sid/dom_name
- name: Ensure AD-trust idrange is present
ipaidrange:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: ad_id_range
base_id: 150000000
range_size: 200000
rid_base: 1000000
idrange_type: ipa-ad-trust
dom_sid: "{{ ipa_domain_sid }}"
auto_private_groups: "false"
register: result
failed_when: not result.changed or result.failed
- name: Ensure AD-trust idrange is present again
ipaidrange:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: ad_id_range
base_id: 150000000
range_size: 200000
rid_base: 1000000
idrange_type: ipa-ad-trust
dom_sid: "{{ ipa_domain_sid }}"
auto_private_groups: "false"
register: result
failed_when: result.changed or result.failed
- name: Check if AD-trust idrange is present, uning domain name
ipaidrange:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: ad_id_range
base_id: 150000000
range_size: 200000
rid_base: 1000000
idrange_type: ipa-ad-trust
dom_name: "{{ adserver.domain }}"
auto_private_groups: "false"
check_mode: true
register: result
failed_when: result.changed or result.failed
- name: Modify AD-trust idrange 'base_id'
ipaidrange:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: ad_id_range
base_id: 151230000
register: result
failed_when: not result.changed or result.failed
- name: Modify AD-trust idrange 'base_id', again
ipaidrange:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: ad_id_range
base_id: 151230000
register: result
failed_when: result.changed or result.failed
- name: Modify AD-trust idrange 'range_size'
ipaidrange:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: ad_id_range
range_size: 100000
register: result
failed_when: not result.changed or result.failed
- name: Modify AD-trust idrange 'rid_base'
ipaidrange:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: ad_id_range
rid_base: 12345678
register: result
failed_when: not result.changed or result.failed
- name: Modify AD-trust idrange 'auto_private_groups'
ipaidrange:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: ad_id_range
auto_private_groups: "hybrid"
register: result
failed_when: not result.changed or result.failed
# Remove trust and idrange
- name: Remove test trust.
include_tasks: tasks_remove_trust.yml
- name: Ensure AD-trust idrange is absent
ipaidrange:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: ad_id_range
state: absent
# Create trust with range_type: ipa-ad-trust-posix
- name: Create trust with range_type 'ipa-ad-trust-posix'
include_tasks: tasks_set_trust.yml
vars:
trust_base_id: 10000000
trust_range_size: 2000000
trust_range_type: ipa-ad-trust-posix
# Can't user secondary_rid_base or rid_base with "ad-trust-posix"
- name: Ensure AD-trust-posix idrange is present
ipaidrange:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: ad_posix_id_range
base_id: 150000000
range_size: 200000
idrange_type: ipa-ad-trust-posix
dom_sid: "{{ ipa_domain_sid }}"
register: result
failed_when: not result.changed or result.failed
- name: Ensure AD-trust-posix idrange is present again
ipaidrange:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: ad_posix_id_range
base_id: 150000000
range_size: 200000
idrange_type: ipa-ad-trust-posix
dom_sid: "{{ ipa_domain_sid }}"
register: result
failed_when: result.changed or result.failed
always:
# CLEANUP TEST ITEMS
- name: Remove test trust.
include_tasks: tasks_remove_trust.yml
- name: Ensure testing idranges are absent
ipaidrange:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name:
- "{{ adserver.realm }}_id_range"
- local_id_range
- ad_id_range
- ad_posix_id_range
continue: yes
state: absent
when: trust_test_is_supported | default(false)

View File

@@ -0,0 +1,39 @@
---
- name: Test idrange
hosts: ipaclients, ipaserver
# Change "become" or "gather_facts" to "yes",
# if you test playbook requires any.
become: no
gather_facts: no
tasks:
- name: Include FreeIPA facts.
include_tasks: ../env_freeipa_facts.yml
# Test will only be executed if host is not a server.
- name: Execute with server context in the client.
ipaidrange:
ipaadmin_password: SomeADMINpassword
ipaapi_context: server
name: ThisShouldNotWork
register: result
failed_when: not (result.failed and result.msg is regex("No module named '*ipaserver'*"))
when: ipa_host_is_client
# Import basic module tests, and execute with ipa_context set to 'client'.
# If ipaclients is set, it will be executed using the client, if not,
# ipaserver will be used.
#
# With this setup, tests can be executed against an IPA client, against
# an IPA server using "client" context, and ensure that tests are executed
# in upstream CI.
- name: Test idrange using client context, in client host.
import_playbook: test_idrange.yml
when: groups['ipaclients']
vars:
ipa_test_host: ipaclients
- name: Test idrange using client context, in server host.
import_playbook: test_idrange.yml
when: groups['ipaclients'] is not defined or not groups['ipaclients']

View File

@@ -43,9 +43,9 @@
- name: Verify role privileges.
shell:
cmd: |
echo SomeADMINpassword | kinit -c {{ KRB5CCNAME }} admin
KRB5CCNAME={{ KRB5CCNAME }} ipa role-show testrole
kdestroy -A -q -c {{ KRB5CCNAME }}
echo SomeADMINpassword | kinit -c {{ krb5ccname }} admin
KRB5CCNAME={{ krb5ccname }} ipa role-show testrole
kdestroy -A -q -c {{ krb5ccname }}
register: result
failed_when: |
result.failed or not (
@@ -57,7 +57,7 @@
and "Group Administrators" in result.stdout
)
vars:
KRB5CCNAME: verify_issue_409
krb5ccname: verify_issue_409
# End of test fix for https://github.com/freeipa/ansible-freeipa/issues/409
# Test fix for https://github.com/freeipa/ansible-freeipa/issues/412
@@ -73,9 +73,9 @@
- name: Verify role users.
shell:
cmd: |
echo SomeADMINpassword | kinit -c {{ KRB5CCNAME }} admin
KRB5CCNAME={{ KRB5CCNAME }} ipa role-show testrole
kdestroy -A -q -c {{ KRB5CCNAME }}
echo SomeADMINpassword | kinit -c {{ krb5ccname }} admin
KRB5CCNAME={{ krb5ccname }} ipa role-show testrole
kdestroy -A -q -c {{ krb5ccname }}
register: result
failed_when: |
result.failed or not (
@@ -83,7 +83,7 @@
and "user02" in result.stdout
)
vars:
KRB5CCNAME: verify_issue_412
krb5ccname: verify_issue_412
- name: Add new group to role.
iparole:
@@ -97,9 +97,9 @@
- name: Verify role group.
shell:
cmd: |
echo SomeADMINpassword | kinit -c {{ KRB5CCNAME }} admin
KRB5CCNAME={{ KRB5CCNAME }} ipa role-show testrole
kdestroy -A -q -c {{ KRB5CCNAME }}
echo SomeADMINpassword | kinit -c {{ krb5ccname }} admin
KRB5CCNAME={{ krb5ccname }} ipa role-show testrole
kdestroy -A -q -c {{ krb5ccname }}
register: result
failed_when: |
result.failed or not (
@@ -107,7 +107,7 @@
and "group02" in result.stdout
)
vars:
KRB5CCNAME: verify_issue_412
krb5ccname: verify_issue_412
- name: Add new host to role.
iparole:
@@ -121,9 +121,9 @@
- name: Verify role hosts.
shell:
cmd: |
echo SomeADMINpassword | kinit -c {{ KRB5CCNAME }} admin
KRB5CCNAME={{ KRB5CCNAME }} ipa role-show testrole
kdestroy -A -q -c {{ KRB5CCNAME }}
echo SomeADMINpassword | kinit -c {{ krb5ccname }} admin
KRB5CCNAME={{ krb5ccname }} ipa role-show testrole
kdestroy -A -q -c {{ krb5ccname }}
register: result
failed_when: |
result.failed or not (
@@ -131,7 +131,7 @@
and host2 in result.stdout
)
vars:
KRB5CCNAME: verify_issue_412
krb5ccname: verify_issue_412
host1: " {{ host1_fqdn }}"
host2: " {{ host2_fqdn }}"
@@ -147,9 +147,9 @@
- name: Verify role hostgroups.
shell:
cmd: |
echo SomeADMINpassword | kinit -c {{ KRB5CCNAME }} admin
KRB5CCNAME={{ KRB5CCNAME }} ipa role-show testrole
kdestroy -A -q -c {{ KRB5CCNAME }}
echo SomeADMINpassword | kinit -c {{ krb5ccname }} admin
KRB5CCNAME={{ krb5ccname }} ipa role-show testrole
kdestroy -A -q -c {{ krb5ccname }}
register: result
failed_when: |
result.failed or not (
@@ -157,7 +157,7 @@
and " hostgroup02" in result.stdout
)
vars:
KRB5CCNAME: verify_issue_412
krb5ccname: verify_issue_412
- name: Add new service to role.
iparole:
@@ -171,9 +171,9 @@
- name: Verify role services.
shell:
cmd: |
echo SomeADMINpassword | kinit -c {{ KRB5CCNAME }} admin
KRB5CCNAME={{ KRB5CCNAME }} ipa role-show testrole
kdestroy -A -q -c {{ KRB5CCNAME }}
echo SomeADMINpassword | kinit -c {{ krb5ccname }} admin
KRB5CCNAME={{ krb5ccname }} ipa role-show testrole
kdestroy -A -q -c {{ krb5ccname }}
register: result
failed_when: |
result.failed or not (
@@ -181,7 +181,7 @@
and service1 in result.stdout
)
vars:
KRB5CCNAME: verify_issue_412
krb5ccname: verify_issue_412
service1: "service01/{{ host1_fqdn }}"
service2: "service02/{{ host2_fqdn }}"
# End of test fix for https://github.com/freeipa/ansible-freeipa/issues/412
@@ -199,9 +199,9 @@
- name: Verify role services.
shell:
cmd: |
echo SomeADMINpassword | kinit -c {{ KRB5CCNAME }} admin
KRB5CCNAME={{ KRB5CCNAME }} ipa role-show testrole
kdestroy -A -q -c {{ KRB5CCNAME }}
echo SomeADMINpassword | kinit -c {{ krb5ccname }} admin
KRB5CCNAME={{ krb5ccname }} ipa role-show testrole
kdestroy -A -q -c {{ krb5ccname }}
register: result
failed_when: |
result.failed or not (
@@ -210,7 +210,7 @@
and "user03" in result.stdout
)
vars:
KRB5CCNAME: verify_issue_413
krb5ccname: verify_issue_413
service1: "service01/{{ host1_fqdn }}"
service2: "service02/{{ host2_fqdn }}"
@@ -227,9 +227,9 @@
- name: Verify role services.
shell:
cmd: |
echo SomeADMINpassword | kinit -c {{ KRB5CCNAME }} admin
KRB5CCNAME={{ KRB5CCNAME }} ipa role-show testrole
kdestroy -A -q -c {{ KRB5CCNAME }}
echo SomeADMINpassword | kinit -c {{ krb5ccname }} admin
KRB5CCNAME={{ krb5ccname }} ipa role-show testrole
kdestroy -A -q -c {{ krb5ccname }}
register: result
failed_when: |
result.failed or not (
@@ -238,7 +238,7 @@
and "user03" not in result.stdout
)
vars:
KRB5CCNAME: verify_issue_413
krb5ccname: verify_issue_413
service1: "service01/{{ host1_fqdn }}"
service2: "service02/{{ host2_fqdn }}"
# End of test fix for https://github.com/freeipa/ansible-freeipa/issues/413

View File

@@ -0,0 +1,110 @@
---
- name: Test service
hosts: "{{ ipa_test_host | default('ipaserver') }}"
become: yes
gather_facts: yes
tasks:
# CLEANUP TEST ITEMS
- name: Ensure service "test-service/{{ ansible_facts['fqdn'] }}" is absent.
ipaservice:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: "test-service/{{ ansible_facts['fqdn'] }}"
continue: yes
state: absent
# CREATE TEST ITEMS
- name: Ensure service "test-service/{{ ansible_facts['fqdn'] }}" is present
ipaservice:
ipaadmin_password: SomeADMINpassword
name: "test-service/{{ ansible_facts['fqdn'] }}"
register: result
failed_when: not result.changed or result.failed
# TESTS
- name: Ensure service "test-service/{{ ansible_facts['fqdn'] }}" is present with pac_type MS-PAC and PAD
ipaservice:
ipaadmin_password: SomeADMINpassword
name: "test-service/{{ ansible_facts['fqdn'] }}"
pac_type:
- MS-PAC
- PAD
register: result
failed_when: not result.changed or result.failed
- name: Ensure service "test-service/{{ ansible_facts['fqdn'] }}" is present with pac_type MS-PAC and PAD, again
ipaservice:
ipaadmin_password: SomeADMINpassword
name: "test-service/{{ ansible_facts['fqdn'] }}"
pac_type:
- MS-PAC
- PAD
register: result
failed_when: result.changed or result.failed
- name: Ensure service "test-service/{{ ansible_facts['fqdn'] }}" is present with empty pac_type
ipaservice:
ipaadmin_password: SomeADMINpassword
name: "test-service/{{ ansible_facts['fqdn'] }}"
pac_type: ""
register: result
failed_when: not result.changed or result.failed
- name: Ensure service "test-service/{{ ansible_facts['fqdn'] }}" is present with empty pac_type, again
ipaservice:
ipaadmin_password: SomeADMINpassword
name: "test-service/{{ ansible_facts['fqdn'] }}"
pac_type: ""
register: result
failed_when: result.changed or result.failed
- name: Ensure service "test-service/{{ ansible_facts['fqdn'] }}" is present with auth_ind otp and radius
ipaservice:
ipaadmin_password: SomeADMINpassword
name: "test-service/{{ ansible_facts['fqdn'] }}"
auth_ind:
- otp
- radius
register: result
failed_when: not result.changed or result.failed
- name: Ensure service "test-service/{{ ansible_facts['fqdn'] }}" is present with auth_ind otp and radius, again
ipaservice:
ipaadmin_password: SomeADMINpassword
name: "test-service/{{ ansible_facts['fqdn'] }}"
auth_ind:
- otp
- radius
register: result
failed_when: result.changed or result.failed
- name: Ensure service "test-service/{{ ansible_facts['fqdn'] }}" is present with empty auth_ind
ipaservice:
ipaadmin_password: SomeADMINpassword
name: "test-service/{{ ansible_facts['fqdn'] }}"
auth_ind: ""
register: result
failed_when: not result.changed or result.failed
- name: Ensure service "test-service/{{ ansible_facts['fqdn'] }}" is present with empty auth_ind, again
ipaservice:
ipaadmin_password: SomeADMINpassword
name: "test-service/{{ ansible_facts['fqdn'] }}"
auth_ind: ""
register: result
failed_when: result.changed or result.failed
# CLEANUP TEST ITEMS
- name: Ensure service "test-service/{{ ansible_facts['fqdn'] }}" is absent.
ipaservice:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: "test-service/{{ ansible_facts['fqdn'] }}"
continue: yes
state: absent

View File

@@ -0,0 +1,214 @@
---
- name: Test servicedelegationrule
hosts: "{{ ipa_test_host | default('ipaserver') }}"
# Change "become" or "gather_facts" to "yes",
# if you test playbook requires any.
become: no
gather_facts: yes
tasks:
# CLEANUP TEST ITEMS
- name: Ensure servicedelegationrule test-delegation-rule is absent
ipaservicedelegationrule:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: test-delegation-rule
state: absent
- name: Ensure service is absent
ipaservice:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name:
- "{{ 'test-service/' + ansible_facts['fqdn'] }}"
- "{{ 'not-existing-test-service/' + ansible_facts['fqdn'] }}"
state: absent
continue: yes
- name: Ensure servicedelegationrule test-delegation-target is absent
ipaservicedelegationtarget:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name:
- test-delegation-target
- not-existing-test-delegation-target
state: absent
# CREATE TEST ITEMS
- name: Ensure service test-sevice is present
ipaservice:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: "{{ 'test-service/' + ansible_facts['fqdn'] }}"
register: result
failed_when: not result.changed or result.failed
- name: Ensure servicedelegationrule test-delegation-target is present
ipaservicedelegationtarget:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: test-delegation-target
register: result
failed_when: not result.changed or result.failed
# TESTS
- name: Ensure servicedelegationrule test-delegation-rule is present
ipaservicedelegationrule:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: test-delegation-rule
register: result
failed_when: not result.changed or result.failed
- name: Ensure servicedelegationrule test-delegation-rule is present again
ipaservicedelegationrule:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: test-delegation-rule
register: result
failed_when: result.changed or result.failed
- name: Do not fail to ensure absence of not existing servicedelegationrule test-delegation-rule member principal
ipaservicedelegationrule:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: test-delegation-rule
principal: "{{ 'not-existing-test-service/' + ansible_facts['fqdn'] }}"
action: member
state: absent
register: result
failed_when: result.changed or result.failed
- name: Do not fail to ensure absence of not existing servicedelegationrule test-delegation-rule member target
ipaservicedelegationrule:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: test-delegation-rule
target: not-existing-test-delegation-target
action: member
state: absent
register: result
failed_when: result.changed or result.failed
- name: Ensure servicedelegationrule test-delegation-rule member target test-delegation-target is present
ipaservicedelegationrule:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: test-delegation-rule
target: test-delegation-target
action: member
register: result
failed_when: not result.changed or result.failed
- name: Ensure servicedelegationrule test-delegation-rule member target test-delegation-target is present, again
ipaservicedelegationrule:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: test-delegation-rule
target: test-delegation-target
action: member
register: result
failed_when: result.changed or result.failed
- name: Ensure servicedelegationrule test-delegation-rule member principal "{{ 'test-service/' + ansible_facts['fqdn'] }}" is present
ipaservicedelegationrule:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: test-delegation-rule
principal: "{{ 'test-service/' + ansible_facts['fqdn'] }}"
action: member
register: result
failed_when: not result.changed or result.failed
- name: Ensure servicedelegationrule test-delegation-rule member principal "{{ 'test-service/' + ansible_facts['fqdn'] }}" is present again
ipaservicedelegationrule:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: test-delegation-rule
principal: "{{ 'test-service/' + ansible_facts['fqdn'] }}"
action: member
register: result
failed_when: result.changed or result.failed
- name: Ensure servicedelegationrule test-delegation-rule member principal "{{ 'test-service/' + ansible_facts['fqdn'] }}" is absent
ipaservicedelegationrule:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: test-delegation-rule
principal: "{{ 'test-service/' + ansible_facts['fqdn'] }}"
action: member
state: absent
register: result
failed_when: not result.changed or result.failed
- name: Ensure servicedelegationrule test-delegation-rule member principal "{{ 'test-service/' + ansible_facts['fqdn'] }}" is present absent
ipaservicedelegationrule:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: test-delegation-rule
principal: "{{ 'test-service/' + ansible_facts['fqdn'] }}"
action: member
state: absent
register: result
failed_when: result.changed or result.failed
- name: Ensure servicedelegationrule test-delegation-rule member target test-delegation-target is absent
ipaservicedelegationrule:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: test-delegation-rule
target: test-delegation-target
action: member
state: absent
register: result
failed_when: not result.changed or result.failed
- name: Ensure servicedelegationrule test-delegation-rule member target test-delegation-target is absent, again
ipaservicedelegationrule:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: test-delegation-rule
target: test-delegation-target
action: member
state: absent
register: result
failed_when: result.changed or result.failed
- name: Ensure servicedelegationrule test-delegation-rule is absent
ipaservicedelegationrule:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: test-delegation-rule
state: absent
register: result
failed_when: not result.changed or result.failed
- name: Ensure servicedelegationrule test-delegation-rule is absent again
ipaservicedelegationrule:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: test-delegation-rule
state: absent
register: result
failed_when: result.changed or result.failed
# CLEANUP TEST ITEMS
- name: Ensure servicedelegationrule test-delegation-target is absent
ipaservicedelegationtarget:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: test-delegation-target
state: absent
- name: Ensure service is absent
ipaservice:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: "{{ 'test-service/' + ansible_facts['fqdn'] }}"
state: absent
continue: yes

View File

@@ -0,0 +1,39 @@
---
- name: Test servicedelegationrule
hosts: ipaclients, ipaserver
# Change "become" or "gather_facts" to "yes",
# if you test playbook requires any.
become: no
gather_facts: no
tasks:
- name: Include FreeIPA facts.
include_tasks: ../env_freeipa_facts.yml
# Test will only be executed if host is not a server.
- name: Execute with server context in the client.
ipaservicedelegationrule:
ipaadmin_password: SomeADMINpassword
ipaapi_context: server
name: ThisShouldNotWork
register: result
failed_when: not (result.failed and result.msg is regex("No module named '*ipaserver'*"))
when: ipa_host_is_client
# Import basic module tests, and execute with ipa_context set to 'client'.
# If ipaclients is set, it will be executed using the client, if not,
# ipaserver will be used.
#
# With this setup, tests can be executed against an IPA client, against
# an IPA server using "client" context, and ensure that tests are executed
# in upstream CI.
- name: Test servicedelegationrule using client context, in client host.
import_playbook: test_servicedelegationrule.yml
when: groups['ipaclients']
vars:
ipa_test_host: ipaclients
- name: Test servicedelegationrule using client context, in server host.
import_playbook: test_servicedelegationrule.yml
when: groups['ipaclients'] is not defined or not groups['ipaclients']

Some files were not shown because too many files have changed in this diff Show More