diff options
Diffstat (limited to 'ansible_collections/cisco/iosxr/plugins')
6 files changed, 86 insertions, 1279 deletions
diff --git a/ansible_collections/cisco/iosxr/plugins/cliconf/iosxr.py b/ansible_collections/cisco/iosxr/plugins/cliconf/iosxr.py index 6b569ae2a..8a4e8a850 100644 --- a/ansible_collections/cisco/iosxr/plugins/cliconf/iosxr.py +++ b/ansible_collections/cisco/iosxr/plugins/cliconf/iosxr.py @@ -358,6 +358,15 @@ class Cliconf(CliconfBase): resp["response"] = results return resp + def restore(self, filename=None, path=""): + if not filename: + raise ValueError("'file_name' value is required for restore") + self.configure() + cmd = f"load {path}{filename}" + resp = self.send_command(cmd) + self.commit() + return resp + def get_diff( self, candidate=None, @@ -452,7 +461,9 @@ class Cliconf(CliconfBase): if self.get_option("commit_confirmed"): cmd_obj["command"] = "commit replace confirmed" if self.get_option("commit_confirmed_timeout"): - cmd_obj["command"] += " {0}".format(self.get_option("commit_confirmed_timeout")) + cmd_obj["command"] += " {0}".format( + self.get_option("commit_confirmed_timeout"), + ) cmd_obj[ "prompt" @@ -462,11 +473,17 @@ class Cliconf(CliconfBase): elif self.get_option("commit_confirmed"): cmd_obj["command"] = "commit confirmed" if self.get_option("commit_confirmed_timeout"): - cmd_obj["command"] += " {0}".format(self.get_option("commit_confirmed_timeout")) + cmd_obj["command"] += " {0}".format( + self.get_option("commit_confirmed_timeout"), + ) if self.get_option("commit_label"): - cmd_obj["command"] += " label {0}".format(self.get_option("commit_label")) + cmd_obj["command"] += " label {0}".format( + self.get_option("commit_label"), + ) if self.get_option("commit_comment"): - cmd_obj["command"] += " comment {0}".format(self.get_option("commit_comment")) + cmd_obj["command"] += " comment {0}".format( + self.get_option("commit_comment"), + ) else: label = label or self.get_option("commit_label") @@ -498,7 +515,9 @@ class Cliconf(CliconfBase): output = cmd.pop("output", None) if output: - raise ValueError("'output' value %s is not supported for run_commands" % output) + raise ValueError( + "'output' value %s is not supported for run_commands" % output, + ) try: out = self.send_command(**cmd) diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/bgp_templates/bgp_templates.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/bgp_templates/bgp_templates.py index 793f26282..51a70c5fd 100644 --- a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/bgp_templates/bgp_templates.py +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/argspec/bgp_templates/bgp_templates.py @@ -48,7 +48,14 @@ class Bgp_templatesArgs(object): # pylint: disable=R0903 "options": { "afi": { "type": "str", - "choices": ["ipv4", "ipv6"], + "choices": [ + "ipv4", + "ipv6", + "vpnv4", + "vpnv6", + "link-state", + "l2vpn", + ], }, "safi": { "type": "str", @@ -62,6 +69,10 @@ class Bgp_templatesArgs(object): # pylint: disable=R0903 "unicast", "labeled-unicast", "sr-policy", + "link-state", + "evpn", + "mspw", + "vpls-vpws", ], }, "signalling": { diff --git a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/legacy/base.py b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/legacy/base.py index cc657f42a..2baf42c9f 100644 --- a/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/legacy/base.py +++ b/ansible_collections/cisco/iosxr/plugins/module_utils/network/iosxr/facts/legacy/base.py @@ -123,6 +123,8 @@ class Interfaces(FactsBase): "show ipv6 interface", "show lldp", "show lldp neighbors detail", + "show cdp", + "show cdp neighbors detail", ] def populate(self): @@ -142,6 +144,10 @@ class Interfaces(FactsBase): neighbors = self.responses[3] self.facts["neighbors"] = self.parse_neighbors(neighbors) + if "CDP is not enabled" not in self.responses[4]: + neighbors = self.responses[5] + self.facts["neighbors"] = self.parse_cdp_neighbors(neighbors) + def populate_interfaces(self, interfaces): facts = dict() for key, value in iteritems(interfaces): @@ -200,6 +206,25 @@ class Interfaces(FactsBase): facts[intf].append(fact) return facts + def parse_cdp_neighbors(self, neighbors): + facts = dict() + for entry in neighbors.split("-------------------------"): + if entry == "": + continue + intf_port = self.parse_cdp_intf_port(entry) + if intf_port is None: + return facts + intf, port = intf_port + if intf not in facts: + facts[intf] = list() + fact = dict() + fact["host"] = self.parse_cdp_host(entry) + fact["platform"] = self.parse_cdp_platform(entry) + fact["port"] = port + fact["ip"] = self.parse_cdp_ip(entry) + facts[intf].append(fact) + return facts + def parse_interfaces(self, data): parsed = dict() key = "" @@ -281,3 +306,23 @@ class Interfaces(FactsBase): match = re.search(r"Port id: (.+)$", data, re.M) if match: return match.group(1) + + def parse_cdp_intf_port(self, data): + match = re.search(r"^Interface: (.+), Port ID \(outgoing port\): (.+)$", data, re.M) + if match: + return match.group(1), match.group(2) + + def parse_cdp_host(self, data): + match = re.search(r"^Device ID: (.+)$", data, re.M) + if match: + return match.group(1) + + def parse_cdp_platform(self, data): + match = re.search(r"^Platform: (.+),", data, re.M) + if match: + return match.group(1) + + def parse_cdp_ip(self, data): + match = re.search(r"^ IP address: (.+)$", data, re.M) + if match: + return match.group(1) diff --git a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_bgp_templates.py b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_bgp_templates.py index 5db2cb2ad..b57ac4f9f 100644 --- a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_bgp_templates.py +++ b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_bgp_templates.py @@ -46,11 +46,12 @@ options: afi: description: address family. type: str - choices: [ 'ipv4', 'ipv6' ] + choices: [ 'ipv4', 'ipv6', 'vpnv4', 'vpnv6', 'link-state', 'l2vpn'] safi: description: Address Family modifier type: str - choices: [ 'flowspec', 'mdt', 'multicast', 'mvpn', 'rt-filter', 'tunnel', 'unicast', 'labeled-unicast' , 'sr-policy'] + choices: [ 'flowspec', 'mdt', 'multicast', 'mvpn', 'rt-filter', 'tunnel', + 'unicast', 'labeled-unicast' , 'sr-policy', 'link-state', 'evpn', 'mspw', 'vpls-vpws'] signalling: type: dict description: Signalling protocols to disable, BGP or LDP diff --git a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_facts.py b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_facts.py index c406a18b7..a85328ab2 100644 --- a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_facts.py +++ b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_facts.py @@ -172,7 +172,8 @@ ansible_net_interfaces: returned: when interfaces is configured type: dict ansible_net_neighbors: - description: The list of LLDP neighbors from the remote device + description: The list of LLDP and CDP neighbors from the remote device. If both, + CDP and LLDP neighbor data is present on one port, CDP is preferred. returned: when interfaces is configured type: dict diff --git a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_logging.py b/ansible_collections/cisco/iosxr/plugins/modules/iosxr_logging.py deleted file mode 100644 index abca845df..000000000 --- a/ansible_collections/cisco/iosxr/plugins/modules/iosxr_logging.py +++ /dev/null @@ -1,1270 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# (c) 2017, Ansible by Red Hat, inc -# 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 = """ -module: iosxr_logging -author: -- Trishna Guha (@trishnaguha) -- Kedar Kekan (@kedarX) -short_description: (deprecated, removed after 2023-08-01) Configuration management of system logging services on network - devices -description: -- This module provides declarative management configuration of system logging (syslog) - on Cisco IOS XR devices. -version_added: 1.0.0 -deprecated: - alternative: iosxr_logging_global - why: Updated module released with more functionality. - removed_at_date: '2023-08-01' -requirements: -- ncclient >= 0.5.3 when using netconf -- lxml >= 4.1.1 when using netconf -notes: -- This module works with connection C(network_cli) and C(netconf). See L(the IOS-XR - Platform Options,../network/user_guide/platform_iosxr.html). -options: - dest: - description: - - Destination for system logging (syslog) messages. - choices: - - host - - console - - monitor - - buffered - - file - type: str - name: - description: - - When C(dest) = I(file) name indicates file-name - - When C(dest) = I(host) name indicates the host-name or ip-address of syslog - server. - type: str - vrf: - description: - - vrf name when syslog server is configured, C(dest) = C(host) - type: str - default: default - size: - description: - - Size of buffer when C(dest) = C(buffered). The acceptable value is in the range - I(307200 to 125000000 bytes). Default 307200 - - Size of file when C(dest) = C(file). The acceptable value is in the range I(1 - to 2097152)KB. Default 2 GB - type: int - facility: - description: - - To configure the type of syslog facility in which system logging (syslog) messages - are sent to syslog servers Optional config for C(dest) = C(host) - default: local7 - type: str - hostnameprefix: - description: - - To append a hostname prefix to system logging (syslog) messages logged to syslog - servers. Optional config for C(dest) = C(host) - type: str - level: - description: - - Specifies the severity level for the logging. - type: str - default: debugging - aliases: - - severity - choices: ["emergencies", "alerts", "critical", "errors", "warning", "notifications", "informational", "debugging"] - path: - description: - Set file path. - type: str - aggregate: - description: List of syslog logging configuration definitions. - type: list - elements: dict - suboptions: - dest: - description: - - Destination for system logging (syslog) messages. - choices: - - host - - console - - monitor - - buffered - - file - type: str - name: - description: - - When C(dest) = I(file) name indicates file-name - - When C(dest) = I(host) name indicates the host-name or ip-address of syslog - server. - type: str - path: - description: - Set file path. - type: str - vrf: - description: - - vrf name when syslog server is configured, C(dest) = C(host) - type: str - size: - description: - - Size of buffer when C(dest) = C(buffered). The acceptable value is in the range - I(307200 to 125000000 bytes). Default 307200 - - Size of file when C(dest) = C(file). The acceptable value is in the range I(1 - to 2097152)KB. Default 2 GB - type: int - facility: - description: - - To configure the type of syslog facility in which system logging (syslog) messages - are sent to syslog servers Optional config for C(dest) = C(host) - type: str - hostnameprefix: - description: - - To append a hostname prefix to system logging (syslog) messages logged to syslog - servers. Optional config for C(dest) = C(host) - type: str - level: - description: - - Specifies the severity level for the logging. - type: str - aliases: - - severity - choices: ["emergencies", "alerts", "critical", "errors", "warning", "notifications", "informational", "debugging"] - state: - description: - - Existential state of the logging configuration on the node. - choices: - - present - - absent - type: str - state: - description: - - Existential state of the logging configuration on the node. - default: present - choices: - - present - - absent - type: str -extends_documentation_fragment: -- cisco.iosxr.iosxr -""" - -EXAMPLES = """ -- name: configure logging for syslog server host - cisco.iosxr.iosxr_logging: - dest: host - name: 10.10.10.1 - level: critical - state: present - -- name: add hostnameprefix configuration - cisco.iosxr.iosxr_logging: - hostnameprefix: host1 - state: absent - -- name: add facility configuration - cisco.iosxr.iosxr_logging: - facility: local1 - state: present - -- name: configure console logging level - cisco.iosxr.iosxr_logging: - dest: console - level: debugging - state: present - -- name: configure monitor logging level - cisco.iosxr.iosxr_logging: - dest: monitor - level: errors - state: present - -- name: configure syslog to a file - cisco.iosxr.iosxr_logging: - dest: file - name: file_name - size: 2048 - level: errors - state: present - -- name: configure buffered logging with size - cisco.iosxr.iosxr_logging: - dest: buffered - size: 5100000 - -- name: Configure logging using aggregate - cisco.iosxr.iosxr_logging: - aggregate: - - {dest: console, level: warning} - - {dest: buffered, size: 4800000} - - {dest: file, name: file3, size: 2048} - - {dest: host, name: host3, level: critical} - -- name: Delete logging using aggregate - cisco.iosxr.iosxr_logging: - aggregate: - - {dest: console, level: warning} - - {dest: buffered, size: 4800000} - - {dest: file, name: file3, size: 2048} - - {dest: host, name: host3, level: critical} - state: absent -""" - -RETURN = """ -commands: - description: The list of configuration mode commands to send to the device - returned: always (empty list when no commands to send) - type: list - sample: - - logging 10.10.10.1 vrf default severity debugging - - logging facility local7 - - logging hostnameprefix host1 - - logging console critical - - logging buffered 2097153 - - logging buffered warnings - - logging monitor errors - - logging file log_file maxfilesize 1024 severity info -xml: - description: NetConf rpc xml sent to device with transport C(netconf) - returned: always (empty list when no xml rpc to send) - type: list - sample: - - '<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0"> - <syslog xmlns="http://cisco.com/ns/yang/Cisco-IOS-XR-infra-syslog-cfg"> - <files> - <file xc:operation="delete"> - <file-name>file1</file-name> - <file-log-attributes> - <max-file-size>2097152</max-file-size> - <severity>2</severity> - </file-log-attributes> - </file> - </files> - </syslog> - </config>' -""" - -import collections -import re - -from copy import deepcopy - -from ansible.module_utils._text import to_text -from ansible.module_utils.basic import AnsibleModule -from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import ( - remove_default_spec, -) - -from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.iosxr import ( - build_xml, - etree_find, - etree_findall, - get_capabilities, - get_config, - get_os_version, - is_cliconf, - is_netconf, - load_config, -) -from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.utils.utils import Version - - -severity_level = { - "emergency": "0", - "alert": "1", - "critical": "2", - "error": "3", - "warning": "4", - "notice": "5", - "info": "6", - "debug": "7", - "disable": "15", -} - -severity_transpose = { - "emergencies": "emergency", - "alerts": "alert", - "critical": "critical", - "errors": "error", - "warning": "warning", - "notifications": "notice", - "informational": "info", - "debugging": "debug", -} - - -class ConfigBase(object): - def __init__(self, module): - self._flag = None - self._module = module - self._result = {"changed": False, "warnings": []} - self._want = list() - self._have = list() - - def validate_size(self, value, type=None): - if value: - if type == "buffer": - if value and not int(307200) <= value <= int(125000000): - self._module.fail_json( - msg="buffer size must be between 307200 and 125000000", - ) - elif type == "file": - if value and not int(1) <= value <= int(2097152): - self._module.fail_json( - msg="file size must be between 1 and 2097152", - ) - return value - - def map_params_to_obj(self, required_if=None): - aggregate = self._module.params.get("aggregate") - if aggregate: - for item in aggregate: - for key in item: - if item.get(key) is None: - item[key] = self._module.params[key] - - d = item.copy() - - if d["dest"] not in ("host", "file"): - d["name"] = None - - if d["dest"] == "buffered": - if d["size"] is not None: - d["size"] = str( - self.validate_size(d["size"], "buffer"), - ) - else: - d["size"] = str(307200) - elif d["dest"] == "file": - if d["size"] is not None: - d["size"] = str(self.validate_size(d["size"], "file")) - else: - d["size"] = str(2097152) - else: - d["size"] = None - - if self._flag == "NC": - d["level"] = severity_transpose[d["level"]] - - self._want.append(d) - - else: - params = self._module.params - if params["dest"] not in ("host", "file"): - params["name"] = None - - if params["dest"] == "buffered": - if params["size"] is not None: - params["size"] = str( - self.validate_size(params["size"], "buffer"), - ) - else: - params["size"] = str(307200) - elif params["dest"] == "file": - if params["size"] is not None: - params["size"] = str( - self.validate_size(params["size"], "file"), - ) - else: - params["size"] = str(2097152) - else: - params["size"] = None - - if self._flag == "NC": - params["level"] = severity_transpose[params["level"]] - - self._want.append( - { - "dest": params["dest"], - "name": params["name"], - "vrf": params["vrf"], - "size": params["size"], - "path": params["path"], - "facility": params["facility"], - "level": params["level"], - "hostnameprefix": params["hostnameprefix"], - "state": params["state"], - }, - ) - - -class CliConfiguration(ConfigBase): - def __init__(self, module): - super(CliConfiguration, self).__init__(module) - self._file_list = set() - self._host_list = set() - - def map_obj_to_commands(self, os_version): - commands = list() - for want_item in self._want: - dest = want_item["dest"] - name = want_item["name"] - size = want_item["size"] - path = want_item["path"] - facility = want_item["facility"] - level = want_item["level"] - vrf = want_item["vrf"] - hostnameprefix = want_item["hostnameprefix"] - state = want_item["state"] - del want_item["state"] - - have_size = None - have_console_level = None - have_monitor_level = None - have_prefix = None - have_facility = None - - for item in self._have: - if item["dest"] == "buffered": - have_size = item["size"] - if item["dest"] == "console": - have_console_level = item["level"] - if item["dest"] == "monitor": - have_monitor_level = item["level"] - if item["dest"] is None and item["hostnameprefix"] is not None: - have_prefix = item["hostnameprefix"] - if ( - item["dest"] is None - and item["hostnameprefix"] is None - and item["facility"] is not None - ): - have_facility = item["facility"] - - if state == "absent": - if dest == "host" and name in self._host_list: - commands.append("no logging {0} vrf {1}".format(name, vrf)) - elif dest == "file" and name in self._file_list: - commands.append("no logging file {0}".format(name)) - elif dest == "console" and have_console_level is not None: - commands.append("no logging {0}".format(dest)) - elif dest == "monitor" and have_monitor_level: - commands.append("no logging {0}".format(dest)) - elif dest == "buffered" and have_size: - commands.append("no logging {0}".format(dest)) - - if dest is None and hostnameprefix is not None and have_prefix == hostnameprefix: - commands.append( - "no logging hostnameprefix {0}".format(hostnameprefix), - ) - if dest is None and facility is not None and have_facility == facility: - commands.append("no logging facility {0}".format(facility)) - - if state == "present": - if dest == "host" and name not in self._host_list: - if level == "errors" or level == "informational": - level = severity_transpose[level] - commands.append( - "logging {0} vrf {1} severity {2}".format( - name, - vrf, - level, - ), - ) - elif dest == "file" and name not in self._file_list: - if level == "errors" or level == "informational": - level = severity_transpose[level] - if os_version and Version(os_version) > Version("7.0"): - commands.append( - "logging file {0} path {1} maxfilesize {2} severity {3}".format( - name, - path, - size, - level, - ), - ) - else: - commands.append( - "logging file {0} maxfilesize {1} severity {2}".format( - name, - size, - level, - ), - ) - elif dest == "buffered" and ( - have_size is None or (have_size is not None and size != have_size) - ): - commands.append("logging buffered {0}".format(size)) - elif dest == "console" and ( - have_console_level is None - or (have_console_level is not None and have_console_level != level) - ): - commands.append("logging console {0}".format(level)) - elif dest == "monitor" and ( - have_monitor_level is None - or (have_monitor_level is not None and have_monitor_level != level) - ): - commands.append("logging monitor {0}".format(level)) - - if ( - dest is None - and hostnameprefix is not None - and ( - have_prefix is None - or (have_prefix is not None and hostnameprefix != have_prefix) - ) - ): - commands.append( - "logging hostnameprefix {0}".format(hostnameprefix), - ) - if dest is None and hostnameprefix is None and facility != have_facility: - commands.append("logging facility {0}".format(facility)) - - self._result["commands"] = commands - if commands: - commit = not self._module.check_mode - diff = load_config(self._module, commands, commit=commit) - if diff: - self._result["diff"] = dict(prepared=diff) - self._result["changed"] = True - - def parse_facility(self, line): - match = re.search(r"logging facility (\S+)", line, re.M) - facility = None - if match: - facility = match.group(1) - - return facility - - def parse_size(self, line, dest): - size = None - - if dest == "buffered": - match = re.search(r"logging buffered (\S+)", line, re.M) - if match: - try: - int_size = int(match.group(1)) - except ValueError: - int_size = None - - if int_size is not None: - if isinstance(int_size, int): - size = str(match.group(1)) - if dest == "file": - match = re.search( - r"logging file (\S+) (path\s\S+\s)?maxfilesize (\S+)", - line, - re.M, - ) - if match: - try: - if "path" in line: - int_size = int(match.group(2)) - else: - int_size = int(match.group(1)) - except ValueError: - int_size = None - - if int_size is not None: - if isinstance(int_size, int): - size = str(int_size) - - return size - - def parse_path(self, line, dest): - path = None - - if dest == "file": - match = re.search(r"logging file (\S+) (path\s\S+\s)", line, re.M) - if match: - try: - path = to_text( - match.group(2), - errors="surrogate_or_strict", - ) - except ValueError: - path = None - - return path - - def parse_hostnameprefix(self, line): - prefix = None - match = re.search(r"logging hostnameprefix (\S+)", line, re.M) - if match: - prefix = match.group(1) - return prefix - - def parse_name(self, line, dest): - name = None - if dest == "file": - match = re.search(r"logging file (\S+)", line, re.M) - if match: - name = match.group(1) - elif dest == "host": - match = re.search(r"logging (\S+)", line, re.M) - if match: - name = match.group(1) - - return name - - def parse_level(self, line, dest): - level_group = ( - "emergencies", - "alerts", - "critical", - "errors", - "warning", - "notifications", - "informational", - "debugging", - ) - - level = None - match = re.search(r"logging {0} (\S+)".format(dest), line, re.M) - if match: - if match.group(1) in level_group: - level = match.group(1) - - return level - - def parse_dest(self, line, group): - dest_group = ("console", "monitor", "buffered", "file") - dest = None - if group in dest_group: - dest = group - elif "vrf" in line: - dest = "host" - - return dest - - def parse_vrf(self, line, dest): - vrf = None - if dest == "host": - match = re.search(r"logging (\S+) vrf (\S+)", line, re.M) - if match: - vrf = match.group(2) - return vrf - - def map_config_to_obj(self): - data = get_config(self._module, config_filter="logging") - lines = data.split("\n") - - for line in lines: - match = re.search(r"logging (\S+)", line, re.M) - if match: - dest = self.parse_dest(line, match.group(1)) - name = self.parse_name(line, dest) - if dest == "host" and name is not None: - self._host_list.add(name) - if dest == "file" and name is not None: - self._file_list.add(name) - - self._have.append( - { - "dest": dest, - "name": name, - "size": self.parse_size(line, dest), - "path": self.parse_path(line, dest), - "facility": self.parse_facility(line), - "level": self.parse_level(line, dest), - "vrf": self.parse_vrf(line, dest), - "hostnameprefix": self.parse_hostnameprefix(line), - }, - ) - - def run(self, os_version): - self.map_params_to_obj() - self.map_config_to_obj() - self.map_obj_to_commands(os_version) - - return self._result - - -class NCConfiguration(ConfigBase): - def __init__(self, module): - super(NCConfiguration, self).__init__(module) - self._flag = "NC" - self._log_file_meta = collections.OrderedDict() - self._log_host_meta = collections.OrderedDict() - self._log_console_meta = collections.OrderedDict() - self._log_monitor_meta = collections.OrderedDict() - self._log_buffered_meta = collections.OrderedDict() - self._log_facility_meta = collections.OrderedDict() - self._log_prefix_meta = collections.OrderedDict() - - def map_obj_to_xml_rpc(self, os_version): - file_attribute_path = "file-log-attributes" - if os_version and Version(os_version) > Version("7.0.0"): - file_attribute_path = "file-specification" - self._log_file_meta.update( - [ - ( - "files", - { - "xpath": "syslog/files", - "tag": True, - "operation": "edit", - }, - ), - ( - "file", - { - "xpath": "syslog/files/file", - "tag": True, - "operation": "edit", - "attrib": "operation", - }, - ), - ( - "a:name", - { - "xpath": "syslog/files/file/file-name", - "operation": "edit", - }, - ), - ( - "file-attrib", - { - "xpath": "syslog/files/file/" + file_attribute_path, - "tag": True, - "operation": "edit", - }, - ), - ( - "a:size", - { - "xpath": "syslog/files/file/" + file_attribute_path + "/max-file-size", - "operation": "edit", - }, - ), - ( - "a:level", - { - "xpath": "syslog/files/file/" + file_attribute_path + "/severity", - "operation": "edit", - }, - ), - ( - "a:path", - { - "xpath": "syslog/files/file/" + file_attribute_path + "/path", - "operation": "edit", - }, - ), - ], - ) - else: - self._log_file_meta.update( - [ - ( - "files", - { - "xpath": "syslog/files", - "tag": True, - "operation": "edit", - }, - ), - ( - "file", - { - "xpath": "syslog/files/file", - "tag": True, - "operation": "edit", - "attrib": "operation", - }, - ), - ( - "a:name", - { - "xpath": "syslog/files/file/file-name", - "operation": "edit", - }, - ), - ( - "file-attrib", - { - "xpath": "syslog/files/file/" + file_attribute_path, - "tag": True, - "operation": "edit", - }, - ), - ( - "a:size", - { - "xpath": "syslog/files/file/" + file_attribute_path + "/max-file-size", - "operation": "edit", - }, - ), - ( - "a:level", - { - "xpath": "syslog/files/file/" + file_attribute_path + "/severity", - "operation": "edit", - }, - ), - ], - ) - self._log_host_meta.update( - [ - ( - "host-server", - { - "xpath": "syslog/host-server", - "tag": True, - "operation": "edit", - }, - ), - ( - "vrfs", - { - "xpath": "syslog/host-server/vrfs", - "tag": True, - "operation": "edit", - }, - ), - ( - "vrf", - { - "xpath": "syslog/host-server/vrfs/vrf", - "tag": True, - "operation": "edit", - }, - ), - ( - "a:vrf", - { - "xpath": "syslog/host-server/vrfs/vrf/vrf-name", - "operation": "edit", - }, - ), - ( - "ipv4s", - { - "xpath": "syslog/host-server/vrfs/vrf/ipv4s", - "tag": True, - "operation": "edit", - }, - ), - ( - "ipv4", - { - "xpath": "syslog/host-server/vrfs/vrf/ipv4s/ipv4", - "tag": True, - "operation": "edit", - "attrib": "operation", - }, - ), - ( - "a:name", - { - "xpath": "syslog/host-server/vrfs/vrf/ipv4s/ipv4/address", - "operation": "edit", - }, - ), - ( - "ipv4-sev", - { - "xpath": "syslog/host-server/vrfs/vrf/ipv4s/ipv4/ipv4-severity-port", - "tag": True, - "operation": "edit", - }, - ), - ( - "a:level", - { - "xpath": "syslog/host-server/vrfs/vrf/ipv4s/ipv4/ipv4-severity-port/severity", - "operation": "edit", - }, - ), - ], - ) - self._log_console_meta.update( - [ - ( - "a:enable-console", - { - "xpath": "syslog/enable-console-logging", - "operation": "edit", - "attrib": "operation", - }, - ), - ( - "console", - { - "xpath": "syslog/console-logging", - "tag": True, - "operation": "edit", - "attrib": "operation", - }, - ), - ( - "a:console-level", - { - "xpath": "syslog/console-logging/logging-level", - "operation": "edit", - }, - ), - ], - ) - self._log_monitor_meta.update( - [ - ( - "monitor", - { - "xpath": "syslog/monitor-logging", - "tag": True, - "operation": "edit", - "attrib": "operation", - }, - ), - ( - "a:monitor-level", - { - "xpath": "syslog/monitor-logging/logging-level", - "operation": "edit", - }, - ), - ], - ) - self._log_buffered_meta.update( - [ - ( - "buffered", - { - "xpath": "syslog/buffered-logging", - "tag": True, - "operation": "edit", - "attrib": "operation", - }, - ), - ( - "a:size", - { - "xpath": "syslog/buffered-logging/buffer-size", - "operation": "edit", - }, - ), - ( - "a:level", - { - "xpath": "syslog/buffered-logging/logging-level", - "operation": "edit", - }, - ), - ], - ) - self._log_facility_meta.update( - [ - ( - "facility", - { - "xpath": "syslog/logging-facilities", - "tag": True, - "operation": "edit", - "attrib": "operation", - }, - ), - ( - "a:facility", - { - "xpath": "syslog/logging-facilities/facility-level", - "operation": "edit", - }, - ), - ], - ) - self._log_prefix_meta.update( - [ - ( - "a:hostnameprefix", - { - "xpath": "syslog/host-name-prefix", - "operation": "edit", - "attrib": "operation", - }, - ), - ], - ) - - state = self._module.params["state"] - - _get_filter = build_xml("syslog", opcode="filter") - running = get_config( - self._module, - source="running", - config_filter=_get_filter, - ) - - file_ele = etree_findall(running, "file") - file_list = list() - if len(file_ele): - for file in file_ele: - file_name = etree_find(file, "file-name") - file_list.append( - file_name.text if file_name is not None else None, - ) - vrf_ele = etree_findall(running, "vrf") - host_list = list() - for vrf in vrf_ele: - host_ele = etree_findall(vrf, "ipv4") - for host in host_ele: - host_name = etree_find(host, "address") - host_list.append( - host_name.text if host_name is not None else None, - ) - - console_ele = etree_find(running, "console-logging") - console_level = ( - etree_find(console_ele, "logging-level") if console_ele is not None else None - ) - have_console = console_level.text if console_level is not None else None - - monitor_ele = etree_find(running, "monitor-logging") - monitor_level = ( - etree_find(monitor_ele, "logging-level") if monitor_ele is not None else None - ) - have_monitor = monitor_level.text if monitor_level is not None else None - - buffered_ele = etree_find(running, "buffered-logging") - buffered_size = ( - etree_find(buffered_ele, "buffer-size") if buffered_ele is not None else None - ) - have_buffered = buffered_size.text if buffered_size is not None else None - - facility_ele = etree_find(running, "logging-facilities") - facility_level = ( - etree_find(facility_ele, "facility-level") if facility_ele is not None else None - ) - have_facility = facility_level.text if facility_level is not None else None - - prefix_ele = etree_find(running, "host-name-prefix") - have_prefix = prefix_ele.text if prefix_ele is not None else None - - file_params = list() - host_params = list() - console_params = dict() - monitor_params = dict() - buffered_params = dict() - facility_params = dict() - prefix_params = dict() - - opcode = None - if state == "absent": - opcode = "delete" - for item in self._want: - if item["dest"] == "file" and item["name"] in file_list: - item["level"] = severity_level[item["level"]] - file_params.append(item) - elif item["dest"] == "host" and item["name"] in host_list: - item["level"] = severity_level[item["level"]] - host_params.append(item) - elif item["dest"] == "console" and have_console: - console_params.update({"console-level": item["level"]}) - elif item["dest"] == "monitor" and have_monitor: - monitor_params.update({"monitor-level": item["level"]}) - elif item["dest"] == "buffered" and have_buffered: - buffered_params["size"] = str(item["size"]) if item["size"] else None - buffered_params["level"] = item["level"] if item["level"] else None - elif ( - item["dest"] is None - and item["hostnameprefix"] is None - and item["facility"] is not None - and have_facility - ): - facility_params.update({"facility": item["facility"]}) - elif item["dest"] is None and item["hostnameprefix"] is not None and have_prefix: - prefix_params.update( - {"hostnameprefix": item["hostnameprefix"]}, - ) - elif state == "present": - opcode = "merge" - for item in self._want: - if item["dest"] == "file": - item["level"] = severity_level[item["level"]] - file_params.append(item) - elif item["dest"] == "host": - item["level"] = severity_level[item["level"]] - host_params.append(item) - elif item["dest"] == "console": - console_params.update({"console-level": item["level"]}) - elif item["dest"] == "monitor": - monitor_params.update({"monitor-level": item["level"]}) - elif item["dest"] == "buffered": - buffered_params["size"] = str(item["size"]) if item["size"] else None - buffered_params["level"] = item["level"] if item["level"] else None - elif ( - item["dest"] is None - and item["hostnameprefix"] is None - and item["facility"] is not None - ): - facility_params.update({"facility": item["facility"]}) - elif item["dest"] is None and item["hostnameprefix"] is not None: - prefix_params.update( - {"hostnameprefix": item["hostnameprefix"]}, - ) - - self._result["xml"] = [] - _edit_filter_list = list() - if opcode: - if len(file_params): - _edit_filter_list.append( - build_xml( - "syslog", - xmap=self._log_file_meta, - params=file_params, - opcode=opcode, - ), - ) - if len(host_params): - _edit_filter_list.append( - build_xml( - "syslog", - xmap=self._log_host_meta, - params=host_params, - opcode=opcode, - ), - ) - if len(console_params): - _edit_filter_list.append( - build_xml( - "syslog", - xmap=self._log_console_meta, - params=console_params, - opcode=opcode, - ), - ) - if len(monitor_params): - _edit_filter_list.append( - build_xml( - "syslog", - xmap=self._log_monitor_meta, - params=monitor_params, - opcode=opcode, - ), - ) - if len(buffered_params): - _edit_filter_list.append( - build_xml( - "syslog", - xmap=self._log_buffered_meta, - params=buffered_params, - opcode=opcode, - ), - ) - if len(facility_params): - _edit_filter_list.append( - build_xml( - "syslog", - xmap=self._log_facility_meta, - params=facility_params, - opcode=opcode, - ), - ) - if len(prefix_params): - _edit_filter_list.append( - build_xml( - "syslog", - xmap=self._log_prefix_meta, - params=prefix_params, - opcode=opcode, - ), - ) - - diff = None - if len(_edit_filter_list): - commit = not self._module.check_mode - diff = load_config( - self._module, - _edit_filter_list, - commit=commit, - running=running, - nc_get_filter=_get_filter, - ) - if diff: - if self._module._diff: - self._result["diff"] = dict(prepared=diff) - - self._result["xml"] = _edit_filter_list - self._result["changed"] = True - - def run(self, os_version): - self.map_params_to_obj() - self.map_obj_to_xml_rpc(os_version) - - return self._result - - -def main(): - """main entry point for module execution""" - element_spec = dict( - dest=dict( - type="str", - choices=["host", "console", "monitor", "buffered", "file"], - ), - name=dict(type="str"), - size=dict(type="int"), - path=dict(type="str"), - vrf=dict(type="str", default="default"), - facility=dict(type="str", default="local7"), - hostnameprefix=dict(type="str"), - level=dict( - type="str", - default="debugging", - aliases=["severity"], - choices=[ - "emergencies", - "alerts", - "critical", - "errors", - "warning", - "notifications", - "informational", - "debugging", - ], - ), - state=dict(default="present", choices=["present", "absent"]), - ) - - aggregate_spec = deepcopy(element_spec) - - # remove default in aggregate spec, to handle common arguments - remove_default_spec(aggregate_spec) - - mutually_exclusive = [("dest", "facility", "hostnameprefix")] - - required_if = [ - ("dest", "host", ["name"]), - ("dest", "file", ["name"]), - ("dest", "buffered", ["size"]), - ("dest", "console", ["level"]), - ("dest", "monitor", ["level"]), - ] - - argument_spec = dict( - aggregate=dict( - type="list", - elements="dict", - options=aggregate_spec, - mutually_exclusive=mutually_exclusive, - required_if=required_if, - ), - ) - - argument_spec.update(element_spec) - - module = AnsibleModule( - argument_spec=argument_spec, - mutually_exclusive=mutually_exclusive, - required_if=required_if, - supports_check_mode=True, - ) - config_object = None - if is_cliconf(module): - config_object = CliConfiguration(module) - os_version = get_os_version(module) - elif is_netconf(module): - config_object = NCConfiguration(module) - os_version = get_capabilities(module).get("device_info").get("network_os_version") - - if config_object: - result = config_object.run(os_version) - module.exit_json(**result) - - -if __name__ == "__main__": - main() |