mirror of
https://github.com/freeipa/ansible-freeipa.git
synced 2026-03-27 05:43:05 +00:00
Compare commits
57 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
62fd1551eb | ||
|
|
a24e90ad0c | ||
|
|
0b9718b3ec | ||
|
|
226b8c4d75 | ||
|
|
2f34e1ac6a | ||
|
|
e4ea7c8983 | ||
|
|
b3f024869c | ||
|
|
355438cea9 | ||
|
|
30b72422d9 | ||
|
|
10a84429e2 | ||
|
|
bf384ab1aa | ||
|
|
536b7cb5f3 | ||
|
|
17b100baec | ||
|
|
1488fb7b5e | ||
|
|
a733c031b0 | ||
|
|
ff1a026ef4 | ||
|
|
fa5d056e72 | ||
|
|
e0e3cb041e | ||
|
|
b54aaf127d | ||
|
|
4e16126b29 | ||
|
|
ed62c2f1bf | ||
|
|
dc9b0ce4e8 | ||
|
|
aa3bf1f015 | ||
|
|
f0aa531b28 | ||
|
|
6407fd8b2e | ||
|
|
2a1be13d3e | ||
|
|
2afca1fa5e | ||
|
|
2a40e42b0c | ||
|
|
8a33941188 | ||
|
|
0aef995bbe | ||
|
|
e75efb7a13 | ||
|
|
ed44344519 | ||
|
|
b186a1f28f | ||
|
|
d307635c38 | ||
|
|
74f3817531 | ||
|
|
97378c38cf | ||
|
|
6f15cd093a | ||
|
|
52f7f7848e | ||
|
|
fdd45cc475 | ||
|
|
a1cad32a46 | ||
|
|
7036fa3e1b | ||
|
|
95d935f185 | ||
|
|
dd3bc4fcdd | ||
|
|
c405229553 | ||
|
|
3fa3bf0822 | ||
|
|
7cef44c01d | ||
|
|
cd7d19bfeb | ||
|
|
0e748d372a | ||
|
|
e24340447d | ||
|
|
092ad81d03 | ||
|
|
4d22e917df | ||
|
|
a04a357b6a | ||
|
|
2081a1a8dd | ||
|
|
d1dfdc38c9 | ||
|
|
668830fc94 | ||
|
|
5ae39ec9de | ||
|
|
3f59332d99 |
18
.github/workflows/docs.yml
vendored
18
.github/workflows/docs.yml
vendored
@@ -5,7 +5,7 @@ on:
|
||||
- pull_request
|
||||
jobs:
|
||||
check_docs_oldest_supported:
|
||||
name: Check Ansible Documentation with ansible-core 2.13.
|
||||
name: Check Ansible Documentation with ansible-core 2.16.
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.1
|
||||
@@ -14,15 +14,15 @@ jobs:
|
||||
- uses: actions/setup-python@v5.1.0
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Install Ansible 2.13
|
||||
- name: Install Ansible 2.16
|
||||
run: |
|
||||
python -m pip install "ansible-core >=2.13,<2.14"
|
||||
python -m pip install "ansible-core >=2.16,<2.17"
|
||||
- name: Run ansible-doc-test
|
||||
run: |
|
||||
ANSIBLE_LIBRARY="." ANSIBLE_DOC_FRAGMENT_PLUGINS="." python utils/ansible-doc-test -v roles plugins
|
||||
|
||||
check_docs_previous:
|
||||
name: Check Ansible Documentation with ansible-core 2.14.
|
||||
name: Check Ansible Documentation with ansible-core 2.18.
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.1
|
||||
@@ -31,15 +31,15 @@ jobs:
|
||||
- uses: actions/setup-python@v5.1.0
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Install Ansible 2.14
|
||||
- name: Install Ansible 2.18
|
||||
run: |
|
||||
python -m pip install "ansible-core >=2.14,<2.15"
|
||||
python -m pip install "ansible-core >=2.18,<2.19"
|
||||
- name: Run ansible-doc-test
|
||||
run: |
|
||||
ANSIBLE_LIBRARY="." ANSIBLE_DOC_FRAGMENT_PLUGINS="." python utils/ansible-doc-test -v roles plugins
|
||||
|
||||
check_docs_current:
|
||||
name: Check Ansible Documentation with ansible-core 2.15.
|
||||
name: Check Ansible Documentation with ansible-core 2.19.
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.1
|
||||
@@ -48,9 +48,9 @@ jobs:
|
||||
- uses: actions/setup-python@v5.1.0
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Install Ansible 2.15
|
||||
- name: Install Ansible 2.20
|
||||
run: |
|
||||
python -m pip install "ansible-core >=2.15,<2.16"
|
||||
python -m pip install "ansible-core <2.20"
|
||||
- name: Run ansible-doc-test
|
||||
run: |
|
||||
ANSIBLE_LIBRARY="." ANSIBLE_DOC_FRAGMENT_PLUGINS="." python utils/ansible-doc-test -v roles plugins
|
||||
|
||||
6
.github/workflows/lint.yml
vendored
6
.github/workflows/lint.yml
vendored
@@ -13,12 +13,12 @@ jobs:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@v5.1.0
|
||||
with:
|
||||
python-version: "3.x"
|
||||
python-version: "3.13"
|
||||
- name: Run ansible-lint
|
||||
run: |
|
||||
pip install "ansible-core>=2.16,<2.17" 'ansible-lint==6.22'
|
||||
utils/build-galaxy-release.sh -ki
|
||||
cd .galaxy-build
|
||||
utils/build-collection.sh -ki rpm
|
||||
cd .collection-build
|
||||
ansible-lint --profile production --exclude tests/integration/ --exclude tests/unit/ --parseable --nocolor
|
||||
|
||||
yamllint:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
repos:
|
||||
- repo: https://github.com/ansible/ansible-lint.git
|
||||
rev: v24.5.0
|
||||
rev: v25.9.2
|
||||
hooks:
|
||||
- id: ansible-lint
|
||||
always_run: false
|
||||
@@ -21,16 +21,16 @@ repos:
|
||||
--parseable
|
||||
--nocolor
|
||||
- repo: https://github.com/adrienverge/yamllint.git
|
||||
rev: v1.35.1
|
||||
rev: v1.37.1
|
||||
hooks:
|
||||
- id: yamllint
|
||||
files: \.(yaml|yml)$
|
||||
- repo: https://github.com/pycqa/flake8
|
||||
rev: 7.2.0
|
||||
rev: 7.3.0
|
||||
hooks:
|
||||
- id: flake8
|
||||
- repo: https://github.com/pycqa/pylint
|
||||
rev: v3.2.2
|
||||
rev: v4.0.2
|
||||
hooks:
|
||||
- id: pylint
|
||||
args:
|
||||
|
||||
@@ -145,7 +145,7 @@ Variable | Description | Required
|
||||
`selinuxusermaporder` \| `ipaselinuxusermaporder`| Set ordered list in increasing priority of SELinux users | no
|
||||
`selinuxusermapdefault`\| `ipaselinuxusermapdefault` | Set default SELinux user when no match is found in SELinux map rule | no
|
||||
`pac_type` \| `ipakrbauthzdata` | set default types of PAC supported for services (choices: `MS-PAC`, `PAD`, `nfs:NONE`). Use `""` to clear this variable. | no
|
||||
`user_auth_type` \| `ipauserauthtype` | set default types of supported user authentication (choices: `password`, `radius`, `otp`, `pkinit`, `hardened`, `idp`, `disabled`, `""`). An additional check ensures that only types can be used that are supported by the IPA version. Use `""` to clear this variable. | no
|
||||
`user_auth_type` \| `ipauserauthtype` | set default types of supported user authentication (choices: `password`, `radius`, `otp`, `pkinit`, `hardened`, `idp`, `passkey`, `disabled`, `""`). An additional check ensures that only types can be used that are supported by the IPA version. Use `""` to clear this variable. | no
|
||||
`domain_resolution_order` \| `ipadomainresolutionorder` | Set list of domains used for short name qualification | no
|
||||
`ca_renewal_master_server` \| `ipacarenewalmasterserver`| Renewal master for IPA certificate authority. | no
|
||||
`enable_sid` | New users and groups automatically get a SID assigned. Cannot be deactivated once activated. Requires IPA 4.9.8+. (bool) | no
|
||||
|
||||
@@ -354,7 +354,7 @@ Variable | Description | Required
|
||||
`mac_address` \| `macaddress` | List of hardware MAC addresses. | no
|
||||
`sshpubkey` \| `ipasshpubkey` | List of SSH public keys | no
|
||||
`userclass` \| `class` | Host category (semantics placed on this attribute are for local interpretation) | no
|
||||
`auth_ind` \| `krbprincipalauthind` | Defines an allow list for Authentication Indicators. Use 'otp' to allow OTP-based 2FA authentications. Use 'radius' to allow RADIUS-based 2FA authentications. Use empty string to reset auth_ind to the initial value. Other values may be used for custom configurations. An additional check ensures that only types can be used that are supported by the IPA version. Choices: ["radius", "otp", "pkinit", "hardened", "idp", ""] | no
|
||||
`auth_ind` \| `krbprincipalauthind` | Defines an allow list for Authentication Indicators. Use 'otp' to allow OTP-based 2FA authentications. Use 'radius' to allow RADIUS-based 2FA authentications. Use empty string to reset auth_ind to the initial value. Other values may be used for custom configurations. An additional check ensures that only types can be used that are supported by the IPA version. Choices: ["radius", "otp", "pkinit", "hardened", "idp", "passkey", ""] | no
|
||||
`requires_pre_auth` \| `ipakrbrequirespreauth` | Pre-authentication is required for the service (bool) | no
|
||||
`ok_as_delegate` \| `ipakrbokasdelegate` | Client credentials may be delegated to the service (bool) | no
|
||||
`ok_to_auth_as_delegate` \| `ipakrboktoauthasdelegate` | The service is allowed to authenticate on behalf of a client (bool) | no
|
||||
|
||||
88
README-passkeyconfig.md
Normal file
88
README-passkeyconfig.md
Normal file
@@ -0,0 +1,88 @@
|
||||
Passkeyconfig module
|
||||
============
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The passkeyconfig module allows to manage FreeIPA passkey configuration settings.
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* Passkeyconfig management
|
||||
|
||||
|
||||
Supported FreeIPA Versions
|
||||
--------------------------
|
||||
|
||||
FreeIPA versions 4.4.0 and up are supported by the ipapasskeyconfig module.
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
**Controller**
|
||||
* Ansible version: 2.15+
|
||||
|
||||
**Node**
|
||||
* Supported FreeIPA version (see above)
|
||||
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
Example inventory file
|
||||
|
||||
```ini
|
||||
[ipaserver]
|
||||
ipaserver.test.local
|
||||
```
|
||||
|
||||
|
||||
By default, user verification for passkey authentication is turned on (`true`). Example playbook to ensure that the requirement for user verification for passkey authentication is turned off:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA passkeyconfig.
|
||||
hosts: ipaserver
|
||||
become: false
|
||||
|
||||
tasks:
|
||||
- name: Ensure require_user_verification is false
|
||||
ipapasskeyconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
require_user_verification: false
|
||||
```
|
||||
|
||||
|
||||
Example playbook to get current passkeyconfig:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to get IPA passkeyconfig.
|
||||
hosts: ipaserver
|
||||
become: false
|
||||
|
||||
tasks:
|
||||
- name: Retrieve current passkey configuration
|
||||
ipapasskeyconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
```
|
||||
|
||||
|
||||
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 true. (bool) | no
|
||||
`require_user_verification` \| `iparequireuserverification` | Require user verification for passkey authentication. (bool) | no
|
||||
|
||||
|
||||
Authors
|
||||
=======
|
||||
|
||||
Rafael Guterres Jeffman
|
||||
@@ -230,6 +230,8 @@ Example playbook to ensure that different members are not associated with a role
|
||||
- User Administrators
|
||||
service:
|
||||
- service01
|
||||
sysaccount:
|
||||
- my-app
|
||||
action: member
|
||||
state: absent
|
||||
```
|
||||
@@ -253,7 +255,8 @@ Variable | Description | Required
|
||||
`host` | List of hosts to be assigned or not assigned to the role. | no
|
||||
`hostgroup` | List of hostgroups to be assigned or not assigned to the role. | no
|
||||
`service` | List of services to be assigned or not assigned to the role. | no
|
||||
`action` | Work on role or member level. It can be on of `member` or `role` and defaults to `role`. | no
|
||||
`sysaccount` | List of sysaccounts to be assigned or not assigned to the role. | no
|
||||
`action` | Work on role or member level. It can be one of `member` or `role` and defaults to `role`. | no
|
||||
`state` | The state to ensure. It can be one of `present`, `absent`, default: `present`. | no
|
||||
|
||||
|
||||
@@ -261,3 +264,4 @@ Authors
|
||||
=======
|
||||
|
||||
Rafael Jeffman
|
||||
Thomas Woerner
|
||||
|
||||
@@ -361,7 +361,7 @@ Variable | Description | Required
|
||||
-------- | ----------- | --------
|
||||
`certificate` \| `usercertificate` | Base-64 encoded service certificate. | 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`, `hardened`, `idp` or `""`. An additional check ensures that only types can be used that are supported by the IPA version. Use empty string to reset auth_ind to the initial value. | no
|
||||
`auth_ind` \| `krbprincipalauthind` | Defines an allow list for Authentication Indicators. It can be any of `otp`, `radius`, `pkinit`, `hardened`, `idp`, `passkey` or `""`. An additional check ensures that only types can be used that are supported by the IPA version. 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
|
||||
|
||||
196
README-sysaccount.md
Normal file
196
README-sysaccount.md
Normal file
@@ -0,0 +1,196 @@
|
||||
Sysaccount module
|
||||
============
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The sysaccount module allows to ensure presence and absence of system accounts.
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* Sysaccount management
|
||||
|
||||
|
||||
Supported FreeIPA Versions
|
||||
--------------------------
|
||||
|
||||
FreeIPA versions 4.4.0 and up are supported by the ipasysaccount module.
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
**Controller**
|
||||
* Ansible version: 2.15+
|
||||
|
||||
**Node**
|
||||
* Supported FreeIPA version (see above)
|
||||
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
Example inventory file
|
||||
|
||||
```ini
|
||||
[ipaserver]
|
||||
ipaserver.test.local
|
||||
```
|
||||
|
||||
|
||||
Example playbook to make sure sysaccount "my-app" is present with random password:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA sysaccount.
|
||||
hosts: ipaserver
|
||||
become: false
|
||||
|
||||
tasks:
|
||||
- name: Ensure sysaccount "my-app" is present with random password
|
||||
ipasysaccount:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: my-app
|
||||
random: true
|
||||
register: result
|
||||
|
||||
- name: Print generated random password
|
||||
debug:
|
||||
var: result.sysaccount.randompassword
|
||||
|
||||
```
|
||||
|
||||
|
||||
Example playbook to make sure sysaccount "my-app" is present with given password:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA sysaccount.
|
||||
hosts: ipaserver
|
||||
become: false
|
||||
|
||||
tasks:
|
||||
- name: Ensure sysaccount "my-app" is present with given password
|
||||
ipasysaccount:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: my-app
|
||||
password: SomeAPPpassword
|
||||
```
|
||||
|
||||
|
||||
Example playbook to make sure sysaccount "my-app" is absent:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA sysaccount.
|
||||
hosts: ipaserver
|
||||
become: false
|
||||
|
||||
tasks:
|
||||
- name: Ensure sysaccount "my-app" is absent
|
||||
ipasysaccount:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: my-app
|
||||
state: absent
|
||||
```
|
||||
|
||||
Example playbook to ensure existing sysaccount my-app is privileged
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA sysaccount.
|
||||
hosts: ipaserver
|
||||
become: false
|
||||
|
||||
tasks:
|
||||
- name: Ensure existing sysaccount my-app is privileged
|
||||
ipasysaccount:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: my-app
|
||||
privileged: true
|
||||
```
|
||||
|
||||
Example playbook to ensure existing sysaccount my-app is not privileged
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA sysaccount.
|
||||
hosts: ipaserver
|
||||
become: false
|
||||
|
||||
tasks:
|
||||
- name: Ensure existing sysaccount my-app is not privileged
|
||||
ipasysaccount:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: my-app
|
||||
privileged: false
|
||||
```
|
||||
|
||||
Example playbook to ensure existing sysaccount my-app is disabled
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA sysaccount.
|
||||
hosts: ipaserver
|
||||
become: false
|
||||
|
||||
tasks:
|
||||
- name: Ensure existing sysaccount my-app is disabled
|
||||
ipasysaccount:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: my-app
|
||||
state: disabled
|
||||
```
|
||||
|
||||
Example playbook to ensure existing sysaccount my-app is enabled
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA sysaccount.
|
||||
hosts: ipaserver
|
||||
become: false
|
||||
|
||||
tasks:
|
||||
- name: Ensure existing sysaccount my-app is enabled
|
||||
ipasysaccount:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: my-app
|
||||
state: enabled
|
||||
```
|
||||
|
||||
|
||||
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 true. (bool) | no
|
||||
`name` \| `login` | The list of sysaccount name strings - internally uid. (list of strings) | yes
|
||||
`description` | A description for the sysaccount. (string) | no
|
||||
`privileged` | Allow password updates without reset. This flag is not replicated. It is needed to set privileged on all servers, where it is needed. (bool) | no
|
||||
`random` | Generate a random user password. (bool) | no
|
||||
`password` \| `userpassword` | Set the password. (string) | no
|
||||
`update_password` | Set password for a sysaccount in present state only on creation or always. It can be one of `always` or `on_create` and defaults to `always`. | no
|
||||
`state` | The state to ensure. It can be one of `present`, `absent`, 'enabled', 'disabled', default: `present`. | no
|
||||
|
||||
|
||||
Return Values
|
||||
=============
|
||||
|
||||
There are only return values if a random passwords has been generated.
|
||||
|
||||
Variable | Description | Returned When
|
||||
-------- | ----------- | -------------
|
||||
`sysaccount` | Sysaccount dict (dict) <br>Options: | Always
|
||||
| `randompassword` - The generated random password | If random is yes and sysaccount did not exist or update_password is yes
|
||||
|
||||
|
||||
|
||||
Authors
|
||||
=======
|
||||
|
||||
Thomas Woerner
|
||||
@@ -452,7 +452,7 @@ Variable | Description | Required
|
||||
`manager` | List of manager user names. | no
|
||||
`carlicense` | List of car licenses. | no
|
||||
`sshpubkey` \| `ipasshpubkey` | List of SSH public keys. | no
|
||||
`userauthtype` \| `ipauserauthtype` | List of supported user authentication types. Choices: `password`, `radius`, `otp`, `pkinit`, `hardened`, `idp` and `""`. An additional check ensures that only types can be used that are supported by the IPA version. Use empty string to reset userauthtype to the initial value. | no
|
||||
`userauthtype` \| `ipauserauthtype` | List of supported user authentication types. Choices: `password`, `radius`, `otp`, `pkinit`, `hardened`, `idp`, `passkey` and `""`. An additional check ensures that only types can be used that are supported by the IPA version. Use empty string to reset userauthtype to the initial value. | no
|
||||
`userclass` | User category. (semantics placed on this attribute are for local interpretation). | no
|
||||
`radius` | RADIUS proxy configuration | no
|
||||
`radiususer` | RADIUS proxy username | no
|
||||
|
||||
@@ -38,6 +38,7 @@ Features
|
||||
* Modules for idview management
|
||||
* Modules for location management
|
||||
* Modules for netgroup management
|
||||
* Modules for passkeyconfig management
|
||||
* Modules for permission management
|
||||
* Modules for privilege management
|
||||
* Modules for pwpolicy management
|
||||
@@ -50,6 +51,7 @@ Features
|
||||
* Modules for sudocmd management
|
||||
* Modules for sudocmdgroup management
|
||||
* Modules for sudorule management
|
||||
* Modules for sysaccount management
|
||||
* Modules for topology management
|
||||
* Modules for trust management
|
||||
* Modules for user management
|
||||
@@ -453,6 +455,7 @@ Modules in plugin/modules
|
||||
* [idview](README-idview.md)
|
||||
* [ipalocation](README-location.md)
|
||||
* [ipanetgroup](README-netgroup.md)
|
||||
* [ipapasskeyconfig](README-passkeyconfig.md)
|
||||
* [ipapermission](README-permission.md)
|
||||
* [ipaprivilege](README-privilege.md)
|
||||
* [ipapwpolicy](README-pwpolicy.md)
|
||||
@@ -465,6 +468,7 @@ Modules in plugin/modules
|
||||
* [ipasudocmd](README-sudocmd.md)
|
||||
* [ipasudocmdgroup](README-sudocmdgroup.md)
|
||||
* [ipasudorule](README-sudorule.md)
|
||||
* [ipasysaccount](README-sysaccount.md)
|
||||
* [ipatopologysegment](README-topology.md)
|
||||
* [ipatopologysuffix](README-topology.md)
|
||||
* [ipatrust](README-trust.md)
|
||||
|
||||
@@ -6,7 +6,7 @@ pool:
|
||||
vmImage: 'ubuntu-24.04'
|
||||
|
||||
variables:
|
||||
ansible_version: "-core >=2.16,<2.17"
|
||||
ansible_version: "-core >=2.18,<2.19"
|
||||
ansible_latest: "-core"
|
||||
ansible_minimum: "-core <2.16"
|
||||
distros: "fedora-latest,c9s,c10s,fedora-rawhide"
|
||||
@@ -36,7 +36,7 @@ stages:
|
||||
# Supported distros
|
||||
|
||||
- ${{ each distro in split(variables.distros, ',') }}:
|
||||
- stage: ${{ replace(distro, '-', '_') }}_ansible_2_16
|
||||
- stage: ${{ replace(distro, '-', '_') }}_ansible_2_18
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/group_tests.yml
|
||||
@@ -49,7 +49,7 @@ stages:
|
||||
|
||||
# Galaxy on Fedora
|
||||
|
||||
- stage: galaxy_fedora_latest_ansible_2_16
|
||||
- stage: galaxy_fedora_latest_ansible_2_18
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/group_tests.yml
|
||||
|
||||
@@ -12,13 +12,24 @@ trigger: none
|
||||
pool:
|
||||
vmImage: 'ubuntu-24.04'
|
||||
|
||||
parameters:
|
||||
# Not really a parameter, but variables cannot be arrays or dicts
|
||||
# This maps the distro LATEST version to the avaiable ansible-core
|
||||
# version of the latest released compose.
|
||||
- name: "distro_ansible_map"
|
||||
type: object
|
||||
default:
|
||||
- { distro: "c8s", ansible_version: "<2.17", version_name: "2.16" }
|
||||
# c9s should use 2.14, but this version has an invalid certificate
|
||||
# and so is unsuable against ansible-galaxy.
|
||||
- { distro: "c9s", ansible_version: "<2.17", version_name: "2.16" }
|
||||
- { distro: "c10s", ansible_version: "<2.17", version_name: "2.16" }
|
||||
|
||||
variables:
|
||||
# We need to have two sets, as c8s is not supported by all ansible versions
|
||||
recent_distros: "fedora-latest,fedora-rawhide,c10s,c9s"
|
||||
distros: "fedora-latest,fedora-rawhide,c10s,c9s,c8s"
|
||||
distros: "fedora-latest,c10s,c9s,fedora-rawhide"
|
||||
ansible_version: "-core >=2.18,<2.19"
|
||||
ansible_latest: "-core"
|
||||
ansible_minimum: "-core <2.16"
|
||||
ansible_version: "-core >=2.16,<2.17"
|
||||
|
||||
stages:
|
||||
|
||||
@@ -38,7 +49,7 @@ stages:
|
||||
|
||||
# Latest ansible
|
||||
|
||||
- ${{ each distro in split(variables.recent_distros, ',') }}:
|
||||
- ${{ each distro in split(variables.distros, ',') }}:
|
||||
- stage: ${{ replace(distro, '-', '_') }}_ansible_latest
|
||||
dependsOn: []
|
||||
jobs:
|
||||
@@ -50,30 +61,44 @@ stages:
|
||||
skip_git_test: true
|
||||
test_galaxy: false
|
||||
|
||||
# Selected ansible-core version
|
||||
# Galaxy with Latest ansible
|
||||
|
||||
- ${{ each distro in split(variables.distros, ',') }}:
|
||||
- stage: ${{ replace(distro, '-', '_') }}_ansible_2_16
|
||||
- stage: galaxy_${{ replace(distro, '-', '_') }}_ansible_latest
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/group_tests.yml
|
||||
parameters:
|
||||
build_number: $(Build.BuildNumber)
|
||||
distro: ${{ distro }}
|
||||
ansible_version: ${{ variables.ansible_version }}
|
||||
ansible_version: ${{ variables.ansible_latest }}
|
||||
skip_git_test: true
|
||||
test_galaxy: true
|
||||
|
||||
# Test with pinned ansible version for the distro
|
||||
|
||||
- ${{ each config in parameters.distro_ansible_map }}:
|
||||
- stage: ${{ config.distro }}_distro_ansible_${{ replace(config.version_name, '.', '_') }}
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/group_tests.yml
|
||||
parameters:
|
||||
build_number: $(Build.BuildNumber)
|
||||
distro: ${{ config.distro }}
|
||||
ansible_version: -core${{ config.ansible_version }}
|
||||
skip_git_test: true
|
||||
test_galaxy: false
|
||||
|
||||
# Galaxy collection with selected ansible-core version
|
||||
# Test Galaxy collection with pinned ansible version for the distro
|
||||
|
||||
- ${{ each distro in split(variables.distros, ',') }}:
|
||||
- stage: galaxy_${{ replace(distro, '-', '_') }}_asible_2_16
|
||||
- ${{ each config in parameters.distro_ansible_map }}:
|
||||
- stage: galaxy_${{ config.distro }}_distro_ansible_${{ replace(config.version_name, '.', '_') }}
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/group_tests.yml
|
||||
parameters:
|
||||
build_number: $(Build.BuildNumber)
|
||||
distro: ${{ distro }}
|
||||
ansible_version: ${{ variables.ansible_version }}
|
||||
distro: ${{ config.distro }}
|
||||
ansible_version: -core${{ config.ansible_version }}
|
||||
skip_git_test: true
|
||||
test_galaxy: true
|
||||
|
||||
@@ -5,16 +5,29 @@ trigger:
|
||||
pool:
|
||||
vmImage: 'ubuntu-24.04'
|
||||
|
||||
parameters:
|
||||
# Not really a parameter, but variables cannot be arrays or dicts
|
||||
# This maps the distro LATEST version to the avaiable ansible-core
|
||||
# version of the latest released compose.
|
||||
- name: "distro_ansible_map"
|
||||
type: object
|
||||
default:
|
||||
- { distro: "c8s", ansible_version: "<2.17", version_name: "2.16" }
|
||||
# c9s should use 2.14, but this version has an invalid certificate
|
||||
# and so is unsuable against ansible-galaxy.
|
||||
- { distro: "c9s", ansible_version: "<2.17", version_name: "2.16" }
|
||||
- { distro: "c10s", ansible_version: "<2.17", version_name: "2.16" }
|
||||
|
||||
variables:
|
||||
distros: "fedora-latest,c10s,c9s,c8s,fedora-rawhide"
|
||||
ansible_version: "-core >=2.15,<2.16"
|
||||
distros: "fedora-latest,c10s,c9s,fedora-rawhide"
|
||||
ansible_version: "-core >=2.18,<2.19"
|
||||
|
||||
stages:
|
||||
|
||||
# Test with repository in all distros
|
||||
# Test with repository in all "current" distros
|
||||
|
||||
- ${{ each distro in split(variables.distros, ',') }}:
|
||||
- stage: ${{ replace(distro, '-', '_') }}_ansible_2_16
|
||||
- stage: ${{ replace(distro, '-', '_') }}_ansible_2_18
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/run_tests.yml
|
||||
@@ -27,7 +40,7 @@ stages:
|
||||
|
||||
# Galaxy on Fedora
|
||||
|
||||
- stage: galaxy_fedora_latest_ansible_2_16
|
||||
- stage: galaxy_fedora_latest_ansible_2_18
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/run_tests.yml
|
||||
@@ -37,3 +50,18 @@ stages:
|
||||
ansible_version: ${{ variables.ansible_version }}
|
||||
skip_git_test: false
|
||||
test_galaxy: true
|
||||
|
||||
|
||||
# Test with pinned ansible version for the distro
|
||||
|
||||
- ${{ each config in parameters.distro_ansible_map }}:
|
||||
- stage: ${{ config.distro }}_distro_ansible_${{ replace(config.version_name, '.', '_') }}
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/run_tests.yml
|
||||
parameters:
|
||||
build_number: $(Build.BuildNumber)
|
||||
distro: ${{ config.distro }}
|
||||
ansible_version: -core${{ config.ansible_version }}
|
||||
skip_git_test: false
|
||||
test_galaxy: false
|
||||
|
||||
@@ -54,7 +54,7 @@ jobs:
|
||||
|
||||
- script: |
|
||||
git fetch --unshallow
|
||||
utils/build-galaxy-release.sh -i
|
||||
utils/build-collection.sh -i rpm
|
||||
retryCountOnTaskFailure: 5
|
||||
displayName: Build Galaxy release
|
||||
condition: ${{ parameters.test_galaxy }}
|
||||
|
||||
@@ -12,6 +12,7 @@ dnf --assumeyes install \
|
||||
bash \
|
||||
systemd \
|
||||
procps-ng \
|
||||
hostname \
|
||||
iproute; \
|
||||
dnf clean all; \
|
||||
rm -rf /var/cache/dnf/;
|
||||
|
||||
@@ -9,6 +9,7 @@ dnf --assumeyes install \
|
||||
bash \
|
||||
systemd \
|
||||
procps-ng \
|
||||
hostname \
|
||||
iproute; \
|
||||
rm -rf /var/cache/dnf/;
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ dnf --assumeyes install \
|
||||
bash \
|
||||
systemd \
|
||||
procps-ng \
|
||||
hostname \
|
||||
iproute; \
|
||||
dnf clean all; \
|
||||
rm -rf /var/cache/dnf/;
|
||||
|
||||
@@ -11,6 +11,7 @@ dnf --assumeyes install \
|
||||
bash \
|
||||
systemd \
|
||||
procps-ng \
|
||||
hostname \
|
||||
iproute; \
|
||||
dnf clean all; \
|
||||
rm -rf /var/cache/dnf/;
|
||||
|
||||
@@ -228,3 +228,22 @@ container_tee() {
|
||||
rm "${tmpfile}"
|
||||
echo
|
||||
}
|
||||
|
||||
container_save() {
|
||||
local name=${1}
|
||||
|
||||
archive="${name}.tar"
|
||||
log info "= Saving ${name} to ${archive} ="
|
||||
# podman is not able to overwrite the archive
|
||||
[ -f "${archive}" ] && rm "${archive}"
|
||||
podman save -o "${archive}" "${name}"
|
||||
echo
|
||||
}
|
||||
|
||||
container_load() {
|
||||
local name=${1}
|
||||
|
||||
image_name=$(podman load -q -i "${name}" | sed -e "s/^Loaded image: //")
|
||||
image=$(podman image list -q "${image_name}")
|
||||
echo "$image"
|
||||
}
|
||||
|
||||
@@ -6,4 +6,6 @@
|
||||
CAP_DEFAULTS=(
|
||||
"+DAC_READ_SEARCH" # Required for SSSD
|
||||
"+SYS_PTRACE" # Required for debugging
|
||||
"+SYS_ADMIN" # Required to make dbus-brokder for systemd 258 work
|
||||
# Should be "+AUDIT_WRITE", "+SETUID", "+SETGID"
|
||||
)
|
||||
|
||||
10
playbooks/passkeyconfig/passkeyconfig-present.yml
Normal file
10
playbooks/passkeyconfig/passkeyconfig-present.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
- name: Passkeyconfig example
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Set passkeyconfig require_user_verification to false
|
||||
ipapasskeyconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
require_user_verification: false
|
||||
14
playbooks/passkeyconfig/passkeyconfig-retrieve.yml
Normal file
14
playbooks/passkeyconfig/passkeyconfig-retrieve.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
- name: Passkeyconfig get current configuration example
|
||||
hosts: ipaserver
|
||||
become: true
|
||||
|
||||
tasks:
|
||||
- name: Get current passkey configuration
|
||||
ipapasskeyconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
register: result
|
||||
|
||||
- name: Display current passkey configuration
|
||||
ansible.builtin.debug:
|
||||
var: result.passkeyconfig
|
||||
11
playbooks/sysaccount/sysaccount-absent.yml
Normal file
11
playbooks/sysaccount/sysaccount-absent.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
- name: Sysaccount example
|
||||
hosts: ipaserver
|
||||
become: false
|
||||
|
||||
tasks:
|
||||
- name: Ensure sysaccount my-app is absent
|
||||
ipasysaccount:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: my-app
|
||||
state: absent
|
||||
11
playbooks/sysaccount/sysaccount-disabled.yml
Normal file
11
playbooks/sysaccount/sysaccount-disabled.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
- name: Sysaccount example
|
||||
hosts: ipaserver
|
||||
become: false
|
||||
|
||||
tasks:
|
||||
- name: Ensure sysaccount my-app is disabled
|
||||
ipasysaccount:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: my-app
|
||||
state: disabled
|
||||
11
playbooks/sysaccount/sysaccount-enabled.yml
Normal file
11
playbooks/sysaccount/sysaccount-enabled.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
- name: Sysaccount example
|
||||
hosts: ipaserver
|
||||
become: false
|
||||
|
||||
tasks:
|
||||
- name: Ensure sysaccount my-app is enabled
|
||||
ipasysaccount:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: my-app
|
||||
state: enabled
|
||||
11
playbooks/sysaccount/sysaccount-present.yml
Normal file
11
playbooks/sysaccount/sysaccount-present.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
- name: Sysaccount example
|
||||
hosts: ipaserver
|
||||
become: false
|
||||
|
||||
tasks:
|
||||
- name: Ensure sysaccount my-app is present with random password
|
||||
ipasysaccount:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: my-app
|
||||
random: true
|
||||
11
playbooks/sysaccount/sysaccount-privileged.yml
Normal file
11
playbooks/sysaccount/sysaccount-privileged.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
- name: Sysaccount example
|
||||
hosts: ipaserver
|
||||
become: false
|
||||
|
||||
tasks:
|
||||
- name: Ensure sysaccount my-app is privileged
|
||||
ipasysaccount:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: my-app
|
||||
privileged: true
|
||||
11
playbooks/sysaccount/sysaccount-unprivileged.yml
Normal file
11
playbooks/sysaccount/sysaccount-unprivileged.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
- name: Sysaccount example
|
||||
hosts: ipaserver
|
||||
become: false
|
||||
|
||||
tasks:
|
||||
- name: Ensure sysaccount my-app is not privileged
|
||||
ipasysaccount:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: my-app
|
||||
privileged: false
|
||||
@@ -107,7 +107,7 @@ from ansible.plugins.inventory import BaseInventoryPlugin
|
||||
from ansible.module_utils.six.moves.urllib.parse import quote
|
||||
|
||||
|
||||
class InventoryModule(BaseInventoryPlugin):
|
||||
class InventoryModule(BaseInventoryPlugin): # pylint: disable=R0901
|
||||
|
||||
NAME = 'freeipa'
|
||||
|
||||
|
||||
@@ -161,7 +161,7 @@ options:
|
||||
type: list
|
||||
elements: str
|
||||
choices: ["password", "radius", "otp", "pkinit", "hardened", "idp",
|
||||
"disabled", ""]
|
||||
"passkey", "disabled", ""]
|
||||
aliases: ["ipauserauthtype"]
|
||||
ca_renewal_master_server:
|
||||
description: Renewal master for IPA certificate authority.
|
||||
@@ -426,7 +426,7 @@ def main():
|
||||
user_auth_type=dict(type="list", elements="str", required=False,
|
||||
choices=["password", "radius", "otp",
|
||||
"pkinit", "hardened", "idp",
|
||||
"disabled", ""],
|
||||
"passkey", "disabled", ""],
|
||||
aliases=["ipauserauthtype"]),
|
||||
ca_renewal_master_server=dict(type="str", required=False),
|
||||
domain_resolution_order=dict(type="list", elements="str",
|
||||
|
||||
@@ -1454,11 +1454,13 @@ def define_commands_for_present_state(module, zone_name, entry, res_find):
|
||||
# Create reverse records for existing records
|
||||
for ipv in ['a', 'aaaa']:
|
||||
record = '%srecord' % ipv
|
||||
if record in args and ('%s_extra_create_reverse' % ipv) in args:
|
||||
if (
|
||||
record in args
|
||||
and args.pop('%s_extra_create_reverse' % ipv, False)
|
||||
):
|
||||
cmds = create_reverse_ip_record(
|
||||
module, zone_name, name, args[record])
|
||||
_commands.extend(cmds)
|
||||
del args['%s_extra_create_reverse' % ipv]
|
||||
for record, fields in _RECORD_PARTS.items():
|
||||
part_fields = [f for f in fields if f in args]
|
||||
if part_fields:
|
||||
@@ -1620,7 +1622,6 @@ def main():
|
||||
commands.extend(cmds)
|
||||
|
||||
# Execute commands
|
||||
|
||||
changed = ansible_module.execute_ipa_commands(
|
||||
commands, exception_handler=exception_handler)
|
||||
|
||||
|
||||
@@ -184,7 +184,7 @@ options:
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["krbprincipalauthind"]
|
||||
choices: ["radius", "otp", "pkinit", "hardened", "idp", ""]
|
||||
choices: ["radius", "otp", "pkinit", "hardened", "idp", "passkey", ""]
|
||||
required: false
|
||||
requires_pre_auth:
|
||||
description: Pre-authentication is required for the service
|
||||
@@ -356,7 +356,7 @@ options:
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["krbprincipalauthind"]
|
||||
choices: ["radius", "otp", "pkinit", "hardened", "idp", ""]
|
||||
choices: ["radius", "otp", "pkinit", "hardened", "idp", "passkey", ""]
|
||||
required: false
|
||||
requires_pre_auth:
|
||||
description: Pre-authentication is required for the service
|
||||
@@ -758,7 +758,7 @@ def main():
|
||||
auth_ind=dict(type='list', elements="str",
|
||||
aliases=["krbprincipalauthind"], default=None,
|
||||
choices=["radius", "otp", "pkinit", "hardened", "idp",
|
||||
""]),
|
||||
"passkey", ""]),
|
||||
requires_pre_auth=dict(type="bool", aliases=["ipakrbrequirespreauth"],
|
||||
default=None),
|
||||
ok_as_delegate=dict(type="bool", aliases=["ipakrbokasdelegate"],
|
||||
|
||||
174
plugins/modules/ipapasskeyconfig.py
Normal file
174
plugins/modules/ipapasskeyconfig.py
Normal file
@@ -0,0 +1,174 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Authors:
|
||||
# Rafael Guterres Jeffman <rjeffman@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2025 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: ipapasskeyconfig
|
||||
short_description: Manage FreeIPA passkeyconfig
|
||||
description: Manage FreeIPA passkeyconfig
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
options:
|
||||
require_user_verification:
|
||||
description: Require user verification for passkey authentication
|
||||
required: false
|
||||
type: bool
|
||||
default: true
|
||||
aliases: ["iparequireuserverification"]
|
||||
author:
|
||||
- Rafael Guterres Jeffman (@rjeffman)
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
# Set passkeyconfig
|
||||
- ipapasskeyconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
require_user_verification: false
|
||||
|
||||
# Get current passkeyconfig
|
||||
- ipapasskeyconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
"""
|
||||
|
||||
RETURN = """
|
||||
passkeyconfig:
|
||||
description: Dict of passkeyconfig settings
|
||||
returned: always
|
||||
type: dict
|
||||
contains:
|
||||
require_user_verification:
|
||||
description: Require user verification for passkey authentication
|
||||
type: bool
|
||||
returned: always
|
||||
"""
|
||||
|
||||
|
||||
from ansible.module_utils.ansible_freeipa_module import \
|
||||
IPAAnsibleModule, compare_args_ipa, ipalib_errors
|
||||
from ansible.module_utils import six
|
||||
|
||||
if six.PY3:
|
||||
unicode = str
|
||||
|
||||
|
||||
def find_passkeyconfig(module):
|
||||
"""Find the current passkeyconfig settings."""
|
||||
try:
|
||||
_result = module.ipa_command_no_name(
|
||||
"passkeyconfig_show", {"all": True})
|
||||
except ipalib_errors.NotFound:
|
||||
# An exception is raised if passkeyconfig is not found.
|
||||
return None
|
||||
return _result["result"]
|
||||
|
||||
|
||||
def gen_args(require_user_verification):
|
||||
_args = {}
|
||||
if require_user_verification is not None:
|
||||
_args["iparequireuserverification"] = require_user_verification
|
||||
return _args
|
||||
|
||||
|
||||
def main():
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
# passkeyconfig
|
||||
require_user_verification=dict(
|
||||
required=False, type='bool',
|
||||
aliases=["iparequireuserverification"],
|
||||
default=None
|
||||
),
|
||||
),
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
ansible_module._ansible_debug = True
|
||||
|
||||
# Get parameters
|
||||
require_user_verification = (
|
||||
ansible_module.params_get("require_user_verification")
|
||||
)
|
||||
|
||||
# Init
|
||||
changed = False
|
||||
exit_args = {}
|
||||
|
||||
# Connect to IPA API
|
||||
with ansible_module.ipa_connect():
|
||||
|
||||
if not ansible_module.ipa_command_exists("passkeyconfig_show"):
|
||||
msg = "Managing passkeyconfig is not supported by your IPA version"
|
||||
ansible_module.fail_json(msg=msg)
|
||||
|
||||
result = find_passkeyconfig(ansible_module)
|
||||
|
||||
if result is None:
|
||||
ansible_module.fail_json(msg="Could not retrieve passkeyconfig")
|
||||
|
||||
if require_user_verification is not None:
|
||||
# Generate args
|
||||
args = gen_args(require_user_verification)
|
||||
|
||||
# Check if there are different settings in the find result.
|
||||
# If yes: modify
|
||||
if not compare_args_ipa(ansible_module, args, result):
|
||||
changed = True
|
||||
if not ansible_module.check_mode:
|
||||
try:
|
||||
ansible_module.ipa_command_no_name(
|
||||
"passkeyconfig_mod", args)
|
||||
except ipalib_errors.EmptyModlist:
|
||||
changed = False
|
||||
except Exception as e:
|
||||
ansible_module.fail_json(
|
||||
msg="passkeyconfig_mod failed: %s" % str(e))
|
||||
else:
|
||||
# No parameters provided, just return current config
|
||||
pass
|
||||
|
||||
# Get updated config if changes were made
|
||||
if changed:
|
||||
result = find_passkeyconfig(ansible_module)
|
||||
|
||||
# Prepare exit args
|
||||
exit_args["passkeyconfig"] = {}
|
||||
if result:
|
||||
# Map IPA API field to module parameter
|
||||
if "iparequireuserverification" in result:
|
||||
exit_args["passkeyconfig"]["require_user_verification"] = \
|
||||
result["iparequireuserverification"][0]
|
||||
|
||||
# Done
|
||||
ansible_module.exit_json(changed=changed, **exit_args)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -85,6 +85,11 @@ options:
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
sysaccount:
|
||||
description: List of sysaccounts.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
action:
|
||||
description: Work on role or member level.
|
||||
type: str
|
||||
@@ -177,7 +182,7 @@ def check_parameters(module):
|
||||
"description",
|
||||
"user", "group",
|
||||
"host", "hostgroup",
|
||||
"service",
|
||||
"service", "sysaccount",
|
||||
"privilege",
|
||||
]
|
||||
|
||||
@@ -225,7 +230,7 @@ def ensure_absent_state(module, name, action, res_find):
|
||||
{"privilege": del_list}])
|
||||
|
||||
member_args = {}
|
||||
for key in ['user', 'group', 'hostgroup']:
|
||||
for key in ['user', 'group', 'hostgroup', 'sysaccount']:
|
||||
_members = module.params_get_lowercase(key)
|
||||
if _members:
|
||||
del_list = gen_intersection_list(
|
||||
@@ -335,7 +340,7 @@ def ensure_role_with_members_is_present(module, name, res_find, action):
|
||||
add_members = {}
|
||||
del_members = {}
|
||||
|
||||
for key in ["user", "group", "hostgroup"]:
|
||||
for key in ["user", "group", "hostgroup", "sysaccount"]:
|
||||
_members = module.params_get_lowercase(key)
|
||||
if _members is not None:
|
||||
add_list, del_list = gen_add_del_lists(
|
||||
@@ -437,6 +442,8 @@ def create_module():
|
||||
default=None),
|
||||
service=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
sysaccount=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
|
||||
# state
|
||||
action=dict(type="str", default="role",
|
||||
@@ -467,8 +474,15 @@ def main():
|
||||
state = ansible_module.params_get("state")
|
||||
action = ansible_module.params_get("action")
|
||||
names = ansible_module.params_get("name")
|
||||
sysaccount = ansible_module.params_get("sysaccount")
|
||||
commands = []
|
||||
|
||||
has_sysaccount_member = ansible_module.ipa_command_param_exists(
|
||||
"role_add_member", "sysaccount")
|
||||
if not has_sysaccount_member and sysaccount is not None:
|
||||
ansible_module.fail_json(
|
||||
msg="sysaccount members are not supported by your IPA version")
|
||||
|
||||
for name in names:
|
||||
cmds = role_commands_for_name(ansible_module, state, action, name)
|
||||
commands.extend(cmds)
|
||||
|
||||
@@ -74,7 +74,7 @@ options:
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
choices: ["otp", "radius", "pkinit", "hardened", "idp", ""]
|
||||
choices: ["otp", "radius", "pkinit", "hardened", "idp", "passkey", ""]
|
||||
aliases: ["krbprincipalauthind"]
|
||||
skip_host_check:
|
||||
description: Skip checking if host object exists.
|
||||
@@ -192,7 +192,7 @@ options:
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
choices: ["otp", "radius", "pkinit", "hardened", "idp", ""]
|
||||
choices: ["otp", "radius", "pkinit", "hardened", "idp", "passkey", ""]
|
||||
aliases: ["krbprincipalauthind"]
|
||||
skip_host_check:
|
||||
description: Skip checking if host object exists.
|
||||
@@ -560,7 +560,7 @@ def init_ansible_module():
|
||||
auth_ind=dict(type="list", elements="str",
|
||||
aliases=["krbprincipalauthind"],
|
||||
choices=["otp", "radius", "pkinit", "hardened", "idp",
|
||||
""]),
|
||||
"passkey", ""]),
|
||||
skip_host_check=dict(type="bool"),
|
||||
force=dict(type="bool"),
|
||||
requires_pre_auth=dict(
|
||||
|
||||
309
plugins/modules/ipasysaccount.py
Normal file
309
plugins/modules/ipasysaccount.py
Normal file
@@ -0,0 +1,309 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Authors:
|
||||
# Thomas Woerner <twoerner@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2025 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: ipasysaccount
|
||||
short_description: Manage FreeIPA system account
|
||||
description: Manage FreeIPA system account
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
- ipamodule_base_docs.delete_continue
|
||||
options:
|
||||
name:
|
||||
description: The list of sysaccount name strings (internally uid).
|
||||
required: true
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["login"]
|
||||
description:
|
||||
description: A description for the sysaccount.
|
||||
type: str
|
||||
required: false
|
||||
privileged:
|
||||
description: Allow password updates without reset.
|
||||
type: bool
|
||||
required: false
|
||||
random:
|
||||
description: Generate a random user password.
|
||||
required: false
|
||||
type: bool
|
||||
password:
|
||||
description: Set the user password.
|
||||
required: false
|
||||
type: str
|
||||
aliases: ["userpassword"]
|
||||
update_password:
|
||||
description:
|
||||
Set password for a sysaccount in present state only on creation or always
|
||||
type: str
|
||||
choices: ["always", "on_create"]
|
||||
required: false
|
||||
state:
|
||||
description: The state to ensure.
|
||||
choices: ["present", "absent", "enabled", "disabled"]
|
||||
default: present
|
||||
type: str
|
||||
author:
|
||||
- Thomas Woerner (@t-woerner)
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
# Ensure sysaccount my-app is present
|
||||
- ipasysaccount:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: my-app
|
||||
random: true
|
||||
|
||||
# Ensure sysaccount my-app is absent
|
||||
- ipasysaccount:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: my-app
|
||||
state: absent
|
||||
|
||||
# Ensure existing sysaccount my-app is privileged
|
||||
- ipasysaccount:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: my-app
|
||||
privileged: true
|
||||
|
||||
# Ensure existing sysaccount my-app is not privileged
|
||||
- ipasysaccount:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: my-app
|
||||
privileged: false
|
||||
|
||||
# Ensure existing sysaccount my-app is disabled
|
||||
- ipasysaccount:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: my-app
|
||||
state: disabled
|
||||
|
||||
# Ensure existing sysaccount my-app is enabled
|
||||
- ipasysaccount:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: my-app
|
||||
state: enabled
|
||||
"""
|
||||
|
||||
RETURN = """
|
||||
sysaccount:
|
||||
description: Sysaccount dict with random password
|
||||
returned: |
|
||||
If random is yes and user sysaccount not exist or update_password is yes
|
||||
type: dict
|
||||
contains:
|
||||
randompassword:
|
||||
description: The generated random password
|
||||
type: str
|
||||
"""
|
||||
|
||||
|
||||
from ansible.module_utils.ansible_freeipa_module import \
|
||||
IPAAnsibleModule, compare_args_ipa, ipalib_errors
|
||||
from ansible.module_utils import six
|
||||
|
||||
if six.PY3:
|
||||
unicode = str
|
||||
|
||||
|
||||
def find_sysaccount(module, name):
|
||||
"""Find if a sysaccount with the given name already exist."""
|
||||
try:
|
||||
_result = module.ipa_command("sysaccount_show", name, {"all": True})
|
||||
except ipalib_errors.NotFound:
|
||||
# An exception is raised if sysaccount name is not found.
|
||||
return None
|
||||
return _result["result"]
|
||||
|
||||
|
||||
def gen_args(description, random, privileged, password):
|
||||
_args = {}
|
||||
if description is not None:
|
||||
_args["description"] = description
|
||||
if random is not None:
|
||||
_args["random"] = random
|
||||
if privileged is not None:
|
||||
_args["privileged"] = privileged
|
||||
if password is not None:
|
||||
_args["userpassword"] = password
|
||||
return _args
|
||||
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
def result_handler(module, result, command, name, args, exit_args, errors):
|
||||
if "random" in args and command in ["sysaccount_add", "sysaccount_mod"] \
|
||||
and "randompassword" in result["result"]:
|
||||
exit_args["randompassword"] = \
|
||||
result["result"]["randompassword"]
|
||||
|
||||
|
||||
def main():
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
# general
|
||||
name=dict(type="list", elements="str", required=True,
|
||||
aliases=["login"]),
|
||||
# present
|
||||
description=dict(required=False, type='str', default=None),
|
||||
random=dict(required=False, type='bool', default=None),
|
||||
privileged=dict(required=False, type='bool', default=None),
|
||||
password=dict(required=False, type='str',
|
||||
aliases=["userpassword"], default=None),
|
||||
|
||||
# mod
|
||||
update_password=dict(type='str', default=None, no_log=False,
|
||||
choices=['always', 'on_create']),
|
||||
|
||||
# state
|
||||
state=dict(type="str", default="present",
|
||||
choices=["present", "absent", "enabled", "disabled"]),
|
||||
),
|
||||
supports_check_mode=True,
|
||||
ipa_module_options=["delete_continue"],
|
||||
mutually_exclusive=[["random", "password"]]
|
||||
)
|
||||
|
||||
ansible_module._ansible_debug = True
|
||||
|
||||
# Get parameters
|
||||
|
||||
# general
|
||||
names = ansible_module.params_get("name")
|
||||
|
||||
# present
|
||||
description = ansible_module.params_get("description")
|
||||
random = ansible_module.params_get("random")
|
||||
privileged = ansible_module.params_get("privileged")
|
||||
password = ansible_module.params_get("password")
|
||||
|
||||
# mod
|
||||
update_password = ansible_module.params_get("update_password")
|
||||
|
||||
# absent
|
||||
delete_continue = ansible_module.params_get("delete_continue")
|
||||
|
||||
# state
|
||||
state = ansible_module.params_get("state")
|
||||
|
||||
# Check parameters
|
||||
|
||||
invalid = []
|
||||
|
||||
if state == "present" and len(names) != 1:
|
||||
ansible_module.fail_json(
|
||||
msg="Only one sysaccount can be added at a time.")
|
||||
|
||||
if state in ["absent", "enabled", "disabled"]:
|
||||
if len(names) < 1:
|
||||
ansible_module.fail_json(msg="No name given.")
|
||||
invalid = ["description", "random", "privileged", "password"]
|
||||
|
||||
ansible_module.params_fail_used_invalid(invalid, state)
|
||||
|
||||
# Init
|
||||
|
||||
changed = False
|
||||
exit_args = {}
|
||||
|
||||
# Connect to IPA API
|
||||
with ansible_module.ipa_connect():
|
||||
|
||||
if not ansible_module.ipa_command_exists("sysaccount_add"):
|
||||
ansible_module.fail_json(
|
||||
msg=("Managing sysaccounts is not supported by your "
|
||||
"IPA version")
|
||||
)
|
||||
|
||||
commands = []
|
||||
for name in names:
|
||||
# Make sure sysaccount exists
|
||||
res_find = find_sysaccount(ansible_module, name)
|
||||
|
||||
# Create command
|
||||
if state == "present":
|
||||
|
||||
# Generate args
|
||||
args = gen_args(description, random, privileged, password)
|
||||
|
||||
# Found the sysaccount
|
||||
if res_find is not None:
|
||||
# Ignore password and random with
|
||||
# update_password == on_create
|
||||
if update_password == "on_create":
|
||||
if "userpassword" in args:
|
||||
del args["userpassword"]
|
||||
if "random" in args:
|
||||
del args["random"]
|
||||
# if using "random:false" password should not be
|
||||
# generated.
|
||||
if not args.get("random", True):
|
||||
del args["random"]
|
||||
|
||||
# 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):
|
||||
commands.append([name, "sysaccount_mod", args])
|
||||
else:
|
||||
commands.append([name, "sysaccount_add", args])
|
||||
|
||||
elif state == "absent":
|
||||
if res_find is not None:
|
||||
commands.append(
|
||||
[name, "sysaccount_del", {"continue": delete_continue}]
|
||||
)
|
||||
|
||||
elif state == "enabled":
|
||||
if res_find is not None and res_find["nsaccountlock"]:
|
||||
commands.append([name, "sysaccount_enable", {}])
|
||||
|
||||
elif state == "disabled":
|
||||
if res_find is not None and not res_find["nsaccountlock"]:
|
||||
commands.append([name, "sysaccount_disable", {}])
|
||||
|
||||
else:
|
||||
ansible_module.fail_json(msg="Unkown state '%s'" % state)
|
||||
|
||||
# Execute commands
|
||||
|
||||
changed = ansible_module.execute_ipa_commands(
|
||||
commands, result_handler, keeponly=["randompassword"],
|
||||
exit_args=exit_args)
|
||||
|
||||
# Done
|
||||
|
||||
ansible_module.exit_json(changed=changed, sysaccount=exit_args)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -208,7 +208,8 @@ options:
|
||||
Use empty string to reset userauthtype to the initial value.
|
||||
type: list
|
||||
elements: str
|
||||
choices: ["password", "radius", "otp", "pkinit", "hardened", "idp", ""]
|
||||
choices: ["password", "radius", "otp", "pkinit", "hardened", "idp",
|
||||
"passkey", ""]
|
||||
required: false
|
||||
aliases: ["ipauserauthtype"]
|
||||
userclass:
|
||||
@@ -480,7 +481,8 @@ options:
|
||||
Use empty string to reset userauthtype to the initial value.
|
||||
type: list
|
||||
elements: str
|
||||
choices: ["password", "radius", "otp", "pkinit", "hardened", "idp", ""]
|
||||
choices: ["password", "radius", "otp", "pkinit", "hardened", "idp",
|
||||
"passkey", ""]
|
||||
required: false
|
||||
aliases: ["ipauserauthtype"]
|
||||
userclass:
|
||||
@@ -1070,7 +1072,7 @@ def main():
|
||||
userauthtype=dict(type='list', elements="str",
|
||||
aliases=["ipauserauthtype"], default=None,
|
||||
choices=["password", "radius", "otp", "pkinit",
|
||||
"hardened", "idp", ""]),
|
||||
"hardened", "idp", "passkey", ""]),
|
||||
userclass=dict(type="list", elements="str", aliases=["class"],
|
||||
default=None),
|
||||
radius=dict(type="str", aliases=["ipatokenradiusconfiglink"],
|
||||
|
||||
@@ -4,3 +4,4 @@ junit_family = xunit1
|
||||
markers=
|
||||
source_order: mark test as order bound
|
||||
playbook: playbook tests
|
||||
pythonpath = tests
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
-r requirements.txt
|
||||
pytest==7.1.3
|
||||
pytest-sourceorder==0.6.0
|
||||
pytest
|
||||
pytest-sourceorder
|
||||
pytest-split>=0.8.0
|
||||
pytest-custom_exit_code>=0.3.0
|
||||
pytest-testinfra==6.8.0
|
||||
pytest-randomly==3.12.0
|
||||
pytest-testinfra
|
||||
pytest-randomly
|
||||
pyyaml>=3
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
setuptools
|
||||
|
||||
@@ -91,20 +91,21 @@
|
||||
enabled: yes
|
||||
state: started
|
||||
|
||||
- name: Firewalld - Verify runtime zone "{{ ipabackup_firewalld_zone }}"
|
||||
ansible.builtin.shell: >
|
||||
firewall-cmd
|
||||
--info-zone="{{ ipabackup_firewalld_zone }}"
|
||||
>/dev/null
|
||||
- name: Firewalld - Verify zones
|
||||
when: ipabackup_firewalld_zone is defined
|
||||
block:
|
||||
- name: Firewalld - Verify runtime zone from ipabackup_firewalld_zone
|
||||
ansible.builtin.shell: >
|
||||
firewall-cmd
|
||||
--info-zone="{{ ipabackup_firewalld_zone }}"
|
||||
>/dev/null
|
||||
|
||||
- name: Firewalld - Verify permanent zone "{{ ipabackup_firewalld_zone }}"
|
||||
ansible.builtin.shell: >
|
||||
firewall-cmd
|
||||
--permanent
|
||||
--info-zone="{{ ipabackup_firewalld_zone }}"
|
||||
>/dev/null
|
||||
when: ipabackup_firewalld_zone is defined
|
||||
- name: Firewalld - Verify permanent zone from ipabackup_firewalld_zone
|
||||
ansible.builtin.shell: >
|
||||
firewall-cmd
|
||||
--permanent
|
||||
--info-zone="{{ ipabackup_firewalld_zone }}"
|
||||
>/dev/null
|
||||
|
||||
### RESTORE
|
||||
|
||||
|
||||
@@ -181,10 +181,10 @@
|
||||
|
||||
- name: Install - Store the previously obtained OTP
|
||||
no_log: yes
|
||||
when: result_ipaclient_get_otp.host is defined
|
||||
ansible.builtin.set_fact:
|
||||
ipaadmin_orig_password: "{{ ipaadmin_password | default(omit) }}"
|
||||
ipaadmin_password: "{{ result_ipaclient_get_otp.host.randompassword
|
||||
if result_ipaclient_get_otp.host is defined }}"
|
||||
ipaadmin_password: "{{ result_ipaclient_get_otp.host.randompassword | default(omit) }}"
|
||||
rescue:
|
||||
- name: Install - Report error for OTP generation
|
||||
ansible.builtin.debug:
|
||||
|
||||
@@ -47,20 +47,21 @@
|
||||
enabled: yes
|
||||
state: started
|
||||
|
||||
- name: Firewalld - Verify runtime zone "{{ ipareplica_firewalld_zone }}"
|
||||
ansible.builtin.shell: >
|
||||
firewall-cmd
|
||||
--info-zone="{{ ipareplica_firewalld_zone }}"
|
||||
>/dev/null
|
||||
- name: Firewalld - Verify zones
|
||||
when: ipareplica_firewalld_zone is defined
|
||||
block:
|
||||
- name: Firewalld - Verify runtime zone from ipareplica_firewalld_zone
|
||||
ansible.builtin.shell: >
|
||||
firewall-cmd
|
||||
--info-zone="{{ ipareplica_firewalld_zone }}"
|
||||
>/dev/null
|
||||
|
||||
- name: Firewalld - Verify permanent zone "{{ ipareplica_firewalld_zone }}"
|
||||
ansible.builtin.shell: >
|
||||
firewall-cmd
|
||||
--permanent
|
||||
--info-zone="{{ ipareplica_firewalld_zone }}"
|
||||
>/dev/null
|
||||
when: ipareplica_firewalld_zone is defined
|
||||
- name: Firewalld - Verify permanent zone from ipareplica_firewalld_zone
|
||||
ansible.builtin.shell: >
|
||||
firewall-cmd
|
||||
--permanent
|
||||
--info-zone="{{ ipareplica_firewalld_zone }}"
|
||||
>/dev/null
|
||||
|
||||
- name: Install - Set ipareplica_servers
|
||||
ansible.builtin.set_fact:
|
||||
|
||||
@@ -47,20 +47,21 @@
|
||||
enabled: yes
|
||||
state: started
|
||||
|
||||
- name: Firewalld - Verify runtime zone "{{ ipaserver_firewalld_zone }}"
|
||||
ansible.builtin.shell: >
|
||||
firewall-cmd
|
||||
--info-zone="{{ ipaserver_firewalld_zone }}"
|
||||
>/dev/null
|
||||
- name: Firewalld - verify zones
|
||||
when: ipaserver_firewalld_zone is defined
|
||||
block:
|
||||
- name: Firewalld - Verify runtime zone from ipaserver_firewalld_zone
|
||||
ansible.builtin.shell: >
|
||||
firewall-cmd
|
||||
--info-zone="{{ ipaserver_firewalld_zone }}"
|
||||
>/dev/null
|
||||
|
||||
- name: Firewalld - Verify permanent zone "{{ ipaserver_firewalld_zone }}"
|
||||
ansible.builtin.shell: >
|
||||
firewall-cmd
|
||||
--permanent
|
||||
--info-zone="{{ ipaserver_firewalld_zone }}"
|
||||
>/dev/null
|
||||
when: ipaserver_firewalld_zone is defined
|
||||
- name: Firewalld - Verify permanent zone from ipaserver_firewalld_zone
|
||||
ansible.builtin.shell: >
|
||||
firewall-cmd
|
||||
--permanent
|
||||
--info-zone="{{ ipaserver_firewalld_zone }}"
|
||||
>/dev/null
|
||||
|
||||
- name: Copy external certs
|
||||
ansible.builtin.include_tasks: "{{ role_path }}/tasks/copy_external_cert.yml"
|
||||
|
||||
@@ -61,7 +61,12 @@ good-names =
|
||||
dt, ca,
|
||||
# These are utils tools, and not part of the released collection.
|
||||
galaxyfy-playbook, galaxyfy-README, galaxyfy-module-EXAMPLES,
|
||||
module_EXAMPLES
|
||||
module_EXAMPLES,
|
||||
MODULE_IMPORT_ERROR, ANSIBLE_IPA_CLIENT_MODULE_IMPORT_ERROR,
|
||||
CLIENT_SUPPORTS_NO_DNSSEC_VALIDATION, ANSIBLE_IPA_REPLICA_MODULE_IMPORT_ERROR,
|
||||
SYSTEMD_RESOLVED_IPA_CONF, ANSIBLE_IPA_SERVER_MODULE_IMPORT_ERROR,
|
||||
NETWORK_MANAGER_IPA_CONF, ANSIBLE_FREEIPA_MODULE_IMPORT_ERROR,
|
||||
FIX_6741_DEEPCOPY_OBJECTCLASSES
|
||||
|
||||
|
||||
[pylint.IMPORTS]
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
recurse: no
|
||||
file_type: directory
|
||||
register: result
|
||||
failed_when: not result.files
|
||||
failed_when: result.files | length == 0
|
||||
|
||||
# Test backup and copy to controller, don't keep copy on server
|
||||
- name: Remove all backup from server.
|
||||
@@ -108,7 +108,7 @@
|
||||
recurse: no
|
||||
file_type: directory
|
||||
register: backups
|
||||
failed_when: backups.files
|
||||
failed_when: backups.files | length > 0
|
||||
|
||||
- name: Verify backup on controller.
|
||||
ansible.builtin.find:
|
||||
@@ -116,7 +116,7 @@
|
||||
pattern: "{{ ansible_facts.fqdn }}*"
|
||||
file_type: directory
|
||||
register: backups
|
||||
failed_when: not backups.files
|
||||
failed_when: backups.files | length == 0
|
||||
delegate_to: localhost
|
||||
become: no
|
||||
|
||||
@@ -161,7 +161,7 @@
|
||||
recurse: no
|
||||
file_type: directory
|
||||
register: result
|
||||
failed_when: not result.files
|
||||
failed_when: result.files | length == 0
|
||||
|
||||
- name: Verify backup on controller.
|
||||
ansible.builtin.find:
|
||||
@@ -169,7 +169,7 @@
|
||||
pattern: "{{ ansible_facts.fqdn }}*"
|
||||
file_type: directory
|
||||
register: backups
|
||||
failed_when: not backups.files
|
||||
failed_when: backups.files | length == 0
|
||||
delegate_to: localhost
|
||||
become: no
|
||||
|
||||
@@ -214,7 +214,7 @@
|
||||
pattern: "{{ ansible_facts.fqdn }}*"
|
||||
file_type: directory
|
||||
register: backups
|
||||
failed_when: not backups.files
|
||||
failed_when: backups.files | length == 0
|
||||
delegate_to: localhost
|
||||
become: no
|
||||
|
||||
@@ -232,7 +232,7 @@
|
||||
pattern: "{{ ansible_facts.fqdn }}*"
|
||||
file_type: directory
|
||||
register: backups
|
||||
failed_when: not backups.files
|
||||
failed_when: backups.files | length == 0
|
||||
delegate_to: localhost
|
||||
become: no
|
||||
|
||||
@@ -252,7 +252,7 @@
|
||||
path: /var/lib/ipa/backup
|
||||
file_type: directory
|
||||
register: backups
|
||||
failed_when: not backups.files
|
||||
failed_when: backups.files | length == 0
|
||||
|
||||
# Copy backup from server to controller
|
||||
- name: List all existing backups on controller
|
||||
@@ -280,7 +280,7 @@
|
||||
recurse: no
|
||||
file_type: directory
|
||||
register: server_backups
|
||||
failed_when: not server_backups.files
|
||||
failed_when: server_backups.files | length == 0
|
||||
|
||||
- name: Copy backup from server to controller.
|
||||
ansible.builtin.include_role:
|
||||
@@ -300,7 +300,7 @@
|
||||
pattern: "{{ ansible_facts.fqdn }}*"
|
||||
file_type: directory
|
||||
register: backups
|
||||
failed_when: not backups.files
|
||||
failed_when: backups.files | length == 0
|
||||
delegate_to: localhost
|
||||
become: no
|
||||
|
||||
@@ -311,7 +311,7 @@
|
||||
recurse: no
|
||||
file_type: directory
|
||||
register: backups
|
||||
failed_when: not backups.files
|
||||
failed_when: backups.files | length == 0
|
||||
|
||||
- name: Remov all backup from server.
|
||||
ansible.builtin.include_role:
|
||||
@@ -326,7 +326,7 @@
|
||||
recurse: no
|
||||
file_type: directory
|
||||
register: backups
|
||||
failed_when: backups.files
|
||||
failed_when: backups.files | length > 0
|
||||
|
||||
# Remove all backups from server
|
||||
- name: Create a backup on the server
|
||||
@@ -348,7 +348,7 @@
|
||||
recurse: no
|
||||
file_type: directory
|
||||
register: backups
|
||||
failed_when: backups.files
|
||||
failed_when: backups.files | length > 0
|
||||
|
||||
# Remove all backup from server
|
||||
- name: Remove all backup from server.
|
||||
@@ -370,7 +370,7 @@
|
||||
recurse: no
|
||||
file_type: directory
|
||||
register: server_backups
|
||||
failed_when: not server_backups.files
|
||||
failed_when: server_backups.files | length == 0
|
||||
|
||||
- name: Remove backup from server.
|
||||
ansible.builtin.include_role:
|
||||
@@ -406,7 +406,7 @@
|
||||
recurse: no
|
||||
file_type: directory
|
||||
register: server_backups
|
||||
failed_when: server_backups.files
|
||||
failed_when: server_backups.files | length > 0
|
||||
|
||||
# CLEANUP
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@
|
||||
reason: 9
|
||||
state: revoked
|
||||
register: result
|
||||
failed_when: not (result.failed and ("Request failed with status 404" in result.msg or "Certificate serial number 0x123456789 not found" in result.msg))
|
||||
failed_when: not (result.failed and ("Request failed with status 404" in result.msg or result.msg is regex("Certificate [^0]*0x123456789 not found")))
|
||||
|
||||
- name: Try to release revoked certificate
|
||||
ipacert:
|
||||
@@ -140,7 +140,7 @@
|
||||
certificate_out: "/root/cert_1.pem"
|
||||
state: requested
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed or result.certificate
|
||||
failed_when: not result.changed or result.failed or result.certificate != {}
|
||||
|
||||
- name: Check requested certificate file
|
||||
ansible.builtin.file:
|
||||
@@ -155,7 +155,7 @@
|
||||
certificate_out: "/root/retrieved.pem"
|
||||
state: retrieved
|
||||
register: result
|
||||
failed_when: result.changed or result.failed or result.certificate
|
||||
failed_when: result.changed or result.failed or result.certificate != {}
|
||||
|
||||
- name: Check retrieved certificate file
|
||||
ansible.builtin.file:
|
||||
@@ -194,7 +194,7 @@
|
||||
profile: invalid_profile
|
||||
state: requested
|
||||
register: result
|
||||
failed_when: not (result.failed and "Request failed with status 400" in result.msg)
|
||||
failed_when: not (result.failed and ("Request failed with status 400" in result.msg or "Profile not found" in result.msg))
|
||||
|
||||
|
||||
# CLEANUP TEST ITEMS
|
||||
|
||||
@@ -136,7 +136,7 @@
|
||||
reason: 9
|
||||
state: revoked
|
||||
register: result
|
||||
failed_when: not (result.failed and ("Request failed with status 404" in result.msg or "Certificate serial number 0x123456789 not found" in result.msg))
|
||||
failed_when: not (result.failed and ("Request failed with status 404" in result.msg or result.msg is regex("Certificate [^0]*0x123456789 not found")))
|
||||
|
||||
- name: Try to release revoked certificate
|
||||
ipacert:
|
||||
@@ -153,7 +153,7 @@
|
||||
certificate_out: "/root/cert_1.pem"
|
||||
state: requested
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed or result.certificate
|
||||
failed_when: not result.changed or result.failed or result.certificate != {}
|
||||
|
||||
- name: Check requested certificate file
|
||||
ansible.builtin.file:
|
||||
@@ -168,7 +168,7 @@
|
||||
certificate_out: "/root/retrieved.pem"
|
||||
state: retrieved
|
||||
register: result
|
||||
failed_when: result.changed or result.failed or result.certificate
|
||||
failed_when: result.changed or result.failed or result.certificate != {}
|
||||
|
||||
- name: Check retrieved certificate file
|
||||
ansible.builtin.file:
|
||||
@@ -207,7 +207,7 @@
|
||||
profile: invalid_profile
|
||||
state: requested
|
||||
register: result
|
||||
failed_when: not (result.failed and "Request failed with status 400" in result.msg)
|
||||
failed_when: not (result.failed and ("Request failed with status 400" in result.msg or "Profile not found" in result.msg))
|
||||
|
||||
# CLEANUP TEST ITEMS
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@
|
||||
reason: 9
|
||||
state: revoked
|
||||
register: result
|
||||
failed_when: not (result.failed and ("Request failed with status 404" in result.msg or "Certificate serial number 0x123456789 not found" in result.msg))
|
||||
failed_when: not (result.failed and ("Request failed with status 404" in result.msg or result.msg is regex("Certificate [^0]*0x123456789 not found")))
|
||||
|
||||
- name: Try to release revoked certificate
|
||||
ipacert:
|
||||
@@ -140,7 +140,7 @@
|
||||
certificate_out: "/root/cert_1.pem"
|
||||
state: requested
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed or result.certificate
|
||||
failed_when: not result.changed or result.failed or result.certificate != {}
|
||||
|
||||
- name: Check requested certificate file
|
||||
ansible.builtin.file:
|
||||
@@ -155,7 +155,7 @@
|
||||
certificate_out: "/root/retrieved.pem"
|
||||
state: retrieved
|
||||
register: result
|
||||
failed_when: result.changed or result.failed or result.certificate
|
||||
failed_when: result.changed or result.failed or result.certificate != {}
|
||||
|
||||
- name: Check retrieved certificate file
|
||||
ansible.builtin.file:
|
||||
@@ -194,7 +194,7 @@
|
||||
profile: invalid_profile
|
||||
state: requested
|
||||
register: result
|
||||
failed_when: not (result.failed and "Request failed with status 400" in result.msg)
|
||||
failed_when: not (result.failed and ("Request failed with status 400" in result.msg or "Profile not found" in result.msg))
|
||||
|
||||
# CLEANUP TEST ITEMS
|
||||
|
||||
|
||||
@@ -400,7 +400,7 @@
|
||||
searchrecordslimit: '{{ previousconfig.config.searchrecordslimit | default(100) | int }}'
|
||||
usersearch: '{{ previousconfig.config.usersearch | default(omit) }}'
|
||||
groupsearch: '{{ previousconfig.config.groupsearch | default(omit) }}'
|
||||
enable_migration: '{{ previousconfig.config.enable_migration | default(False) | bool }}'
|
||||
enable_migration: '{{ omit if previousconfig.config.enable_migration is not defined else (previousconfig.config.enable_migration | bool) }}'
|
||||
groupobjectclasses: '{{ previousconfig.config.groupobjectclasses | default(omit) }}'
|
||||
userobjectclasses: '{{ previousconfig.config.userobjectclasses | default(omit) }}'
|
||||
pwdexpnotify: '{{ previousconfig.config.pwdexpnotify | default(4) | int }}'
|
||||
@@ -436,7 +436,7 @@
|
||||
searchrecordslimit: '{{ previousconfig.config.searchrecordslimit | default(omit) | int }}'
|
||||
usersearch: '{{ previousconfig.config.usersearch | default(omit) }}'
|
||||
groupsearch: '{{ previousconfig.config.groupsearch | default(omit) }}'
|
||||
enable_migration: '{{ previousconfig.config.enable_migration | default(omit) | bool }}'
|
||||
enable_migration: '{{ omit if previousconfig.config.enable_migration is not defined else (previousconfig.config.enable_migration | bool) }}'
|
||||
groupobjectclasses: '{{ previousconfig.config.groupobjectclasses | default(omit) }}'
|
||||
userobjectclasses: '{{ previousconfig.config.userobjectclasses | default(omit) }}'
|
||||
pwdexpnotify: '{{ previousconfig.config.pwdexpnotify | default(omit) | int }}'
|
||||
@@ -473,7 +473,7 @@
|
||||
searchrecordslimit: '{{ previousconfig.config.searchrecordslimit | default(omit) | int }}'
|
||||
usersearch: '{{ previousconfig.config.usersearch | default(omit) }}'
|
||||
groupsearch: '{{ previousconfig.config.groupsearch | default(omit) }}'
|
||||
enable_migration: '{{ previousconfig.config.enable_migration | default(omit) | bool }}'
|
||||
enable_migration: '{{ omit if previousconfig.config.enable_migration is not defined else (previousconfig.config.enable_migration | bool) }}'
|
||||
groupobjectclasses: '{{ previousconfig.config.groupobjectclasses | default(omit) }}'
|
||||
userobjectclasses: '{{ previousconfig.config.userobjectclasses | default(omit) }}'
|
||||
pwdexpnotify: '{{ previousconfig.config.pwdexpnotify | default(omit) | int }}'
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
gather_facts: no
|
||||
|
||||
tasks:
|
||||
- name: Include tasks ../env_freeipa_facts.yml
|
||||
ansible.builtin.include_tasks: ../env_freeipa_facts.yml
|
||||
|
||||
# GET CURRENT CONFIG
|
||||
|
||||
@@ -80,6 +82,36 @@
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Ensure config with user_auth_type passkey
|
||||
ipaconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
user_auth_type:
|
||||
- passkey
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
when: passkey_is_supported
|
||||
|
||||
- name: Ensure config with user_auth_type passkey, again
|
||||
ipaconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
user_auth_type:
|
||||
- passkey
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
when: passkey_is_supported
|
||||
|
||||
- name: Check if correct message is given if passkey is not supported.
|
||||
ipaconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
user_auth_type:
|
||||
- passkey
|
||||
register: result
|
||||
failed_when: not result.failed or "'passkey' is not supported" not in result.msg
|
||||
when: not passkey_is_supported
|
||||
|
||||
- name: Ensure config with empty user_auth_type
|
||||
ipaconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
@@ -138,6 +170,6 @@
|
||||
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 }}'
|
||||
pac_type: '{{ previousconfig.config.pac_type | default("") }}'
|
||||
user_auth_type: '{{ previousconfig.config.user_auth_type | default("") }}'
|
||||
configstring: '{{ previousconfig.config.configstring | default("") }}'
|
||||
|
||||
@@ -134,11 +134,9 @@
|
||||
name: "{{ item }}"
|
||||
state: absent
|
||||
with_items:
|
||||
- "{{ zone_prefix_reverse }}"
|
||||
- "{{ zone_prefix_reverse_24 }}"
|
||||
- "{{ zone_prefix_reverse_16 }}"
|
||||
- "{{ zone_prefix_reverse_8 }}"
|
||||
- "{{ zone_ipv6_reverse }}"
|
||||
- "{{ zone_ipv6_reverse_workaround }}"
|
||||
- "{{ testzone }}"
|
||||
- "{{ safezone }}"
|
||||
|
||||
@@ -15,13 +15,11 @@
|
||||
skip_nameserver_check: yes
|
||||
skip_overlap_check: yes
|
||||
with_items:
|
||||
- "{{ zone_prefix_reverse }}"
|
||||
- "{{ zone_prefix_reverse_24 }}"
|
||||
- "{{ zone_prefix_reverse_16 }}"
|
||||
- "{{ zone_prefix_reverse_8 }}"
|
||||
- "{{ zone_ipv6_reverse_workaround }}"
|
||||
- "{{ testzone }}"
|
||||
- "{{ zone_ipv6_reverse }}"
|
||||
|
||||
- name: Ensure DNSSEC zone '"{{ safezone }}"' is present.
|
||||
ipadnszone:
|
||||
|
||||
@@ -7,14 +7,17 @@
|
||||
ipv4_reverse: "{{ ansible_facts['default_ipv4'].address.split('.')[:-1] |
|
||||
reverse |
|
||||
join('.') }}"
|
||||
# The 'external_ipv4_address' represents an IP address that
|
||||
# is not part of the expected CIDR zones managed by the IPA
|
||||
# deployment. It is used to test the cases were the the reverse
|
||||
# DNS zone must not be available in the embedded DNS nameserver.
|
||||
external_ipv4_address: "1.2.3.4"
|
||||
|
||||
- name: Set zone prefixes.
|
||||
ansible.builtin.set_fact:
|
||||
testzone: 'testzone.test'
|
||||
safezone: 'safezone.test'
|
||||
zone_ipv6_reverse: "ip6.arpa."
|
||||
zone_ipv6_reverse_workaround: "d.f.ip6.arpa."
|
||||
zone_prefix_reverse: "in-addr.arpa."
|
||||
zone_prefix_reverse_24: "{{ ipv4_reverse.split('.')[:] | join('.') }}.in-addr.arpa."
|
||||
zone_prefix_reverse_16: "{{ ipv4_reverse.split('.')[1:] | join('.') }}.in-addr.arpa."
|
||||
zone_prefix_reverse_8: "{{ ipv4_reverse.split('.')[2:] | join('.') }}.in-addr.arpa."
|
||||
|
||||
@@ -1545,6 +1545,28 @@
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Ensure host has IP in subnet not managed by IPA, without PTR record
|
||||
ipadnsrecord:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
zone_name: "{{ testzone }}"
|
||||
name: host01
|
||||
a_rec: "{{ external_ipv4_address }}"
|
||||
a_create_reverse: false
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure host has IP in subnet not managed by IPA, without PTR record, again
|
||||
ipadnsrecord:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
zone_name: "{{ testzone }}"
|
||||
name: host01
|
||||
a_rec: "{{ external_ipv4_address }}"
|
||||
a_create_reverse: false
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
# cleanup
|
||||
- name: Cleanup test environment.
|
||||
ansible.builtin.include_tasks: env_cleanup.yml
|
||||
|
||||
@@ -38,12 +38,24 @@
|
||||
krb5ccname: "__check_ipa_host_is_client_or_server__"
|
||||
register: check_ad_support
|
||||
|
||||
- name: Verify if passkey tests are possible
|
||||
ansible.builtin.shell:
|
||||
cmd: |
|
||||
echo SomeADMINpassword | kinit -c {{ krb5ccname }} admin > /dev/null
|
||||
RESULT=$(KRB5CCNAME={{ krb5ccname }} ipa command-find passkey | grep "Number of entries returned")
|
||||
kdestroy -A -c {{ krb5ccname }} > /dev/null
|
||||
echo $RESULT
|
||||
vars:
|
||||
krb5ccname: "__check_ipa_host_is_client_or_server__"
|
||||
register: check_passkey_support
|
||||
|
||||
- name: Set FreeIPA facts.
|
||||
ansible.builtin.set_fact:
|
||||
ipa_version: "{{ ipa_cmd_version.stdout_lines[0] }}"
|
||||
ipa_api_version: "{{ ipa_cmd_version.stdout_lines[1] }}"
|
||||
ipa_host_is_client: "{{ (check_client.stdout_lines[-1] == 'CLIENT') | bool }}"
|
||||
trust_test_is_supported: "{{ 'AD trust agent' in check_ad_support.stdout }}"
|
||||
passkey_is_supported: "{{ 'Number of entries returned 0' not in check_passkey_support.stdout }}"
|
||||
|
||||
- name: Ensure ipaserver_domain is set
|
||||
when: ipaserver_domain is not defined
|
||||
|
||||
@@ -49,8 +49,8 @@
|
||||
- { id: 2, value: "{{ user_names[0] | upper }}", expected: false }
|
||||
- { id: 3, value: "{{ user_names[0] }}", expected: false }
|
||||
- { id: 4, value: "{{ user_names }}", expected: true }
|
||||
- { id: 5, value: "{{ user_names | upper }}", expected: false }
|
||||
- { id: 6, value: "{{ user_names | lower }}", expected: false }
|
||||
- { id: 5, value: "{{ user_names | map('upper') }}", expected: false }
|
||||
- { id: 6, value: "{{ user_names | map('lower') }}", expected: false }
|
||||
- { id: 7, value: "{{ user_names[1] }}", expected: true }
|
||||
- { id: 8, value: "{{ user_names[1] | upper }}", expected: false }
|
||||
- { id: 9, value: "{{ user_names[1] | lower }}", expected: false }
|
||||
@@ -64,7 +64,7 @@
|
||||
failed_when: output.changed != item.expected or output.failed
|
||||
loop: "{{ test_cases }}"
|
||||
loop_control:
|
||||
label: "Test id: {{ item.id }}"
|
||||
label: "Test id: {{ item.id }} - {{ item.value }}"
|
||||
|
||||
- name: Test group presence with group parameter
|
||||
vars:
|
||||
@@ -73,8 +73,8 @@
|
||||
- { id: 2, value: "{{ group_names[0] | upper }}", expected: false }
|
||||
- { id: 3, value: "{{ group_names[0] }}", expected: false }
|
||||
- { id: 4, value: "{{ group_names }}", expected: true }
|
||||
- { id: 5, value: "{{ group_names | upper }}", expected: false }
|
||||
- { id: 6, value: "{{ group_names | lower }}", expected: false }
|
||||
- { id: 5, value: "{{ group_names | map('upper') }}", expected: false }
|
||||
- { id: 6, value: "{{ group_names | map('lower') }}", expected: false }
|
||||
- { id: 7, value: "{{ group_names[1] }}", expected: true }
|
||||
- { id: 8, value: "{{ group_names[1] | upper }}", expected: false }
|
||||
- { id: 9, value: "{{ group_names[1] | lower }}", expected: false }
|
||||
@@ -159,8 +159,8 @@
|
||||
- { id: 2, value: "{{ user_names[0] | upper }}", expected: false }
|
||||
- { id: 3, value: "{{ user_names[0] }}", expected: false }
|
||||
- { id: 4, value: "{{ user_names }}", expected: true }
|
||||
- { id: 5, value: "{{ user_names | upper }}", expected: false }
|
||||
- { id: 6, value: "{{ user_names | lower }}", expected: false }
|
||||
- { id: 5, value: "{{ user_names | map('upper') }}", expected: false }
|
||||
- { id: 6, value: "{{ user_names | map('lower') }}", expected: false }
|
||||
- { id: 7, value: "{{ user_names[1] }}", expected: true }
|
||||
- { id: 8, value: "{{ user_names[1] | upper }}", expected: false }
|
||||
- { id: 9, value: "{{ user_names[1] | lower }}", expected: false }
|
||||
@@ -183,8 +183,8 @@
|
||||
- { id: 2, value: "{{ group_names[0] | upper }}", expected: false }
|
||||
- { id: 3, value: "{{ group_names[0] }}", expected: false }
|
||||
- { id: 4, value: "{{ group_names }}", expected: true }
|
||||
- { id: 5, value: "{{ group_names | upper }}", expected: false }
|
||||
- { id: 6, value: "{{ group_names | lower }}", expected: false }
|
||||
- { id: 5, value: "{{ group_names | map('upper') }}", expected: false }
|
||||
- { id: 6, value: "{{ group_names | map('lower') }}", expected: false }
|
||||
- { id: 7, value: "{{ group_names[1] }}", expected: true }
|
||||
- { id: 8, value: "{{ group_names[1] | upper }}", expected: false }
|
||||
- { id: 9, value: "{{ group_names[1] | lower }}", expected: false }
|
||||
|
||||
@@ -97,7 +97,7 @@
|
||||
ipahbacsvcgroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: testgroup
|
||||
hbacsvc: "{{ hbacsvc_list | lower }}"
|
||||
hbacsvc: "{{ hbacsvc_list | map('lower') }}"
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
ipahbacsvcgroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: testgroup
|
||||
hbacsvc: "{{ hbacsvc_list | upper }}"
|
||||
hbacsvc: "{{ hbacsvc_list | map('upper') }}"
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
@@ -153,7 +153,7 @@
|
||||
ipahbacsvcgroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: testgroup
|
||||
hbacsvc: "{{ hbacsvc_list | lower }}"
|
||||
hbacsvc: "{{ hbacsvc_list | map('lower') }}"
|
||||
action: member
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
@@ -162,7 +162,7 @@
|
||||
ipahbacsvcgroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: testgroup
|
||||
hbacsvc: "{{ hbacsvc_list | upper }}"
|
||||
hbacsvc: "{{ hbacsvc_list | map('upper') }}"
|
||||
action: member
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
@@ -171,7 +171,7 @@
|
||||
ipahbacsvcgroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: testgroup
|
||||
hbacsvc: "{{ hbacsvc_list | upper }}"
|
||||
hbacsvc: "{{ hbacsvc_list | map('upper') }}"
|
||||
action: member
|
||||
state: absent
|
||||
check_mode: yes
|
||||
@@ -182,7 +182,7 @@
|
||||
ipahbacsvcgroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: testgroup
|
||||
hbacsvc: "{{ hbacsvc_list | upper }}"
|
||||
hbacsvc: "{{ hbacsvc_list | map('upper') }}"
|
||||
action: member
|
||||
state: absent
|
||||
register: result
|
||||
@@ -192,7 +192,7 @@
|
||||
ipahbacsvcgroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: testgroup
|
||||
hbacsvc: "{{ hbacsvc_list | upper }}"
|
||||
hbacsvc: "{{ hbacsvc_list | map('upper') }}"
|
||||
action: member
|
||||
state: absent
|
||||
check_mode: yes
|
||||
@@ -213,7 +213,7 @@
|
||||
ipahbacsvcgroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: testgroup
|
||||
hbacsvc: "{{ hbacsvc_list | lower }}"
|
||||
hbacsvc: "{{ hbacsvc_list | map('lower') }}"
|
||||
action: member
|
||||
state: absent
|
||||
register: result
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
gather_facts: yes
|
||||
|
||||
tasks:
|
||||
- name: Include FreeIPA facts.
|
||||
ansible.builtin.include_tasks: ../env_freeipa_facts.yml
|
||||
|
||||
- name: Get Domain from server name
|
||||
ansible.builtin.set_fact:
|
||||
ipaserver_domain: "{{ ansible_facts['fqdn'].split('.')[1:] | join('.') }}"
|
||||
@@ -58,6 +61,39 @@
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Ensure host "{{ host1_fqdn }}" present with auth_ind passkey
|
||||
ipahost:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: "{{ host1_fqdn }}"
|
||||
auth_ind:
|
||||
- passkey
|
||||
register: result
|
||||
when: passkey_is_supported
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure host "{{ host1_fqdn }}" present with auth_ind passkey, again
|
||||
ipahost:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: "{{ host1_fqdn }}"
|
||||
auth_ind:
|
||||
- passkey
|
||||
register: result
|
||||
when: passkey_is_supported
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Check if correct message is given if passkey is not supported.
|
||||
ipahost:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: "{{ host1_fqdn }}"
|
||||
auth_ind:
|
||||
- passkey
|
||||
register: result
|
||||
when: not passkey_is_supported
|
||||
failed_when: not result.failed or "'passkey' is not supported" not in result.msg
|
||||
|
||||
- name: Ensure host "{{ host1_fqdn }}" present with empty auth_ind
|
||||
ipahost:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
@@ -92,11 +92,11 @@
|
||||
|
||||
- name: Print generated random password for "{{ host1_fqdn }}"
|
||||
ansible.builtin.debug:
|
||||
var: ipahost.host["{{ host1_fqdn }}"].randompassword
|
||||
var: ipahost.host[host1_fqdn].randompassword
|
||||
|
||||
- name: Print generated random password for "{{ host2_fqdn }}"
|
||||
ansible.builtin.debug:
|
||||
var: ipahost.host["{{ host2_fqdn }}"].randompassword
|
||||
var: ipahost.host[host2_fqdn].randompassword
|
||||
|
||||
- name: Enrolled host "{{ server_fqdn }}" fails to set random password with update_password always
|
||||
ipahost:
|
||||
|
||||
@@ -1,8 +1,16 @@
|
||||
---
|
||||
- name: Test host
|
||||
- name: Test host reverse attribute
|
||||
hosts: ipaserver
|
||||
become: true
|
||||
|
||||
module_defaults:
|
||||
ipahost:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
ipadnszone:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
|
||||
tasks:
|
||||
- name: Get Domain from server name
|
||||
ansible.builtin.set_fact:
|
||||
@@ -15,7 +23,6 @@
|
||||
|
||||
- name: Host absent
|
||||
ipahost:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name:
|
||||
- "{{ host1_fqdn }}"
|
||||
update_dns: yes
|
||||
@@ -28,30 +35,24 @@
|
||||
|
||||
- name: Set zone prefixes.
|
||||
ansible.builtin.set_fact:
|
||||
zone_ipv6_reverse: "ip6.arpa."
|
||||
zone_ipv6_reverse_workaround: "d.f.ip6.arpa."
|
||||
zone_prefix_reverse: "in-addr.arpa"
|
||||
zone_prefix_reverse_8: "{{ ipv4_prefix.split('.')[2::-1] | join('.') }}.in-addr.arpa"
|
||||
zone_prefix_reverse_16: "{{ ipv4_prefix.split('.')[1::-1] | join('.') }}.in-addr.arpa"
|
||||
zone_prefix_reverse_24: "{{ ipv4_prefix.split('.')[::-1] | join('.') }}.in-addr.arpa"
|
||||
|
||||
- name: Set zone for reverse address.
|
||||
ipadnszone:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: "{{ item }}"
|
||||
skip_nameserver_check: yes
|
||||
skip_overlap_check: yes
|
||||
with_items:
|
||||
- "{{ zone_ipv6_reverse }}"
|
||||
- "{{ zone_ipv6_reverse_workaround }}"
|
||||
- "{{ zone_prefix_reverse }}"
|
||||
- "{{ zone_prefix_reverse_8 }}"
|
||||
- "{{ zone_prefix_reverse_16 }}"
|
||||
- "{{ zone_prefix_reverse_24 }}"
|
||||
|
||||
- name: Host "{{ host1_fqdn }}" present
|
||||
ipahost:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: "{{ host1_fqdn }}"
|
||||
ip_address: "{{ ipv4_prefix + '.201' }}"
|
||||
update_dns: yes
|
||||
@@ -61,7 +62,6 @@
|
||||
|
||||
- name: Host "{{ host1_fqdn }}" present, again.
|
||||
ipahost:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: "{{ host1_fqdn }}"
|
||||
ip_address: "{{ ipv4_prefix + '.201' }}"
|
||||
update_dns: yes
|
||||
@@ -71,7 +71,6 @@
|
||||
|
||||
- name: Hosts host1 absent
|
||||
ipahost:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name:
|
||||
- "{{ host1_fqdn }}"
|
||||
update_dns: yes
|
||||
@@ -81,7 +80,6 @@
|
||||
|
||||
- name: Host "{{ host1_fqdn }}" present with IPv6
|
||||
ipahost:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: "{{ host1_fqdn }}"
|
||||
ip_address: "fd00::0001"
|
||||
update_dns: yes
|
||||
@@ -91,7 +89,6 @@
|
||||
|
||||
- name: Host "{{ host1_fqdn }}" present with IPv6, again.
|
||||
ipahost:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: "{{ host1_fqdn }}"
|
||||
ip_address: "fd00::0001"
|
||||
update_dns: yes
|
||||
@@ -101,7 +98,6 @@
|
||||
|
||||
- name: Hosts host1 absent
|
||||
ipahost:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name:
|
||||
- "{{ host1_fqdn }}"
|
||||
update_dns: yes
|
||||
@@ -111,13 +107,10 @@
|
||||
|
||||
- name: Delete zone for reverse address.
|
||||
ipadnszone:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: "{{ item }}"
|
||||
state: absent
|
||||
with_items:
|
||||
- "{{ zone_ipv6_reverse }}"
|
||||
- "{{ zone_ipv6_reverse_workaround }}"
|
||||
- "{{ zone_prefix_reverse }}"
|
||||
- "{{ zone_prefix_reverse_8 }}"
|
||||
- "{{ zone_prefix_reverse_16 }}"
|
||||
- "{{ zone_prefix_reverse_24 }}"
|
||||
|
||||
@@ -81,8 +81,8 @@
|
||||
- name: Test hostgroup presence with multiple hosts and action hostgroup
|
||||
vars:
|
||||
test_cases:
|
||||
- { id: 1, value: "{{ test_hosts | lower }}", expected: true }
|
||||
- { id: 2, value: "{{ test_hosts | upper }}", expected: false }
|
||||
- { id: 1, value: "{{ test_hosts | map('lower') }}", expected: true }
|
||||
- { id: 2, value: "{{ test_hosts | map('upper') }}", expected: false }
|
||||
- { id: 3, value: "{{ test_hosts }}", expected: false }
|
||||
- { id: 4, value: "{{ test_hosts[1] }}", expected: true }
|
||||
- { id: 5, value: "{{ test_hosts[1] | lower }}", expected: false }
|
||||
@@ -104,8 +104,8 @@
|
||||
- name: Test hostgroup with multiple hosts and action member
|
||||
vars:
|
||||
test_cases:
|
||||
- { id: 1, value: "{{ test_hosts | lower }}", state: "absent", expected: true }
|
||||
- { id: 2, value: "{{ test_hosts | upper }}", state: "absent", expected: false }
|
||||
- { id: 1, value: "{{ test_hosts | map('lower') }}", state: "absent", expected: true }
|
||||
- { id: 2, value: "{{ test_hosts | map('upper') }}", state: "absent", expected: false }
|
||||
- { id: 3, value: "{{ test_hosts }}", state: "present", expected: true }
|
||||
- { id: 4, value: "{{ test_hosts[1] }}", state: "absent", expected: true }
|
||||
- { id: 5, value: "{{ test_hosts[1] | lower }}", state: "absent", expected: false }
|
||||
@@ -113,7 +113,7 @@
|
||||
- { id: 7, value: "{{ test_hosts[0] | lower }}", state: "present", expected: false }
|
||||
- { id: 8, value: "{{ test_hosts[0] }}", state: "present", expected: false }
|
||||
- { id: 9, value: "{{ test_hosts[0] | upper }}", state: "present", expected: false }
|
||||
- { id: 10, value: "{{ test_hosts | upper }}", state: "present", expected: true }
|
||||
- { id: 10, value: "{{ test_hosts | map('upper') }}", state: "present", expected: true }
|
||||
- { id: 11, value: "{{ test_hosts[1] }}", state: "present", expected: false }
|
||||
- { id: 12, value: "{{ test_hosts[0] | lower }}", state: "present", expected: false }
|
||||
- { id: 13, value: "{{ test_hosts[0] }}", state: "absent", expected: true }
|
||||
|
||||
67
tests/passkeyconfig/test_passkeyconfig.yml
Normal file
67
tests/passkeyconfig/test_passkeyconfig.yml
Normal file
@@ -0,0 +1,67 @@
|
||||
---
|
||||
- name: Test passkeyconfig
|
||||
hosts: "{{ ipa_test_host | default('ipaserver') }}"
|
||||
# It is normally not needed to set "become" to "true" for a module test.
|
||||
# Only set it to true if it is needed to execute commands as root.
|
||||
become: false
|
||||
# Enable "gather_facts" only if "ansible_facts" variable needs to be used.
|
||||
gather_facts: false
|
||||
module_defaults:
|
||||
ipapasskeyconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
|
||||
tasks:
|
||||
|
||||
- name: Include FreeIPA facts.
|
||||
ansible.builtin.include_tasks: ../env_freeipa_facts.yml
|
||||
|
||||
- name: Run tests only if passkey is supported
|
||||
when: passkey_is_supported
|
||||
block:
|
||||
# TESTS
|
||||
|
||||
- name: Get current passkeyconfig
|
||||
ipapasskeyconfig:
|
||||
register: result_initial
|
||||
failed_when: result_initial.failed
|
||||
|
||||
- name: Ensure require_user_verification is set to false
|
||||
ipapasskeyconfig:
|
||||
require_user_verification: false
|
||||
register: result
|
||||
failed_when: result.failed
|
||||
|
||||
- name: Ensure require_user_verification is set to false again
|
||||
ipapasskeyconfig:
|
||||
require_user_verification: false
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Verify require_user_verification is false
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- result.passkeyconfig.require_user_verification == false
|
||||
|
||||
- name: Ensure require_user_verification is set to true
|
||||
ipapasskeyconfig:
|
||||
require_user_verification: true
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure require_user_verification is set to true again
|
||||
ipapasskeyconfig:
|
||||
require_user_verification: true
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Verify require_user_verification is true
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- result.passkeyconfig.require_user_verification == true
|
||||
|
||||
# CLEANUP: Restore original configuration
|
||||
- name: Restore original passkeyconfig
|
||||
ipapasskeyconfig:
|
||||
require_user_verification: "{{ result_initial.passkeyconfig.require_user_verification }}"
|
||||
when: result_initial.passkeyconfig is defined and result_initial.passkeyconfig.require_user_verification is defined
|
||||
40
tests/passkeyconfig/test_passkeyconfig_client_context.yml
Normal file
40
tests/passkeyconfig/test_passkeyconfig_client_context.yml
Normal file
@@ -0,0 +1,40 @@
|
||||
---
|
||||
- name: Test passkeyconfig
|
||||
hosts: ipaclients, ipaserver
|
||||
# It is normally not needed to set "become" to "true" for a module test.
|
||||
# Only set it to true if it is needed to execute commands as root.
|
||||
become: false
|
||||
# Enable "gather_facts" only if "ansible_facts" variable needs to be used.
|
||||
gather_facts: false
|
||||
|
||||
tasks:
|
||||
- name: Include FreeIPA facts.
|
||||
ansible.builtin.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.
|
||||
ipapasskeyconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: server
|
||||
require_user_verification: false
|
||||
register: result
|
||||
failed_when: not (result.failed and result.msg is regex("No module named '*ipaserver'*"))
|
||||
when: ipa_host_is_client and passkey_is_supported
|
||||
|
||||
# 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 passkeyconfig using client context, in client host.
|
||||
import_playbook: test_passkeyconfig.yml
|
||||
when: groups['ipaclients'] and passkey_is_supported
|
||||
vars:
|
||||
ipa_test_host: ipaclients
|
||||
|
||||
- name: Test passkeyconfig using client context, in server host.
|
||||
import_playbook: test_passkeyconfig.yml
|
||||
when: passkey_is_supported and (groups['ipaclients'] is not defined or not groups['ipaclients'])
|
||||
161
tests/role/test_role_sysaccount_member.yml
Normal file
161
tests/role/test_role_sysaccount_member.yml
Normal file
@@ -0,0 +1,161 @@
|
||||
---
|
||||
- name: Test sysaccount
|
||||
hosts: "{{ ipa_test_host | default('ipaserver') }}"
|
||||
# It is normally not needed to set "become" to "true" for a module test.
|
||||
# Only set it to true if it is needed to execute commands as root.
|
||||
become: false
|
||||
# Enable "gather_facts" only if "ansible_facts" variable needs to be used.
|
||||
gather_facts: false
|
||||
module_defaults:
|
||||
ipaprivilege:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
iparole:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
ipasysaccount:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
|
||||
tasks:
|
||||
|
||||
- name: Verify if role sysaccount member tests are possible
|
||||
ansible.builtin.shell:
|
||||
cmd: |
|
||||
echo SomeADMINpassword | kinit -c {{ krb5ccname }} admin > /dev/null
|
||||
RESULT=$(KRB5CCNAME={{ krb5ccname }} ipa role-add-member --help)
|
||||
kdestroy -A -c {{ krb5ccname }} > /dev/null
|
||||
echo $RESULT
|
||||
vars:
|
||||
krb5ccname: "__check_ipa_role_add_member__"
|
||||
register: check_role_add_member
|
||||
|
||||
- name: Execute tests
|
||||
when: '"sysaccounts" in check_role_add_member.stdout'
|
||||
block:
|
||||
|
||||
# CLEANUP TEST ITEMS
|
||||
|
||||
- name: Ensure sysaccount my-app is absent
|
||||
ipasysaccount:
|
||||
name: my-app
|
||||
state: absent
|
||||
|
||||
- name: Ensure role "my-app role" is absent
|
||||
iparole:
|
||||
name: my-app role
|
||||
state: absent
|
||||
|
||||
- name: Ensure privilege "my-app password change privilege" is absent
|
||||
ipaprivilege:
|
||||
name: my-app password change privilege
|
||||
state: absent
|
||||
|
||||
# CREATE TEST ITEMS
|
||||
|
||||
- name: Ensure privilege "my-app password change privilege" is present
|
||||
ipaprivilege:
|
||||
name: my-app password change privilege
|
||||
permission:
|
||||
- "System: Change User password"
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
# TESTS
|
||||
|
||||
- name: Ensure sysaccount my-app is present with random password
|
||||
ipasysaccount:
|
||||
name: my-app
|
||||
random: true
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure role "my-app role" is present with sysaccount member my-app
|
||||
iparole:
|
||||
name: my-app role
|
||||
sysaccount: my-app
|
||||
privilege: my-app password change privilege
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure role "my-app role" is present with sysaccount member my-app, again
|
||||
iparole:
|
||||
name: my-app role
|
||||
sysaccount: my-app
|
||||
privilege: my-app password change privilege
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Ensure role my-app role does not have sysaccount member my-app
|
||||
iparole:
|
||||
name: my-app role
|
||||
sysaccount: my-app
|
||||
action: member
|
||||
state: absent
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure role my-app role does not have sysaccount member my-app, again
|
||||
iparole:
|
||||
name: my-app role
|
||||
sysaccount: my-app
|
||||
action: member
|
||||
state: absent
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Ensure role my-app role has sysaccount member my-app
|
||||
iparole:
|
||||
name: my-app role
|
||||
sysaccount: my-app
|
||||
action: member
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure role my-app role has sysaccount member my-app, again
|
||||
iparole:
|
||||
name: my-app role
|
||||
sysaccount: my-app
|
||||
action: member
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Ensure role my-app role has zero sysaccount members
|
||||
iparole:
|
||||
name: my-app role
|
||||
sysaccount: []
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure role my-app role has zero sysaccount members, again
|
||||
iparole:
|
||||
name: my-app role
|
||||
sysaccount: []
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Ensure role my-app role does not have sysaccount member my-app, again
|
||||
iparole:
|
||||
name: my-app role
|
||||
sysaccount: my-app
|
||||
action: member
|
||||
state: absent
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
# CLEANUP TEST ITEMS
|
||||
|
||||
- name: Ensure sysaccount my-app is absent
|
||||
ipasysaccount:
|
||||
name: my-app
|
||||
state: absent
|
||||
|
||||
- name: Ensure role my-app role is absent
|
||||
iparole:
|
||||
name: my-app role
|
||||
state: absent
|
||||
|
||||
- name: Ensure privilege "my-app password change privilege" is absent
|
||||
ipaprivilege:
|
||||
name: my-app password change privilege
|
||||
state: absent
|
||||
@@ -19,7 +19,7 @@ pip install galaxy_importer
|
||||
rm -f "$ANSIBLE_COLLECTION"-*.tar.gz
|
||||
rm -f importer_result.json
|
||||
|
||||
utils/build-galaxy-release.sh
|
||||
utils/build-collection.sh rpm
|
||||
|
||||
sed "s/LOCAL_IMAGE_DOCKER = True/LOCAL_IMAGE_DOCKER = ${use_docker}/" < tests/sanity/galaxy-importer.cfg > ${VENV}/galaxy-importer.cfg
|
||||
export GALAXY_IMPORTER_CONFIG=${VENV}/galaxy-importer.cfg
|
||||
|
||||
@@ -48,7 +48,8 @@
|
||||
- name: Verify keytab
|
||||
ansible.builtin.shell: ipa service-find "mysvc1/{{ ansible_facts['fqdn'] }}"
|
||||
register: result
|
||||
failed_when: result.failed or result.stdout | regex_search(" Keytab. true")
|
||||
changed_when: false
|
||||
failed_when: result.failed or (result.stdout | regex_search(" Keytab. [Tt]rue")) in [None, ""]
|
||||
|
||||
- name: Ensure service is disabled
|
||||
ipaservice:
|
||||
@@ -61,7 +62,8 @@
|
||||
- name: Verify keytab
|
||||
ansible.builtin.shell: ipa service-find "mysvc1/{{ ansible_facts['fqdn'] }}"
|
||||
register: result
|
||||
failed_when: result.failed or result.stdout | regex_search(" Keytab. true")
|
||||
changed_when: false
|
||||
failed_when: result.failed or (result.stdout | regex_search(" Keytab. [Ff]alse")) in [None, ""]
|
||||
|
||||
- name: Obtain keytab
|
||||
ansible.builtin.shell: ipa-getkeytab -s "{{ ansible_facts['fqdn'] }}" -p "mysvc1/{{ ansible_facts['fqdn'] }}" -k mysvc1.keytab
|
||||
@@ -69,7 +71,8 @@
|
||||
- name: Verify keytab
|
||||
ansible.builtin.shell: ipa service-find "mysvc1/{{ ansible_facts['fqdn'] }}"
|
||||
register: result
|
||||
failed_when: result.failed or result.stdout | regex_search(" Keytab. true")
|
||||
changed_when: false
|
||||
failed_when: result.failed or (result.stdout | regex_search(" Keytab. [Tt]rue")) in [None, ""]
|
||||
|
||||
- name: Ensure service is disabled
|
||||
ipaservice:
|
||||
@@ -82,7 +85,8 @@
|
||||
- name: Verify keytab
|
||||
ansible.builtin.shell: ipa service-find "mysvc1/{{ ansible_facts['fqdn'] }}"
|
||||
register: result
|
||||
failed_when: result.failed or result.stdout | regex_search(" Keytab. true")
|
||||
changed_when: false
|
||||
failed_when: result.failed or (result.stdout | regex_search(" Keytab. [Ff]alse")) in [None, ""]
|
||||
|
||||
- name: Ensure service is disabled, with no keytab.
|
||||
ipaservice:
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
gather_facts: yes
|
||||
|
||||
tasks:
|
||||
- name: Include tasks ../env_freeipa_facts.yml
|
||||
ansible.builtin.include_tasks: ../env_freeipa_facts.yml
|
||||
|
||||
# CLEANUP TEST ITEMS
|
||||
|
||||
@@ -83,6 +85,37 @@
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Ensure service "test-service/{{ ansible_facts['fqdn'] }}" is present with auth_ind passkey
|
||||
ipaservice:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: "test-service/{{ ansible_facts['fqdn'] }}"
|
||||
auth_ind:
|
||||
- passkey
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
when: passkey_is_supported
|
||||
|
||||
- name: Ensure service "test-service/{{ ansible_facts['fqdn'] }}" is present with auth_ind passkey, again
|
||||
ipaservice:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: "test-service/{{ ansible_facts['fqdn'] }}"
|
||||
auth_ind:
|
||||
- passkey
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
when: passkey_is_supported
|
||||
|
||||
- name: Check if correct message is given if passkey is not supported.
|
||||
ipaservice:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: "test-service/{{ ansible_facts['fqdn'] }}"
|
||||
auth_ind:
|
||||
- passkey
|
||||
register: result
|
||||
failed_when: not result.failed or "'passkey' is not supported" not in result.msg
|
||||
when: not passkey_is_supported
|
||||
|
||||
- name: Ensure service "test-service/{{ ansible_facts['fqdn'] }}" is present with empty auth_ind
|
||||
ipaservice:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
|
||||
150
tests/sysaccount/test_sysaccount.yml
Normal file
150
tests/sysaccount/test_sysaccount.yml
Normal file
@@ -0,0 +1,150 @@
|
||||
---
|
||||
- name: Test sysaccount
|
||||
hosts: "{{ ipa_test_host | default('ipaserver') }}"
|
||||
# It is normally not needed to set "become" to "true" for a module test.
|
||||
# Only set it to true if it is needed to execute commands as root.
|
||||
become: false
|
||||
# Enable "gather_facts" only if "ansible_facts" variable needs to be used.
|
||||
gather_facts: false
|
||||
module_defaults:
|
||||
ipasysaccount:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
|
||||
tasks:
|
||||
|
||||
- name: Verify sysaccount tests are possible
|
||||
ansible.builtin.shell:
|
||||
cmd: |
|
||||
echo SomeADMINpassword | kinit -c {{ krb5ccname }} admin > /dev/null
|
||||
RESULT=$(KRB5CCNAME={{ krb5ccname }} ipa sysaccount-add --help)
|
||||
kdestroy -A -c {{ krb5ccname }} > /dev/null
|
||||
echo $RESULT
|
||||
vars:
|
||||
krb5ccname: "__check_ipa_sysaccount_add__"
|
||||
register: check_sysaccount_add
|
||||
|
||||
- name: Execute tests
|
||||
when: '"ipa: ERROR: unknown command" not in check_sysaccount_add.stderr'
|
||||
block:
|
||||
|
||||
# CLEANUP TEST ITEMS
|
||||
|
||||
- name: Ensure sysaccount my-app is absent
|
||||
ipasysaccount:
|
||||
name: my-app
|
||||
state: absent
|
||||
|
||||
# CREATE TEST ITEMS
|
||||
|
||||
# TESTS
|
||||
|
||||
- name: Ensure sysaccount my-app is present with random password
|
||||
ipasysaccount:
|
||||
name: my-app
|
||||
random: true
|
||||
register: result
|
||||
failed_when: not result.changed or
|
||||
result.sysaccount.randompassword is not defined or
|
||||
result.failed
|
||||
|
||||
- name: Ensure sysaccount my-app is present, again with updated random password and update_password always
|
||||
ipasysaccount:
|
||||
name: my-app
|
||||
random: true
|
||||
register: result2
|
||||
failed_when: not result2.changed or
|
||||
result2.sysaccount.randompassword is not defined or
|
||||
result2.sysaccount.randompassword == result.sysaccount.randompassword or
|
||||
result2.failed
|
||||
|
||||
- name: Ensure sysaccount my-app is present, again with random password and update_password on_create
|
||||
ipasysaccount:
|
||||
name: my-app
|
||||
random: true
|
||||
update_password: on_create
|
||||
register: result
|
||||
failed_when: not result2.changed or
|
||||
result.sysaccount.randompassword is defined or
|
||||
result.failed
|
||||
|
||||
# more tests here
|
||||
|
||||
- name: Ensure sysaccount my-app is disabled
|
||||
ipasysaccount:
|
||||
name: my-app
|
||||
state: disabled
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure sysaccount my-app is disabled, again
|
||||
ipasysaccount:
|
||||
name: my-app
|
||||
state: disabled
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Ensure sysaccount my-app is enabled
|
||||
ipasysaccount:
|
||||
name: my-app
|
||||
state: enabled
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure sysaccount my-app is enabled, again
|
||||
ipasysaccount:
|
||||
name: my-app
|
||||
state: enabled
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Ensure sysaccount my-app is privileged
|
||||
ipasysaccount:
|
||||
name: my-app
|
||||
privileged: true
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure sysaccount my-app is privileged, again
|
||||
ipasysaccount:
|
||||
name: my-app
|
||||
privileged: true
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
# ADDITIONAL TEST HERE?
|
||||
|
||||
- name: Ensure sysaccount my-app is not privileged
|
||||
ipasysaccount:
|
||||
name: my-app
|
||||
privileged: false
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure sysaccount my-app is not privileged, again
|
||||
ipasysaccount:
|
||||
name: my-app
|
||||
privileged: false
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Ensure sysaccount my-app is absent
|
||||
ipasysaccount:
|
||||
name: my-app
|
||||
state: absent
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure sysaccount my-app is absent again
|
||||
ipasysaccount:
|
||||
name: my-app
|
||||
state: absent
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
# CLEANUP TEST ITEMS
|
||||
|
||||
- name: Ensure sysaccount my-app is absent
|
||||
ipasysaccount:
|
||||
name: my-app
|
||||
state: absent
|
||||
40
tests/sysaccount/test_sysaccount_client_context.yml
Normal file
40
tests/sysaccount/test_sysaccount_client_context.yml
Normal file
@@ -0,0 +1,40 @@
|
||||
---
|
||||
- name: Test sysaccount
|
||||
hosts: ipaclients, ipaserver
|
||||
# It is normally not needed to set "become" to "true" for a module test.
|
||||
# Only set it to true if it is needed to execute commands as root.
|
||||
become: false
|
||||
# Enable "gather_facts" only if "ansible_facts" variable needs to be used.
|
||||
gather_facts: false
|
||||
|
||||
tasks:
|
||||
- name: Include FreeIPA facts.
|
||||
ansible.builtin.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.
|
||||
ipasysaccount:
|
||||
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 sysaccount using client context, in client host.
|
||||
import_playbook: test_sysaccount.yml
|
||||
when: groups['ipaclients']
|
||||
vars:
|
||||
ipa_test_host: ipaclients
|
||||
|
||||
- name: Test sysaccount using client context, in server host.
|
||||
import_playbook: test_sysaccount.yml
|
||||
when: groups['ipaclients'] is not defined or not groups['ipaclients']
|
||||
@@ -5,6 +5,9 @@
|
||||
gather_facts: false
|
||||
|
||||
tasks:
|
||||
- name: Include FreeIPA facts.
|
||||
ansible.builtin.include_tasks: ../env_freeipa_facts.yml
|
||||
|
||||
- name: Remove test users
|
||||
ipauser:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
@@ -392,6 +395,42 @@
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure user pinky with userauthtype passkey exists
|
||||
ipauser:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: pinky
|
||||
first: pinky
|
||||
last: user
|
||||
userauthtype: passkey
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
when: passkey_is_supported
|
||||
|
||||
- name: Ensure user pinky with userauthtype passkey exists, again
|
||||
ipauser:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: pinky
|
||||
first: pinky
|
||||
last: user
|
||||
userauthtype: passkey
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
when: passkey_is_supported
|
||||
|
||||
- name: Check if correct message is given if passkey is not supported.
|
||||
ipauser:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: pinky
|
||||
first: pinky
|
||||
last: user
|
||||
userauthtype: passkey
|
||||
register: result
|
||||
when: not passkey_is_supported
|
||||
failed_when: not result.failed or "'passkey' is not supported" not in result.msg
|
||||
|
||||
- name: User pinky absent and preserved for future exclusion.
|
||||
ipauser:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
|
||||
@@ -8,21 +8,28 @@ pwd=$(pwd)
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: $prog [options] [<namespace> <name>]
|
||||
Usage: $prog [options] rpm|aah|galaxy
|
||||
|
||||
Build Anible Collection for ansible-freeipa.
|
||||
|
||||
The namespace defaults to freeipa an name defaults to ansible_freeipa,
|
||||
if namespace and name are not given. Namespace and name need to be set
|
||||
together.
|
||||
The namespace and name are defined according to the argument:
|
||||
|
||||
rpm freeipa.ansible_freeipa - General use and RPMs
|
||||
galaxy freeipa.ansible_freeipa - Ansible Galaxy
|
||||
aah redhat.rhel_idm - Ansible AutomationHub
|
||||
|
||||
The generated file README-COLLECTION.md is set in galaxy.yml as the
|
||||
documentation entry point for the collections generated with aah and galaxy
|
||||
as Ansible AutomationHub and also Ansible Galaxy are not able to render the
|
||||
documentation README files in the collection properly.
|
||||
|
||||
Options:
|
||||
-a Add all files, no only files known to git repo
|
||||
-a Add all files, not only files known to git repo
|
||||
-k Keep build directory
|
||||
-i Install the generated collection
|
||||
-o <A.B.C> Build offline without using git, using version A.B.C
|
||||
Also enables -a
|
||||
-p <path> Installation the generated collection in the path, the
|
||||
-p <path> Install the generated collection in the given path, the
|
||||
ansible_collections sub directory will be created and will
|
||||
contain the collection: ansible_collections/<namespace>/<name>
|
||||
Also enables -i
|
||||
@@ -36,7 +43,9 @@ keep=0
|
||||
install=0
|
||||
path=
|
||||
offline=
|
||||
galaxy_version=
|
||||
version=
|
||||
namespace="freeipa"
|
||||
name="ansible_freeipa"
|
||||
while getopts "ahkio:p:" arg; do
|
||||
case $arg in
|
||||
a)
|
||||
@@ -53,7 +62,7 @@ while getopts "ahkio:p:" arg; do
|
||||
install=1
|
||||
;;
|
||||
o)
|
||||
galaxy_version=$OPTARG
|
||||
version=$OPTARG
|
||||
offline=1
|
||||
all=1
|
||||
;;
|
||||
@@ -70,60 +79,97 @@ while getopts "ahkio:p:" arg; do
|
||||
done
|
||||
shift $((OPTIND-1))
|
||||
|
||||
if [ $# != 0 ] && [ $# != 2 ]; then
|
||||
if [ $# != 1 ]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
namespace="${1-freeipa}"
|
||||
name="${2-ansible_freeipa}"
|
||||
if [ -z "$namespace" ]; then
|
||||
echo "Namespace might not be empty"
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$name" ]; then
|
||||
echo "Name might not be empty"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
collection="$1"
|
||||
case "$collection" in
|
||||
rpm|galaxy)
|
||||
# namespace and name are already set
|
||||
;;
|
||||
aah)
|
||||
namespace="redhat"
|
||||
name="rhel_idm"
|
||||
;;
|
||||
*)
|
||||
echo "Unknown collection '$collection'"
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
collection_prefix="${namespace}.${name}"
|
||||
collection_uname="${collection^^}"
|
||||
|
||||
[ -z "$galaxy_version" ] && \
|
||||
galaxy_version=$(git describe --tags 2>/dev/null | sed -e "s/^v//")
|
||||
[ -z "$version" ] && \
|
||||
version=$(git describe --tags 2>/dev/null | sed -e "s/^v//")
|
||||
|
||||
if [ -z "$galaxy_version" ]; then
|
||||
if [ -z "$version" ]; then
|
||||
echo "Version could not be detected"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Building collection: ${namespace}-${name}-${galaxy_version}"
|
||||
echo "Building collection: ${namespace}-${name}-${version} for ${collection_uname}"
|
||||
|
||||
GALAXY_BUILD=".galaxy-build"
|
||||
BUILD=".collection-build"
|
||||
|
||||
if [ -e "$GALAXY_BUILD" ]; then
|
||||
echo "Removing existing $GALAXY_BUILD ..."
|
||||
rm -rf "$GALAXY_BUILD"
|
||||
echo -e "\033[ARemoving existing $GALAXY_BUILD ... \033[32;1mDONE\033[0m"
|
||||
if [ -e "$BUILD" ]; then
|
||||
echo "Removing existing $BUILD ..."
|
||||
rm -rf "$BUILD"
|
||||
echo -e "\033[ARemoving existing $BUILD ... \033[32;1mDONE\033[0m"
|
||||
fi
|
||||
mkdir "$GALAXY_BUILD"
|
||||
echo "Copying files to build dir $GALAXY_BUILD ..."
|
||||
mkdir "$BUILD"
|
||||
echo "Copying files to build dir $BUILD ..."
|
||||
if [ $all == 1 ]; then
|
||||
# Copy all files except galaxy build dir
|
||||
# Copy all files except collection build dir
|
||||
for file in .[A-z]* [A-z]*; do
|
||||
[[ "$file" == "${GALAXY_BUILD}" ]] && continue
|
||||
cp -a "$file" "${GALAXY_BUILD}/"
|
||||
[[ "$file" == "${BUILD}" ]] && continue
|
||||
cp -a "$file" "${BUILD}/"
|
||||
done
|
||||
else
|
||||
# git ls-tree is quoting, therefore ignore SC2046: Quote this to prevent
|
||||
# word splitting
|
||||
# shellcheck disable=SC2046
|
||||
tar -cf - $(git ls-tree HEAD --name-only -r) | (cd "$GALAXY_BUILD/" && tar -xf -)
|
||||
tar -cf - $(git ls-tree HEAD --name-only -r) | (cd "$BUILD/" && tar -xf -)
|
||||
fi
|
||||
echo -e "\033[ACopying files to build dir $GALAXY_BUILD ... \033[32;1mDONE\033[0m"
|
||||
cd "$GALAXY_BUILD" || exit 1
|
||||
echo -e "\033[ACopying files to build dir $BUILD ... \033[32;1mDONE\033[0m"
|
||||
cd "$BUILD" || exit 1
|
||||
|
||||
sed -i -e "s/version: .*/version: \"$galaxy_version\"/" galaxy.yml
|
||||
echo "Removing .copr, .git* and .pre* files from build dir $BUILD ..."
|
||||
rm -rf .copr .git* .pre*
|
||||
echo -e "\033[ARemoving files from build dir $BUILD ... \033[32;1mDONE\033[0m"
|
||||
|
||||
if [ "$collection" != "rpm" ]; then
|
||||
cat > README-COLLECTION.md <<EOF
|
||||
FreeIPA Ansible collection
|
||||
==========================
|
||||
|
||||
Important
|
||||
---------
|
||||
|
||||
For the documentation of this collection, please have a look at the documentation in the collection archive. Starting point: Base collection directory, file \`README.md\`.
|
||||
|
||||
${collection_uname} is not providing proper user documentation nor is able to render the documentation part of the collection. Please ignore any modules and plugins in ${collection_uname} documentation section with the prefix \`ipaserver_\`, \`ipareplica_\`, \`ipaclient_\`, \`ipabackup_\` and \`ipasmartcard_\` and also \`module_utils\` and \`doc_fragments\`. These files are used internally only and are not supported to be used otherwise.
|
||||
|
||||
There is the [generic ansible-freeipa upstream documentation](https://github.com/freeipa/ansible-freeipa/blob/v${version}/README.md) specific to the version and also the [latest generic ansible-freeipa upstream documentation](https://github.com/freeipa/ansible-freeipa/blob/master/README.md), both without using the collection prefix \`${collection_prefix}\`.
|
||||
EOF
|
||||
if [ "$collection" == "aah" ]; then
|
||||
cat >> README-COLLECTION.md <<EOF
|
||||
|
||||
Support
|
||||
-------
|
||||
|
||||
This collection is maintained by Red Hat RHEL team.
|
||||
|
||||
As Red Hat Ansible Certified Content, this collection is entitled to support through the Ansible Automation Platform (AAP) using the **Create issue** button on the top right corner.
|
||||
EOF
|
||||
fi
|
||||
sed -i -e "s/readme: .*/readme: README-COLLECTION.md/" galaxy.yml
|
||||
fi
|
||||
sed -i -e "s/version: .*/version: \"$version\"/" galaxy.yml
|
||||
sed -i -e "s/namespace: .*/namespace: \"$namespace\"/" galaxy.yml
|
||||
sed -i -e "s/name: .*/name: \"$name\"/" galaxy.yml
|
||||
|
||||
find . -name "*~" -exec rm {} \;
|
||||
find . -name "__py*__" -exec rm -rf {} \;
|
||||
|
||||
@@ -210,14 +256,14 @@ ansible-galaxy collection build --force --output-path="$pwd"
|
||||
cd "$pwd" || exit 1
|
||||
|
||||
if [ $keep == 0 ]; then
|
||||
echo "Removing build dir $GALAXY_BUILD ..."
|
||||
rm -rf "$GALAXY_BUILD"
|
||||
echo -e "\033[ARemoving build dir $GALAXY_BUILD ... \033[32;1mDONE\033[0m"
|
||||
echo "Removing build dir $BUILD ..."
|
||||
rm -rf "$BUILD"
|
||||
echo -e "\033[ARemoving build dir $BUILD ... \033[32;1mDONE\033[0m"
|
||||
else
|
||||
echo "Keeping build dir $GALAXY_BUILD"
|
||||
echo "Keeping build dir $BUILD"
|
||||
fi
|
||||
|
||||
if [ $install == 1 ]; then
|
||||
echo "Installing collection ${namespace}-${name}-${galaxy_version}.tar.gz ..."
|
||||
ansible-galaxy collection install ${path:+"-p$path"} "${namespace}-${name}-${galaxy_version}.tar.gz" --force ${offline/1/--offline}
|
||||
echo "Installing collection ${namespace}-${name}-${version}.tar.gz ..."
|
||||
ansible-galaxy collection install ${path:+"-p$path"} "${namespace}-${name}-${version}.tar.gz" --force ${offline/1/--offline}
|
||||
fi
|
||||
Reference in New Issue
Block a user