diff --git a/docs/api/user-management/group.md b/docs/api/user-management/group.md
index 100a2fd4..8ba52da0 100644
--- a/docs/api/user-management/group.md
+++ b/docs/api/user-management/group.md
@@ -125,7 +125,7 @@ register: group_response
create_datacenter bool |
False |
- Boolean value indicating if the group is allowed to create virtual data centers. |
+ Create data center privilege. |
create_snapshot bool |
@@ -351,7 +351,7 @@ ionoscloudsdk.ionoscloud.group:
create_datacenter bool |
False |
- Boolean value indicating if the group is allowed to create virtual data centers. |
+ Create data center privilege. |
create_snapshot bool |
diff --git a/docs/api/user-management/user.md b/docs/api/user-management/user.md
index 73530376..f49c40bc 100644
--- a/docs/api/user-management/user.md
+++ b/docs/api/user-management/user.md
@@ -16,6 +16,9 @@ ionoscloudsdk.ionoscloud.user:
user_password: '{{ lookup('ansible.builtin.password', '/dev/null chars=ascii_letters,digits') }}'
force_sec_auth: false
state: present
+check_mode: true
+diff: true
+register: user_response
name: Add user to first group
@@ -30,6 +33,9 @@ name: Delete user
ionoscloudsdk.ionoscloud.user:
user: ''
state: absent
+check_mode: true
+diff: true
+register: user_response
```
@@ -83,6 +89,9 @@ ionoscloudsdk.ionoscloud.user:
user_password: '{{ lookup('ansible.builtin.password', '/dev/null chars=ascii_letters,digits') }}'
force_sec_auth: false
state: present
+check_mode: true
+diff: true
+register: user_response
```
### Available parameters for state **present**:
@@ -138,6 +147,11 @@ ionoscloudsdk.ionoscloud.user:
Indicates if secure authentication is active for the user. |
+ ignored_properties list |
+ False |
+ A list of field to ignore changes to when evaluating whether to make changes to the ionos resource. These fields will still be used when creating or recreating the resource, but will not cause the operation themselves Default: |
+
+
api_url str |
False |
The Ionos API base URL. |
@@ -190,6 +204,9 @@ name: Delete user
ionoscloudsdk.ionoscloud.user:
user: ''
state: absent
+check_mode: true
+diff: true
+register: user_response
```
### Available parameters for state **absent**:
@@ -324,6 +341,11 @@ ionoscloudsdk.ionoscloud.user:
Indicates if secure authentication is active for the user. |
+ ignored_properties list |
+ False |
+ A list of field to ignore changes to when evaluating whether to make changes to the ionos resource. These fields will still be used when creating or recreating the resource, but will not cause the operation themselves Default: |
+
+
api_url str |
False |
The Ionos API base URL. |
diff --git a/docs/changelog.md b/docs/changelog.md
index 0dd08cbb..adff2266 100644
--- a/docs/changelog.md
+++ b/docs/changelog.md
@@ -1,5 +1,16 @@
# Changelog
+## 7.5.0-beta.1
+### Features
+* Added check_mode and diff to the user module
+* Added ignored_properties to the user module
+### Changes
+* use filters when retrieving user to speed up the request
+### Fixes
+* mark RegEx pattern as a raw string (fix by @jaudriga)
+### Docs
+* Added declarative modules page to summary
+
## 7.4.1
### Fixes
* disk_type on cube_server now defaults to DAS, other arguments would have caused the call to fail
diff --git a/docs/summary.md b/docs/summary.md
index d2bc29e9..30816873 100644
--- a/docs/summary.md
+++ b/docs/summary.md
@@ -10,9 +10,11 @@
* [Ansible Playbooks](usage/ansibleplaybooks.md)
* [Wait for Services](usage/waitforservices.md)
* [Incrementing servers](usage/incrementingservers.md)
+* [Check Mode and Diff](usage/check_mode_and_diff.md)
* [SSH Key Authentication](usage/sshkeyauthentication.md)
* [Return values](usage/returnvalues.md)
* [Testing](usage/testing.md)
+* [Declarative Changes](usage/declarative_changes.md)
## Tutorials
* [Tutorials introduction](tutorials/README.md)
diff --git a/docs/templates/summary.mustache b/docs/templates/summary.mustache
index 31d67504..9b767dd1 100644
--- a/docs/templates/summary.mustache
+++ b/docs/templates/summary.mustache
@@ -10,9 +10,11 @@
* [Ansible Playbooks](usage/ansibleplaybooks.md)
* [Wait for Services](usage/waitforservices.md)
* [Incrementing servers](usage/incrementingservers.md)
+* [Check Mode and Diff](usage/check_mode_and_diff.md)
* [SSH Key Authentication](usage/sshkeyauthentication.md)
* [Return values](usage/returnvalues.md)
* [Testing](usage/testing.md)
+* [Declarative Changes](usage/declarative_changes.md)
## Tutorials
* [Tutorials introduction](tutorials/README.md)
diff --git a/docs/usage/check_mode_and_diff.md b/docs/usage/check_mode_and_diff.md
new file mode 100644
index 00000000..0d1c049c
--- /dev/null
+++ b/docs/usage/check_mode_and_diff.md
@@ -0,0 +1,64 @@
+# Using check_mode and diff
+
+> **_NOTE:_** More info on using check_mode and diff can be found here https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_checkmode.html
+
+Read bellow for info on how the IONOS Ansible module handles check mode and diff.
+
+### Check Mode
+When using check_mode the playbook will not make changes in the API and a message will be returned if such changes would have been made. Example: "user would be updated.". The returned state is "changed".
+For operations that do not cause changes the regular response will be returned.
+
+### Diff
+When using diff an additional property will be returned on the object showing the object states with before and after. These states only include the attributes which are checked by Ansible for update and recreate.
+Diff is not shown for when the object does not exist or for when it ill be deleted
+
+> **_NOTE:_** Check mode and diff more are independent! Using diff does not stop the changes from being made in the api. To check what changes will be made without actually making them use both check_mode and diff.
+
+For now only the user modules offers support for check_mode and diff.
+
+### Examples
+Usage:
+```yaml
+tasks:
+- name: Create user
+ ionoscloudsdk.ionoscloud.user:
+ firstname: John
+ lastname: Doe
+ email:
+ administrator: false
+ user_password:
+ force_sec_auth: false
+ state: present
+ check_mode: true
+ diff: true
+```
+
+Output:
+```json
+{
+ "user_response": {
+ "changed": true,
+ "diff": {
+ "after": {
+ "administrator": false,
+ "email": "",
+ "firstname": "John",
+ "force_sec_auth": false,
+ "groups": "",
+ "lastname": "Doe",
+ "user_password": "user password will be updated"
+ },
+ "before": {
+ "administrator": false,
+ "email": "",
+ "firstname": "John",
+ "force_sec_auth": false,
+ "groups": "",
+ "lastname": "Doe",
+ "user_password": ""
+ }
+ },
+ "failed": false,
+ "msg": "User would be updated"
+ }
+}
diff --git a/galaxy.yml b/galaxy.yml
index 3e516e98..92e86335 100644
--- a/galaxy.yml
+++ b/galaxy.yml
@@ -5,7 +5,7 @@ namespace: ionoscloudsdk
name: ionoscloud
# The version of the collection.
-version: 7.4.1
+version: 7.5.0-beta.1
readme: README.md
diff --git a/plugins/module_utils/common_ionos_methods.py b/plugins/module_utils/common_ionos_methods.py
index ae77b006..3644bad2 100644
--- a/plugins/module_utils/common_ionos_methods.py
+++ b/plugins/module_utils/common_ionos_methods.py
@@ -1,4 +1,5 @@
import re
+import uuid
from ansible.module_utils.basic import AnsibleModule, env_fallback
from ansible.module_utils._text import to_native
@@ -55,15 +56,39 @@ def _get_request_id(headers):
return None
-def get_users(api, all_users, depth=2):
+def get_users_by_identifier(api, all_users, identifier_value, depth=2):
+ if identifier_value is None:
+ return all_users
+
+ # check if identifier_value is a valid email
+ if re.match(r"[^@]+@[^@]+\.[^@]+", identifier_value):
+ get_users(
+ api,
+ all_users,
+ query_params={'filter.email': identifier_value},
+ )
+ else:
+ # check if identifier_value is a UUID then try to get the user
+ try:
+ uuid.UUID(identifier_value)
+ user = api.um_users_find_by_id(identifier_value, depth=2)
+ all_users.items += [user]
+ except Exception as e:
+ pass
+
+ return all_users
+
+
+def get_users(api, all_users, depth=2, query_params=None):
+ query_params = query_params if query_params else {}
offset = 0
limit = 100
- users = api.um_users_get(depth=depth, limit=limit, offset=offset)
+ users = api.um_users_get(depth=depth, limit=limit, offset=offset, query_params=query_params)
all_users.items += users.items
while(users.links.next is not None):
offset += limit
- users = api.um_users_get(depth=depth, limit=limit, offset=offset)
+ users = api.um_users_get(depth=depth, limit=limit, offset=offset, query_params=query_params)
all_users.items += users.items
return all_users
diff --git a/plugins/module_utils/common_ionos_module.py b/plugins/module_utils/common_ionos_module.py
index 2654db71..1dad361c 100644
--- a/plugins/module_utils/common_ionos_module.py
+++ b/plugins/module_utils/common_ionos_module.py
@@ -1,3 +1,5 @@
+import yaml
+
from ansible.module_utils._text import to_native
from .common_ionos_methods import (
@@ -34,6 +36,18 @@ def _should_update_object(self, existing_object, clients):
"""
pass
+ def calculate_object_diff(self, existing_object, clients):
+ """
+ Calculate before and after for the object, only used in diff mode
+
+ existing_object : Ionoscloud object returned by API object
+ clients: authenticated ionoscloud clients list.
+
+ Returns:
+ dict, a dict with 2 keys: 'before' and 'after' which compares only the attributes watched by ansible in their states
+ """
+ pass
+
def _get_object_list(self, clients):
"""
@@ -67,25 +81,51 @@ def _get_object_identifier(self):
def update_replace_object(self, existing_object, clients):
module = self.module
+ obj_identifier = self._get_object_identifier() if self._get_object_identifier() is not None else self._get_object_name()
+ module_diff = {}
+ if module._diff:
+ module_diff = self.calculate_object_diff(existing_object, clients)
+
if self._should_replace_object(existing_object, clients):
if not module.params.get('allow_replace'):
module.fail_json(msg="{} should be replaced but allow_replace is set to False.".format(self.object_name))
+ if module.check_mode:
+ return {
+ 'changed': True,
+ 'msg': '{object_name} {object_name_identifier} would be recreated'.format(
+ object_name=self.object_name, object_name_identifier=obj_identifier,
+ ),
+ 'diff': module_diff,
+ }
+
new_object = self._create_object(existing_object, clients).to_dict()
self._remove_object(existing_object, clients)
return {
'changed': True,
'failed': False,
'action': 'create',
+ 'diff': module_diff,
self.returned_key: new_object,
}
+
if self._should_update_object(existing_object, clients):
+ if module.check_mode:
+ return {
+ 'changed': True,
+ 'msg': '{object_name} {object_name_identifier} would be updated'.format(
+ object_name=self.object_name, object_name_identifier=obj_identifier,
+ ),
+ 'diff': module_diff,
+ }
+
# Update
return {
'changed': True,
'failed': False,
'action': 'update',
+ 'diff': module_diff,
self.returned_key: self._update_object(existing_object, clients).to_dict()
}
@@ -94,6 +134,7 @@ def update_replace_object(self, existing_object, clients):
'changed': False,
'failed': False,
'action': 'create',
+ 'diff': module_diff,
self.returned_key: existing_object.to_dict()
}
@@ -107,6 +148,14 @@ def present_object(self, clients):
if existing_object:
return self.update_replace_object(existing_object, clients)
+ if self.module.check_mode:
+ return {
+ 'skipped': True,
+ 'msg': '{object_name} {object_name_identifier} would be created'.format(
+ object_name=self.object_name, object_name_identifier=self._get_object_name(),
+ )
+ }
+
return {
'changed': True,
'failed': False,
@@ -159,6 +208,14 @@ def absent_object(self, clients):
self.module.exit_json(changed=False)
return
+ if self.module.check_mode:
+ return {
+ 'skipped': True,
+ 'msg': '{object_name} {object_name_identifier} would be deleted'.format(
+ object_name=self.object_name, object_name_identifier=self._get_object_identifier(),
+ )
+ }
+
self._remove_object(existing_object, clients)
return {
diff --git a/plugins/modules/cube_server.py b/plugins/modules/cube_server.py
index 88fd08d2..22fc8e5c 100644
--- a/plugins/modules/cube_server.py
+++ b/plugins/modules/cube_server.py
@@ -502,7 +502,7 @@
state: suspend
"""
-uuid_match = re.compile('[\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12}', re.I)
+uuid_match = re.compile(r'[\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12}', re.I)
def _get_lan_by_id_or_properties(networks, id=None, **kwargs):
diff --git a/plugins/modules/group.py b/plugins/modules/group.py
index aa68ed81..b558e23f 100644
--- a/plugins/modules/group.py
+++ b/plugins/modules/group.py
@@ -53,7 +53,7 @@
'type': 'str',
},
'create_datacenter': {
- 'description': ['Boolean value indicating if the group is allowed to create virtual data centers.'],
+ 'description': ['Create data center privilege.'],
'available': ['present', 'update'],
'type': 'bool',
},
@@ -165,7 +165,7 @@
required: false
create_datacenter:
description:
- - Boolean value indicating if the group is allowed to create virtual data centers.
+ - Create data center privilege.
required: false
create_flow_log:
description:
diff --git a/plugins/modules/group_info.py b/plugins/modules/group_info.py
index 97764568..c01d7e0d 100644
--- a/plugins/modules/group_info.py
+++ b/plugins/modules/group_info.py
@@ -7,7 +7,7 @@
from ansible import __version__
-from ansible_collections.ionoscloudsdk.ionoscloud.plugins.module_utils.common_ionos_methods import default_main_info, get_resource_id, get_users
+from ansible_collections.ionoscloudsdk.ionoscloud.plugins.module_utils.common_ionos_methods import default_main_info, get_resource_id, get_users_by_identifier
from ansible_collections.ionoscloudsdk.ionoscloud.plugins.module_utils.common_ionos_options import get_info_default_options_with_depth
@@ -105,7 +105,7 @@ def get_objects(module, client):
if user:
# Locate UUID for User
- user_list = get_users(client, ionoscloud.Users(items=[]))
+ user_list = get_users_by_identifier(client, ionoscloud.Users(items=[]), user)
user_id = get_resource_id(module, user_list, user)
groups = um_api.um_users_groups_get(user_id, depth=module.params.get('depth'))
diff --git a/plugins/modules/s3key.py b/plugins/modules/s3key.py
index e6aa2e8b..394d5cfd 100644
--- a/plugins/modules/s3key.py
+++ b/plugins/modules/s3key.py
@@ -19,7 +19,7 @@
from ansible_collections.ionoscloudsdk.ionoscloud.plugins.module_utils.common_ionos_module import CommonIonosModule
from ansible_collections.ionoscloudsdk.ionoscloud.plugins.module_utils.common_ionos_methods import (
- get_module_arguments, _get_request_id, get_resource_id, get_resource, get_users
+ get_module_arguments, _get_request_id, get_resource_id, get_resource, get_users_by_identifier
)
from ansible_collections.ionoscloudsdk.ionoscloud.plugins.module_utils.common_ionos_options import get_default_options
@@ -212,11 +212,9 @@ def __init__(self) -> None:
def present_object(self, clients):
client = clients[0]
+ user_list = get_users_by_identifier(ionoscloud.UserManagementApi(client), ionoscloud.Users(items=[]), self.module.params.get('user'))
user_id = get_resource_id(
- self.module,
- get_users(ionoscloud.UserManagementApi(client), ionoscloud.Users(items=[])),
- self.module.params.get('user'),
- [['id'], ['properties', 'email']],
+ self.module, user_list, self.module.params.get('user'), [['id'], ['properties', 'email']],
)
do_idempotency = self.module.params.get('idempotency')
key_id = self.module.params.get('key_id')
@@ -267,11 +265,9 @@ def present_object(self, clients):
def absent_object(self, clients):
client = clients[0]
+ user_list = get_users_by_identifier(ionoscloud.UserManagementApi(client), ionoscloud.Users(items=[]), self.module.params.get('user'))
user_id = get_resource_id(
- self.module,
- get_users(ionoscloud.UserManagementApi(client), ionoscloud.Users(items=[])),
- self.module.params.get('user'),
- [['id'], ['properties', 'email']],
+ self.module, user_list, self.module.params.get('user'), [['id'], ['properties', 'email']],
)
key_id = self.module.params.get('key_id')
@@ -302,11 +298,10 @@ def absent_object(self, clients):
def update_object(self, clients):
client = clients[0]
+
+ user_list = get_users_by_identifier(ionoscloud.UserManagementApi(client), ionoscloud.Users(items=[]), self.module.params.get('user'))
user_id = get_resource_id(
- self.module,
- get_users(ionoscloud.UserManagementApi(client), ionoscloud.Users(items=[])),
- self.module.params.get('user'),
- [['id'], ['properties', 'email']],
+ self.module, user_list, self.module.params.get('user'), [['id'], ['properties', 'email']],
)
key_id = self.module.params.get('key_id')
active = self.module.params.get('active')
diff --git a/plugins/modules/s3key_info.py b/plugins/modules/s3key_info.py
index d005a8fd..eb4f28cd 100644
--- a/plugins/modules/s3key_info.py
+++ b/plugins/modules/s3key_info.py
@@ -7,7 +7,7 @@
from ansible import __version__
-from ansible_collections.ionoscloudsdk.ionoscloud.plugins.module_utils.common_ionos_methods import default_main_info, get_resource_id, get_users
+from ansible_collections.ionoscloudsdk.ionoscloud.plugins.module_utils.common_ionos_methods import default_main_info, get_resource_id, get_users_by_identifier
from ansible_collections.ionoscloudsdk.ionoscloud.plugins.module_utils.common_ionos_options import get_info_default_options_with_depth
@@ -103,11 +103,9 @@
def get_objects(module, client):
+ user_list = get_users_by_identifier(ionoscloud.UserManagementApi(client), ionoscloud.Users(items=[]), module.params.get('user'))
user_id = get_resource_id(
- module,
- get_users(ionoscloud.UserManagementApi(client), ionoscloud.Users(items=[])),
- module.params.get('user'),
- [['id'], ['properties', 'email']],
+ module, user_list, module.params.get('user'), [['id'], ['properties', 'email']],
)
user_s3keys_server = ionoscloud.UserS3KeysApi(client)
diff --git a/plugins/modules/server.py b/plugins/modules/server.py
index 24de590b..914b2749 100644
--- a/plugins/modules/server.py
+++ b/plugins/modules/server.py
@@ -585,7 +585,7 @@
state: stopped
"""
-uuid_match = re.compile('[\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12}', re.I)
+uuid_match = re.compile(r'[\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12}', re.I)
def _get_lan_by_id_or_properties(networks, id=None, **kwargs):
diff --git a/plugins/modules/user.py b/plugins/modules/user.py
index 2d594a50..c2354692 100644
--- a/plugins/modules/user.py
+++ b/plugins/modules/user.py
@@ -22,7 +22,7 @@
from ansible_collections.ionoscloudsdk.ionoscloud.plugins.module_utils.common_ionos_module import CommonIonosModule
from ansible_collections.ionoscloudsdk.ionoscloud.plugins.module_utils.common_ionos_methods import (
- get_module_arguments, _get_request_id, get_users, get_resource_id,
+ get_module_arguments, _get_request_id, get_users_by_identifier, get_resource_id,
)
from ansible_collections.ionoscloudsdk.ionoscloud.plugins.module_utils.common_ionos_options import get_default_options
@@ -90,6 +90,12 @@
'available': ['present', 'update'],
'type': 'bool',
},
+ 'ignored_properties': {
+ 'description': ['A list of field to ignore changes to when evaluating whether to make changes to the ionos resource. These fields will still be used when creating or recreating the resource, but will not cause the operation themselves'],
+ 'available': ['present', 'update'],
+ 'type': 'list',
+ 'default': [],
+ },
**get_default_options(STATES),
}
@@ -132,6 +138,13 @@
- A list of group IDs or names where the user (non-administrator) is to be added.
Set to empty list ([]) to remove the user from all groups.
required: false
+ ignored_properties:
+ default: []
+ description:
+ - A list of field to ignore changes to when evaluating whether to make changes
+ to the ionos resource. These fields will still be used when creating or recreating
+ the resource, but will not cause the operation themselves
+ required: false
lastname:
description:
- The last name of the user.
@@ -210,6 +223,9 @@
user_password: '{{ lookup('ansible.builtin.password', '/dev/null chars=ascii_letters,digits') }}'
force_sec_auth: false
state: present
+check_mode: true
+diff: true
+register: user_response
''',
'update': '''
name: Add user to first group
@@ -224,6 +240,9 @@
ionoscloudsdk.ionoscloud.user:
user: ''
state: absent
+check_mode: true
+diff: true
+register: user_response
''',
}
@@ -237,6 +256,9 @@
user_password: '{{ lookup('ansible.builtin.password', '/dev/null chars=ascii_letters,digits') }}'
force_sec_auth: false
state: present
+check_mode: true
+diff: true
+register: user_response
name: Add user to first group
@@ -251,13 +273,16 @@
ionoscloudsdk.ionoscloud.user:
user: ''
state: absent
+check_mode: true
+diff: true
+register: user_response
"""
class UserModule(CommonIonosModule):
def __init__(self) -> None:
super().__init__()
- self.module = AnsibleModule(argument_spec=get_module_arguments(OPTIONS, STATES))
+ self.module = AnsibleModule(argument_spec=get_module_arguments(OPTIONS, STATES), supports_check_mode=True)
self.returned_key = RETURNED_KEY
self.object_name = OBJECT_NAME
self.sdks = [ionoscloud]
@@ -271,24 +296,63 @@ def _should_replace_object(self, existing_object, clients):
def _should_update_object(self, existing_object, clients):
+ ignored_properties = self.module.params.get('ignored_properties')
+
+ if not isinstance(ignored_properties, list):
+ ignored_properties = []
+
return (
self.module.params.get('lastname') is not None
+ and 'lastname' not in ignored_properties
and existing_object.properties.lastname != self.module.params.get('lastname')
or self.module.params.get('firstname') is not None
+ and 'firstname' not in ignored_properties
and existing_object.properties.firstname != self.module.params.get('firstname')
or self.module.params.get('email') is not None
+ and 'email' not in ignored_properties
and existing_object.properties.email != self.module.params.get('email')
or self.module.params.get('administrator') is not None
+ and 'administrator' not in ignored_properties
and existing_object.properties.administrator != self.module.params.get('administrator')
or self.module.params.get('force_sec_auth') is not None
+ and 'force_sec_auth' not in ignored_properties
and existing_object.properties.force_sec_auth != self.module.params.get('force_sec_auth')
or self.module.params.get('user_password') is not None
+ and 'user_password' not in ignored_properties
or self.module.params.get('groups') is not None
+ and 'groups' not in ignored_properties
)
+ def calculate_object_diff(self, existing_object, clients):
+ return {
+ 'before': {
+ 'lastname': existing_object.properties.lastname,
+ 'firstname': existing_object.properties.firstname,
+ 'email': existing_object.properties.email,
+ 'administrator': existing_object.properties.administrator,
+ 'force_sec_auth': existing_object.properties.force_sec_auth,
+ 'user_password': '',
+ 'groups': '',
+ },
+ 'after': {
+ 'lastname': existing_object.properties.lastname if self.module.params.get('lastname') is None else self.module.params.get('lastname'),
+ 'firstname': existing_object.properties.firstname if self.module.params.get('firstname') is None else self.module.params.get('firstname'),
+ 'email': existing_object.properties.email if self.module.params.get('email') is None else self.module.params.get('email'),
+ 'administrator': existing_object.properties.administrator if self.module.params.get('administrator') is None else self.module.params.get('administrator'),
+ 'force_sec_auth': existing_object.properties.force_sec_auth if self.module.params.get('force_sec_auth') is None else self.module.params.get('force_sec_auth'),
+ 'user_password': '' if self.module.params.get('user_password') is None else 'user password will be updated',
+ 'groups': '' if self.module.params.get('groups') is None else 'user groups will be updated',
+ }
+ }
+
def _get_object_list(self, clients):
- return get_users(ionoscloud.UserManagementApi(clients[0]), ionoscloud.Users(items=[]))
+ all_users = ionoscloud.Users(items=[])
+
+ get_users_by_identifier(ionoscloud.UserManagementApi(clients[0]), all_users, self._get_object_name())
+ get_users_by_identifier(ionoscloud.UserManagementApi(clients[0]), all_users, self._get_object_identifier())
+
+ return all_users
def _get_object_name(self):
diff --git a/plugins/modules/user_info.py b/plugins/modules/user_info.py
index a0cb1df5..21eaa76a 100644
--- a/plugins/modules/user_info.py
+++ b/plugins/modules/user_info.py
@@ -7,7 +7,7 @@
from ansible import __version__
-from ansible_collections.ionoscloudsdk.ionoscloud.plugins.module_utils.common_ionos_methods import default_main_info, get_resource_id
+from ansible_collections.ionoscloudsdk.ionoscloud.plugins.module_utils.common_ionos_methods import default_main_info, get_resource_id, get_users
from ansible_collections.ionoscloudsdk.ionoscloud.plugins.module_utils.common_ionos_options import get_info_default_options_with_depth
@@ -99,23 +99,14 @@
"""
-def list_users(depth, users_get_method, extra_args):
- all_users = ionoscloud.Users(items=[])
- offset = 0
- limit = 100
-
- users = users_get_method(**extra_args, depth=depth, limit=limit, offset=offset)
- all_users.items += users.items
- while(users.links.next is not None):
- offset += limit
- users = users_get_method(**extra_args, depth=depth, limit=limit, offset=offset)
- all_users.items += users.items
-
- return all_users
-
-
def get_objects(module, client):
group = module.params.get('group')
+ filters = module.params.get('filters')
+ query_params = {}
+ if filters is not None:
+ for k, v in filters.items():
+ query_params['filter.' + k.split('.')[-1]] = v
+
um_api = ionoscloud.UserManagementApi(api_client=client)
if group:
@@ -123,17 +114,15 @@ def get_objects(module, client):
group_list = um_api.um_groups_get(depth=1)
group_id = get_resource_id(module, group_list, group)
- users = list_users(
- module.params.get('depth'),
- users_get_method=um_api.um_groups_users_get,
- extra_args={'group_id': group_id},
- )
+ users = um_api.um_groups_users_get(group_id=group_id, depth=module.params.get('depth'), query_params=query_params)
else:
- users = list_users(
- module.params.get('depth'),
- users_get_method=um_api.um_users_get,
- extra_args={},
+ users = get_users(
+ api=um_api,
+ all_users=ionoscloud.Users(items=[]),
+ depth=module.params.get('depth'),
+ query_params=query_params,
)
+
return users
diff --git a/plugins/modules/vcpu_server.py b/plugins/modules/vcpu_server.py
index fd1f07d8..4736fc01 100644
--- a/plugins/modules/vcpu_server.py
+++ b/plugins/modules/vcpu_server.py
@@ -561,7 +561,7 @@
state: stopped
"""
-uuid_match = re.compile('[\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12}', re.I)
+uuid_match = re.compile(r'[\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12}', re.I)
def _get_lan_by_id_or_properties(networks, id=None, **kwargs):
diff --git a/plugins/modules/volume.py b/plugins/modules/volume.py
index 435e767e..4acf85fb 100644
--- a/plugins/modules/volume.py
+++ b/plugins/modules/volume.py
@@ -508,7 +508,7 @@
state: absent
"""
-uuid_match = re.compile('[\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12}', re.I)
+uuid_match = re.compile(r'[\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12}', re.I)
def _should_replace_object(module, existing_object, client):
diff --git a/reset.sh b/reset.sh
index b69bff5c..0769ab62 100755
--- a/reset.sh
+++ b/reset.sh
@@ -1,3 +1,3 @@
ansible-galaxy collection build . --force
-ansible-galaxy collection install ionoscloudsdk-ionoscloud-7.3.0.tar.gz --force
-rm ionoscloudsdk-ionoscloud-7.3.0.tar.gz
+ansible-galaxy collection install ionoscloudsdk-ionoscloud-7.4.1.tar.gz --force
+rm ionoscloudsdk-ionoscloud-7.4.1.tar.gz
diff --git a/tests/user-management/group-test.yml b/tests/user-management/group-test.yml
index 3bf98f1a..33b14db4 100644
--- a/tests/user-management/group-test.yml
+++ b/tests/user-management/group-test.yml
@@ -27,6 +27,24 @@
email: "{{ random_user2 }}"
administrator: false
register: user_response
+
+ - name: Update user2
+ ionoscloudsdk.ionoscloud.user:
+ firstname: John2
+ lastname: Doe
+ email: "{{ random_user1 }}"
+ user: "{{ random_user2 }}"
+ administrator: false
+ state: update
+ ignore_errors: true
+ register: user_response
+
+ - name: Testing update with existing email return error
+ assert:
+ that:
+ - user_response.failed == true
+ - user_response.msg == "failed to update the User{{ ":" }} Another resource with the desired name ({{ random_user1 }}) exists"
+ msg: "object list no complete in user module"
# - name: Print output to file
# ansible.builtin.copy:
@@ -42,6 +60,18 @@
# content: "{{user_list_response}}"
# dest: ../../docs/returned_object_examples/user_info.json
+ - name: List Users Filter
+ ionoscloudsdk.ionoscloud.user_info:
+ filters:
+ properties.email: "{{ random_user2 }}"
+ register: user_list_response
+
+ - name: Testing if only one user returned
+ assert:
+ that:
+ - user_list_response.users | length == 1
+ msg: "user filters not working correctly"
+
- name: Create group
ionoscloudsdk.ionoscloud.group:
name: "{{ name }}"
@@ -81,10 +111,76 @@
- "{{ random_user1 }}"
state: update
+ - name: List Users Filter Group
+ ionoscloudsdk.ionoscloud.user_info:
+ group: "{{ name }}"
+ filters:
+ properties.email: "{{ random_user1 }}"
+ register: user_list_response
+
+ - name: Testing if only one user returned
+ assert:
+ that:
+ - user_list_response.users | length == 1
+ msg: "user filters not working correctly"
+
+ - name: List Users Filter Group
+ ionoscloudsdk.ionoscloud.user_info:
+ group: "{{ name }}"
+ filters:
+ properties.email: "{{ random_user1 }}"
+ properties.firstname: John1
+ register: user_list_response
+
+ - name: Testing if only one user returned
+ assert:
+ that:
+ - user_list_response.users | length == 1
+ msg: "user filters not working correctly"
+
+ - name: List Users Filter Group
+ ionoscloudsdk.ionoscloud.user_info:
+ group: "{{ name }}"
+ filters:
+ properties.firstname: John2
+ register: user_list_response
+
+ - name: Testing if no user returned
+ assert:
+ that:
+ - user_list_response.users | length == 0
+ msg: "user filters not working correctly"
+
+ - name: List Users Filter Group
+ ionoscloudsdk.ionoscloud.user_info:
+ group: "{{ name }}"
+ filters:
+ properties.email: "{{ random_user2 }}"
+ register: user_list_response
+
+ - name: Testing if no user returned
+ assert:
+ that:
+ - user_list_response.users | length == 0
+ msg: "user filters not working correctly"
+
- name: Debug - show response
debug:
msg: "{{ group_response }}"
+ - name: List Users Filter Group
+ ionoscloudsdk.ionoscloud.user_info:
+ group: "{{ name }}"
+ filters:
+ properties.lastname: Doe
+ register: user_list_response
+
+ - name: Testing if only one user returned
+ assert:
+ that:
+ - user_list_response.users | length == 1
+ msg: "user filters not working correctly"
+
- name: Update group
ionoscloudsdk.ionoscloud.group:
group: "{{ name }}"
@@ -118,6 +214,45 @@
- group_response.group['entities']['users']['items'] | length == 2
msg: "Group-test: updating a group must keep its users"
+ - name: List Users Filter Group
+ ionoscloudsdk.ionoscloud.user_info:
+ group: "{{ name }}"
+ filters:
+ properties.email: "{{ random_user2 }}"
+ register: user_list_response
+
+ - name: Testing if only one user returned
+ assert:
+ that:
+ - user_list_response.users | length == 1
+ msg: "user filters not working correctly"
+
+ - name: List Users Filter Group
+ ionoscloudsdk.ionoscloud.user_info:
+ group: "{{ name }}"
+ filters:
+ properties.lastname: Doe
+ register: user_list_response
+
+ - name: Testing if only two users returned
+ assert:
+ that:
+ - user_list_response.users | length == 2
+ msg: "user filters not working correctly"
+
+ - name: List Users Filter Group
+ ionoscloudsdk.ionoscloud.user_info:
+ group: "{{ name }}"
+ filters:
+ properties.administrator: False
+ register: user_list_response
+
+ - name: Testing if only two users returned
+ assert:
+ that:
+ - user_list_response.users | length == 2
+ msg: "user filters not working correctly"
+
- name: Remove user from group
ionoscloudsdk.ionoscloud.group:
group: "{{ name }}"
diff --git a/tests/user-management/s3key-test.yml b/tests/user-management/s3key-test.yml
index 78a87dc5..85e868bf 100644
--- a/tests/user-management/s3key-test.yml
+++ b/tests/user-management/s3key-test.yml
@@ -74,7 +74,7 @@
- name: Testing if only one s3key exists
assert:
that:
- - s3keys_info_response.s3keys | length == 2
+ - s3keys_info_response.s3keys | length == 1
msg: "s3key idempotency not working correctly"
- name: Remove an s3key
diff --git a/tests/user-management/user-test.yml b/tests/user-management/user-test.yml
index 7d69a077..92e44940 100644
--- a/tests/user-management/user-test.yml
+++ b/tests/user-management/user-test.yml
@@ -19,6 +19,182 @@
user_password: "{{ password }}"
force_sec_auth: false
state: present
+ check_mode: true
+ diff: true
+ register: user_response
+
+ - name: Asserting that check_mode and diff work correctly
+ assert:
+ that:
+ - user_response.msg == "User {{ random_user }} would be created"
+ - user_response.diff is not defined
+ msg: "check_mode and diff don't work correctly"
+
+ - name: Create user
+ ionoscloudsdk.ionoscloud.user:
+ firstname: John
+ lastname: Doe
+ email: "{{ random_user }}"
+ administrator: false
+ user_password: "{{ password }}"
+ force_sec_auth: false
+ state: present
+
+ - name: Create user
+ ionoscloudsdk.ionoscloud.user:
+ firstname: John
+ lastname: Doe
+ email: "{{ random_user }}"
+ administrator: false
+ user_password: "{{ password }}"
+ force_sec_auth: false
+ state: present
+ check_mode: true
+ diff: false
+ register: user_response
+
+ - name: Asserting that check_mode and diff work correctly
+ assert:
+ that:
+ - user_response.msg == "User {{ random_user }} would be updated"
+ - user_response.diff == {}
+ msg: "check_mode and diff don't work correctly"
+
+ - name: Create user
+ ionoscloudsdk.ionoscloud.user:
+ firstname: John
+ lastname: Doe
+ email: "{{ random_user }}"
+ administrator: false
+ user_password: "{{ password }}"
+ force_sec_auth: false
+ state: present
+ check_mode: true
+ diff: true
+ register: user_response
+
+ - name: Asserting that check_mode and diff work correctly
+ assert:
+ that:
+ - user_response.msg == "User {{ random_user }} would be updated"
+ - user_response.diff.before.administrator == user_response.diff.after.administrator == false
+ - user_response.diff.before.email == user_response.diff.after.email == "{{ random_user }}"
+ - user_response.diff.before.firstname == user_response.diff.after.firstname == 'John'
+ - user_response.diff.before.lastname == user_response.diff.after.lastname == 'Doe'
+ - user_response.diff.before.groups == user_response.diff.after.groups == ''
+ - user_response.diff.before.user_password != user_response.diff.after.user_password
+ - user_response.diff.before.user_password == ''
+ - user_response.diff.after.user_password == 'user password will be updated'
+ msg: "check_mode and diff don't work correctly"
+
+ - name: Create user
+ ionoscloudsdk.ionoscloud.user:
+ firstname: John changed
+ lastname: Doe changed
+ email: "{{ random_user }}"
+ administrator: true
+ user_password: "{{ password }}"
+ force_sec_auth: false
+ state: present
+ check_mode: true
+ diff: true
+ register: user_response
+
+ - name: Asserting that check_mode and diff work correctly 2
+ assert:
+ that:
+ - user_response.msg == "User {{ random_user }} would be updated"
+ - user_response.diff.before.administrator == false
+ - user_response.diff.after.administrator == true
+ - user_response.diff.before.email == user_response.diff.after.email == "{{ random_user }}"
+ - user_response.diff.before.firstname == 'John'
+ - user_response.diff.after.firstname == 'John changed'
+ - user_response.diff.before.lastname == 'Doe'
+ - user_response.diff.after.lastname == 'Doe changed'
+ - user_response.diff.before.groups == user_response.diff.after.groups == ''
+ - user_response.diff.before.user_password == ''
+ - user_response.diff.after.user_password == 'user password will be updated'
+ msg: "check_mode and diff don't work correctly"
+
+ - name: Test ignored fields
+ ionoscloudsdk.ionoscloud.user:
+ firstname: John
+ lastname: Doe
+ email: "{{ random_user }}"
+ administrator: false
+ user_password: "{{ password }}"
+ force_sec_auth: false
+ ignored_properties:
+ - user_password
+ state: present
+ register: user_response
+
+ - name: Asserting that the user was not updated
+ assert:
+ that:
+ - user_response.changed == false
+ msg: "User should not be changed when changed fields are in ignored_properties"
+
+ - name: Test ignored fields
+ ionoscloudsdk.ionoscloud.user:
+ firstname: John
+ lastname: Doe Changed
+ email: "{{ random_user }}"
+ administrator: false
+ user_password: "{{ password }}"
+ groups:
+ - "{{ name }} 1"
+ force_sec_auth: false
+ ignored_properties:
+ - user_password
+ - groups
+ - lastname
+ state: present
+ register: user_response
+
+ - name: Asserting that the user was not updated
+ assert:
+ that:
+ - user_response.changed == false
+ msg: "User should not be changed when changed fields are in ignored_properties"
+
+ - name: Test ignored fields not set
+ ionoscloudsdk.ionoscloud.user:
+ firstname: John
+ lastname: Doe
+ email: "{{ random_user }}"
+ administrator: false
+ user_password: "{{ password }}"
+ force_sec_auth: false
+ state: present
+ register: user_response
+
+ - name: Asserting that the user was updated
+ assert:
+ that:
+ - user_response.changed == true
+ msg: "User should be changed when changed fields are not in ignored_properties"
+
+ - name: Test ignored fields
+ ionoscloudsdk.ionoscloud.user:
+ firstname: John Changed
+ lastname: Doe Changed
+ email: "{{ random_user }}"
+ administrator: false
+ user_password: "{{ password }}"
+ force_sec_auth: false
+ ignored_properties:
+ - user_password
+ - lastname
+ state: present
+ register: user_response
+
+ - name: Asserting that all the user fields were updated
+ assert:
+ that:
+ - user_response.changed == true
+ - user_response.user.properties.lastname == 'Doe Changed'
+ - user_response.user.properties.firstname == 'John Changed'
- name: Create first group
ionoscloudsdk.ionoscloud.group:
@@ -58,12 +234,59 @@
- user_response.user['entities']['groups']['items'] | length == 2
msg: "user-test: updating a user must keep its groups"
+ - name: Update user
+ ionoscloudsdk.ionoscloud.user:
+ firstname: John
+ lastname: Doe
+ user: "{{ random_user }}"
+ administrator: false
+ force_sec_auth: false
+ state: update
+ register: user_response
+
+ - name: Testing user update no change
+ assert:
+ that:
+ - user_response.changed == false
+ msg: "user update not working correctly"
+
+ - name: Update user by ID
+ ionoscloudsdk.ionoscloud.user:
+ firstname: John
+ lastname: Doe
+ user: "{{ user_response.user.id }}"
+ administrator: false
+ force_sec_auth: false
+ state: update
+ register: user_response
+
+ - name: Testing user update no change
+ assert:
+ that:
+ - user_response.changed == false
+ msg: "user update not working correctly"
+
- name: Remove user from groups
ionoscloudsdk.ionoscloud.user:
user: "{{ random_user }}"
groups: []
state: update
+ - name: Delete user
+ ionoscloudsdk.ionoscloud.user:
+ user: "{{ random_user }}"
+ state: absent
+ check_mode: true
+ diff: true
+ register: user_response
+
+ - name: Asserting that check_mode and diff work correctly
+ assert:
+ that:
+ - user_response.msg == "User {{ random_user }} would be deleted"
+ - user_response.diff is not defined
+ msg: "check_mode and diff don't work correctly"
+
- name: Delete user
ionoscloudsdk.ionoscloud.user:
user: "{{ random_user }}"