mirror of
https://github.com/freeipa/ansible-freeipa.git
synced 2026-03-26 21:33:05 +00:00
[RFE] Allow multiple groups creation.
Adding an option `groups` to create multiple groups in one operation.
Adding tests (present/absent/external/nonposix) with server and
client context.
Simple example of `groups` option:
```
tasks:
- name: Ensure 2 groups are present
ipagroup:
ipaadmin_password: SomeADMINpassword
groups:
- name: group1
- name: group2
```
Signed-off-by: Denis Karpelevich <dkarpele@redhat.com>
This commit is contained in:
105
README-group.md
105
README-group.md
@@ -8,6 +8,9 @@ The group module allows to ensure presence and absence of groups and members of
|
||||
|
||||
The group module is as compatible as possible to the Ansible upstream `ipa_group` module, but additionally offers to add users to a group and also to remove users from a group.
|
||||
|
||||
## Note
|
||||
Ensuring presence (adding) of several groups with mixed types (`external`, `nonposix` and `posix`) requires a fix in FreeIPA. The module implements a workaround to automatically use `client` context if the fix is not present in the target node FreeIPA and if more than one group is provided to the task using the `groups` parameter. If `ipaapi_context` is forced to be `server`, the module will fail in this case.
|
||||
|
||||
|
||||
Features
|
||||
--------
|
||||
@@ -71,6 +74,62 @@ Example playbook to add groups:
|
||||
name: appops
|
||||
```
|
||||
|
||||
These three `ipagroup` module calls can be combined into one with the `groups` variable:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to handle groups
|
||||
hosts: ipaserver
|
||||
|
||||
tasks:
|
||||
- name: Ensure groups ops, sysops and appops are present
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: ops
|
||||
gidnumber: 1234
|
||||
- name: sysops
|
||||
user:
|
||||
- pinky
|
||||
- name: appops
|
||||
```
|
||||
|
||||
You can also alternatively use a json file containing the groups, here `groups_present.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"groups": [
|
||||
{
|
||||
"name": "group1",
|
||||
"description": "description group1"
|
||||
},
|
||||
{
|
||||
"name": "group2",
|
||||
"description": "description group2"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
And ensure the presence of the groups with this example playbook:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Tests
|
||||
hosts: ipaserver
|
||||
gather_facts: false
|
||||
|
||||
tasks:
|
||||
- name: Include groups_present.json
|
||||
include_vars:
|
||||
file: groups_present.json
|
||||
|
||||
- name: Groups present
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups: "{{ groups }}"
|
||||
```
|
||||
|
||||
Example playbook to add users to a group:
|
||||
|
||||
```yaml
|
||||
@@ -112,11 +171,11 @@ Example playbook to add group members to a group:
|
||||
Example playbook to add members from a trusted realm to an external group:
|
||||
|
||||
```yaml
|
||||
--
|
||||
---
|
||||
- name: Playbook to handle groups.
|
||||
hosts: ipaserver
|
||||
became: true
|
||||
|
||||
|
||||
tasks:
|
||||
- name: Create an external group and add members from a trust to it.
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
@@ -127,6 +186,24 @@ Example playbook to add members from a trusted realm to an external group:
|
||||
- WINIPA\\Developers
|
||||
```
|
||||
|
||||
Example playbook to add nonposix and external groups:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to add nonposix and external groups
|
||||
hosts: ipaserver
|
||||
|
||||
tasks:
|
||||
- name: Add nonposix group sysops and external group appops
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: sysops
|
||||
nonposix: true
|
||||
- name: appops
|
||||
external: true
|
||||
```
|
||||
|
||||
Example playbook to remove groups:
|
||||
|
||||
```yaml
|
||||
@@ -136,13 +213,29 @@ Example playbook to remove groups:
|
||||
become: true
|
||||
|
||||
tasks:
|
||||
# Remove goups sysops, appops and ops
|
||||
# Remove groups sysops, appops and ops
|
||||
- ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: sysops,appops,ops
|
||||
state: absent
|
||||
```
|
||||
|
||||
Example playbook to ensure groups are absent:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to handle groups
|
||||
hosts: ipaserver
|
||||
|
||||
tasks:
|
||||
- name: Ensure groups ops and sysops are absent
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: ops
|
||||
- name: sysops
|
||||
state: absent
|
||||
```
|
||||
|
||||
Variables
|
||||
=========
|
||||
@@ -152,8 +245,10 @@ Variable | Description | Required
|
||||
`ipaadmin_principal` | The admin principal is a string and defaults to `admin` | no
|
||||
`ipaadmin_password` | The admin password is a string and is required if there is no admin ticket available on the node | no
|
||||
`ipaapi_context` | The context in which the module will execute. Executing in a server context is preferred. If not provided context will be determined by the execution environment. Valid values are `server` and `client`. | no
|
||||
`ipaapi_ldap_cache` | Use LDAP cache for IPA connection. The bool setting defaults to yes. (bool) | no
|
||||
`ipaapi_ldap_cache` | Use LDAP cache for IPA connection. The bool setting defaults to <br/>. (bool) | no
|
||||
`name` \| `cn` | The list of group name strings. | no
|
||||
`groups` | The list of group dicts. Each `groups` dict entry can contain group variables.<br>There is one required option in the `groups` dict:| no
|
||||
| `name` - The group name string of the entry. | yes
|
||||
`description` | The group description string. | no
|
||||
`gid` \| `gidnumber` | The GID integer. | no
|
||||
`posix` | Create a non-POSIX group or change a non-POSIX to a posix group. `nonposix`, `posix` and `external` are mutually exclusive. (bool) | no
|
||||
|
||||
32
playbooks/group/add-groups.yml
Normal file
32
playbooks/group/add-groups.yml
Normal file
@@ -0,0 +1,32 @@
|
||||
---
|
||||
- name: Playbook to handle multiple groups
|
||||
hosts: ipaserver
|
||||
|
||||
tasks:
|
||||
- name: Create multiple groups ops, sysops
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: ops
|
||||
gidnumber: 1234
|
||||
- name: sysops
|
||||
|
||||
- name: Add user and group members to groups sysops and appops
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: sysops
|
||||
user:
|
||||
- user1
|
||||
- name: appops
|
||||
group:
|
||||
- group2
|
||||
|
||||
- name: Create multiple non-POSIX and external groups
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: nongroup
|
||||
nonposix: true
|
||||
- name: extgroup
|
||||
external: true
|
||||
@@ -41,8 +41,88 @@ options:
|
||||
description: The group name
|
||||
type: list
|
||||
elements: str
|
||||
required: true
|
||||
required: false
|
||||
aliases: ["cn"]
|
||||
groups:
|
||||
description: The list of group dicts (internally gid).
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
name:
|
||||
description: The group (internally gid).
|
||||
type: str
|
||||
required: true
|
||||
aliases: ["cn"]
|
||||
description:
|
||||
description: The group description
|
||||
type: str
|
||||
required: false
|
||||
gid:
|
||||
description: The GID
|
||||
type: int
|
||||
required: false
|
||||
aliases: ["gidnumber"]
|
||||
nonposix:
|
||||
description: Create as a non-POSIX group
|
||||
required: false
|
||||
type: bool
|
||||
external:
|
||||
description: Allow adding external non-IPA members from trusted domains
|
||||
required: false
|
||||
type: bool
|
||||
posix:
|
||||
description:
|
||||
Create a non-POSIX group or change a non-POSIX to a posix group.
|
||||
required: false
|
||||
type: bool
|
||||
nomembers:
|
||||
description: Suppress processing of membership attributes
|
||||
required: false
|
||||
type: bool
|
||||
user:
|
||||
description: List of user names assigned to this group.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
group:
|
||||
description: List of group names assigned to this group.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
service:
|
||||
description:
|
||||
- List of service names assigned to this group.
|
||||
- Only usable with IPA versions 4.7 and up.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
membermanager_user:
|
||||
description:
|
||||
- List of member manager users assigned to this group.
|
||||
- Only usable with IPA versions 4.8.4 and up.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
membermanager_group:
|
||||
description:
|
||||
- List of member manager groups assigned to this group.
|
||||
- Only usable with IPA versions 4.8.4 and up.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
externalmember:
|
||||
description:
|
||||
- List of members of a trusted domain in DOM\\name or name@domain form.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaexternalmember", "external_member"]
|
||||
idoverrideuser:
|
||||
description:
|
||||
- User ID overrides to add
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
description:
|
||||
description: The group description
|
||||
type: str
|
||||
@@ -144,6 +224,14 @@ EXAMPLES = """
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: appops
|
||||
|
||||
# Create multiple groups ops, sysops
|
||||
- ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: ops
|
||||
gidnumber: 1234
|
||||
- name: sysops
|
||||
|
||||
# Add user member pinky to group sysops
|
||||
- ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
@@ -160,7 +248,7 @@ EXAMPLES = """
|
||||
user:
|
||||
- brain
|
||||
|
||||
# Add group members sysops and appops to group sysops
|
||||
# Add group members sysops and appops to group ops
|
||||
- ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: ops
|
||||
@@ -168,6 +256,17 @@ EXAMPLES = """
|
||||
- sysops
|
||||
- appops
|
||||
|
||||
# Add user and group members to groups sysops and appops
|
||||
- ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: sysops
|
||||
user:
|
||||
- user1
|
||||
- name: appops
|
||||
group:
|
||||
- group2
|
||||
|
||||
# Create a non-POSIX group
|
||||
- ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
@@ -189,7 +288,16 @@ EXAMPLES = """
|
||||
- WINIPA\\Web Users
|
||||
- WINIPA\\Developers
|
||||
|
||||
# Remove goups sysops, appops, ops and nongroup
|
||||
# Create multiple non-POSIX and external groups
|
||||
- ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: nongroup
|
||||
nonposix: true
|
||||
- name: extgroup
|
||||
external: true
|
||||
|
||||
# Remove groups sysops, appops, ops and nongroup
|
||||
- ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: sysops,appops,ops, nongroup
|
||||
@@ -203,6 +311,9 @@ from ansible.module_utils._text import to_text
|
||||
from ansible.module_utils.ansible_freeipa_module import \
|
||||
IPAAnsibleModule, compare_args_ipa, gen_add_del_lists, \
|
||||
gen_add_list, gen_intersection_list, api_check_param
|
||||
from ansible.module_utils import six
|
||||
if six.PY3:
|
||||
unicode = str
|
||||
|
||||
|
||||
def find_group(module, name):
|
||||
@@ -257,6 +368,22 @@ def gen_member_args(user, group, service, externalmember, idoverrideuser):
|
||||
return _args
|
||||
|
||||
|
||||
def check_parameters(module, state, action):
|
||||
invalid = []
|
||||
if state == "present":
|
||||
if action == "member":
|
||||
invalid = ["description", "gid", "posix", "nonposix", "external",
|
||||
"nomembers"]
|
||||
|
||||
else:
|
||||
invalid = ["description", "gid", "posix", "nonposix", "external",
|
||||
"nomembers"]
|
||||
if action == "group":
|
||||
invalid.extend(["user", "group", "service", "externalmember"])
|
||||
|
||||
module.params_fail_used_invalid(invalid, state, action)
|
||||
|
||||
|
||||
def is_external_group(res_find):
|
||||
"""Verify if the result group is an external group."""
|
||||
return res_find and 'ipaexternalgroup' in res_find['objectclass']
|
||||
@@ -285,45 +412,63 @@ def check_objectclass_args(module, res_find, posix, external):
|
||||
|
||||
|
||||
def main():
|
||||
group_spec = dict(
|
||||
# present
|
||||
description=dict(type="str", default=None),
|
||||
gid=dict(type="int", aliases=["gidnumber"], default=None),
|
||||
nonposix=dict(required=False, type='bool', default=None),
|
||||
external=dict(required=False, type='bool', default=None),
|
||||
posix=dict(required=False, type='bool', default=None),
|
||||
nomembers=dict(required=False, type='bool', default=None),
|
||||
user=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
group=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
service=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
idoverrideuser=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
membermanager_user=dict(required=False, type='list',
|
||||
elements="str", default=None),
|
||||
membermanager_group=dict(required=False, type='list',
|
||||
elements="str", default=None),
|
||||
externalmember=dict(required=False, type='list', elements="str",
|
||||
default=None,
|
||||
aliases=[
|
||||
"ipaexternalmember",
|
||||
"external_member"
|
||||
])
|
||||
)
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
# general
|
||||
name=dict(type="list", elements="str", aliases=["cn"],
|
||||
required=True),
|
||||
# present
|
||||
description=dict(type="str", default=None),
|
||||
gid=dict(type="int", aliases=["gidnumber"], default=None),
|
||||
nonposix=dict(required=False, type='bool', default=None),
|
||||
external=dict(required=False, type='bool', default=None),
|
||||
posix=dict(required=False, type='bool', default=None),
|
||||
nomembers=dict(required=False, type='bool', default=None),
|
||||
user=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
group=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
service=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
idoverrideuser=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
membermanager_user=dict(required=False, type='list',
|
||||
elements="str", default=None),
|
||||
membermanager_group=dict(required=False, type='list',
|
||||
elements="str", default=None),
|
||||
externalmember=dict(required=False, type='list', elements="str",
|
||||
default=None,
|
||||
aliases=[
|
||||
"ipaexternalmember",
|
||||
"external_member"
|
||||
]),
|
||||
default=None, required=False),
|
||||
groups=dict(type="list",
|
||||
default=None,
|
||||
options=dict(
|
||||
# Here name is a simple string
|
||||
name=dict(type="str", required=True,
|
||||
aliases=["cn"]),
|
||||
# Add group specific parameters
|
||||
**group_spec
|
||||
),
|
||||
elements='dict',
|
||||
required=False),
|
||||
# general
|
||||
action=dict(type="str", default="group",
|
||||
choices=["member", "group"]),
|
||||
# state
|
||||
state=dict(type="str", default="present",
|
||||
choices=["present", "absent"]),
|
||||
|
||||
# Add group specific parameters for simple use case
|
||||
**group_spec
|
||||
),
|
||||
# It does not make sense to set posix, nonposix or external at the
|
||||
# same time
|
||||
mutually_exclusive=[['posix', 'nonposix', 'external']],
|
||||
mutually_exclusive=[['posix', 'nonposix', 'external'],
|
||||
["name", "groups"]],
|
||||
required_one_of=[["name", "groups"]],
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
@@ -333,6 +478,7 @@ def main():
|
||||
|
||||
# general
|
||||
names = ansible_module.params_get("name")
|
||||
groups = ansible_module.params_get("groups")
|
||||
|
||||
# present
|
||||
description = ansible_module.params_get("description")
|
||||
@@ -354,31 +500,26 @@ def main():
|
||||
state = ansible_module.params_get("state")
|
||||
|
||||
# Check parameters
|
||||
invalid = []
|
||||
|
||||
if (names is None or len(names) < 1) and \
|
||||
(groups is None or len(groups) < 1):
|
||||
ansible_module.fail_json(msg="At least one name or groups is required")
|
||||
|
||||
if state == "present":
|
||||
if len(names) != 1:
|
||||
if names is not None and len(names) != 1:
|
||||
ansible_module.fail_json(
|
||||
msg="Only one group can be added at a time.")
|
||||
if action == "member":
|
||||
invalid = ["description", "gid", "posix", "nonposix", "external",
|
||||
"nomembers"]
|
||||
msg="Only one group can be added at a time using 'name'.")
|
||||
|
||||
if state == "absent":
|
||||
if len(names) < 1:
|
||||
ansible_module.fail_json(
|
||||
msg="No name given.")
|
||||
invalid = ["description", "gid", "posix", "nonposix", "external",
|
||||
"nomembers"]
|
||||
if action == "group":
|
||||
invalid.extend(["user", "group", "service", "externalmember"])
|
||||
|
||||
ansible_module.params_fail_used_invalid(invalid, state, action)
|
||||
check_parameters(ansible_module, state, action)
|
||||
|
||||
if external is False:
|
||||
ansible_module.fail_json(
|
||||
msg="group can not be non-external")
|
||||
|
||||
# Use groups if names is None
|
||||
if groups is not None:
|
||||
names = groups
|
||||
|
||||
# Init
|
||||
|
||||
changed = False
|
||||
@@ -415,8 +556,57 @@ def main():
|
||||
"supported by your IPA version")
|
||||
|
||||
commands = []
|
||||
group_set = set()
|
||||
|
||||
for group_name in names:
|
||||
if isinstance(group_name, dict):
|
||||
name = group_name.get("name")
|
||||
if name in group_set:
|
||||
ansible_module.fail_json(
|
||||
msg="group '%s' is used more than once" % name)
|
||||
group_set.add(name)
|
||||
# present
|
||||
description = group_name.get("description")
|
||||
gid = group_name.get("gid")
|
||||
nonposix = group_name.get("nonposix")
|
||||
external = group_name.get("external")
|
||||
idoverrideuser = group_name.get("idoverrideuser")
|
||||
posix = group_name.get("posix")
|
||||
# Check mutually exclusive condition for multiple groups
|
||||
# creation. It's not possible to check it with
|
||||
# `mutually_exclusive` argument in `IPAAnsibleModule` class
|
||||
# because it accepts only (list[str] or list[list[str]]). Here
|
||||
# we need to loop over all groups and fail on mutually
|
||||
# exclusive ones.
|
||||
if all((posix, nonposix)) or\
|
||||
all((posix, external)) or\
|
||||
all((nonposix, external)):
|
||||
ansible_module.fail_json(
|
||||
msg="parameters are mutually exclusive for group "
|
||||
"`{0}`: posix|nonposix|external".format(name))
|
||||
# Duplicating the condition for multiple group creation
|
||||
if external is False:
|
||||
ansible_module.fail_json(
|
||||
msg="group can not be non-external")
|
||||
# If nonposix is used, set posix as not nonposix
|
||||
if nonposix is not None:
|
||||
posix = not nonposix
|
||||
user = group_name.get("user")
|
||||
group = group_name.get("group")
|
||||
service = group_name.get("service")
|
||||
membermanager_user = group_name.get("membermanager_user")
|
||||
membermanager_group = group_name.get("membermanager_group")
|
||||
externalmember = group_name.get("externalmember")
|
||||
nomembers = group_name.get("nomembers")
|
||||
|
||||
check_parameters(ansible_module, state, action)
|
||||
|
||||
elif isinstance(group_name, (str, unicode)):
|
||||
name = group_name
|
||||
else:
|
||||
ansible_module.fail_json(msg="Group '%s' is not valid" %
|
||||
repr(group_name))
|
||||
|
||||
for name in names:
|
||||
# Make sure group exists
|
||||
res_find = find_group(ansible_module, name)
|
||||
|
||||
|
||||
13
tests/group/create_groups_json.yml
Normal file
13
tests/group/create_groups_json.yml
Normal file
@@ -0,0 +1,13 @@
|
||||
---
|
||||
- name: Create groups.json
|
||||
hosts: localhost
|
||||
|
||||
tasks:
|
||||
- name: Check if groups.json exists
|
||||
ansible.builtin.stat:
|
||||
path: groups.json
|
||||
register: register_stat_groups
|
||||
|
||||
- name: Create groups.json
|
||||
ansible.builtin.command: /bin/bash groups.sh 500
|
||||
when: not register_stat_groups.stat.exists
|
||||
25
tests/group/groups.sh
Normal file
25
tests/group/groups.sh
Normal file
@@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
|
||||
NUM=${1-1000}
|
||||
FILE="groups.json"
|
||||
|
||||
echo "{" > "$FILE"
|
||||
|
||||
echo " \"group_list\": [" >> "$FILE"
|
||||
|
||||
for i in $(seq 1 "$NUM"); do
|
||||
{
|
||||
echo " {"
|
||||
echo " \"name\": \"group$i\","
|
||||
echo " \"description\": \"group description $i\""
|
||||
} >> "$FILE"
|
||||
if [ "$i" -lt "$NUM" ]; then
|
||||
echo " }," >> "$FILE"
|
||||
else
|
||||
echo " }" >> "$FILE"
|
||||
fi
|
||||
done
|
||||
|
||||
echo " ]" >> "$FILE"
|
||||
|
||||
echo "}" >> "$FILE"
|
||||
@@ -37,3 +37,27 @@
|
||||
when: groups['ipaclients'] is not defined or not groups['ipaclients']
|
||||
vars:
|
||||
ipa_context: client
|
||||
|
||||
- name: Test groups using client context, in client host.
|
||||
ansible.builtin.import_playbook: test_groups.yml
|
||||
when: groups['ipaclients']
|
||||
vars:
|
||||
ipa_test_host: ipaclients
|
||||
|
||||
- name: Test groups using client context, in server host.
|
||||
ansible.builtin.import_playbook: test_groups.yml
|
||||
when: groups['ipaclients'] is not defined or not groups['ipaclients']
|
||||
vars:
|
||||
ipa_context: client
|
||||
|
||||
- name: Test groups with mixed types using client context, in client host.
|
||||
ansible.builtin.import_playbook: test_groups_external_nonposix.yml
|
||||
when: groups['ipaclients']
|
||||
vars:
|
||||
ipa_test_host: ipaclients
|
||||
|
||||
- name: Test groups with mixed types using client context, in server host.
|
||||
ansible.builtin.import_playbook: test_groups_external_nonposix.yml
|
||||
when: groups['ipaclients'] is not defined or not groups['ipaclients']
|
||||
vars:
|
||||
ipa_context: client
|
||||
|
||||
143
tests/group/test_groups.yml
Normal file
143
tests/group/test_groups.yml
Normal file
@@ -0,0 +1,143 @@
|
||||
---
|
||||
- name: Test groups
|
||||
hosts: "{{ ipa_test_host | default('ipaserver') }}"
|
||||
gather_facts: true
|
||||
|
||||
tasks:
|
||||
# setup
|
||||
- name: Include tasks ../env_freeipa_facts.yml
|
||||
ansible.builtin.include_tasks: ../env_freeipa_facts.yml
|
||||
|
||||
# GET FQDN_AT_DOMAIN
|
||||
|
||||
- name: Get fqdn_at_domain
|
||||
ansible.builtin.set_fact:
|
||||
fqdn_at_domain: "{{ ansible_facts['fqdn'] + '@' + ipaserver_realm }}"
|
||||
|
||||
# CLEANUP TEST ITEMS
|
||||
|
||||
- name: Remove test groups
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: group1,group2,group3,group4,group5,group6,group7,group8,group9,group10
|
||||
state: absent
|
||||
|
||||
- name: Remove test users
|
||||
ipauser:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: user1,user2,user3
|
||||
state: absent
|
||||
|
||||
# CREATE TEST ITEMS
|
||||
|
||||
- name: Users user1..3 present
|
||||
ipauser:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
users:
|
||||
- name: user1
|
||||
first: user1
|
||||
last: Last
|
||||
- name: user2
|
||||
first: user2
|
||||
last: Last
|
||||
- name: user3
|
||||
first: user3
|
||||
last: Last
|
||||
|
||||
# TESTS
|
||||
|
||||
- name: Groups group1..10 present
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: group1
|
||||
- name: group2
|
||||
user:
|
||||
- user1
|
||||
- user2
|
||||
- user3
|
||||
- name: group3
|
||||
group:
|
||||
- group1
|
||||
- group2
|
||||
- name: group4
|
||||
- name: group5
|
||||
- name: group6
|
||||
- name: group7
|
||||
- name: group8
|
||||
- name: group9
|
||||
- name: group10
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Groups group1..10 present again
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: group1
|
||||
- name: group2
|
||||
- name: group3
|
||||
- name: group4
|
||||
- name: group5
|
||||
- name: group6
|
||||
- name: group7
|
||||
- name: group8
|
||||
- name: group9
|
||||
- name: group10
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
# failed_when: not result.failed has been added as this test needs to
|
||||
# fail because two groups with the same name should be added in the same
|
||||
# task.
|
||||
- name: Duplicate names in groups failure test
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: group1
|
||||
- name: group2
|
||||
- name: group3
|
||||
- name: group3
|
||||
register: result
|
||||
failed_when: result.changed or not result.failed or "is used more than once" not in result.msg
|
||||
|
||||
- name: Groups/name and name group11 present
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: group11
|
||||
groups:
|
||||
- name: group11
|
||||
register: result
|
||||
failed_when: result.changed or not result.failed or "parameters are mutually exclusive" not in result.msg
|
||||
|
||||
- name: Groups/name and name are absent
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
register: result
|
||||
failed_when: result.changed or not result.failed or "one of the following is required" not in result.msg
|
||||
|
||||
- name: Name is absent
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name:
|
||||
register: result
|
||||
failed_when: result.changed or not result.failed or "At least one name or groups is required" not in result.msg
|
||||
|
||||
- name: Only one group can be added at a time using name.
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: group11,group12
|
||||
register: result
|
||||
failed_when: result.changed or not result.failed or "Only one group can be added at a time using 'name'." not in result.msg
|
||||
|
||||
- name: Remove test groups
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: group1,group2,group3,group4,group5,group6,group7,group8,group9,group10
|
||||
state: absent
|
||||
|
||||
- name: Remove test users
|
||||
ipauser:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: user1,user2,user3
|
||||
state: absent
|
||||
35
tests/group/test_groups_absent.yml
Normal file
35
tests/group/test_groups_absent.yml
Normal file
@@ -0,0 +1,35 @@
|
||||
---
|
||||
- name: Include create_groups_json.yml
|
||||
ansible.builtin.import_playbook: create_groups_json.yml
|
||||
|
||||
- name: Test groups absent
|
||||
hosts: ipaserver
|
||||
gather_facts: false
|
||||
|
||||
tasks:
|
||||
- name: Include groups.json
|
||||
ansible.builtin.include_vars:
|
||||
file: groups.json # noqa 505
|
||||
|
||||
- name: Initialize groups_names
|
||||
ansible.builtin.set_fact:
|
||||
groups_names: []
|
||||
|
||||
- name: Create dict with group names
|
||||
ansible.builtin.set_fact:
|
||||
groups_names: "{{ groups_names | default([]) + [{'name': item.name}] }}"
|
||||
loop: "{{ group_list }}"
|
||||
|
||||
- name: Groups absent len:{{ group_list | length }}
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups: "{{ groups_names }}"
|
||||
state: absent
|
||||
|
||||
- name: Remove groups.json
|
||||
hosts: localhost
|
||||
tasks:
|
||||
- name: Remove groups.json
|
||||
ansible.builtin.file:
|
||||
state: absent
|
||||
path: groups.json
|
||||
395
tests/group/test_groups_external_nonposix.yml
Normal file
395
tests/group/test_groups_external_nonposix.yml
Normal file
@@ -0,0 +1,395 @@
|
||||
---
|
||||
- name: Test multiple external and nonposix groups
|
||||
hosts: "{{ ipa_test_host | default('ipaserver') }}"
|
||||
gather_facts: true
|
||||
|
||||
tasks:
|
||||
# setup
|
||||
- name: Include tasks ../env_freeipa_facts.yml
|
||||
ansible.builtin.include_tasks: ../env_freeipa_facts.yml
|
||||
|
||||
# GET FQDN_AT_DOMAIN
|
||||
|
||||
- name: Get fqdn_at_domain
|
||||
ansible.builtin.set_fact:
|
||||
fqdn_at_domain: "{{ ansible_facts['fqdn'] + '@' + ipaserver_realm }}"
|
||||
|
||||
# CLEANUP TEST ITEMS
|
||||
|
||||
- name: Remove testing groups.
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name:
|
||||
- extgroup
|
||||
- nonposixgroup
|
||||
- posixgroup
|
||||
- fail_group
|
||||
- group_1
|
||||
- posix_group_1
|
||||
- nonposix_group_1
|
||||
- external_group_1
|
||||
- external_group_2
|
||||
state: absent
|
||||
|
||||
- name: Ensure test users testuser1, testuser2 and testuser3 are absent
|
||||
ipauser:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: testuser1,testuser2,testuser3
|
||||
state: absent
|
||||
|
||||
# CREATE TEST ITEMS
|
||||
|
||||
- name: Ensure test users testuser1..testuser3 are present
|
||||
ipauser:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
users:
|
||||
- name: testuser1
|
||||
first: testuser1
|
||||
last: Last
|
||||
- name: testuser2
|
||||
first: testuser2
|
||||
last: Last
|
||||
- name: testuser3
|
||||
first: testuser3
|
||||
last: Last
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Add nonposix group.
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: extgroup
|
||||
nonposix: true
|
||||
register: result
|
||||
failed_when: result.failed or not result.changed
|
||||
|
||||
- name: Add nonposix group, again.
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: extgroup
|
||||
nonposix: true
|
||||
register: result
|
||||
failed_when: result.failed or result.changed
|
||||
|
||||
- name: Set group to be external
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: extgroup
|
||||
external: true
|
||||
register: result
|
||||
failed_when: result.failed or not result.changed
|
||||
|
||||
- name: Set group to be external, again.
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: extgroup
|
||||
external: true
|
||||
register: result
|
||||
failed_when: result.failed or result.changed
|
||||
|
||||
- name: Set external group to be non-external.
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: extgroup
|
||||
external: false
|
||||
register: result
|
||||
failed_when: not result.failed or "group can not be non-external" not in result.msg
|
||||
|
||||
- name: Set external group to be posix.
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: extgroup
|
||||
posix: true
|
||||
register: result
|
||||
failed_when: not result.failed or "Cannot change `external` group" not in result.msg
|
||||
|
||||
- name: Add nonposix group.
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: posixgroup
|
||||
nonposix: true
|
||||
register: result
|
||||
failed_when: result.failed or not result.changed
|
||||
|
||||
- name: Set group to be posix
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: posixgroup
|
||||
posix: true
|
||||
register: result
|
||||
failed_when: result.failed or not result.changed
|
||||
|
||||
- name: Set group to be posix, again.
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: posixgroup
|
||||
posix: true
|
||||
register: result
|
||||
failed_when: result.failed or result.changed
|
||||
|
||||
- name: Set posix group to be external.
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: posixgroup
|
||||
external: true
|
||||
register: result
|
||||
failed_when: not result.failed or "Cannot change `posix` group" not in result.msg
|
||||
|
||||
- name: Set posix group to be non-posix.
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: posixgroup
|
||||
posix: false
|
||||
register: result
|
||||
failed_when: not result.failed or "Cannot change `posix` group" not in result.msg
|
||||
|
||||
- name: Set posix group to be non-posix.
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: posixgroup
|
||||
nonposix: true
|
||||
register: result
|
||||
failed_when: not result.failed or "Cannot change `posix` group" not in result.msg
|
||||
|
||||
- name: Add nonposix group.
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: nonposixgroup
|
||||
posix: false
|
||||
register: result
|
||||
failed_when: result.failed or not result.changed
|
||||
|
||||
- name: Add nonposix group, again.
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: nonposixgroup
|
||||
nonposix: true
|
||||
register: result
|
||||
failed_when: result.failed or result.changed
|
||||
|
||||
|
||||
# NONPOSIX MEMBER TEST
|
||||
|
||||
- name: Ensure users testuser1, testuser2 and testuser3 are present in group nonposixgroup
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: nonposixgroup
|
||||
nonposix: true
|
||||
user:
|
||||
- testuser1
|
||||
- testuser2
|
||||
- testuser3
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure users testuser1, testuser2 and testuser3 are present in group nonposixgroup again
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: nonposixgroup
|
||||
nonposix: true
|
||||
user:
|
||||
- testuser1
|
||||
- testuser2
|
||||
- testuser3
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
|
||||
# POSIX MEMBER TEST
|
||||
|
||||
- name: Ensure users testuser1, testuser2 and testuser3 are present in group posixgroup
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: posixgroup
|
||||
posix: true
|
||||
user:
|
||||
- testuser1
|
||||
- testuser2
|
||||
- testuser3
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure users testuser1, testuser2 and testuser3 are present in group posixgroup again
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: posixgroup
|
||||
posix: true
|
||||
user:
|
||||
- testuser1
|
||||
- testuser2
|
||||
- testuser3
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
# EXTERNAL MEMBER TEST (REQUIRES AD)
|
||||
|
||||
- name: Execute group tests if trust test environment is supported
|
||||
when: trust_test_is_supported | default(false)
|
||||
block:
|
||||
- name: Ensure users testuser1, testuser2 and testuser3 are present in group externalgroup
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: externalgroup
|
||||
external: true
|
||||
user:
|
||||
- testuser1
|
||||
- testuser2
|
||||
- testuser3
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure users testuser1, testuser2 and testuser3 are present in group externalgroup again
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: externalgroup
|
||||
external: true
|
||||
user:
|
||||
- testuser1
|
||||
- testuser2
|
||||
- testuser3
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
|
||||
# CONVERT NONPOSIX TO POSIX GROUP WITH USERS
|
||||
|
||||
- name: Ensure nonposix group nonposixgroup as posix
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: nonposixgroup
|
||||
posix: true
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure nonposix group nonposixgroup as posix, again
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: nonposixgroup
|
||||
posix: true
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Ensure nonposix group nonposixgroup (now posix) has users still
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: nonposixgroup
|
||||
posix: true
|
||||
user:
|
||||
- testuser1
|
||||
- testuser2
|
||||
- testuser3
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
# FAIL ON COMBINATIONS OF NONPOSIX, POSIX AND EXTERNAL
|
||||
|
||||
- name: Fail to ensure group as nonposix and posix
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: firstgroup
|
||||
nonposix: true
|
||||
posix: false
|
||||
- name: fail_group
|
||||
nonposix: true
|
||||
posix: true
|
||||
register: result
|
||||
failed_when: not result.failed or "parameters are mutually exclusive for group `fail_group`" not in result.msg
|
||||
|
||||
- name: Fail to ensure group as nonposix and external
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: firstgroup
|
||||
nonposix: true
|
||||
posix: false
|
||||
- name: fail_group
|
||||
nonposix: true
|
||||
external: true
|
||||
register: result
|
||||
failed_when: not result.failed or "parameters are mutually exclusive for group `fail_group`" not in result.msg
|
||||
|
||||
- name: Fail to ensure group as posix and external
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: firstgroup
|
||||
nonposix: true
|
||||
posix: false
|
||||
- name: fail_group
|
||||
posix: true
|
||||
external: true
|
||||
register: result
|
||||
failed_when: not result.failed or "parameters are mutually exclusive for group `fail_group`" not in result.msg
|
||||
|
||||
# GROUPS WITH MIXED TYPES
|
||||
|
||||
- name: Adding posix, nonposix and external groups in one batch
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: posix_group_1
|
||||
posix: true
|
||||
- name: nonposix_group_1
|
||||
nonposix: true
|
||||
- name: external_group_1
|
||||
external: true
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Adding non-external and external groups in one batch
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: non_external_group_2
|
||||
- name: external_group_2
|
||||
external: true
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
# CLEANUP
|
||||
|
||||
- name: Remove testing groups.
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name:
|
||||
- extgroup
|
||||
- nonposixgroup
|
||||
- posixgroup
|
||||
- fail_group
|
||||
- group_1
|
||||
- posix_group_1
|
||||
- nonposix_group_1
|
||||
- external_group_1
|
||||
- external_group_2
|
||||
- non_external_group_2
|
||||
state: absent
|
||||
|
||||
- name: Ensure test users testuser1, testuser2 and testuser3 are absent
|
||||
ipauser:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: testuser1,testuser2,testuser3
|
||||
state: absent
|
||||
40
tests/group/test_groups_present.yml
Normal file
40
tests/group/test_groups_present.yml
Normal file
@@ -0,0 +1,40 @@
|
||||
---
|
||||
- name: Include create_groups_json.yml
|
||||
ansible.builtin.import_playbook: create_groups_json.yml
|
||||
|
||||
- name: Test groups present
|
||||
hosts: ipaserver
|
||||
gather_facts: false
|
||||
|
||||
tasks:
|
||||
- name: Include groups.json
|
||||
ansible.builtin.include_vars:
|
||||
file: groups.json # noqa 505
|
||||
|
||||
- name: Groups present len:{{ group_list | length }}
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups: "{{ group_list }}"
|
||||
|
||||
- name: Initialize groups_names
|
||||
ansible.builtin.set_fact:
|
||||
groups_names: []
|
||||
|
||||
- name: Create dict with group names
|
||||
ansible.builtin.set_fact:
|
||||
groups_names: "{{ groups_names | default([]) + [{'name': item.name}] }}"
|
||||
loop: "{{ group_list }}"
|
||||
|
||||
- name: Remove groups
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups: "{{ groups_names }}"
|
||||
state: absent
|
||||
|
||||
- name: Remove groups.json
|
||||
hosts: localhost
|
||||
tasks:
|
||||
- name: Remove groups.json
|
||||
ansible.builtin.file:
|
||||
state: absent
|
||||
path: groups.json
|
||||
47
tests/group/test_groups_present_slice.yml
Normal file
47
tests/group/test_groups_present_slice.yml
Normal file
@@ -0,0 +1,47 @@
|
||||
---
|
||||
- name: Include create_groups_json.yml
|
||||
ansible.builtin.import_playbook: create_groups_json.yml
|
||||
|
||||
- name: Test groups present slice
|
||||
hosts: ipaserver
|
||||
gather_facts: false
|
||||
|
||||
vars:
|
||||
slice_size: 500
|
||||
tasks:
|
||||
- name: Include groups.json
|
||||
ansible.builtin.include_vars:
|
||||
file: groups.json # noqa 505
|
||||
|
||||
- name: Size of groups slice.
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ group_list | length }}"
|
||||
|
||||
- name: Groups present
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups: "{{ group_list[item : item + slice_size] }}"
|
||||
loop: "{{ range(0, group_list | length, slice_size) | list }}"
|
||||
|
||||
- name: Initialize groups_names
|
||||
ansible.builtin.set_fact:
|
||||
groups_names: []
|
||||
|
||||
- name: Create dict with group names
|
||||
ansible.builtin.set_fact:
|
||||
groups_names: "{{ groups_names | default([]) + [{'name': item.name}] }}"
|
||||
loop: "{{ group_list }}"
|
||||
|
||||
- name: Remove groups
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups: "{{ groups_names }}"
|
||||
state: absent
|
||||
|
||||
- name: Remove groups.json
|
||||
hosts: localhost
|
||||
tasks:
|
||||
- name: Remove groups.json
|
||||
ansible.builtin.file:
|
||||
state: absent
|
||||
path: groups.json
|
||||
@@ -39,6 +39,7 @@ tests/pytests/conftest.py pylint:ansible-format-automatic-specification
|
||||
tests/sanity/sanity.sh shebang!skip
|
||||
tests/user/users.sh shebang!skip
|
||||
tests/user/users_absent.sh shebang!skip
|
||||
tests/group/groups.sh shebang!skip
|
||||
tests/utils.py pylint:ansible-format-automatic-specification
|
||||
utils/ansible-doc-test shebang!skip
|
||||
utils/build-galaxy-release.sh shebang!skip
|
||||
|
||||
@@ -21,6 +21,7 @@ tests/pytests/conftest.py pylint:ansible-format-automatic-specification
|
||||
tests/sanity/sanity.sh shebang!skip
|
||||
tests/user/users.sh shebang!skip
|
||||
tests/user/users_absent.sh shebang!skip
|
||||
tests/group/groups.sh shebang!skip
|
||||
tests/utils.py pylint:ansible-format-automatic-specification
|
||||
utils/ansible-doc-test shebang!skip
|
||||
utils/build-galaxy-release.sh shebang!skip
|
||||
|
||||
@@ -21,6 +21,7 @@ tests/pytests/conftest.py pylint:ansible-format-automatic-specification
|
||||
tests/sanity/sanity.sh shebang!skip
|
||||
tests/user/users.sh shebang!skip
|
||||
tests/user/users_absent.sh shebang!skip
|
||||
tests/group/groups.sh shebang!skip
|
||||
tests/utils.py pylint:ansible-format-automatic-specification
|
||||
utils/ansible-doc-test shebang!skip
|
||||
utils/build-galaxy-release.sh shebang!skip
|
||||
|
||||
Reference in New Issue
Block a user