diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 076aa6b..3da7c9b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,14 @@ Sva.Sentinelone Release Notes .. contents:: Topics +v1.0.3 +====== + +Release Summary +--------------- + +Increased request timeout and implemented error handling for requests that timed out. + v1.0.2 ====== diff --git a/README.md b/README.md index 81dbf77..e5dc3df 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,8 @@ See [Ansible Using collections](https://docs.ansible.com/ansible/devel/user_guid The module documentation can be found [here](https://svalabs.github.io/ansible-collection-sva.sentinelone/branch/main/collections/index_module.html). ## Changelog +**v1.0.3**: Increased request timeout and implemented error handling for requests that timed out. + **v1.0.2**: Added detailed error message to module output if an API call fails **v1.0.1**: Bugfix release diff --git a/changelogs/.plugin-cache.yaml b/changelogs/.plugin-cache.yaml index 499bd8f..1b02b50 100644 --- a/changelogs/.plugin-cache.yaml +++ b/changelogs/.plugin-cache.yaml @@ -48,4 +48,4 @@ plugins: shell: {} strategy: {} vars: {} -version: 1.0.2 +version: 1.0.3 diff --git a/changelogs/changelog.yaml b/changelogs/changelog.yaml index dcda5bc..388a18a 100644 --- a/changelogs/changelog.yaml +++ b/changelogs/changelog.yaml @@ -46,3 +46,10 @@ releases: fragments: - v1.0.2.yml release_date: '2023-03-08' + 1.0.3: + changes: + release_summary: Increased request timeout and implemented error handling for + requests that timed out. + fragments: + - v1.0.3.yml + release_date: '2023-03-13' diff --git a/galaxy.yml b/galaxy.yml index 3cd81e3..3329e39 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -8,7 +8,7 @@ namespace: "sva" name: "sentinelone" # The version of the collection. Must be compatible with semantic versioning -version: "1.0.2" +version: "1.0.3" # The path to the Markdown (.md) readme file. This path is relative to the root of the collection readme: "README.md" diff --git a/plugins/module_utils/sentinelone/sentinelone_base.py b/plugins/module_utils/sentinelone/sentinelone_base.py index b6fa32a..b6e138c 100644 --- a/plugins/module_utils/sentinelone/sentinelone_base.py +++ b/plugins/module_utils/sentinelone/sentinelone_base.py @@ -109,6 +109,7 @@ def api_call(self, module: AnsibleModule, api_endpoint: str, http_method: str = :rtype: dict """ + request_timeout = 120 retries = 3 retry_pause = 3 @@ -131,12 +132,16 @@ def api_call(self, module: AnsibleModule, api_endpoint: str, http_method: str = if body: body_json = json.dumps(body) response_raw, response_info = fetch_url(module, api_endpoint, headers=headers, data=body_json, - method=http_method) + method=http_method, timeout=request_timeout) else: response_raw, response_info = fetch_url(module, api_endpoint, headers=headers, - method=http_method) + method=http_method, timeout=request_timeout) + status_code = response_info['status'] - if status_code >= 400: + if status_code == -1: + # If the request runtime exceeds the timout + module.exit_json(msg=f"{error_msg} Error: {response_info['msg']} after {request_timeout}s.") + elif status_code >= 400: response_unparsed = response_info['body'].decode('utf-8') response = json.loads(response_unparsed) raise response_raw @@ -152,7 +157,7 @@ def api_call(self, module: AnsibleModule, api_endpoint: str, http_method: str = module.fail_json(msg=f"API response is no valid JSON. Error: {str(err)}") except urllib_error.HTTPError as err: module.fail_json( - msg=f"{error_msg} Status code: {err.code} {err.reason}. Response body: {response_unparsed}") + msg=f"{error_msg} Status code: {err.code} {err.reason}. Error: {response_unparsed}") return response diff --git a/plugins/modules/sentinelone_groups.py b/plugins/modules/sentinelone_groups.py index eb024f4..5b9df41 100644 --- a/plugins/modules/sentinelone_groups.py +++ b/plugins/modules/sentinelone_groups.py @@ -215,12 +215,14 @@ def get_desired_state_group_body(self, group_name: str): return desired_state_groups - def create_group(self, create_body: dict, module: AnsibleModule): + def create_group(self, create_body: dict, error_msg: str, module: AnsibleModule): """ API call to create a group :param create_body: Body for the create query :type create_body: dict + :param error_msg: Message used if an API request failes + :type error_msg: str :param module: Ansible module for error handling :type module: AnsibleModule :return: create query response object @@ -228,7 +230,6 @@ def create_group(self, create_body: dict, module: AnsibleModule): """ api_url = self.api_endpoint_groups - error_msg = "Failed to create group." response = self.api_call(module, api_url, "POST", body=create_body, error_msg=error_msg) if response['data']['name'] != create_body['data']['name']: @@ -237,7 +238,7 @@ def create_group(self, create_body: dict, module: AnsibleModule): return response - def update_group(self, update_body: dict, groupid: str, module: AnsibleModule): + def update_group(self, update_body: dict, groupid: str, error_msg: str, module: AnsibleModule): """ API call to update a group @@ -245,6 +246,8 @@ def update_group(self, update_body: dict, groupid: str, module: AnsibleModule): :type update_body: dict :param groupid: ID of the group which should be updated :type groupid: str + :param error_msg: Message used if an API request failes + :type error_msg: str :param module: Ansible module for error handling :type module: AnsibleModule :return: API response of the update query @@ -252,7 +255,6 @@ def update_group(self, update_body: dict, groupid: str, module: AnsibleModule): """ api_url = f"{self.api_endpoint_groups}/{groupid}" - error_msg = "Failed to update group." response = self.api_call(module, api_url, "PUT", body=update_body, error_msg=error_msg) if response['data']['name'] != update_body['data']['name']: @@ -261,12 +263,14 @@ def update_group(self, update_body: dict, groupid: str, module: AnsibleModule): return response - def delete_group(self, group_id: str, module: AnsibleModule): + def delete_group(self, group_id: str, error_msg: str, module: AnsibleModule): """ API call to delete a group :param group_id: ID of the group which should be deleted :type group_id: str + :type error_msg: Message used if an API request failes + :type error_msg: str :param module: Ansible module for error handling :type module: AnsibleModule :return: API response of the delete-query @@ -274,7 +278,6 @@ def delete_group(self, group_id: str, module: AnsibleModule): """ api_url = f"{self.api_endpoint_groups}/{group_id}" - error_msg = "Failed to delete group." response = self.api_call(module, api_url, "DELETE", error_msg=error_msg) if not response['data']['success']: @@ -349,14 +352,16 @@ def run_module(): # Inheritance and policy should not be maintained by this module. # Removing the key because if not the module will update the inherintance property del desired_state_group['data']['inherits'] - groups_obj.update_group(desired_state_group, group_id, module) + error_msg = f"Failed to update group {group_name}." + groups_obj.update_group(desired_state_group, group_id, error_msg, module) basic_message.append(f"Group {group_name} updated") diffs.append({'changes': dict(diff), 'groupName': group_name}) else: basic_message.append("Can not convert dynamic to static group and vice versa. Nothing changed.") else: # Group does not exist. Creating the group - groups_obj.create_group(desired_state_group, module) + error_msg = f"Failed to create group {group_name}." + groups_obj.create_group(desired_state_group, error_msg, module) basic_message.append(f"Group {group_name} created.") diffs.append({'changes': "Group created", 'groupName': group_name}) else: @@ -366,8 +371,9 @@ def run_module(): current_group = list(filter(lambda filterobj: filterobj['name'] == group_name, current_groups)) if current_group: # if group exists delete it + error_msg = f"Failed to delete group {group_name}." group_id = current_group[0]['id'] - groups_obj.delete_group(group_id, module) + groups_obj.delete_group(group_id, error_msg, module) basic_message.append(f"Group {group_name} deleted.") diffs.append({'changes': 'Group deleted', 'groupName': group_name})