diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 12:04:41 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 12:04:41 +0000 |
commit | 975f66f2eebe9dadba04f275774d4ab83f74cf25 (patch) | |
tree | 89bd26a93aaae6a25749145b7e4bca4a1e75b2be /ansible_collections/ibm/qradar/plugins/action | |
parent | Initial commit. (diff) | |
download | ansible-975f66f2eebe9dadba04f275774d4ab83f74cf25.tar.xz ansible-975f66f2eebe9dadba04f275774d4ab83f74cf25.zip |
Adding upstream version 7.7.0+dfsg.upstream/7.7.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ansible_collections/ibm/qradar/plugins/action')
3 files changed, 532 insertions, 0 deletions
diff --git a/ansible_collections/ibm/qradar/plugins/action/__init__.py b/ansible_collections/ibm/qradar/plugins/action/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/ansible_collections/ibm/qradar/plugins/action/__init__.py diff --git a/ansible_collections/ibm/qradar/plugins/action/qradar_analytics_rules.py b/ansible_collections/ibm/qradar/plugins/action/qradar_analytics_rules.py new file mode 100644 index 000000000..906cbc9e5 --- /dev/null +++ b/ansible_collections/ibm/qradar/plugins/action/qradar_analytics_rules.py @@ -0,0 +1,226 @@ +# +# Copyright 2022 Red Hat Inc. +# +# This file is part of Ansible +# +# Ansible 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. +# +# Ansible 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 Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +""" +The module file for qradar_analytics_rules +""" + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +import json +from ansible.plugins.action import ActionBase +from ansible.module_utils.connection import Connection +from ansible.module_utils._text import to_text +from ansible.module_utils.six.moves.urllib.parse import quote + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import ( + utils, +) +from ansible_collections.ibm.qradar.plugins.module_utils.qradar import ( + QRadarRequest, + remove_unsupported_keys_from_payload_dict, +) +from ansible_collections.ansible.utils.plugins.module_utils.common.argspec_validate import ( + AnsibleArgSpecValidator, +) +from ansible_collections.ibm.qradar.plugins.modules.qradar_analytics_rules import ( + DOCUMENTATION, +) + + +class ActionModule(ActionBase): + """action module""" + + def __init__(self, *args, **kwargs): + super(ActionModule, self).__init__(*args, **kwargs) + self._supports_async = True + self._result = None + self.api_object = "/api/analytics/rules" + self.api_return = "rules_management" + self.module_return = "qradar_analytics_rules" + self.supported_params = [ + "id", + "name", + "enabled", + "owner", + "fields", + "range", + ] + + def _check_argspec(self): + aav = AnsibleArgSpecValidator( + data=self._task.args, + schema=DOCUMENTATION, + schema_format="doc", + name=self._task.action, + ) + valid, errors, self._task.args = aav.validate() + if not valid: + self._result["failed"] = True + self._result["msg"] = errors + + def search_for_resource(self, qradar_request, search_for_resource=None): + """The fn TC of GATHER operation + :param qradar_request: Qradar connection request + :param search_for_resource: Module input config with either ID, NAME, or RANGE with field input + :rtype: A dict + :returns: dict with module prams transformed having API expected params + """ + if search_for_resource.get("id"): + api_obj_url = self.api_object + "/{0}".format( + search_for_resource["id"] + ) + elif search_for_resource.get("name"): + api_obj_url = self.api_object + "?filter={0}".format( + quote( + 'name="{0}"'.format(to_text(search_for_resource["name"])) + ) + ) + elif search_for_resource.get("range"): + api_obj_url = self.api_object + if search_for_resource.get("fields"): + fields = ",".join(search_for_resource["fields"]) + fields_url = "?fields={0}".format(quote("{0}".format(fields))) + api_obj_url += fields_url + code, rule_source_exists = qradar_request.get(api_obj_url) + if ( + rule_source_exists + and len(rule_source_exists) == 1 + and ( + search_for_resource.get("name") + and not search_for_resource.get("id") + ) + ): + rule_source_exists = rule_source_exists[0] + return rule_source_exists + + def delete_module_api_config(self, qradar_request, module_config_params): + """The fn TC of DELETE operation + :param qradar_request: Qradar connection request + :param module_config_params: Module input config + :rtype: A dict + :returns: Delete output with before and after dict + """ + config = {} + before = {} + after = {} + changed = False + rule_exists = self.search_for_resource( + qradar_request, module_config_params + ) + if rule_exists: + changed = True + before = rule_exists + code, qradar_return_data = qradar_request.delete( + self.api_object + "/{0}".format(rule_exists["id"]) + ) + config.update({"before": before, "after": after}) + else: + config.update({"before": before}) + return config, changed + + def configure_module_api(self, qradar_request, module_config_params): + """The fn TC of MERGE operation + :param qradar_request: Qradar connection request + :param module_config_params: Module input config + :rtype: A dict + :returns: Merge output with before and after dict + """ + config = {} + before = {} + changed = False + + rule_exists = self.search_for_resource( + qradar_request, module_config_params + ) + if rule_exists: + if isinstance(rule_exists, list): + for each in rule_exists: + if each.get("origin") == "OVERRIDE": + rule_exists = each + break + before = rule_exists + module_config_params = utils.remove_empties(module_config_params) + diff = utils.dict_diff(rule_exists, module_config_params) + if diff: + changed = True + qradar_return_data = qradar_request.post_by_path( + self.api_object + "/{0}".format(rule_exists["id"]), + data=json.dumps(diff), + ) + if qradar_return_data[0] >= 200: + config.update( + {"before": before, "after": qradar_return_data[1]} + ) + else: + config.update({"before": before}) + return config, changed + + def run(self, tmp=None, task_vars=None): + self._supports_check_mode = True + self._result = super(ActionModule, self).run(tmp, task_vars) + headers = None + if self._task.args.get("config"): + self._task.args[ + "config" + ] = remove_unsupported_keys_from_payload_dict( + self._task.args["config"], self.supported_params + ) + self._check_argspec() + if self._result.get("failed"): + return self._result + if self._task.args["config"].get("range"): + headers = { + "Content-Type": "application/json", + "Range": "items={0}".format( + self._task.args["config"]["range"] + ), + } + conn = Connection(self._connection.socket_path) + if headers: + conn_request = QRadarRequest( + connection=conn, headers=headers, task_vars=task_vars + ) + else: + conn_request = QRadarRequest(connection=conn, task_vars=task_vars) + if self._task.args["state"] == "gathered": + if self._task.args.get("config"): + self._result["gathered"] = self.search_for_resource( + conn_request, self._task.args["config"] + ) + elif self._task.args["state"] == "merged": + if self._task.args.get("config"): + ( + self._result[self.module_return], + self._result["changed"], + ) = self.configure_module_api( + conn_request, self._task.args["config"] + ) + elif self._task.args["state"] == "deleted": + if self._task.args.get("config"): + ( + self._result[self.module_return], + self._result["changed"], + ) = self.delete_module_api_config( + conn_request, self._task.args["config"] + ) + + return self._result diff --git a/ansible_collections/ibm/qradar/plugins/action/qradar_log_sources_management.py b/ansible_collections/ibm/qradar/plugins/action/qradar_log_sources_management.py new file mode 100644 index 000000000..5d5efcd5e --- /dev/null +++ b/ansible_collections/ibm/qradar/plugins/action/qradar_log_sources_management.py @@ -0,0 +1,306 @@ +# +# Copyright 2022 Red Hat Inc. +# +# This file is part of Ansible +# +# Ansible 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. +# +# Ansible 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 Ansible. If not, see <http://www.gnu.org/licenses/>. +# + +""" +The module file for qradar_log_sources_management +""" + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +from copy import copy +import json +from ansible.plugins.action import ActionBase +from ansible.errors import AnsibleActionFail +from ansible.module_utils.connection import Connection +from ansible.module_utils.six.moves.urllib.parse import quote + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import ( + utils, +) +from ansible_collections.ibm.qradar.plugins.module_utils.qradar import ( + QRadarRequest, + find_dict_in_list, + list_to_dict, + remove_unsupported_keys_from_payload_dict, +) +from ansible_collections.ansible.utils.plugins.module_utils.common.argspec_validate import ( + AnsibleArgSpecValidator, +) +from ansible_collections.ibm.qradar.plugins.modules.qradar_log_sources_management import ( + DOCUMENTATION, +) + + +class ActionModule(ActionBase): + """action module""" + + def __init__(self, *args, **kwargs): + super(ActionModule, self).__init__(*args, **kwargs) + self._result = None + self.api_object = ( + "/api/config/event_sources/log_source_management/log_sources" + ) + self.api_object_types = "/api/config/event_sources/log_source_management/log_source_types?filter=" + self.api_object_search = "/api/config/event_sources/log_source_management/log_sources?filter=" + self.api_return = "log_sources_management" + self.module_return = "qradar_log_sources_management" + self.supported_params = [ + "name", + "description", + "type_name", + "type_id", + "identifier", + "protocol_type_id", + "enabled", + "gateway", + "internal", + "target_event_collector_id", + "coalesce_events", + "store_event_payload", + "language_id", + "group_ids", + "requires_deploy", + "status", + "average_eps", + "protocol_parameters", + ] + + def _check_argspec(self): + aav = AnsibleArgSpecValidator( + data=self._task.args, + schema=DOCUMENTATION, + schema_format="doc", + name=self._task.action, + ) + valid, errors, self._task.args = aav.validate() + if not valid: + self._result["failed"] = True + self._result["msg"] = errors + + def set_log_source_values(self, qradar_request, config_params): + # find log source types details + if config_params.get("type_name"): + + api_object = self.api_object_types + "{0}".format( + quote('name="{0}"'.format(config_params["type_name"])) + ) + code, log_source_type_found = qradar_request.get(api_object) + if config_params.get("type_id"): + log_source_type_found = [] + if config_params.get("group_ids"): + del config_params["group_ids"] + elif log_source_type_found and not config_params.get("type_id"): + config_params["type_id"] = log_source_type_found[0]["id"] + config_params.pop("type_name") + else: + raise AnsibleActionFail( + "Incompatible type provided, please consult QRadar Documentation for Log Source Types!" + ) + + if log_source_type_found: + if config_params.get("protocol_type_id"): + found_dict_in_list, _fdil_index = find_dict_in_list( + log_source_type_found[0]["protocol_types"], + "protocol_id", + config_params["protocol_type_id"], + ) + if not found_dict_in_list: + config_params.fail_json( + msg="Incompatible protocol_type_id provided, please consult QRadar Documentation for Log Source Types" + ) + elif log_source_type_found[0].get("protocol_types"): + # Set it to the default as provided by the QRadar Instance + protocol_type_id = 0 + for each in log_source_type_found[0]["protocol_types"]: + if each.get("protocol_id") == 0 and each.get("documented"): + protocol_type_id = 0 + break + elif each.get("documented"): + protocol_type_id = each["protocol_id"] + config_params["protocol_type_id"] = protocol_type_id + + config_params["protocol_parameters"] = [ + { + "id": config_params["protocol_type_id"], + "name": "identifier", + "value": config_params["identifier"], + } + ] + config_params.pop("identifier") + return config_params + + def search_for_resource_name( + self, qradar_request, search_resource_by_names=None + ): + search_result = [] + if isinstance(search_resource_by_names, list): + for each in search_resource_by_names: + each = utils.remove_empties(each) + query_api_object = self.api_object_search + "{0}".format( + quote('name="{0}"'.format(each["name"])) + ) + code, log_source_exists = qradar_request.get(query_api_object) + if log_source_exists and (code >= 200 and code < 300): + search_result.append(log_source_exists[0]) + elif isinstance(search_resource_by_names, str): + query_api_object = self.api_object_search + "{0}".format( + quote('name="{0}"'.format(search_resource_by_names)) + ) + code, log_source_exists = qradar_request.get(query_api_object) + if log_source_exists and (code >= 200 and code < 300): + search_result.append(log_source_exists[0]) + return search_result[0] + else: + code, log_source_exists = qradar_request.get(self.api_object) + if log_source_exists and (code >= 200 and code < 300): + search_result = log_source_exists + return search_result + + def delete_module_api_config(self, qradar_request, module_config_params): + config = {} + before = [] + after = [] + changed = False + for each in module_config_params: + each = utils.remove_empties(each) + log_source_exists = self.search_for_resource_name( + qradar_request, each["name"] + ) + if log_source_exists: + before.append(log_source_exists) + query_object = self.api_object + "/{0}".format( + log_source_exists["id"] + ) + code, qradar_return_data = qradar_request.delete(query_object) + if code >= 200 and code < 300: + changed = True + config.update({"before": before, "after": after}) + else: + config.update({"before": before}) + return config, changed + + def configure_module_api(self, conn_request, module_config_params): + config = {} + before = [] + after = [] + changed = False + temp_request_param = [] + for each in module_config_params: + each = utils.remove_empties(each) + each = self.set_log_source_values(conn_request, each) + search_result = self.search_for_resource_name( + conn_request, each["name"] + ) + if search_result: + if search_result["name"] == each["name"]: + temp_each = copy(each) + temp_search_result = copy(search_result) + list_to_dict(temp_each) + list_to_dict(temp_search_result) + diff = utils.dict_diff(temp_search_result, temp_each) + if diff: + if self._task.args["state"] == "merged": + each = utils.remove_empties( + utils.dict_merge(search_result, each) + ) + temp_request_param.append(each) + elif self._task.args["state"] == "replaced": + query_object = self.api_object + "/{0}".format( + search_result["id"] + ) + code, qradar_return_data = conn_request.delete( + query_object + ) + temp_request_param.append(each) + else: + after.append(search_result) + before.append(search_result) + else: + each = utils.remove_empties(each) + temp_request_param.append(each) + if temp_request_param: + code, response = conn_request.create_update( + self.api_object, + data=json.dumps(temp_request_param), + ) + if code >= 200 and code < 300: + changed = True + search_result = self.search_for_resource_name(conn_request) + for each in temp_request_param: + for every in search_result: + if each["name"] == every["name"]: + after.append(every) + break + elif code >= 400: + raise AnsibleActionFail( + "Failed with http_response: {0} and message: {1}".format( + response["http_response"]["message"], + response["message"], + ) + ) + config.update({"before": before, "after": after}) + else: + config.update({"before": before}) + + return config, changed + + def run(self, tmp=None, task_vars=None): + self._supports_check_mode = True + self._result = super(ActionModule, self).run(tmp, task_vars) + if self._task.args.get("config"): + self._task.args[ + "config" + ] = remove_unsupported_keys_from_payload_dict( + self._task.args["config"], self.supported_params + ) + self._check_argspec() + if self._result.get("failed"): + return self._result + conn = Connection(self._connection.socket_path) + conn_request = QRadarRequest(connection=conn, task_vars=task_vars) + if self._task.args["state"] == "gathered": + if self._task.args.get("config"): + self._result["gathered"] = self.search_for_resource_name( + conn_request, self._task.args["config"] + ) + else: + self._result["gathered"] = conn_request.get(self.api_object) + elif ( + self._task.args["state"] == "merged" + or self._task.args["state"] == "replaced" + ): + if self._task.args.get("config"): + ( + self._result[self.module_return], + self._result["changed"], + ) = self.configure_module_api( + conn_request, self._task.args["config"] + ) + elif self._task.args["state"] == "deleted": + if self._task.args.get("config"): + ( + self._result[self.module_return], + self._result["changed"], + ) = self.delete_module_api_config( + conn_request, self._task.args["config"] + ) + + return self._result |