diff options
Diffstat (limited to 'lib/ansible/modules/monitoring/zabbix/zabbix_map.py')
-rw-r--r-- | lib/ansible/modules/monitoring/zabbix/zabbix_map.py | 829 |
1 files changed, 0 insertions, 829 deletions
diff --git a/lib/ansible/modules/monitoring/zabbix/zabbix_map.py b/lib/ansible/modules/monitoring/zabbix/zabbix_map.py deleted file mode 100644 index bfd59609d6..0000000000 --- a/lib/ansible/modules/monitoring/zabbix/zabbix_map.py +++ /dev/null @@ -1,829 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# (c) 2017-2018, Antony Alekseyev <antony.alekseyev@gmail.com> -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - -DOCUMENTATION = r''' ---- -module: zabbix_map -author: - - "Antony Alekseyev (@Akint)" -short_description: Create/update/delete Zabbix maps -description: - - "This module allows you to create, modify and delete Zabbix map entries, - using Graphviz binaries and text description written in DOT language. - Nodes of the graph will become map elements and edges will become links between map elements. - See U(https://en.wikipedia.org/wiki/DOT_(graph_description_language)) and U(https://www.graphviz.org/) for details. - Inspired by U(http://blog.zabbix.com/maps-for-the-lazy/)." - - "The following extra node attributes are supported: - C(zbx_host) contains name of the host in Zabbix. Use this if desired type of map element is C(host). - C(zbx_group) contains name of the host group in Zabbix. Use this if desired type of map element is C(host group). - C(zbx_map) contains name of the map in Zabbix. Use this if desired type of map element is C(map). - C(zbx_label) contains label of map element. - C(zbx_image) contains name of the image used to display the element in default state. - C(zbx_image_disabled) contains name of the image used to display disabled map element. - C(zbx_image_maintenance) contains name of the image used to display map element in maintenance. - C(zbx_image_problem) contains name of the image used to display map element with problems. - C(zbx_url) contains map element URL in C(name:url) format. - More than one URL could be specified by adding a postfix (e.g., C(zbx_url1), C(zbx_url2))." - - "The following extra link attributes are supported: - C(zbx_draw_style) contains link line draw style. Possible values: C(line), C(bold), C(dotted), C(dashed). - C(zbx_trigger) contains name of the trigger used as a link indicator in C(host_name:trigger_name) format. - More than one trigger could be specified by adding a postfix (e.g., C(zbx_trigger1), C(zbx_trigger2)). - C(zbx_trigger_color) contains indicator color specified either as CSS3 name or as a hexadecimal code starting with C(#). - C(zbx_trigger_draw_style) contains indicator draw style. Possible values are the same as for C(zbx_draw_style)." -requirements: - - "python >= 2.6" - - "zabbix-api >= 0.5.4" - - pydotplus - - webcolors - - Pillow - - Graphviz -version_added: "2.8" -options: - name: - description: - - Name of the map. - required: true - aliases: [ "map_name" ] - type: str - data: - description: - - Graph written in DOT language. - required: false - aliases: [ "dot_data" ] - type: str - state: - description: - - State of the map. - - On C(present), it will create if map does not exist or update the map if the associated data is different. - - On C(absent) will remove the map if it exists. - required: false - choices: ['present', 'absent'] - default: "present" - type: str - width: - description: - - Width of the map. - required: false - default: 800 - type: int - height: - description: - - Height of the map. - required: false - default: 600 - type: int - margin: - description: - - Size of white space between map's borders and its elements. - required: false - default: 40 - type: int - expand_problem: - description: - - Whether the problem trigger will be displayed for elements with a single problem. - required: false - type: bool - default: true - highlight: - description: - - Whether icon highlighting is enabled. - required: false - type: bool - default: true - label_type: - description: - - Map element label type. - required: false - choices: ['label', 'ip', 'name', 'status', 'nothing', 'custom'] - default: "name" - type: str - default_image: - description: - - Name of the Zabbix image used to display the element if this element doesn't have the C(zbx_image) attribute defined. - required: false - aliases: [ "image" ] - type: str - -extends_documentation_fragment: - - zabbix -''' - -RETURN = r''' # ''' - -EXAMPLES = r''' -### -### Example inventory: -# [web] -# web[01:03].example.com ansible_host=127.0.0.1 -# [db] -# db.example.com ansible_host=127.0.0.1 -# [backup] -# backup.example.com ansible_host=127.0.0.1 -### -### Each inventory host is present in Zabbix with a matching name. -### -### Contents of 'map.j2': -# digraph G { -# graph [layout=dot splines=false overlap=scale] -# INTERNET [zbx_url="Google:https://google.com" zbx_image="Cloud_(96)"] -# {% for web_host in groups.web %} -# {% set web_loop = loop %} -# web{{ '%03d' % web_loop.index }} [zbx_host="{{ web_host }}"] -# INTERNET -> web{{ '%03d' % web_loop.index }} [zbx_trigger="{{ web_host }}:Zabbix agent on {HOST.NAME} is unreachable for 5 minutes"] -# {% for db_host in groups.db %} -# {% set db_loop = loop %} -# web{{ '%03d' % web_loop.index }} -> db{{ '%03d' % db_loop.index }} -# {% endfor %} -# {% endfor %} -# { rank=same -# {% for db_host in groups.db %} -# {% set db_loop = loop %} -# db{{ '%03d' % db_loop.index }} [zbx_host="{{ db_host }}"] -# {% for backup_host in groups.backup %} -# {% set backup_loop = loop %} -# db{{ '%03d' % db_loop.index }} -> backup{{ '%03d' % backup_loop.index }} [color="blue"] -# {% endfor %} -# {% endfor %} -# {% for backup_host in groups.backup %} -# {% set backup_loop = loop %} -# backup{{ '%03d' % backup_loop.index }} [zbx_host="{{ backup_host }}"] -# {% endfor %} -# } -# } -### -### Create Zabbix map "Demo Map" made of template 'map.j2' -- name: Create Zabbix map - zabbix_map: - server_url: http://zabbix.example.com - login_user: username - login_password: password - name: Demo map - state: present - data: "{{ lookup('template', 'map.j2') }}" - default_image: Server_(64) - expand_problem: no - highlight: no - label_type: label - delegate_to: localhost - run_once: yes -''' - -ANSIBLE_METADATA = { - 'metadata_version': '1.1', - 'supported_by': 'community', - 'status': ['preview'] -} - - -import atexit -import base64 -import traceback - -from io import BytesIO -from operator import itemgetter -from distutils.version import StrictVersion -from ansible.module_utils.basic import AnsibleModule, missing_required_lib - -try: - import pydotplus - HAS_PYDOTPLUS = True -except ImportError: - PYDOT_IMP_ERR = traceback.format_exc() - HAS_PYDOTPLUS = False - -try: - import webcolors - HAS_WEBCOLORS = True -except ImportError: - WEBCOLORS_IMP_ERR = traceback.format_exc() - HAS_WEBCOLORS = False - -try: - from zabbix_api import ZabbixAPI - HAS_ZABBIX_API = True -except ImportError: - ZBX_IMP_ERR = traceback.format_exc() - HAS_ZABBIX_API = False - -try: - from PIL import Image - HAS_PIL = True -except ImportError: - PIL_IMP_ERR = traceback.format_exc() - HAS_PIL = False - - -class Map(): - def __init__(self, module, zbx): - self._module = module - self._zapi = zbx - - self.map_name = module.params['name'] - self.dot_data = module.params['data'] - self.width = module.params['width'] - self.height = module.params['height'] - self.state = module.params['state'] - self.default_image = module.params['default_image'] - self.map_id = self._get_sysmap_id(self.map_name) - self.margin = module.params['margin'] - self.expand_problem = module.params['expand_problem'] - self.highlight = module.params['highlight'] - self.label_type = module.params['label_type'] - self.api_version = self._zapi.api_version() - self.selements_sort_keys = self._get_selements_sort_keys() - - def _build_graph(self): - try: - graph_without_positions = pydotplus.graph_from_dot_data(self.dot_data) - dot_data_with_positions = graph_without_positions.create_dot() - graph_with_positions = pydotplus.graph_from_dot_data(dot_data_with_positions) - if graph_with_positions: - return graph_with_positions - except Exception as e: - self._module.fail_json(msg="Failed to build graph from DOT data: %s" % e) - - def get_map_config(self): - if not self.dot_data: - self._module.fail_json(msg="'data' is mandatory with state 'present'") - graph = self._build_graph() - nodes = self._get_graph_nodes(graph) - edges = self._get_graph_edges(graph) - icon_ids = self._get_icon_ids() - map_config = { - 'name': self.map_name, - 'label_type': self._get_label_type_id(self.label_type), - 'expandproblem': int(self.expand_problem), - 'highlight': int(self.highlight), - 'width': self.width, - 'height': self.height, - 'selements': self._get_selements(graph, nodes, icon_ids), - 'links': self._get_links(nodes, edges), - } - return map_config - - def _get_label_type_id(self, label_type): - label_type_ids = { - 'label': 0, - 'ip': 1, - 'name': 2, - 'status': 3, - 'nothing': 4, - 'custom': 5, - } - try: - label_type_id = label_type_ids[label_type] - except Exception as e: - self._module.fail_json(msg="Failed to find id for label type '%s': %s" % (label_type, e)) - return label_type_id - - def _get_images_info(self, data, icon_ids): - images = [ - { - 'dot_tag': 'zbx_image', - 'zbx_property': 'iconid_off', - 'mandatory': True - }, - { - 'dot_tag': 'zbx_image_disabled', - 'zbx_property': 'iconid_disabled', - 'mandatory': False - }, - { - 'dot_tag': 'zbx_image_maintenance', - 'zbx_property': 'iconid_maintenance', - 'mandatory': False - }, - { - 'dot_tag': 'zbx_image_problem', - 'zbx_property': 'iconid_on', - 'mandatory': False - } - ] - images_info = {} - default_image = self.default_image if self.default_image else sorted(icon_ids.items())[0][0] - for image in images: - image_name = data.get(image['dot_tag'], None) - if not image_name: - if image['mandatory']: - image_name = default_image - else: - continue - image_name = remove_quotes(image_name) - if image_name in icon_ids: - images_info[image['zbx_property']] = icon_ids[image_name] - if not image['mandatory']: - images_info['use_iconmap'] = 0 - else: - self._module.fail_json(msg="Failed to find id for image '%s'" % image_name) - return images_info - - def _get_element_type(self, data): - types = { - 'host': 0, - 'sysmap': 1, - 'trigger': 2, - 'group': 3, - 'image': 4 - } - element_type = { - 'elementtype': types['image'], - } - if StrictVersion(self.api_version) < StrictVersion('3.4'): - element_type.update({ - 'elementid': "0", - }) - for type_name, type_id in sorted(types.items()): - field_name = 'zbx_' + type_name - if field_name in data: - method_name = '_get_' + type_name + '_id' - element_name = remove_quotes(data[field_name]) - get_element_id = getattr(self, method_name, None) - if get_element_id: - elementid = get_element_id(element_name) - if elementid and int(elementid) > 0: - element_type.update({ - 'elementtype': type_id, - 'label': element_name - }) - if StrictVersion(self.api_version) < StrictVersion('3.4'): - element_type.update({ - 'elementid': elementid, - }) - else: - element_type.update({ - 'elements': [{ - type_name + 'id': elementid, - }], - }) - break - else: - self._module.fail_json(msg="Failed to find id for %s '%s'" % (type_name, element_name)) - return element_type - - # get list of map elements (nodes) - def _get_selements(self, graph, nodes, icon_ids): - selements = [] - icon_sizes = {} - scales = self._get_scales(graph) - for selementid, (node, data) in enumerate(nodes.items(), start=1): - selement = { - 'selementid': selementid - } - data['selementid'] = selementid - - images_info = self._get_images_info(data, icon_ids) - selement.update(images_info) - image_id = images_info['iconid_off'] - if image_id not in icon_sizes: - icon_sizes[image_id] = self._get_icon_size(image_id) - - pos = self._convert_coordinates(data['pos'], scales, icon_sizes[image_id]) - selement.update(pos) - - selement['label'] = remove_quotes(node) - element_type = self._get_element_type(data) - selement.update(element_type) - - label = self._get_label(data) - if label: - selement['label'] = label - - urls = self._get_urls(data) - if urls: - selement['urls'] = urls - - selements.append(selement) - return selements - - def _get_links(self, nodes, edges): - links = {} - for edge in edges: - link_id = tuple(sorted(edge.obj_dict['points'])) - node1, node2 = link_id - data = edge.obj_dict['attributes'] - - if "style" in data and data['style'] == "invis": - continue - - if link_id not in links: - links[link_id] = { - 'selementid1': min(nodes[node1]['selementid'], nodes[node2]['selementid']), - 'selementid2': max(nodes[node1]['selementid'], nodes[node2]['selementid']), - } - link = links[link_id] - - if "color" not in link: - link['color'] = self._get_color_hex(remove_quotes(data.get('color', 'green'))) - - if "zbx_draw_style" not in link: - link['drawtype'] = self._get_link_draw_style_id(remove_quotes(data.get('zbx_draw_style', 'line'))) - - label = self._get_label(data) - if label and "label" not in link: - link['label'] = label - - triggers = self._get_triggers(data) - if triggers: - if "linktriggers" not in link: - link['linktriggers'] = [] - link['linktriggers'] += triggers - - return list(links.values()) - - def _get_urls(self, data): - urls = [] - for url_raw in [remove_quotes(value) for key, value in data.items() if key.startswith("zbx_url")]: - try: - name, url = url_raw.split(':', 1) - except Exception as e: - self._module.fail_json(msg="Failed to parse zbx_url='%s': %s" % (url_raw, e)) - urls.append({ - 'name': name, - 'url': url, - }) - return urls - - def _get_triggers(self, data): - triggers = [] - for trigger_definition in [remove_quotes(value) for key, value in data.items() if key.startswith("zbx_trigger")]: - triggerid = self._get_trigger_id(trigger_definition) - if triggerid: - triggers.append({ - 'triggerid': triggerid, - 'color': self._get_color_hex(remove_quotes(data.get('zbx_trigger_color', 'red'))), - 'drawtype': self._get_link_draw_style_id(remove_quotes(data.get('zbx_trigger_draw_style', 'bold'))), - }) - else: - self._module.fail_json(msg="Failed to find trigger '%s'" % (trigger_definition)) - return triggers - - @staticmethod - def _get_label(data, default=None): - if "zbx_label" in data: - label = remove_quotes(data['zbx_label']).replace('\\n', '\n') - elif "label" in data: - label = remove_quotes(data['label']) - else: - label = default - return label - - def _get_sysmap_id(self, map_name): - exist_map = self._zapi.map.get({'filter': {'name': map_name}}) - if exist_map: - return exist_map[0]['sysmapid'] - return None - - def _get_group_id(self, group_name): - exist_group = self._zapi.hostgroup.get({'filter': {'name': group_name}}) - if exist_group: - return exist_group[0]['groupid'] - return None - - def map_exists(self): - return bool(self.map_id) - - def create_map(self, map_config): - try: - if self._module.check_mode: - self._module.exit_json(changed=True) - result = self._zapi.map.create(map_config) - if result: - return result - except Exception as e: - self._module.fail_json(msg="Failed to create map: %s" % e) - - def update_map(self, map_config): - if not self.map_id: - self._module.fail_json(msg="Failed to update map: map_id is unknown. Try to create_map instead.") - try: - if self._module.check_mode: - self._module.exit_json(changed=True) - map_config['sysmapid'] = self.map_id - result = self._zapi.map.update(map_config) - if result: - return result - except Exception as e: - self._module.fail_json(msg="Failed to update map: %s" % e) - - def delete_map(self): - if not self.map_id: - self._module.fail_json(msg="Failed to delete map: map_id is unknown.") - try: - if self._module.check_mode: - self._module.exit_json(changed=True) - self._zapi.map.delete([self.map_id]) - except Exception as e: - self._module.fail_json(msg="Failed to delete map, Exception: %s" % e) - - def is_exist_map_correct(self, generated_map_config): - exist_map_configs = self._zapi.map.get({ - 'sysmapids': self.map_id, - 'selectLinks': 'extend', - 'selectSelements': 'extend' - }) - exist_map_config = exist_map_configs[0] - if not self._is_dicts_equal(generated_map_config, exist_map_config): - return False - if not self._is_selements_equal(generated_map_config['selements'], exist_map_config['selements']): - return False - self._update_ids(generated_map_config, exist_map_config) - if not self._is_links_equal(generated_map_config['links'], exist_map_config['links']): - return False - return True - - def _get_selements_sort_keys(self): - keys_to_sort = ['label'] - if StrictVersion(self.api_version) < StrictVersion('3.4'): - keys_to_sort.insert(0, 'elementid') - return keys_to_sort - - def _is_selements_equal(self, generated_selements, exist_selements): - if len(generated_selements) != len(exist_selements): - return False - generated_selements_sorted = sorted(generated_selements, key=itemgetter(*self.selements_sort_keys)) - exist_selements_sorted = sorted(exist_selements, key=itemgetter(*self.selements_sort_keys)) - for (generated_selement, exist_selement) in zip(generated_selements_sorted, exist_selements_sorted): - if StrictVersion(self.api_version) >= StrictVersion("3.4"): - if not self._is_elements_equal(generated_selement.get('elements', []), exist_selement.get('elements', [])): - return False - if not self._is_dicts_equal(generated_selement, exist_selement, ['selementid']): - return False - if not self._is_urls_equal(generated_selement.get('urls', []), exist_selement.get('urls', [])): - return False - return True - - def _is_urls_equal(self, generated_urls, exist_urls): - if len(generated_urls) != len(exist_urls): - return False - generated_urls_sorted = sorted(generated_urls, key=itemgetter('name', 'url')) - exist_urls_sorted = sorted(exist_urls, key=itemgetter('name', 'url')) - for (generated_url, exist_url) in zip(generated_urls_sorted, exist_urls_sorted): - if not self._is_dicts_equal(generated_url, exist_url, ['selementid']): - return False - return True - - def _is_elements_equal(self, generated_elements, exist_elements): - if len(generated_elements) != len(exist_elements): - return False - generated_elements_sorted = sorted(generated_elements, key=lambda k: k.values()[0]) - exist_elements_sorted = sorted(exist_elements, key=lambda k: k.values()[0]) - for (generated_element, exist_element) in zip(generated_elements_sorted, exist_elements_sorted): - if not self._is_dicts_equal(generated_element, exist_element, ['selementid']): - return False - return True - - # since generated IDs differ from real Zabbix ones, make real IDs match generated ones - def _update_ids(self, generated_map_config, exist_map_config): - generated_selements_sorted = sorted(generated_map_config['selements'], key=itemgetter(*self.selements_sort_keys)) - exist_selements_sorted = sorted(exist_map_config['selements'], key=itemgetter(*self.selements_sort_keys)) - id_mapping = {} - for (generated_selement, exist_selement) in zip(generated_selements_sorted, exist_selements_sorted): - id_mapping[exist_selement['selementid']] = generated_selement['selementid'] - for link in exist_map_config['links']: - link['selementid1'] = id_mapping[link['selementid1']] - link['selementid2'] = id_mapping[link['selementid2']] - if link['selementid2'] < link['selementid1']: - link['selementid1'], link['selementid2'] = link['selementid2'], link['selementid1'] - - def _is_links_equal(self, generated_links, exist_links): - if len(generated_links) != len(exist_links): - return False - generated_links_sorted = sorted(generated_links, key=itemgetter('selementid1', 'selementid2', 'color', 'drawtype')) - exist_links_sorted = sorted(exist_links, key=itemgetter('selementid1', 'selementid2', 'color', 'drawtype')) - for (generated_link, exist_link) in zip(generated_links_sorted, exist_links_sorted): - if not self._is_dicts_equal(generated_link, exist_link, ['selementid1', 'selementid2']): - return False - if not self._is_triggers_equal(generated_link.get('linktriggers', []), exist_link.get('linktriggers', [])): - return False - return True - - def _is_triggers_equal(self, generated_triggers, exist_triggers): - if len(generated_triggers) != len(exist_triggers): - return False - generated_triggers_sorted = sorted(generated_triggers, key=itemgetter('triggerid')) - exist_triggers_sorted = sorted(exist_triggers, key=itemgetter('triggerid')) - for (generated_trigger, exist_trigger) in zip(generated_triggers_sorted, exist_triggers_sorted): - if not self._is_dicts_equal(generated_trigger, exist_trigger): - return False - return True - - @staticmethod - def _is_dicts_equal(d1, d2, exclude_keys=None): - if exclude_keys is None: - exclude_keys = [] - for key in d1.keys(): - if isinstance(d1[key], dict) or isinstance(d1[key], list): - continue - if key in exclude_keys: - continue - # compare as strings since Zabbix API returns everything as strings - if key not in d2 or str(d2[key]) != str(d1[key]): - return False - return True - - def _get_host_id(self, hostname): - hostid = self._zapi.host.get({'filter': {'host': hostname}}) - if hostid: - return str(hostid[0]['hostid']) - - def _get_trigger_id(self, trigger_definition): - try: - host, trigger = trigger_definition.split(':', 1) - except Exception as e: - self._module.fail_json(msg="Failed to parse zbx_trigger='%s': %s" % (trigger_definition, e)) - triggerid = self._zapi.trigger.get({ - 'host': host, - 'filter': { - 'description': trigger - } - }) - if triggerid: - return str(triggerid[0]['triggerid']) - - def _get_icon_ids(self): - icons_list = self._zapi.image.get({}) - icon_ids = {} - for icon in icons_list: - icon_ids[icon['name']] = icon['imageid'] - return icon_ids - - def _get_icon_size(self, icon_id): - icons_list = self._zapi.image.get({ - 'imageids': [ - icon_id - ], - 'select_image': True - }) - if len(icons_list) > 0: - icon_base64 = icons_list[0]['image'] - else: - self._module.fail_json(msg="Failed to find image with id %s" % icon_id) - image = Image.open(BytesIO(base64.b64decode(icon_base64))) - icon_width, icon_height = image.size - return icon_width, icon_height - - @staticmethod - def _get_node_attributes(node): - attr = {} - if "attributes" in node.obj_dict: - attr.update(node.obj_dict['attributes']) - pos = node.get_pos() - if pos is not None: - pos = remove_quotes(pos) - xx, yy = pos.split(",") - attr['pos'] = (float(xx), float(yy)) - return attr - - def _get_graph_nodes(self, parent): - nodes = {} - for node in parent.get_nodes(): - node_name = node.get_name() - if node_name in ('node', 'graph', 'edge'): - continue - nodes[node_name] = self._get_node_attributes(node) - for subgraph in parent.get_subgraphs(): - nodes.update(self._get_graph_nodes(subgraph)) - return nodes - - def _get_graph_edges(self, parent): - edges = [] - for edge in parent.get_edges(): - edges.append(edge) - for subgraph in parent.get_subgraphs(): - edges += self._get_graph_edges(subgraph) - return edges - - def _get_scales(self, graph): - bb = remove_quotes(graph.get_bb()) - min_x, min_y, max_x, max_y = bb.split(",") - scale_x = (self.width - self.margin * 2) / (float(max_x) - float(min_x)) if float(max_x) != float(min_x) else 0 - scale_y = (self.height - self.margin * 2) / (float(max_y) - float(min_y)) if float(max_y) != float(min_y) else 0 - return { - 'min_x': float(min_x), - 'min_y': float(min_y), - 'max_x': float(max_x), - 'max_y': float(max_y), - 'scale_x': float(scale_x), - 'scale_y': float(scale_y), - } - - # transform Graphviz coordinates to Zabbix's ones - def _convert_coordinates(self, pos, scales, icon_size): - return { - 'x': int((pos[0] - scales['min_x']) * scales['scale_x'] - icon_size[0] / 2 + self.margin), - 'y': int((scales['max_y'] - pos[1] + scales['min_y']) * scales['scale_y'] - icon_size[1] / 2 + self.margin), - } - - def _get_color_hex(self, color_name): - if color_name.startswith('#'): - color_hex = color_name - else: - try: - color_hex = webcolors.name_to_hex(color_name) - except Exception as e: - self._module.fail_json(msg="Failed to get RGB hex for color '%s': %s" % (color_name, e)) - color_hex = color_hex.strip('#').upper() - return color_hex - - def _get_link_draw_style_id(self, draw_style): - draw_style_ids = { - 'line': 0, - 'bold': 2, - 'dotted': 3, - 'dashed': 4 - } - try: - draw_style_id = draw_style_ids[draw_style] - except Exception as e: - self._module.fail_json(msg="Failed to find id for draw type '%s': %s" % (draw_style, e)) - return draw_style_id - - -# If a string has single or double quotes around it, remove them. -def remove_quotes(s): - if (s[0] == s[-1]) and s.startswith(("'", '"')): - s = s[1:-1] - return s - - -def main(): - module = AnsibleModule( - argument_spec=dict( - server_url=dict(type='str', required=True, aliases=['url']), - login_user=dict(type='str', required=True), - login_password=dict(type='str', required=True, no_log=True), - http_login_user=dict(type='str', required=False, default=None), - http_login_password=dict(type='str', required=False, default=None, no_log=True), - timeout=dict(type='int', default=10), - validate_certs=dict(type='bool', required=False, default=True), - name=dict(type='str', required=True, aliases=['map_name']), - data=dict(type='str', required=False, aliases=['dot_data']), - width=dict(type='int', default=800), - height=dict(type='int', default=600), - state=dict(type='str', default="present", choices=['present', 'absent']), - default_image=dict(type='str', required=False, aliases=['image']), - margin=dict(type='int', default=40), - expand_problem=dict(type='bool', default=True), - highlight=dict(type='bool', default=True), - label_type=dict(type='str', default='name', choices=['label', 'ip', 'name', 'status', 'nothing', 'custom']), - ), - supports_check_mode=True - ) - - if not HAS_ZABBIX_API: - module.fail_json(msg=missing_required_lib('zabbix-api', url='https://pypi.org/project/zabbix-api/'), exception=ZBX_IMP_ERR) - if not HAS_PYDOTPLUS: - module.fail_json(msg=missing_required_lib('pydotplus', url='https://pypi.org/project/pydotplus/'), exception=PYDOT_IMP_ERR) - if not HAS_WEBCOLORS: - module.fail_json(msg=missing_required_lib('webcolors', url='https://pypi.org/project/webcolors/'), exception=WEBCOLORS_IMP_ERR) - if not HAS_PIL: - module.fail_json(msg=missing_required_lib('Pillow', url='https://pypi.org/project/Pillow/'), exception=PIL_IMP_ERR) - - server_url = module.params['server_url'] - login_user = module.params['login_user'] - login_password = module.params['login_password'] - http_login_user = module.params['http_login_user'] - http_login_password = module.params['http_login_password'] - timeout = module.params['timeout'] - validate_certs = module.params['validate_certs'] - - zbx = None - - # login to zabbix - try: - zbx = ZabbixAPI(server_url, timeout=timeout, user=http_login_user, passwd=http_login_password, - validate_certs=validate_certs) - zbx.login(login_user, login_password) - atexit.register(zbx.logout) - except Exception as e: - module.fail_json(msg="Failed to connect to Zabbix server: %s" % e) - - sysmap = Map(module, zbx) - - if sysmap.state == "absent": - if sysmap.map_exists(): - sysmap.delete_map() - module.exit_json(changed=True, result="Successfully deleted map: %s" % sysmap.map_name) - else: - module.exit_json(changed=False) - else: - map_config = sysmap.get_map_config() - if sysmap.map_exists(): - if sysmap.is_exist_map_correct(map_config): - module.exit_json(changed=False) - else: - sysmap.update_map(map_config) - module.exit_json(changed=True, result="Successfully updated map: %s" % sysmap.map_name) - else: - sysmap.create_map(map_config) - module.exit_json(changed=True, result="Successfully created map: %s" % sysmap.map_name) - - -if __name__ == '__main__': - main() |