From cc5132a8bac6cee49b86d6c8ea2f281dc62871f7 Mon Sep 17 00:00:00 2001 From: Xu Yuandong Date: Wed, 20 Nov 2019 22:37:13 +0800 Subject: [PATCH] add a new module to configure isis on isis-view. (#63720) * add a new module. * update docs. * update docs. * update again. * add __future__ * update docs, some args type * update docs, some args type * add integration test. * add unittest. * update for shippabel. * update for syntax error. * Update setup.yaml * Update setup.yaml * Update cleanup.yaml * update for review. * add notes. --- .../network/cloudengine/ce_is_is_view.py | 1956 +++++++++++++++++ .../targets/ce_is_is_view/defaults/main.yaml | 3 + .../targets/ce_is_is_view/tasks/main.yaml | 2 + .../targets/ce_is_is_view/tasks/netconf.yaml | 17 + .../ce_is_is_view/tests/netconf/cleanup.yaml | 21 + .../ce_is_is_view/tests/netconf/setup.yaml | 22 + .../netconf/test_ce_is_is_view_entity .yaml | 78 + .../tests/netconf/test_ce_isis_bfd.yaml | 92 + .../tests/netconf/test_ce_isis_export.yaml | 96 + .../tests/netconf/test_ce_isis_import.yaml | 124 ++ .../tests/netconf/test_ce_isis_l1tol2.yaml | 109 + .../tests/netconf/test_ce_isis_l2tol1.yaml | 109 + .../tests/netconf/test_ce_isis_max_load.yaml | 80 + .../netconf/test_ce_isis_preferences.yaml | 87 + .../netconf/test_ce_isis_view_basic.yaml | 115 + .../tests/netconf/test_ce_issi_default.yaml | 111 + .../netconf/test_isis_filter_import.yaml | 97 + .../tests/netconf/test_isis_next_hop.yaml | 87 + .../fixtures/ce_is_is_view/after.txt | 104 + .../fixtures/ce_is_is_view/before.txt | 10 + .../network/cloudengine/test_ce_is_is_view.py | 248 +++ 21 files changed, 3568 insertions(+) create mode 100644 lib/ansible/modules/network/cloudengine/ce_is_is_view.py create mode 100644 test/integration/targets/ce_is_is_view/defaults/main.yaml create mode 100644 test/integration/targets/ce_is_is_view/tasks/main.yaml create mode 100644 test/integration/targets/ce_is_is_view/tasks/netconf.yaml create mode 100644 test/integration/targets/ce_is_is_view/tests/netconf/cleanup.yaml create mode 100644 test/integration/targets/ce_is_is_view/tests/netconf/setup.yaml create mode 100644 test/integration/targets/ce_is_is_view/tests/netconf/test_ce_is_is_view_entity .yaml create mode 100644 test/integration/targets/ce_is_is_view/tests/netconf/test_ce_isis_bfd.yaml create mode 100644 test/integration/targets/ce_is_is_view/tests/netconf/test_ce_isis_export.yaml create mode 100644 test/integration/targets/ce_is_is_view/tests/netconf/test_ce_isis_import.yaml create mode 100644 test/integration/targets/ce_is_is_view/tests/netconf/test_ce_isis_l1tol2.yaml create mode 100644 test/integration/targets/ce_is_is_view/tests/netconf/test_ce_isis_l2tol1.yaml create mode 100644 test/integration/targets/ce_is_is_view/tests/netconf/test_ce_isis_max_load.yaml create mode 100644 test/integration/targets/ce_is_is_view/tests/netconf/test_ce_isis_preferences.yaml create mode 100644 test/integration/targets/ce_is_is_view/tests/netconf/test_ce_isis_view_basic.yaml create mode 100644 test/integration/targets/ce_is_is_view/tests/netconf/test_ce_issi_default.yaml create mode 100644 test/integration/targets/ce_is_is_view/tests/netconf/test_isis_filter_import.yaml create mode 100644 test/integration/targets/ce_is_is_view/tests/netconf/test_isis_next_hop.yaml create mode 100644 test/units/modules/network/cloudengine/fixtures/ce_is_is_view/after.txt create mode 100644 test/units/modules/network/cloudengine/fixtures/ce_is_is_view/before.txt create mode 100644 test/units/modules/network/cloudengine/test_ce_is_is_view.py diff --git a/lib/ansible/modules/network/cloudengine/ce_is_is_view.py b/lib/ansible/modules/network/cloudengine/ce_is_is_view.py new file mode 100644 index 00000000000..7dad9a86eeb --- /dev/null +++ b/lib/ansible/modules/network/cloudengine/ce_is_is_view.py @@ -0,0 +1,1956 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# 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 + +ANSIBLE_METADATA = {'metadata_version': '1.1', + 'status': ['preview'], + 'supported_by': 'community'} + +DOCUMENTATION = """ +--- +module: ce_is_is_view +version_added: "2.10" +author: xuxiaowei0512 (@CloudEngine-Ansible) +short_description: Manages isis view configuration on HUAWEI CloudEngine devices. +description: + - Manages isis process id, creates a isis instance id or deletes a process id + on HUAWEI CloudEngine devices. +options: + coststyle: + description: + - Specifies the cost style. + type: str + choices: ['narrow', 'wide', 'transition', 'ntransition', 'wtransition'] + cost_type: + description: + - Specifies the cost type. + type: str + choices: ['external', 'internal'] + defaultmode: + description: + - Specifies the default mode. + type: str + choices: ['always', 'matchDefault', 'matchAny'] + export_policytype: + description: + - Specifies the default mode. + type: str + choices: ['aclNumOrName', 'ipPrefix', 'routePolicy'] + export_protocol: + description: + - Specifies the export router protocol. + type: str + choices: ['direct', 'ospf', 'isis', 'static', 'rip', 'bgp', 'ospfv3', 'all'] + impotr_leveltype: + description: + - Specifies the export router protocol. + type: str + choices: ['level_1', 'level_2', 'level_1_2'] + islevel: + description: + - Specifies the isis level. + type: str + choices: ['level_1', 'level_2', 'level_1_2'] + level_type: + description: + - Specifies the isis level type. + type: str + choices: ['level_1', 'level_2', 'level_1_2'] + penetration_direct: + description: + - Specifies the penetration direct. + type: str + choices: ['level2-level1', 'level1-level2'] + protocol: + description: + - Specifies the protocol. + type: str + choices: ['direct', 'ospf', 'isis', 'static', 'rip', 'bgp', 'ospfv3', 'all'] + aclnum_or_name: + description: + - Specifies the acl number or name for isis. + type: str + allow_filter: + description: + - Specifies the alow filter or not. + type: bool + allow_up_down: + description: + - Specifies the alow up or down. + type: bool + autocostenable: + description: + - Specifies the alow auto cost enable. + type: bool + autocostenablecompatible: + description: + - Specifies the alow auto cost enable compatible. + type: bool + avoid_learning: + description: + - Specifies the alow avoid learning. + type: bool + bfd_min_tx: + description: + - Specifies the bfd min sent package. + type: int + bfd_min_rx: + description: + - Specifies the bfd min received package. + type: int + bfd_multiplier_num: + description: + - Specifies the bfd multiplier number. + type: int + cost: + description: + - Specifies the bfd cost. + type: int + description: + description: + - Specifies description of isis. + type: str + enablelevel1tolevel2: + description: + - Enable level1 to level2. + type: bool + export_aclnumorname: + description: + - Specifies export acl number or name. + type: str + export_ipprefix: + description: + - Specifies export ip prefix. + type: str + export_processid: + description: + - Specifies export process id. + type: int + export_routepolicyname: + description: + - Specifies export route policy name. + type: str + import_aclnumorname: + description: + - Specifies import acl number or name. + type: str + import_cost: + description: + - Specifies import cost. + type: int + import_ipprefix: + description: + - Specifies import ip prefix. + type: str + import_route_policy: + description: + - Specifies import route policy. + type: str + import_routepolicy_name: + description: + - Specifies import route policy name. + type: str + import_routepolicyname: + description: + - Specifies import route policy name. + type: str + import_tag: + description: + - Specifies import tag. + type: int + inheritcost: + description: + - Enable inherit cost. + type: bool + instance_id: + description: + - Specifies instance id. + type: int + ip_address: + description: + - Specifies ip address. + type: str + ip_prefix_name: + description: + - Specifies ip prefix name. + type: str + max_load: + description: + - Specifies route max load. + type: int + mode_routepolicyname: + description: + - Specifies the mode of route polic yname. + type: str + mode_tag: + description: + - Specifies the tag of mode. + type: int + netentity: + description: + - Specifies the netentity. + type: str + permitibgp: + description: + - Specifies the permitibgp. + type: bool + processid: + description: + - Specifies the process id. + type: int + relaxspfLimit: + description: + - Specifies enable the relax spf limit. + type: bool + route_policy_name: + description: + - Specifies the route policy name. + type: str + stdbandwidth: + description: + - Specifies the std band width. + type: int + stdlevel1cost: + description: + - Specifies the std level1 cost. + type: int + stdlevel2cost: + description: + - Specifies the std level2 cost. + type: int + tag: + description: + - Specifies the isis tag. + type: int + weight: + description: + - Specifies the isis weight. + type: int + preference_value: + description: + - Specifies the preference value. + type: int + state: + description: + - Determines whether the config should be present or not on the device. + default: present + type: str + choices: ['present', 'absent'] +notes: + - This module requires the netconf system service be enabled on the remote device being managed. + - This module works with connection C(netconf). +""" + +EXAMPLES = ''' + - name: Set isis description + ce_is_is_view: + instance_id: 3 + description: abcdeggfs + state: present + + - name: Set isis islevel + ce_is_is_view: + instance_id: 3 + islevel: level_1 + state: present + - name: Set isis coststyle + ce_is_is_view: + instance_id: 3 + coststyle: narrow + state: present + + - name: Set isis stdlevel1cost + ce_is_is_view: + instance_id: 3 + stdlevel1cost: 63 + state: present + + - name: set isis stdlevel2cost + ce_is_is_view: + instance_id: 3 + stdlevel2cost: 63 + state: present + + - name: set isis stdbandwidth + ce_is_is_view: + instance_id: 3 + stdbandwidth: 1 + state: present +''' + +RETURN = ''' +proposed: + description: k/v pairs of parameters passed into module + returned: always + type: dict + sample: { + "state": "present" + } +existing: + description: k/v pairs of existing configuration + returned: always + type: dict + sample: { + "session": {} + } +end_state: + description: k/v pairs of configuration after module execution + returned: always + type: dict + sample: { + "session": { + "addrType": "IPV4", + "createType": "SESS_STATIC", + "destAddr": null, + "outIfName": "10GE1/0/1", + "sessName": "bfd_l2link", + "srcAddr": null, + "useDefaultIp": "true", + "vrfName": null + } + } +updates: + description: commands sent to the device + returned: always + type: list + sample: [ + "bfd bfd_l2link bind peer-ip default-ip interface 10ge1/0/1" + ] +changed: + description: check to see if a change was made on the device + returned: always + type: bool + sample: true +''' + +import sys +import socket +from xml.etree import ElementTree +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.network.cloudengine.ce import get_nc_config, set_nc_config + +CE_NC_GET_ISIS = """ + + + %s + + +""" + +CE_NC_GET_ISIS_INSTANCE = """ + + + %s + + + + + + + + + + + +""" + +CE_NC_GET_ISIS_ENTITY = """ + + + %s + + + + + + + +""" + +CE_NC_CREAT_ISIS_ENTITY = """ + + + %s + + + %s + + + + +""" + +CE_NC_DELATE_ISIS_ENTITY = """ + + + %s + + + %s + + + + +""" + +CE_NC_GET_ISIS_PREFERENCE = """ + + + %s + + + + + + + + + + + + +""" + +CE_NC_MREGE_ISIS_PREFERENCE = """ + + + %s + + + afIpv4 + 0 + + + %s + + + + + + +""" + +CE_NC_DELETE_ISIS_PREFERENCE = """ + + + %s + + + afIpv4 + 0 + + + %s + + + + + + +""" + +CE_NC_GET_ISIS_MAXLOAD = """ + + + %s + + + afIpv4 + 0 + + + + + +""" + +CE_NC_MERGE_ISIS_MAXLOAD = """ + + + %s + + + afIpv4 + 0 + %s + + + + +""" + +CE_NC_DELETE_ISIS_MAXLOAD = """ + + + %s + + + afIpv4 + 0 + 32 + + + + +""" + +CE_NC_GET_ISIS_NEXTHOP = """ + + + %s + + + afIpv4 + 0 + + + + + + + + + + +""" + +CE_NC_MERGE_ISIS_NEXTHOP = """ + + + %s + + + afIpv4 + 0 + + + %s + %s + + + + + + +""" + +CE_NC_DELETE_ISIS_NEXTHOP = """ + + + %s + + + afIpv4 + 0 + + + %s + 1 + + + + + + +""" + +CE_NC_GET_ISIS_LEAKROUTELEVEL2 = """ + + + %s + + + afIpv4 + 0 + + + + + + + + + + + + + + +""" + +CE_NC_MERGE_ISIS_LEAKROUTELEVEL2 = """ + + + %s + + + afIpv4 + 0 + + + %s + + + + + + +""" + +CE_NC_DELETE_ISIS_LEAKROUTELEVEL2 = """ + + + %s + + + afIpv4 + 0 + + + 0 + + + + false + + + + + + +""" + +CE_NC_GET_ISIS_LEAKROUTELEVEL1 = """ + + + %s + + + afIpv4 + 0 + + + + + + + + + + + + + + +""" + +CE_NC_MERGE_ISIS_LEAKROUTELEVEL1 = """ + + + %s + + + afIpv4 + 0 + + + %s + + + + + + +""" + +CE_NC_DELETE_ISIS_LEAKROUTELEVEL1 = """ + + + %s + + + afIpv4 + 0 + + + 0 + + + + false + false + + + + + + +""" + +CE_NC_GET_ISIS_DEFAULTROUTE = """ + + + %s + + + afIpv4 + 0 + + + + + + + + + + + + + + +""" + +CE_NC_MERGE_ISIS_DEFAULTROUTE = """ + + + %s + + + afIpv4 + 0 + + + %s + + + + + + +""" + +CE_NC_DELETE_ISIS_DEFAULTROUTE = """ + + + %s + + + afIpv4 + 0 + + + always + 0 + 0 + level_2 + false + + + + + + +""" + +CE_NC_GET_ISIS_IMPORTROUTE = """ + + + %s + + + afIpv4 + 0 + + + + + + + + + + + + + + + + + + +""" + +CE_NC_MERGE_ISIS_IMPORTROUTE = """ + + + %s + + + afIpv4 + 0 + + + %s + + + + + + +""" + +CE_NC_GET_ISIS_EXPORTROUTE = """ + + + %s + + + afIpv4 + 0 + + + + + + + + + + + +""" + +CE_NC_MERGE_ISIS_EXPORTROUTE = """ + + + %s + + + afIpv4 + 0 + + + %s + + + + + + +""" + +CE_NC_GET_ISIS_IMPORTIPROUTE = """ + + + %s + + + afIpv4 + 0 + + + + + + + + + + + + +""" + +CE_NC_MERGE_ISIS_IMPORTIPROUTE = """ + + + %s + + + afIpv4 + 0 + + + %s + + + + + + +""" + +CE_NC_GET_ISIS_BFDLINK = """ + + + %s + + + afIpv4 + 0 + + + + + + + +""" + +CE_NC_MERGE_ISIS_BFDLINK = """ + + + %s + + + afIpv4 + 0 + %s + + + + +""" + +CE_NC_DELETE_ISIS_BFDLINK = """ + + + %s + + + afIpv4 + 0 + 3 + 3 + 3 + + + + +""" + + +def is_valid_ip_vpn(vpname): + """check ip vpn""" + + if not vpname: + return False + + if vpname == "_public_": + return False + + if len(vpname) < 1 or len(vpname) > 31: + return False + + return True + + +def check_ip_addr(ipaddr): + """check ip address, Supports IPv4 and IPv6""" + + if not ipaddr or '\x00' in ipaddr: + return False + + try: + res = socket.getaddrinfo(ipaddr, 0, socket.AF_UNSPEC, + socket.SOCK_STREAM, + 0, socket.AI_NUMERICHOST) + return bool(res) + except socket.gaierror: + err = sys.exc_info()[1] + if err.args[0] == socket.EAI_NONAME: + return False + raise + + return True + + +def check_default_ip(ipaddr): + """check the default multicast IP address""" + + # The value ranges from 224.0.0.107 to 224.0.0.250 + if not check_ip_addr(ipaddr): + return False + + if ipaddr.count(".") != 3: + return False + + ips = ipaddr.split(".") + if ips[0] != "224" or ips[1] != "0" or ips[2] != "0": + return False + + if not ips[3].isdigit() or int(ips[3]) < 107 or int(ips[3]) > 250: + return False + + return True + + +def get_interface_type(interface): + """get the type of interface, such as 10GE, ETH-TRUNK, VLANIF...""" + + if interface is None: + return None + + if interface.upper().startswith('GE'): + iftype = 'ge' + elif interface.upper().startswith('10GE'): + iftype = '10ge' + elif interface.upper().startswith('25GE'): + iftype = '25ge' + elif interface.upper().startswith('4X10GE'): + iftype = '4x10ge' + elif interface.upper().startswith('40GE'): + iftype = '40ge' + elif interface.upper().startswith('100GE'): + iftype = '100ge' + elif interface.upper().startswith('VLANIF'): + iftype = 'vlanif' + elif interface.upper().startswith('LOOPBACK'): + iftype = 'loopback' + elif interface.upper().startswith('METH'): + iftype = 'meth' + elif interface.upper().startswith('ETH-TRUNK'): + iftype = 'eth-trunk' + elif interface.upper().startswith('VBDIF'): + iftype = 'vbdif' + elif interface.upper().startswith('NVE'): + iftype = 'nve' + elif interface.upper().startswith('TUNNEL'): + iftype = 'tunnel' + elif interface.upper().startswith('ETHERNET'): + iftype = 'ethernet' + elif interface.upper().startswith('FCOE-PORT'): + iftype = 'fcoe-port' + elif interface.upper().startswith('FABRIC-PORT'): + iftype = 'fabric-port' + elif interface.upper().startswith('STACK-PORT'): + iftype = 'stack-port' + elif interface.upper().startswith('NULL'): + iftype = 'null' + else: + return None + + return iftype.lower() + + +class ISIS_View(object): + """Manages ISIS Instance""" + + def __init__(self, argument_spec): + self.spec = argument_spec + self.module = None + self.__init_module__() + + # module input info + self.instance_id = self.module.params['instance_id'] + self.description = self.module.params['description'] + self.islevel = self.module.params['islevel'] + self.coststyle = self.module.params['coststyle'] + self.relaxspfLimit = self.module.params['relaxspfLimit'] + self.stdlevel1cost = self.module.params['stdlevel1cost'] + self.stdlevel2cost = self.module.params['stdlevel2cost'] + self.stdbandwidth = self.module.params['stdbandwidth'] + self.autocostenable = self.module.params['autocostenable'] + self.autocostenablecompatible = self.module.params['autocostenablecompatible'] + self.netentity = self.module.params['netentity'] + self.preference_value = self.module.params['preference_value'] + self.route_policy_name = self.module.params['route_policy_name'] + self.max_load = self.module.params['max_load'] + self.ip_address = self.module.params['ip_address'] + self.weight = self.module.params['weight'] + self.aclnum_or_name = self.module.params['aclnum_or_name'] + self.ip_prefix_name = self.module.params['ip_prefix_name'] + self.import_routepolicy_name = self.module.params['import_routepolicy_name'] + self.tag = self.module.params['tag'] + self.allow_filter = self.module.params['allow_filter'] + self.allow_up_down = self.module.params['allow_up_down'] + self.penetration_direct = self.module.params['penetration_direct'] + self.enablelevel1tolevel2 = self.module.params['enablelevel1tolevel2'] + self.defaultmode = self.module.params['defaultmode'] + self.mode_routepolicyname = self.module.params['mode_routepolicyname'] + self.cost = self.module.params['cost'] + self.mode_tag = self.module.params['mode_tag'] + self.level_type = self.module.params['level_type'] + self.avoid_learning = self.module.params['avoid_learning'] + self.protocol = self.module.params['protocol'] + self.processid = self.module.params['processid'] + self.cost_type = self.module.params['cost_type'] + self.import_cost = self.module.params['import_cost'] + self.import_tag = self.module.params['import_tag'] + self.impotr_leveltype = self.module.params['impotr_leveltype'] + self.import_route_policy = self.module.params['import_route_policy'] + self.inheritcost = self.module.params['inheritcost'] + self.permitibgp = self.module.params['permitibgp'] + self.avoid_learning = self.module.params['avoid_learning'] + self.export_protocol = self.module.params['export_protocol'] + self.export_policytype = self.module.params['export_policytype'] + self.export_processid = self.module.params['export_processid'] + self.export_aclnumorname = self.module.params['export_aclnumorname'] + self.export_ipprefix = self.module.params['export_ipprefix'] + self.export_routepolicyname = self.module.params['export_routepolicyname'] + self.import_aclnumorname = self.module.params['import_aclnumorname'] + self.import_ipprefix = self.module.params['import_ipprefix'] + self.import_routepolicyname = self.module.params['import_routepolicyname'] + self.bfd_min_rx = self.module.params['bfd_min_rx'] + self.bfd_min_tx = self.module.params['bfd_min_tx'] + self.bfd_multiplier_num = self.module.params['bfd_multiplier_num'] + self.state = self.module.params['state'] + + # state + self.changed = False + self.isis_dict = dict() + self.updates_cmd = list() + self.commands = list() + self.results = dict() + self.proposed = dict() + self.existing = dict() + self.end_state = dict() + + def __init_module__(self): + """init module""" + + mutually_exclusive = [["stdlevel1cost", "stdlevel2cost"], + ["aclnum_or_name", "ip_prefix_name", "import_routepolicy_name"], + ["export_aclnumorname", "import_ipprefix", "import_routepolicyname"]] + required_together = [('ip_address', 'weight')] + self.module = AnsibleModule( + argument_spec=self.spec, + mutually_exclusive=mutually_exclusive, + required_together=required_together, + supports_check_mode=True) + + def get_isis_dict(self): + """bfd config dict""" + + isis_dict = dict() + isis_dict["instance"] = dict() + conf_str = CE_NC_GET_ISIS % ( + (CE_NC_GET_ISIS_INSTANCE % self.instance_id)) + + if self.netentity: + conf_str = CE_NC_GET_ISIS % ( + (CE_NC_GET_ISIS_ENTITY % self.instance_id)) + + if self.route_policy_name or self.preference_value: + conf_str = CE_NC_GET_ISIS % ( + (CE_NC_GET_ISIS_PREFERENCE % self.instance_id)) + if self.max_load: + conf_str = CE_NC_GET_ISIS % ( + (CE_NC_GET_ISIS_MAXLOAD % self.instance_id)) + if self.ip_address: + conf_str = CE_NC_GET_ISIS % ( + (CE_NC_GET_ISIS_NEXTHOP % self.instance_id)) + if self.penetration_direct and self.penetration_direct == "level2-level1": + conf_str = CE_NC_GET_ISIS % ( + (CE_NC_GET_ISIS_LEAKROUTELEVEL2 % self.instance_id)) + elif self.penetration_direct and self.penetration_direct == "level1-level2": + conf_str = CE_NC_GET_ISIS % ( + (CE_NC_GET_ISIS_LEAKROUTELEVEL1 % self.instance_id)) + elif self.defaultmode: + conf_str = CE_NC_GET_ISIS % ( + (CE_NC_GET_ISIS_DEFAULTROUTE % self.instance_id)) + elif self.protocol: + conf_str = CE_NC_GET_ISIS % ( + (CE_NC_GET_ISIS_IMPORTROUTE % self.instance_id)) + elif self.export_protocol: + conf_str = CE_NC_GET_ISIS % ( + (CE_NC_GET_ISIS_EXPORTROUTE % self.instance_id)) + elif self.bfd_min_rx or self.bfd_min_tx or self.bfd_multiplier_num: + conf_str = CE_NC_GET_ISIS % ( + (CE_NC_GET_ISIS_BFDLINK % self.instance_id)) + elif self.import_aclnumorname or self.import_ipprefix or self.import_ipprefix: + conf_str = CE_NC_GET_ISIS % ( + (CE_NC_GET_ISIS_IMPORTIPROUTE % self.instance_id)) + xml_str = get_nc_config(self.module, conf_str) + + if "" in xml_str: + return isis_dict + + xml_str = xml_str.replace('\r', '').replace('\n', '').\ + replace('xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"', "").\ + replace('xmlns="http://www.huawei.com/netconf/vrp"', "") + root = ElementTree.fromstring(xml_str) + + # get bfd global info + if self.netentity: + glb = root.find("isiscomm/isSites/isSite/isNetEntitys/isNetEntity") + elif self.route_policy_name or self.preference_value: + glb = root.find("isiscomm/isSites/isSite//isSiteMTs/isSiteMT/isPreferences/isPreference") + elif self.max_load: + glb = root.find("isiscomm/isSites/isSite/isSiteMTs/isSiteMT") + elif self.ip_address: + glb = root.find("isiscomm/isSites/isSite/isSiteMTs/isSiteMT/isNextHopWeights/isNextHopWeight") + elif self.penetration_direct and self.penetration_direct == "level2-level1": + glb = root.find("isiscomm/isSites/isSite/isSiteMTs/isSiteMT/isLeakRouteLevel2ToLevel1s/isLeakRouteLevel2ToLevel1") + elif self.penetration_direct and self.penetration_direct == "level1-level2": + glb = root.find( + "isiscomm/isSites/isSite/isSiteMTs/isSiteMT/isLeakRouteLevel1ToLevel2s/isLeakRouteLevel1ToLevel2") + elif self.defaultmode: + glb = root.find( + "isiscomm/isSites/isSite/isSiteMTs/isSiteMT/isDefaultRoutes/isDefaultRoute") + elif self.protocol: + glb = root.find( + "isiscomm/isSites/isSite/isSiteMTs/isSiteMT/isImportRoutes/isImportRoute") + elif self.export_protocol: + glb = root.find( + "isiscomm/isSites/isSite/isSiteMTs/isSiteMT/isFilterExports/isFilterExport") + elif self.bfd_min_rx or self.bfd_min_tx or self.bfd_multiplier_num: + glb = root.find( + "isiscomm/isSites/isSite/isSiteMTs/isSiteMT") + elif self.import_aclnumorname or self.import_ipprefix or self.import_ipprefix: + glb = root.find( + "isiscomm/isSites/isSite/isSiteMTs/isSiteMT/isFilterImports/isFilterImport") + else: + glb = root.find("isiscomm/isSites/isSite") + + if glb is not None: + for attr in glb: + isis_dict["instance"][attr.tag] = attr.text + + return isis_dict + + def config_session(self): + """configures bfd session""" + + xml_str = "" + instance = self.isis_dict["instance"] + if not self.instance_id: + return xml_str + xml_str = "%s" % self.instance_id + self.updates_cmd.append("isis %s" % self.instance_id) + cmd_list = list() + + if self.state == "present": + if self.description and self.description != instance.get("description"): + xml_str += "%s" % self.description + self.updates_cmd.append("description %s" % self.description) + + if self.islevel and self.islevel != instance.get("isLevel"): + xml_str += "%s" % self.islevel + self.updates_cmd.append("is-level %s" % self.islevel) + + if self.coststyle: + if self.coststyle != instance.get("costStyle"): + xml_str += "%s" % self.coststyle + self.updates_cmd.append("cost-style %s" % self.coststyle) + if self.relaxspfLimit and instance.get("relaxSpfLimit", "false") == "false": + xml_str += "true" + self.updates_cmd.append("cost-style %s relax-spf-limit" % self.coststyle) + elif not self.relaxspfLimit and instance.get("relaxSpfLimit", "false") == "true": + xml_str += "false" + self.updates_cmd.append("cost-style %s" % self.coststyle) + + if self.stdlevel1cost and str(self.stdlevel1cost) != instance.get("stdLevel1Cost"): + xml_str += "%s" % self.stdlevel1cost + self.updates_cmd.append("circuit-cost %s level-1" % self.stdlevel1cost) + + if self.stdlevel2cost and str(self.stdlevel2cost) != instance.get("stdLevel2Cost"): + xml_str += "%s" % self.stdlevel2cost + self.updates_cmd.append("circuit-cost %s level-2" % self.stdlevel2cost) + + if self.stdbandwidth and str(self.stdbandwidth) != instance.get("stdbandwidth"): + xml_str += "%s" % self.stdbandwidth + self.updates_cmd.append("bandwidth-reference %s" % self.stdbandwidth) + + if self.netentity and self.netentity != instance.get("netEntity"): + xml_str = CE_NC_CREAT_ISIS_ENTITY % (self.instance_id, self.netentity) + self.updates_cmd.append("network-entity %s" % self.netentity) + + if self.preference_value or self.route_policy_name: + xml_str = "" + cmd_session = "preference" + if self.preference_value and str(self.preference_value) != instance.get("preferenceValue"): + xml_str = "%s" % self.preference_value + cmd_session += " %s" % self.preference_value + if self.route_policy_name and self.route_policy_name != instance.get("routePolicyName"): + xml_str += "%s" % self.route_policy_name + cmd_session += " route-policy %s" % self.route_policy_name + cmd_list.insert(0, cmd_session) + self.updates_cmd.extend(cmd_list) + xml_str = CE_NC_MREGE_ISIS_PREFERENCE % (self.instance_id, xml_str) + + if self.max_load and str(self.max_load) != instance.get("maxLoadBalancing"): + xml_str = CE_NC_MERGE_ISIS_MAXLOAD % (self.instance_id, self.max_load) + self.updates_cmd.append("maximum load-balancing %s" % self.max_load) + + if self.ip_address: + xml_str = CE_NC_MERGE_ISIS_NEXTHOP % (self.instance_id, self.ip_address, self.weight) + self.updates_cmd.append("nexthop %s weight %s" % (self.ip_address, self.weight)) + + if self.penetration_direct: + xml_str = "" + if self.penetration_direct == "level2-level1": + cmd_session = "import-route isis level-2 into level-1" + elif self.penetration_direct == "level1-level2": + cmd_session = "import-route isis level-1 into level-2" + if self.aclnum_or_name: + xml_str = "%s" % self.aclnum_or_name + xml_str += "aclNumOrName" + if isinstance(self.aclnum_or_name, int): + cmd_session += " filter-policy %s" % self.aclnum_or_name + elif isinstance(self.aclnum_or_name, str): + cmd_session += " filter-policy acl-name %s" % self.aclnum_or_name + if self.ip_prefix_name: + xml_str = "%s" % self.ip_prefix_name + xml_str += "ipPrefix" + cmd_session += " filter-policy ip-prefix %s" % self.ip_prefix_name + if self.import_routepolicy_name: + xml_str = "%s" % self.import_routepolicy_name + xml_str += "routePolicy" + cmd_session += " filter-policy route-policy %s" % self.import_routepolicy_name + if self.tag: + xml_str += "%s" % self.tag + cmd_session += " tag %s" % self.tag + if self.allow_filter or self.allow_up_down: + cmd_session += " direct" + if self.allow_filter: + xml_str += "true" + cmd_session += " allow-filter-policy" + if self.allow_up_down: + xml_str += "true" + cmd_session += " allow-up-down-bit" + cmd_list.insert(0, cmd_session) + self.updates_cmd.extend(cmd_list) + if self.enablelevel1tolevel2: + xml_str += "true" + self.updates_cmd.append("undo import-route isis level-1 into level-2 disable") + + if self.defaultmode: + cmd_session = "default-route-advertise" + if self.defaultmode == "always": + xml_str = "always" + cmd_session += " always" + elif self.defaultmode == "matchDefault": + xml_str = "matchDefault" + cmd_session += " match default" + elif self.defaultmode == "matchAny": + xml_str = "matchAny" + xml_str += "routePolicy" + xml_str += "%s" % self.mode_routepolicyname + cmd_session += " route-policy %s" % self.mode_routepolicyname + if self.cost is not None: + xml_str += "%s" % self.cost + cmd_session += " cost %s" % self.cost + if self.mode_tag: + xml_str += "%s" % self.mode_tag + cmd_session += " tag %s" % self.mode_tag + if self.level_type: + if self.level_type == "level_1": + xml_str += "level_1" + cmd_session += " level-1" + elif self.level_type == "level_2": + xml_str += "level_2" + cmd_session += " level-2" + elif self.level_type == "level_1_2": + xml_str += "level_1_2" + cmd_session += " level-1-2" + if self.avoid_learning: + xml_str += "true" + cmd_session += " avoid-learning" + elif not self.avoid_learning: + xml_str += "false" + cmd_list.insert(0, cmd_session) + self.updates_cmd.extend(cmd_list) + + if self.protocol: + cmd_session = "import-route" + if self.protocol == "rip": + xml_str = "rip" + cmd_session += " rip" + elif self.protocol == "isis": + xml_str = "isis" + cmd_session += " isis" + elif self.protocol == "ospf": + xml_str = "ospf" + cmd_session += " ospf" + elif self.protocol == "static": + xml_str = "static" + cmd_session += " static" + elif self.protocol == "direct": + xml_str = "direct" + cmd_session += " direct" + elif self.protocol == "bgp": + xml_str = "bgp" + cmd_session += " bgp" + if self.permitibgp: + xml_str += "true" + cmd_session += " permit-ibgp" + if self.protocol == "rip" or self.protocol == "isis" or self.protocol == "ospf": + xml_str += "%s" % self.processid + cmd_session += " %s" % self.processid + if self.inheritcost: + xml_str += "%s" % self.inheritcost + cmd_session += " inherit-cost" + if self.cost_type: + if self.cost_type == "external": + xml_str += "external" + cmd_session += " cost-type external" + elif self.cost_type == "internal": + xml_str += "internal" + cmd_session += " cost-type internal" + if self.import_cost: + xml_str += "%s" % self.import_cost + cmd_session += " cost %s" % self.import_cost + if self.import_tag: + xml_str += "%s" % self.import_tag + cmd_session += " tag %s" % self.import_tag + if self.import_route_policy: + xml_str += "routePolicy" + xml_str += "%s" % self.import_route_policy + cmd_session += " route-policy %s" % self.import_route_policy + if self.impotr_leveltype: + if self.impotr_leveltype == "level_1": + cmd_session += " level-1" + elif self.impotr_leveltype == "level_2": + cmd_session += " level-2" + elif self.impotr_leveltype == "level_1_2": + cmd_session += " level-1-2" + cmd_list.insert(0, cmd_session) + self.updates_cmd.extend(cmd_list) + + if self.bfd_min_rx or self.bfd_min_tx or self.bfd_multiplier_num: + xml_str = "" + self.updates_cmd.append("bfd all-interfaces enable") + cmd_session = "bfd all-interfaces" + if self.bfd_min_rx: + xml_str += "%s" % self.bfd_min_rx + cmd_session += " min-rx-interval %s" % self.bfd_min_rx + if self.bfd_min_tx: + xml_str += "%s" % self.bfd_min_tx + cmd_session += " min-tx-interval %s" % self.bfd_min_tx + if self.bfd_multiplier_num: + xml_str += "%s" % self.bfd_multiplier_num + cmd_session += " detect-multiplier %s" % self.bfd_multiplier_num + cmd_list.insert(0, cmd_session) + self.updates_cmd.extend(cmd_list) + + if self.export_protocol: + cmd_session = "filter-policy" + if self.export_aclnumorname: + xml_str = "aclNumOrName" + xml_str += "%s" % self.export_aclnumorname + if isinstance(self.export_aclnumorname, int): + cmd_session += " %s" % self.export_aclnumorname + elif isinstance(self.export_aclnumorname, str): + cmd_session += " acl-name %s" % self.export_aclnumorname + if self.export_ipprefix: + xml_str = "ipPrefix" + xml_str += "%s" % self.export_ipprefix + cmd_session += " ip-prefix %s" % self.export_ipprefix + if self.export_routepolicyname: + xml_str = "routePolicy" + xml_str += "%s" % self.export_routepolicyname + cmd_session += " route-policy %s" % self.export_routepolicyname + xml_str += "%s" % self.export_protocol + cmd_session += " export %s" % self.export_protocol + if self.export_processid is not None: + xml_str += "%s" % self.export_processid + cmd_session += " %s" % self.export_processid + cmd_list.insert(0, cmd_session) + self.updates_cmd.extend(cmd_list) + + if self.import_ipprefix or self.import_aclnumorname or self.import_routepolicyname: + cmd_session = "filter-policy" + if self.import_aclnumorname: + xml_str = "aclNumOrName" + xml_str += "%s" % self.import_aclnumorname + if isinstance(self.import_aclnumorname, int): + cmd_session += " %s" % self.import_aclnumorname + elif isinstance(self.import_aclnumorname, str): + cmd_session += " acl-name %s" % self.import_aclnumorname + if self.import_ipprefix: + xml_str = "ipPrefix" + xml_str += "%s" % self.import_ipprefix + cmd_session += " ip-prefix %s" % self.import_ipprefix + if self.import_routepolicyname: + xml_str = "routePolicy" + xml_str += "%s" % self.import_routepolicyname + cmd_session += " route-policy %s" % self.import_routepolicyname + cmd_session += "import" + cmd_list.insert(0, cmd_session) + self.updates_cmd.extend(cmd_list) + else: + # absent + if self.description and self.description == instance.get("description"): + xml_str += "%s" % self.description + self.updates_cmd.append("undo description") + + if self.islevel and self.islevel == instance.get("isLevel"): + xml_str += "level_1_2" + self.updates_cmd.append("undo is-level") + + if self.coststyle and self.coststyle == instance.get("costStyle"): + xml_str += "%s" % ("narrow") + xml_str += "false" + self.updates_cmd.append("undo cost-style") + + if self.stdlevel1cost and str(self.stdlevel1cost) == instance.get("stdLevel1Cost"): + xml_str += "%s" % self.stdlevel1cost + self.updates_cmd.append("undo circuit-cost %s level-1" % self.stdlevel1cost) + + if self.stdlevel2cost and str(self.stdlevel2cost) == instance.get("stdLevel2Cost"): + xml_str += "%s" % self.stdlevel2cost + self.updates_cmd.append("undo circuit-cost %s level-2" % self.stdlevel2cost) + + if self.stdbandwidth and str(self.stdbandwidth) == instance.get("stdbandwidth"): + xml_str += "100" + self.updates_cmd.append("undo bandwidth-reference") + + if self.netentity and self.netentity == instance.get("netEntity"): + xml_str = CE_NC_DELATE_ISIS_ENTITY % (self.instance_id, self.netentity) + self.updates_cmd.append("undo network-entity %s" % self.netentity) + + if self.preference_value or self.route_policy_name: + xml_str = "" + if self.preference_value and str(self.preference_value) == instance.get("preferenceValue"): + xml_str = "%s" % self.preference_value + if self.route_policy_name and self.route_policy_name == instance.get("routePolicyName"): + xml_str += "%s" % self.route_policy_name + self.updates_cmd.append("undo preference") + elif not self.preference_value and self.route_policy_name and self.route_policy_name == instance.get("routePolicyName"): + xml_str = "%s" % self.route_policy_name + self.updates_cmd.append("undo preference") + xml_str = CE_NC_DELETE_ISIS_PREFERENCE % (self.instance_id, xml_str) + + if self.max_load and str(self.max_load) == instance.get("maxLoadBalancing"): + xml_str = CE_NC_DELETE_ISIS_MAXLOAD % self.instance_id + self.updates_cmd.append("undo maximum load-balancing") + + if self.ip_address: + xml_str = CE_NC_DELETE_ISIS_NEXTHOP % (self.instance_id, self.ip_address) + self.updates_cmd.append("undo nexthop %s" % self.ip_address) + + if self.penetration_direct: + if self.penetration_direct == "level2-level1": + self.updates_cmd.append("undo import-route isis level-2 into level-1") + elif self.penetration_direct == "level1-level2": + self.updates_cmd.append("undo import-route isis level-1 into level-2") + self.updates_cmd.append("import-route isis level-1 into level-2 disable") + + if self.bfd_min_rx or self.bfd_min_tx or self.bfd_multiplier_num is not None: + xml_str = CE_NC_DELETE_ISIS_BFDLINK % self.instance_id + self.updates_cmd.append("undo bfd all-interfaces enable") + cmd_session = "undo bfd all-interfaces" + if self.bfd_min_rx: + cmd_session += " min-rx-interval %s" % self.bfd_min_rx + if self.bfd_min_tx: + cmd_session += " min-tx-interval %s" % self.bfd_min_tx + if self.bfd_multiplier_num: + cmd_session += " detect-multiplier %s" % self.bfd_multiplier_num + cmd_list.insert(0, cmd_session) + self.updates_cmd.extend(cmd_list) + + if self.defaultmode: + xml_str = CE_NC_DELETE_ISIS_DEFAULTROUTE % self.instance_id + self.updates_cmd.append("undo default-route-advertise") + + if self.protocol: + if self.protocol == "rip" or self.protocol == "isis" or self.protocol == "ospf": + self.updates_cmd.append("undo import-route %s %s" % (self.protocol, self.processid)) + else: + self.updates_cmd.append("undo import-route %s" % self.protocol) + + if self.export_protocol: + cmd_session = "undo filter-policy" + if self.export_aclnumorname: + if isinstance(self.export_aclnumorname, int): + cmd_session += " %s" % self.export_aclnumorname + elif isinstance(self.export_aclnumorname, str): + cmd_session += " acl-name %s" % self.export_aclnumorname + if self.export_ipprefix: + cmd_session += " ip-prefix %s" % self.export_ipprefix + if self.export_routepolicyname: + cmd_session += " route-policy %s" % self.export_routepolicyname + cmd_session += " export %s" % self.export_protocol + if self.export_processid is not None: + cmd_session += " %s" % self.export_processid + cmd_list.insert(0, cmd_session) + self.updates_cmd.extend(cmd_list) + if self.import_ipprefix or self.import_aclnumorname or self.import_routepolicyname: + cmd_session = "undo filter-policy" + if self.import_aclnumorname: + if isinstance(self.import_aclnumorname, int): + cmd_session += " %s" % self.import_aclnumorname + elif isinstance(self.import_aclnumorname, str): + cmd_session += " acl-name %s" % self.import_aclnumorname + if self.import_ipprefix: + cmd_session += " ip-prefix %s" % self.import_ipprefix + if self.import_routepolicyname: + cmd_session += " route-policy %s" % self.import_routepolicyname + cmd_session += " import" + cmd_list.insert(0, cmd_session) + self.updates_cmd.extend(cmd_list) + + if self.autocostenable and instance.get("stdAutoCostEnable", "false") == "false": + xml_str += "true" + self.updates_cmd.append("auto-cost enable") + elif not self.autocostenable and instance.get("stdAutoCostEnable", "false") == "true": + xml_str += "false" + xml_str += "false" + self.updates_cmd.append("undo auto-cost enable") + + if self.autocostenable: + if self.autocostenablecompatible and instance.get("stdAutoCostEnableCompatible", "false") == "false": + xml_str += "true" + self.updates_cmd.append("auto-cost enable compatible") + elif not self.autocostenablecompatible and instance.get("stdAutoCostEnableCompatible", "false") == "true": + xml_str += "false" + self.updates_cmd.append("auto-cost enable") + + if self.state == "present": + if self.netentity or self.preference_value or self.route_policy_name or self.max_load or self.ip_address: + return xml_str + elif self.penetration_direct: + if self.penetration_direct == "level2-level1": + return CE_NC_MERGE_ISIS_LEAKROUTELEVEL2 % (self.instance_id, xml_str) + elif self.penetration_direct == "level1-level2": + return CE_NC_MERGE_ISIS_LEAKROUTELEVEL1 % (self.instance_id, xml_str) + elif self.defaultmode: + return CE_NC_MERGE_ISIS_DEFAULTROUTE % (self.instance_id, xml_str) + elif self.protocol: + return CE_NC_MERGE_ISIS_IMPORTROUTE % (self.instance_id, xml_str) + elif self.export_protocol: + return CE_NC_MERGE_ISIS_EXPORTROUTE % (self.instance_id, xml_str) + elif self.import_routepolicyname or self.import_aclnumorname or self.import_ipprefix: + return CE_NC_MERGE_ISIS_IMPORTIPROUTE % (self.instance_id, xml_str) + elif self.bfd_min_rx or self.bfd_min_tx or self.bfd_multiplier_num: + return CE_NC_MERGE_ISIS_BFDLINK % (self.instance_id, xml_str) + else: + return '' + xml_str + '' + else: + if self.netentity or self.preference_value or self.route_policy_name or self.max_load \ + or self.ip_address or self.defaultmode or self.bfd_min_rx or self.bfd_min_tx or self.bfd_multiplier_num is not None: + return xml_str + else: + return '' + xml_str + '' + + def netconf_load_config(self, xml_str): + """load bfd config by netconf""" + + if not xml_str: + return + if xml_str == "%s" % self.instance_id: + pass + else: + xml_cfg = """ + + + %s + + """ % xml_str + set_nc_config(self.module, xml_cfg) + self.changed = True + + def check_params(self): + """Check all input params""" + levelcost = 16777215 + if not self.instance_id: + self.module.fail_json(msg="Error: Missing required arguments: instance_id.") + + if self.instance_id: + if self.instance_id < 1 or self.instance_id > 4294967295: + self.module.fail_json(msg="Error: Instance id is not ranges from 1 to 4294967295.") + + # check description + if self.description: + if len(self.description) < 1 or len(self.description) > 80: + self.module.fail_json(msg="Error: description is invalid.") + + # + if self.stdbandwidth: + if self.stdbandwidth < 1 or self.stdbandwidth > 2147483648: + self.module.fail_json(msg="Error: stdbandwidth is not ranges from 1 to 2147483648.") + + if self.relaxspfLimit is not None and not self.coststyle: + self.module.fail_json(msg="Error: relaxspfLimit must set after coststyle.") + + if self.coststyle: + if self.coststyle != "wide" and self.coststyle != "wtransition": + levelcost = 63 + else: + levelcost = 16777215 + if self.stdlevel1cost: + if self.stdlevel1cost < 1 or self.stdlevel1cost > levelcost: + self.module.fail_json(msg="Error: stdlevel1cost is not ranges from 1 to %s." % levelcost) + + if self.stdlevel2cost: + if self.stdlevel2cost < 1 or self.stdlevel2cost > levelcost: + self.module.fail_json(msg="Error: stdlevel2cost is not ranges from 1 to %s." % levelcost) + + if self.coststyle: + if self.coststyle != "ntransition" and self.coststyle != "transition": + if self.relaxspfLimit: + self.module.fail_json(msg="Error: relaxspfLimit can not be set while the coststyle is not ntransition or transition") + + if self.autocostenablecompatible: + if not self.autocostenable: + self.module.fail_json(msg="Error: you shoule enable the autocostenable first.") + + if self.preference_value: + if self.preference_value < 1 or self.preference_value > 255: + self.module.fail_json(msg="Error: preference_value is not ranges from 1 to 255.") + + if self.route_policy_name: + if len(self.route_policy_name) < 1 or len(self.route_policy_name) > 200: + self.module.fail_json(msg="Error: route_policy_name is invalid.") + + if self.max_load: + if self.max_load < 1 or self.max_load > 32: + self.module.fail_json(msg="Error: max_load is not ranges from 1 to 32.") + + if self.weight: + if self.weight < 1 or self.weight > 254: + self.module.fail_json(msg="Error: weight is not ranges from 1 to 254.") + + if self.aclnum_or_name: + if isinstance(self.aclnum_or_name, int): + if self.aclnum_or_name < 2000 or self.aclnum_or_name > 2999: + self.module.fail_json(msg="Error: acl_num is not ranges from 2000 to 2999.") + elif isinstance(self.aclnum_or_name, str): + if len(self.aclnum_or_name) < 1 or len(self.aclnum_or_name) > 32: + self.module.fail_json(msg="Error: acl_name is invalid.") + if self.ip_prefix_name: + if len(self.ip_prefix_name) < 1 or len(self.ip_prefix_name) > 169: + self.module.fail_json(msg="Error: ip_prefix_name is invalid.") + if self.import_routepolicy_name: + if len(self.import_routepolicy_name) < 1 or len(self.import_routepolicy_name) > 200: + self.module.fail_json(msg="Error: import_routepolicy_name is invalid.") + if self.tag: + if self.tag < 1 or self.tag > 4294967295: + self.module.fail_json(msg="Error: tag is not ranges from 1 to 4294967295.") + + if self.mode_routepolicyname: + if len(self.mode_routepolicyname) < 1 or len(self.mode_routepolicyname) > 200: + self.module.fail_json(msg="Error: mode_routepolicyname is invalid.") + if self.cost is not None: + if self.cost < 0 or self.cost > 4261412864: + self.module.fail_json(msg="Error: cost is not ranges from 0 to 4261412864.") + if self.mode_tag: + if self.mode_tag < 1 or self.mode_tag > 4294967295: + self.module.fail_json(msg="Error: mode_tag is not ranges from 1 to 4294967295.") + + if self.processid is not None: + if self.processid < 0 or self.processid > 4294967295: + self.module.fail_json(msg="Error: processid is not ranges from 0 to 4294967295.") + + if self.import_cost is not None: + if self.import_cost < 0 or self.import_cost > 4261412864: + self.module.fail_json(msg="Error: import_cost is not ranges from 0 to 4261412864.") + + if self.import_tag: + if self.import_tag < 1 or self.import_tag > 4294967295: + self.module.fail_json(msg="Error: import_tag is not ranges from 1 to 4294967295.") + + if self.export_aclnumorname: + if isinstance(self.export_aclnumorname, int): + if self.export_aclnumorname < 2000 or self.export_aclnumorname > 2999: + self.module.fail_json(msg="Error: acl_num is not ranges from 2000 to 2999.") + elif isinstance(self.export_aclnumorname, str): + if len(self.export_aclnumorname) < 1 or len(self.export_aclnumorname) > 32: + self.module.fail_json(msg="Error: acl_name is invalid.") + + if self.export_processid: + if self.export_processid < 1 or self.export_processid > 4294967295: + self.module.fail_json(msg="Error: export_processid is not ranges from 1 to 4294967295.") + + if self.export_ipprefix: + if len(self.export_ipprefix) < 1 or len(self.export_ipprefix) > 169: + self.module.fail_json(msg="Error: export_ipprefix is invalid.") + + if self.export_routepolicyname: + if len(self.export_routepolicyname) < 1 or len(self.export_routepolicyname) > 200: + self.module.fail_json(msg="Error: export_routepolicyname is invalid.") + + if self.bfd_min_rx: + if self.bfd_min_rx < 50 or self.bfd_min_rx > 1000: + self.module.fail_json(msg="Error: bfd_min_rx is not ranges from 50 to 1000.") + + if self.bfd_min_tx: + if self.bfd_min_tx < 50 or self.bfd_min_tx > 1000: + self.module.fail_json(msg="Error: bfd_min_tx is not ranges from 50 to 1000.") + + if self.bfd_multiplier_num: + if self.bfd_multiplier_num < 3 or self.bfd_multiplier_num > 50: + self.module.fail_json(msg="Error: bfd_multiplier_num is not ranges from 3 to 50.") + + if self.import_routepolicyname: + if len(self.import_routepolicyname) < 1 or len(self.import_routepolicyname) > 200: + self.module.fail_json(msg="Error: import_routepolicyname is invalid.") + + if self.import_aclnumorname: + if isinstance(self.import_aclnumorname, int): + if self.import_aclnumorname < 2000 or self.import_aclnumorname > 2999: + self.module.fail_json(msg="Error: acl_num is not ranges from 2000 to 2999.") + elif isinstance(self.import_aclnumorname, str): + if len(self.import_aclnumorname) < 1 or len(self.import_aclnumorname) > 32: + self.module.fail_json(msg="Error: acl_name is invalid.") + + def get_proposed(self): + """get proposed info""" + # base config + self.proposed["instance_id"] = self.instance_id + self.proposed["description"] = self.description + self.proposed["islevel"] = self.islevel + self.proposed["coststyle"] = self.coststyle + self.proposed["relaxspfLimit"] = self.relaxspfLimit + self.proposed["stdlevel1cost"] = self.stdlevel1cost + self.proposed["stdlevel2cost"] = self.stdlevel2cost + self.proposed["stdbandwidth"] = self.stdbandwidth + self.proposed["autocostenable"] = self.autocostenable + self.proposed["autocostenablecompatible"] = self.autocostenablecompatible + self.proposed["netentity"] = self.netentity + self.proposed["preference_value"] = self.preference_value + self.proposed["route_policy_name"] = self.route_policy_name + self.proposed["max_load"] = self.max_load + self.proposed["ip_address"] = self.ip_address + self.proposed["weight"] = self.weight + self.proposed["penetration_direct"] = self.penetration_direct + self.proposed["aclnum_or_name"] = self.aclnum_or_name + self.proposed["ip_prefix_name"] = self.ip_prefix_name + self.proposed["import_routepolicy_name"] = self.import_routepolicy_name + self.proposed["tag"] = self.tag + self.proposed["allow_filter"] = self.allow_filter + self.proposed["allow_up_down"] = self.allow_up_down + self.proposed["enablelevel1tolevel2"] = self.enablelevel1tolevel2 + self.proposed["protocol"] = self.protocol + self.proposed["processid"] = self.processid + self.proposed["cost_type"] = self.cost_type + self.proposed["import_cost"] = self.import_cost + self.proposed["import_tag"] = self.import_tag + self.proposed["import_route_policy"] = self.import_route_policy + self.proposed["impotr_leveltype"] = self.impotr_leveltype + self.proposed["inheritcost"] = self.inheritcost + self.proposed["permitibgp"] = self.permitibgp + self.proposed["export_protocol"] = self.export_protocol + self.proposed["export_policytype"] = self.export_policytype + self.proposed["export_processid"] = self.export_processid + self.proposed["export_aclnumorname"] = self.export_aclnumorname + self.proposed["export_ipprefix"] = self.export_ipprefix + self.proposed["export_routepolicyname"] = self.export_routepolicyname + self.proposed["import_aclnumorname"] = self.import_aclnumorname + self.proposed["import_ipprefix"] = self.import_ipprefix + self.proposed["import_routepolicyname"] = self.import_routepolicyname + self.proposed["bfd_min_rx"] = self.bfd_min_rx + self.proposed["bfd_min_tx"] = self.bfd_min_tx + self.proposed["bfd_multiplier_num"] = self.bfd_multiplier_num + self.proposed["state"] = self.state + + def get_existing(self): + """get existing info""" + + if not self.isis_dict: + self.existing["instance"] = None + else: + self.existing["instance"] = self.isis_dict.get("instance") + + def get_end_state(self): + """get end state info""" + + isis_dict = self.get_isis_dict() + if not isis_dict: + self.end_state["instance"] = None + else: + self.end_state["instance"] = isis_dict.get("instance") + if self.end_state == self.existing: + self.changed = False + + def work(self): + """worker""" + + self.check_params() + self.isis_dict = self.get_isis_dict() + self.get_existing() + self.get_proposed() + + # deal present or absent + xml_str = '' + if self.instance_id: + xml_str += self.config_session() + # update to device + if xml_str: + self.netconf_load_config(xml_str) + self.changed = True + + self.get_end_state() + self.results['changed'] = self.changed + self.results['proposed'] = self.proposed + self.results['existing'] = self.existing + self.results['end_state'] = self.end_state + if self.changed: + self.results['updates'] = self.updates_cmd + else: + self.results['updates'] = list() + self.module.exit_json(**self.results) + + +def main(): + """Module main""" + + argument_spec = dict( + instance_id=dict(required=True, type='int'), + description=dict(required=False, type='str'), + islevel=dict(required=False, type='str', choices=['level_1', 'level_2', 'level_1_2']), + coststyle=dict(required=False, type='str', choices=['narrow', 'wide', 'transition', 'ntransition', 'wtransition']), + relaxspfLimit=dict(required=False, type='bool'), + stdlevel1cost=dict(required=False, type='int'), + stdlevel2cost=dict(required=False, type='int'), + stdbandwidth=dict(required=False, type='int'), + autocostenable=dict(required=False, type='bool'), + autocostenablecompatible=dict(required=False, type='bool'), + netentity=dict(required=False, type='str'), + preference_value=dict(required=False, type='int'), + route_policy_name=dict(required=False, type='str'), + max_load=dict(required=False, type='int'), + ip_address=dict(required=False, type='str'), + weight=dict(required=False, type='int'), + penetration_direct=dict(required=False, type='str', choices=['level2-level1', 'level1-level2']), + aclnum_or_name=dict(required=False, type='str'), + ip_prefix_name=dict(required=False, type='str'), + import_routepolicy_name=dict(required=False, type='str'), + tag=dict(required=False, type='int'), + allow_filter=dict(required=False, type='bool'), + allow_up_down=dict(required=False, type='bool'), + enablelevel1tolevel2=dict(required=False, type='bool'), + defaultmode=dict(required=False, type='str', choices=['always', 'matchDefault', 'matchAny']), + mode_routepolicyname=dict(required=False, type='str'), + cost=dict(required=False, type='int'), + mode_tag=dict(required=False, type='int'), + level_type=dict(required=False, type='str', choices=['level_1', 'level_2', 'level_1_2']), + avoid_learning=dict(required=False, type='bool'), + protocol=dict(required=False, type='str', choices=['direct', 'ospf', 'isis', 'static', 'rip', 'bgp', 'ospfv3', 'all']), + processid=dict(required=False, type='int'), + cost_type=dict(required=False, type='str', choices=['external', 'internal']), + import_cost=dict(required=False, type='int'), + import_tag=dict(required=False, type='int'), + import_route_policy=dict(required=False, type='str'), + impotr_leveltype=dict(required=False, type='str', choices=['level_1', 'level_2', 'level_1_2']), + inheritcost=dict(required=False, type='bool'), + permitibgp=dict(required=False, type='bool'), + export_protocol=dict(required=False, type='str', choices=['direct', 'ospf', 'isis', 'static', 'rip', 'bgp', 'ospfv3', 'all']), + export_policytype=dict(required=False, type='str', choices=['aclNumOrName', 'ipPrefix', 'routePolicy']), + export_processid=dict(required=False, type='int'), + export_aclnumorname=dict(required=False, type='str'), + export_ipprefix=dict(required=False, type='str'), + export_routepolicyname=dict(required=False, type='str'), + import_aclnumorname=dict(required=False, type='str'), + import_ipprefix=dict(required=False, type='str'), + import_routepolicyname=dict(required=False, type='str'), + bfd_min_rx=dict(required=False, type='int'), + bfd_min_tx=dict(required=False, type='int'), + bfd_multiplier_num=dict(required=False, type='int'), + state=dict(required=False, default='present', choices=['present', 'absent']) + ) + + module = ISIS_View(argument_spec) + module.work() + + +if __name__ == '__main__': + main() diff --git a/test/integration/targets/ce_is_is_view/defaults/main.yaml b/test/integration/targets/ce_is_is_view/defaults/main.yaml new file mode 100644 index 00000000000..164afead284 --- /dev/null +++ b/test/integration/targets/ce_is_is_view/defaults/main.yaml @@ -0,0 +1,3 @@ +--- +testcase: "[^_].*" +test_items: [] diff --git a/test/integration/targets/ce_is_is_view/tasks/main.yaml b/test/integration/targets/ce_is_is_view/tasks/main.yaml new file mode 100644 index 00000000000..cc27f174fd8 --- /dev/null +++ b/test/integration/targets/ce_is_is_view/tasks/main.yaml @@ -0,0 +1,2 @@ +--- +- { include: netconf.yaml, tags: ['netconf'] } diff --git a/test/integration/targets/ce_is_is_view/tasks/netconf.yaml b/test/integration/targets/ce_is_is_view/tasks/netconf.yaml new file mode 100644 index 00000000000..73b91adfaa2 --- /dev/null +++ b/test/integration/targets/ce_is_is_view/tasks/netconf.yaml @@ -0,0 +1,17 @@ +--- +- name: collect all netconf test cases + find: + paths: "{{ role_path }}/tests/netconf" + patterns: "{{ testcase }}.yaml" + use_regex: true + connection: local + register: test_cases + +- name: set test_items + set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}" + +- name: run test case (connection=netconf) + include: "{{ test_case_to_run }} ansible_connection=netconf" + with_items: "{{ test_items }}" + loop_control: + loop_var: test_case_to_run diff --git a/test/integration/targets/ce_is_is_view/tests/netconf/cleanup.yaml b/test/integration/targets/ce_is_is_view/tests/netconf/cleanup.yaml new file mode 100644 index 00000000000..03c0f0ee944 --- /dev/null +++ b/test/integration/targets/ce_is_is_view/tests/netconf/cleanup.yaml @@ -0,0 +1,21 @@ +--- +- debug: + msg: "CLEANUP ce_is_is_view, deleted integration tests on connection={{ ansible_connection }}" + +- name: Get lacp config by ce_netconf. + ce_netconf: + rpc: get + cfg_xml: " + + + + 100 + _public_ + ISIS + + + + " + +- debug: + msg: "END CLEANUP ce_is_is_view, deleted integration tests on connection={{ ansible_connection }}" diff --git a/test/integration/targets/ce_is_is_view/tests/netconf/setup.yaml b/test/integration/targets/ce_is_is_view/tests/netconf/setup.yaml new file mode 100644 index 00000000000..92ec370c28d --- /dev/null +++ b/test/integration/targets/ce_is_is_view/tests/netconf/setup.yaml @@ -0,0 +1,22 @@ +--- +- debug: + msg: "SETUP ce_is_is_view integration tests on connection={{ ansible_connection }}" +# create ISIS 100 + +- name: Get lacp config by ce_netconf. + ce_netconf: + rpc: get + cfg_xml: " + + + + 100 + _public_ + ISIS + + + + " + +- debug: + msg: "END SETUP ce_is_is_view integration tests on connection={{ ansible_connection }}" diff --git a/test/integration/targets/ce_is_is_view/tests/netconf/test_ce_is_is_view_entity .yaml b/test/integration/targets/ce_is_is_view/tests/netconf/test_ce_is_is_view_entity .yaml new file mode 100644 index 00000000000..1c81c2ca7b8 --- /dev/null +++ b/test/integration/targets/ce_is_is_view/tests/netconf/test_ce_is_is_view_entity .yaml @@ -0,0 +1,78 @@ +--- +- debug: + msg: "START ce_is_is_view entity presented integration tests on connection={{ ansible_connection }}" +- include_tasks: setup.yaml + +- name: present the provided configuration with the exisiting running configuration + ce_is_is_view: &present + instance_id: 100 + netentity: isis_net_entity + register: result + +- name: Assert the configuration is reflected on host + assert: + that: + - "result['changed'] == true" + +- name: Get basic config by ce_netconf. + ce_netconf: &get_config + rpc: get + cfg_xml: " + + + + 100 + + + + + + + + + " + register: result_xml + + +- name: present the provided configuration with the existing running configuration (IDEMPOTENT) + ce_is_is_view: *present + register: repeat + +- name: Assert that the previous task was idempotent + assert: + that: + - "repeat.changed == false" + - "'100' in result_xml.end_state.result" + - "'isis_net_entity' in result_xml.end_state.result" + +- name: present the provided configuration with the exisiting running configuration + ce_is_is_view: &absent + instance_id: 100 + netentity: isis_net_entity + state: absent + register: result + + +- name: Assert the configuration is reflected on host + assert: + that: + - "result['changed'] == true" + +- name: present the provided configuration with the existing running configuration (IDEMPOTENT) + ce_is_is_view: *absent + register: repeat + +- name: Get basic config by ce_netconf. + ce_netconf: *get_config + register: result_xml + +- name: Assert that the previous task was idempotent + assert: + that: + - "repeat.changed == false" + - "'100' not in result_xml.end_state.result" + - "''isis_net_entity' not in result_xml.end_state.result" + # after present, isis 100 should be deleted +- include_tasks: cleanup.yaml +- debug: + msg: "END ce_is_is_view pentity resentd integration tests on connection={{ ansible_connection }}" diff --git a/test/integration/targets/ce_is_is_view/tests/netconf/test_ce_isis_bfd.yaml b/test/integration/targets/ce_is_is_view/tests/netconf/test_ce_isis_bfd.yaml new file mode 100644 index 00000000000..6aa200f6e87 --- /dev/null +++ b/test/integration/targets/ce_is_is_view/tests/netconf/test_ce_isis_bfd.yaml @@ -0,0 +1,92 @@ +--- +- debug: + msg: "START ce_is_is_view EXPORTROUTE route policy presented integration tests on connection={{ ansible_connection }}" +- include_tasks: setup.yaml + +- name: present the provided configuration with the exisiting running configuration + ce_is_is_view: &present + instance_id: 100 + bfd_min_rx: 100 + bfd_min_tx: 100 + bfd_multiplier_num: 10 + register: result + +- name: Assert the configuration is reflected on host + assert: + that: + - "result['changed'] == true" + +- name: Get basic config by ce_netconf. + ce_netconf: &get_config + rpc: get + cfg_xml: " + + + + 100 + + + afIpv4 + 0 + + + + + + + + + " + register: result_xml + + +- name: present the provided configuration with the existing running configuration (IDEMPOTENT) + ce_is_is_view: *present + register: repeat + +- name: Assert that the previous task was idempotent + assert: + that: + - "repeat.changed == false" + - "'100' in result_xml.end_state.result" + - "'100' in result_xml.end_state.result" + - "'10' in result_xml.end_state.result" + +- name: present the provided configuration with the exisiting running configuration + ce_is_is_view: &absent + instance_id: 100 + defaultmode: always + cost: 10 + mode_tag: 10 + level_type: level_1 + avoid_learning: true + mode_routepolicyname: routepolicy_name + tag: 100 + state: absent + register: result + + +- name: Assert the configuration is reflected on host + assert: + that: + - "result['changed'] == true" + +- name: present the provided configuration with the existing running configuration (IDEMPOTENT) + ce_is_is_view: *absent + register: repeat + +- name: Get basic config by ce_netconf. + ce_netconf: *get_config + register: result_xml + +- name: Assert that the previous task was idempotent + assert: + that: + - "repeat.changed == false" + - "'100' not in result_xml.end_state.result" + - "'100' not in result_xml.end_state.result" + - "'10' not in result_xml.end_state.result" +# after present, isis 100 should be deleted +- include_tasks: cleanup.yaml +- debug: + msg: "END ce_is_is_view EXPORTROUTE route policy resentd integration tests on connection={{ ansible_connection }}" diff --git a/test/integration/targets/ce_is_is_view/tests/netconf/test_ce_isis_export.yaml b/test/integration/targets/ce_is_is_view/tests/netconf/test_ce_isis_export.yaml new file mode 100644 index 00000000000..f83a07c2cf6 --- /dev/null +++ b/test/integration/targets/ce_is_is_view/tests/netconf/test_ce_isis_export.yaml @@ -0,0 +1,96 @@ +--- +- debug: + msg: "START ce_is_is_view EXPORTROUTE route policy presented integration tests on connection={{ ansible_connection }}" +- include_tasks: setup.yaml + +- name: present the provided configuration with the exisiting running configuration + ce_is_is_view: &present + instance_id: 100 + export_protocol: ospf + export_policytype: aclNumOrName + export_processid: 100 + register: result + +- name: Assert the configuration is reflected on host + assert: + that: + - "result['changed'] == true" + +- name: Get basic config by ce_netconf. + ce_netconf: &get_config + rpc: get + cfg_xml: " + + + + 100 + + + afIpv4 + 0 + + + + + + + + + + + + + " + register: result_xml + + +- name: present the provided configuration with the existing running configuration (IDEMPOTENT) + ce_is_is_view: *present + register: repeat + +- name: Assert that the previous task was idempotent + assert: + that: + - "repeat.changed == false" + - "'ospf' in result_xml.end_state.result" + - "'100' in result_xml.end_state.result" + - "'level_1' in result_xml.end_state.result" + +- name: present the provided configuration with the exisiting running configuration + ce_is_is_view: &absent + instance_id: 100 + defaultmode: always + cost: 10 + mode_tag: 10 + level_type: level_1 + avoid_learning: true + mode_routepolicyname: routepolicy_name + tag: 100 + state: absent + register: result + + +- name: Assert the configuration is reflected on host + assert: + that: + - "result['changed'] == true" + +- name: present the provided configuration with the existing running configuration (IDEMPOTENT) + ce_is_is_view: *absent + register: repeat + +- name: Get basic config by ce_netconf. + ce_netconf: *get_config + register: result_xml + +- name: Assert that the previous task was idempotent + assert: + that: + - "repeat.changed == false" + - "'ospf' not in result_xml.end_state.result" + - "'100' not in result_xml.end_state.result" + - "'level_1' in result_xml.end_state.result" +# after present, isis 100 should be deleted +- include_tasks: cleanup.yaml +- debug: + msg: "END ce_is_is_view EXPORTROUTE route policy resentd integration tests on connection={{ ansible_connection }}" diff --git a/test/integration/targets/ce_is_is_view/tests/netconf/test_ce_isis_import.yaml b/test/integration/targets/ce_is_is_view/tests/netconf/test_ce_isis_import.yaml new file mode 100644 index 00000000000..c5b4e60df48 --- /dev/null +++ b/test/integration/targets/ce_is_is_view/tests/netconf/test_ce_isis_import.yaml @@ -0,0 +1,124 @@ +--- +- debug: + msg: "START ce_is_is_view import route policy presented integration tests on connection={{ ansible_connection }}" +- include_tasks: setup.yaml + +- name: present the provided configuration with the exisiting running configuration + ce_is_is_view: &present + instance_id: 100 + protocol: ospf + processid: 100 + cost_type: external + import_cost: 10 + import_tag: 10 + import_route_policy: routepolicy_name + impotr_leveltype: level_1 + inheritcost: true + permitibgp: true + tag: 100 + register: result + +- name: Assert the configuration is reflected on host + assert: + that: + - "result['changed'] == true" + +- name: Get basic config by ce_netconf. + ce_netconf: &get_config + rpc: get + cfg_xml: " + + + + 100 + + + afIpv4 + 0 + + + + + + + + + + + + + + + + + + + + " + register: result_xml + + +- name: present the provided configuration with the existing running configuration (IDEMPOTENT) + ce_is_is_view: *present + register: repeat + +- name: Assert that the previous task was idempotent + assert: + that: + - "repeat.changed == false" + - "'ospf' in result_xml.end_state.result" + - "'100' in result_xml.end_state.result" + - "'external' in result_xml.end_state.result" + - "'10' in result_xml.end_state.result" + - "'10' in result_xml.end_state.result" + - "'level_1' in result_xml.end_state.result" + - "'routepolicy_name' in result_xml.end_state.result" + - "'level_1' in result_xml.end_state.result" + - "'true' in result_xml.end_state.result" + - "'true' in result_xml.end_state.result" + +- name: present the provided configuration with the exisiting running configuration + ce_is_is_view: &absent + instance_id: 100 + defaultmode: always + cost: 10 + mode_tag: 10 + level_type: level_1 + avoid_learning: true + mode_routepolicyname: routepolicy_name + tag: 100 + state: absent + register: result + + +- name: Assert the configuration is reflected on host + assert: + that: + - "result['changed'] == true" + +- name: present the provided configuration with the existing running configuration (IDEMPOTENT) + ce_is_is_view: *absent + register: repeat + +- name: Get basic config by ce_netconf. + ce_netconf: *get_config + register: result_xml + +- name: Assert that the previous task was idempotent + assert: + that: + - "repeat.changed == false" + - "'ospf' not in result_xml.end_state.result" + - "'100' not in result_xml.end_state.result" + - "'external' not in result_xml.end_state.result" + - "'10' not in result_xml.end_state.result" + - "'10' not in result_xml.end_state.result" + - "'level_1' not in result_xml.end_state.result" + - "'routepolicy_name' not in result_xml.end_state.result" + - "'level_1' not in result_xml.end_state.result" + - "'true' not in result_xml.end_state.result" + - "'true' not in result_xml.end_state.result" +# after present, isis 100 should be deleted +- include_tasks: cleanup.yaml +- debug: + msg: "END ce_is_is_view import route policy resentd integration tests on connection={{ ansible_connection }}" diff --git a/test/integration/targets/ce_is_is_view/tests/netconf/test_ce_isis_l1tol2.yaml b/test/integration/targets/ce_is_is_view/tests/netconf/test_ce_isis_l1tol2.yaml new file mode 100644 index 00000000000..f12b5034bf8 --- /dev/null +++ b/test/integration/targets/ce_is_is_view/tests/netconf/test_ce_isis_l1tol2.yaml @@ -0,0 +1,109 @@ +--- +- debug: + msg: "START ce_is_is_view import route policy presented integration tests on connection={{ ansible_connection }}" +- include_tasks: setup.yaml + +- name: present the provided configuration with the exisiting running configuration + ce_is_is_view: &present + instance_id: 100 + allow_filter: true + allow_up_down: true + ip_prefix_name: prefix_name + aclnum_or_name: 3001 + penetration_direct: level1-level2 + import_routepolicy_name: routepolicy_name + tag: 100 + register: result + +- name: Assert the configuration is reflected on host + assert: + that: + - "result['changed'] == true" + +- name: Get basic config by ce_netconf. + ce_netconf: &get_config + rpc: get + cfg_xml: " + + + + 100 + + + afIpv4 + 0 + + + + + + + + + + + + + + + + " + register: result_xml + + +- name: present the provided configuration with the existing running configuration (IDEMPOTENT) + ce_is_is_view: *present + register: repeat + +- name: Assert that the previous task was idempotent + assert: + that: + - "repeat.changed == false" + - "'100' in result_xml.end_state.result" + - "'routepolicy_name' in result_xml.end_state.result" + - "'true' in result_xml.end_state.result" + - "'3001' in result_xml.end_state.result" + - "'prefix_name' in result_xml.end_state.result" + - "'true' in result_xml.end_state.result" + +- name: present the provided configuration with the exisiting running configuration + ce_is_is_view: &absent + instance_id: 100 + allow_filter: true + allow_up_down: true + ip_prefix_name: prefix_name + aclnum_or_name: 3001 + penetration_direct: level1-level2 + import_routepolicy_name: routepolicy_name + tag: 100 + state: absent + register: result + + +- name: Assert the configuration is reflected on host + assert: + that: + - "result['changed'] == true" + +- name: present the provided configuration with the existing running configuration (IDEMPOTENT) + ce_is_is_view: *absent + register: repeat + +- name: Get basic config by ce_netconf. + ce_netconf: *get_config + register: result_xml + +- name: Assert that the previous task was idempotent + assert: + that: + - "repeat.changed == false" + - "'100' in result_xml.end_state.result" + - "'routepolicy_name' not in result_xml.end_state.result" + - "'true' not in result_xml.end_state.result" + - "'3001' not in result_xml.end_state.result" + - "'prefix_name' not in result_xml.end_state.result" + - "'true' not in result_xml.end_state.result" + # after present, isis 100 should be deleted +- include_tasks: cleanup.yaml +- debug: + msg: "END ce_is_is_view import route policy resentd integration tests on connection={{ ansible_connection }}" diff --git a/test/integration/targets/ce_is_is_view/tests/netconf/test_ce_isis_l2tol1.yaml b/test/integration/targets/ce_is_is_view/tests/netconf/test_ce_isis_l2tol1.yaml new file mode 100644 index 00000000000..3af5111fb4f --- /dev/null +++ b/test/integration/targets/ce_is_is_view/tests/netconf/test_ce_isis_l2tol1.yaml @@ -0,0 +1,109 @@ +--- +- debug: + msg: "START ce_is_is_view import route policy presented integration tests on connection={{ ansible_connection }}" +- include_tasks: setup.yaml + +- name: present the provided configuration with the exisiting running configuration + ce_is_is_view: &present + instance_id: 100 + penetration_direct: level2-level1 + allow_filter: true + allow_up_down: true + ip_prefix_name: prefix_name + aclnum_or_name: 3001 + import_routepolicy_name: routepolicy_name + tag: 100 + register: result + +- name: Assert the configuration is reflected on host + assert: + that: + - "result['changed'] == true" + +- name: Get basic config by ce_netconf. + ce_netconf: &get_config + rpc: get + cfg_xml: " + + + + 100 + + + afIpv4 + 0 + + + + + + + + + + + + + + + + " + register: result_xml + + +- name: present the provided configuration with the existing running configuration (IDEMPOTENT) + ce_is_is_view: *present + register: repeat + +- name: Assert that the previous task was idempotent + assert: + that: + - "repeat.changed == false" + - "'100' in result_xml.end_state.result" + - "'routepolicy_name' in result_xml.end_state.result" + - "'true' in result_xml.end_state.result" + - "'3001' in result_xml.end_state.result" + - "'prefix_name' in result_xml.end_state.result" + - "'true' in result_xml.end_state.result" + +- name: present the provided configuration with the exisiting running configuration + ce_is_is_view: &absent + instance_id: 100 + penetration_direct: level2-level1 + allow_filter: true + allow_up_down: true + ip_prefix_name: prefix_name + aclnum_or_name: 3001 + import_routepolicy_name: routepolicy_name + tag: 100 + state: absent + register: result + + +- name: Assert the configuration is reflected on host + assert: + that: + - "result['changed'] == true" + +- name: present the provided configuration with the existing running configuration (IDEMPOTENT) + ce_is_is_view: *absent + register: repeat + +- name: Get basic config by ce_netconf. + ce_netconf: *get_config + register: result_xml + +- name: Assert that the previous task was idempotent + assert: + that: + - "repeat.changed == false" + - "'100' in result_xml.end_state.result" + - "'routepolicy_name' not in result_xml.end_state.result" + - "'true' not in result_xml.end_state.result" + - "'3001' not in result_xml.end_state.result" + - "'prefix_name' not in result_xml.end_state.result" + - "'true' not in result_xml.end_state.result" + # after present, isis 100 should be deleted +- include_tasks: cleanup.yaml +- debug: + msg: "END ce_is_is_view import route policy resentd integration tests on connection={{ ansible_connection }}" diff --git a/test/integration/targets/ce_is_is_view/tests/netconf/test_ce_isis_max_load.yaml b/test/integration/targets/ce_is_is_view/tests/netconf/test_ce_isis_max_load.yaml new file mode 100644 index 00000000000..0629d3415c1 --- /dev/null +++ b/test/integration/targets/ce_is_is_view/tests/netconf/test_ce_isis_max_load.yaml @@ -0,0 +1,80 @@ +--- +- debug: + msg: "START ce_is_is_view maxLoadBalancing presented integration tests on connection={{ ansible_connection }}" +- include_tasks: setup.yaml + +- name: present the provided configuration with the exisiting running configuration + ce_is_is_view: &present + instance_id: 100 + max_load: 30 + register: result + +- name: Assert the configuration is reflected on host + assert: + that: + - "result['changed'] == true" + +- name: Get basic config by ce_netconf. + ce_netconf: &get_config + rpc: get + cfg_xml: " + + + + 100 + + + afIpv4 + 0 + + + + + + + " + register: result_xml + + +- name: present the provided configuration with the existing running configuration (IDEMPOTENT) + ce_is_is_view: *present + register: repeat + +- name: Assert that the previous task was idempotent + assert: + that: + - "repeat.changed == false" + - "'100' in result_xml.end_state.result" + - "'30' in result_xml.end_state.result" + +- name: present the provided configuration with the exisiting running configuration + ce_is_is_view: &absent + instance_id: 100 + max_load: 30 + state: absent + register: result + + +- name: Assert the configuration is reflected on host + assert: + that: + - "result['changed'] == true" + +- name: present the provided configuration with the existing running configuration (IDEMPOTENT) + ce_is_is_view: *absent + register: repeat + +- name: Get basic config by ce_netconf. + ce_netconf: *get_config + register: result_xml + +- name: Assert that the previous task was idempotent + assert: + that: + - "repeat.changed == false" + - "'100' not in result_xml.end_state.result" + - "'30' not in result_xml.end_state.result" + # after present, isis 100 should be deleted +- include_tasks: cleanup.yaml +- debug: + msg: "END ce_is_is_view maxLoadBalancing resentd integration tests on connection={{ ansible_connection }}" diff --git a/test/integration/targets/ce_is_is_view/tests/netconf/test_ce_isis_preferences.yaml b/test/integration/targets/ce_is_is_view/tests/netconf/test_ce_isis_preferences.yaml new file mode 100644 index 00000000000..97d232fecad --- /dev/null +++ b/test/integration/targets/ce_is_is_view/tests/netconf/test_ce_isis_preferences.yaml @@ -0,0 +1,87 @@ +--- +- debug: + msg: "START ce_is_is_view preferences presented integration tests on connection={{ ansible_connection }}" +- include_tasks: setup.yaml + +- name: present the provided configuration with the exisiting running configuration + ce_is_is_view: &present + instance_id: 100 + preference_value: 100 + route_policy_name: route + register: result + +- name: Assert the configuration is reflected on host + assert: + that: + - "result['changed'] == true" + +- name: Get basic config by ce_netconf. + ce_netconf: &get_config + rpc: get + cfg_xml: " + + + + 100 + + + + + + + + + + + + + + " + register: result_xml + + +- name: present the provided configuration with the existing running configuration (IDEMPOTENT) + ce_is_is_view: *present + register: repeat + +- name: Assert that the previous task was idempotent + assert: + that: + - "repeat.changed == false" + - "'100' in result_xml.end_state.result" + - "'100' in result_xml.end_state.result" + - "'route' in result_xml.end_state.result" + +- name: present the provided configuration with the exisiting running configuration + ce_is_is_view: &absent + instance_id: 100 + preference_value: 100 + route_policy_name: route + state: absent + register: result + + +- name: Assert the configuration is reflected on host + assert: + that: + - "result['changed'] == true" + +- name: present the provided configuration with the existing running configuration (IDEMPOTENT) + ce_is_is_view: *absent + register: repeat + +- name: Get basic config by ce_netconf. + ce_netconf: *get_config + register: result_xml + +- name: Assert that the previous task was idempotent + assert: + that: + - "repeat.changed == false" + - "'100' not in result_xml.end_state.result" + - "''100' not in result_xml.end_state.result" + - "''route' not in result_xml.end_state.result" + # after present, isis 100 should be deleted +- include_tasks: cleanup.yaml +- debug: + msg: "END ce_is_is_view Preference resentd integration tests on connection={{ ansible_connection }}" diff --git a/test/integration/targets/ce_is_is_view/tests/netconf/test_ce_isis_view_basic.yaml b/test/integration/targets/ce_is_is_view/tests/netconf/test_ce_isis_view_basic.yaml new file mode 100644 index 00000000000..ca95d0e0593 --- /dev/null +++ b/test/integration/targets/ce_is_is_view/tests/netconf/test_ce_isis_view_basic.yaml @@ -0,0 +1,115 @@ +--- +- debug: + msg: "START ce_is_is_view presented integration tests on connection={{ ansible_connection }}" +- include_tasks: setup.yaml + +- name: present the provided configuration with the exisiting running configuration + ce_is_is_view: &present + instance_id: 100 + description: ISIS + islevel: level_1 + coststyle: narrow + relaxSpfLimit: true + stdlevel1cost: 60 + stdlevel2cost: 60 + stdbandwidth: 100 + autocostenable: true + autocostenablecompatible: true + register: result + +- name: Assert the configuration is reflected on host + assert: + that: + - "result['changed'] == true" + +- name: Get basic config by ce_netconf. + ce_netconf: &get_config + rpc: get + cfg_xml: " + + + + 100 + + + + + + + + + + + + " + register: result_xml + + +- name: present the provided configuration with the existing running configuration (IDEMPOTENT) + ce_is_is_view: *present + register: repeat + +- name: Assert that the previous task was idempotent + assert: + that: + - "repeat.changed == false" + - "'100' in result_xml.end_state.result" + - "'_public_' in result_xml.end_state.result" + - "'ISIS' in result_xml.end_state.result" + - "'level_1' in result_xml.end_state.result" + - "'narrow' in result_xml.end_state.result" + - "'true' in result_xml.end_state.result" + - "'60' in result_xml.end_state.result" + - "'60' in result_xml.end_state.result" + - "'100' in result_xml.end_state.result" + - "'true' in result_xml.end_state.result" + - "'true' in result_xml.end_state.result" + +- name: present the provided configuration with the exisiting running configuration + ce_is_is_view: &absent + instance_id: 100 + description: ISIS + islevel: level_1 + coststyle: narrow + relaxSpfLimit: true + stdlevel1cost: 60 + stdlevel2cost: 60 + stdbandwidth: 100 + autocostenable: true + autocostenablecompatible: true + state: absent + register: result + + +- name: Assert the configuration is reflected on host + assert: + that: + - "result['changed'] == true" + +- name: present the provided configuration with the existing running configuration (IDEMPOTENT) + ce_is_is_view: *absent + register: repeat + +- name: Get basic config by ce_netconf. + ce_netconf: *get_config + register: result_xml + +- name: Assert that the previous task was idempotent + assert: + that: + - "repeat.changed == false" + - "'100' not in result_xml.end_state.result" + - "'_public_' not in result_xml.end_state.result" + - "'ISIS' not in result_xml.end_state.result" + - "'level_1' not in result_xml.end_state.result" + - "'narrow' not in result_xml.end_state.result" + - "'true' not in result_xml.end_state.result" + - "'60' not in result_xml.end_state.result" + - "'60' not in result_xml.end_state.result" + - "'100' not in result_xml.end_state.result" + - "'true' not in result_xml.end_state.result" + - "'true' not in result_xml.end_state.result" +# after present, isis 100 should be deleted +- include_tasks: cleanup.yaml +- debug: + msg: "END ce_is_is_view presentd integration tests on connection={{ ansible_connection }}" diff --git a/test/integration/targets/ce_is_is_view/tests/netconf/test_ce_issi_default.yaml b/test/integration/targets/ce_is_is_view/tests/netconf/test_ce_issi_default.yaml new file mode 100644 index 00000000000..1059054dcec --- /dev/null +++ b/test/integration/targets/ce_is_is_view/tests/netconf/test_ce_issi_default.yaml @@ -0,0 +1,111 @@ +--- +- debug: + msg: "START ce_is_is_view import route policy presented integration tests on connection={{ ansible_connection }}" +- include_tasks: setup.yaml + +- name: present the provided configuration with the exisiting running configuration + ce_is_is_view: &present + instance_id: 100 + defaultmode: always + cost: 10 + mode_tag: 10 + level_type: level_1 + avoid_learning: true + mode_routepolicyname: routepolicy_name + tag: 100 + register: result + +- name: Assert the configuration is reflected on host + assert: + that: + - "result['changed'] == true" + +- name: Get basic config by ce_netconf. + ce_netconf: &get_config + rpc: get + cfg_xml: " + + + + 100 + + + afIpv4 + 0 + + + + + + + + + + + + + + + + " + register: result_xml + + +- name: present the provided configuration with the existing running configuration (IDEMPOTENT) + ce_is_is_view: *present + register: repeat + +- name: Assert that the previous task was idempotent + assert: + that: + - "repeat.changed == false" + - "'100' in result_xml.end_state.result" + - "'always' in result_xml.end_state.result" + - "'routepolicy_name' in result_xml.end_state.result" + - "'10' in result_xml.end_state.result" + - "'10' in result_xml.end_state.result" + - "'level_1' in result_xml.end_state.result" + - "'true' in result_xml.end_state.result" + +- name: present the provided configuration with the exisiting running configuration + ce_is_is_view: &absent + instance_id: 100 + defaultmode: always + cost: 10 + mode_tag: 10 + level_type: level_1 + avoid_learning: true + mode_routepolicyname: routepolicy_name + tag: 100 + state: absent + register: result + + +- name: Assert the configuration is reflected on host + assert: + that: + - "result['changed'] == true" + +- name: present the provided configuration with the existing running configuration (IDEMPOTENT) + ce_is_is_view: *absent + register: repeat + +- name: Get basic config by ce_netconf. + ce_netconf: *get_config + register: result_xml + +- name: Assert that the previous task was idempotent + assert: + that: + - "repeat.changed == false" + - "'100' not in result_xml.end_state.result" + - "'always' not in result_xml.end_state.result" + - "'routepolicy_name' not in result_xml.end_state.result" + - "'10' not in result_xml.end_state.result" + - "'10' not in result_xml.end_state.result" + - "'level_1' not in result_xml.end_state.result" + - "'true' not in result_xml.end_state.result" +# after present, isis 100 should be deleted +- include_tasks: cleanup.yaml +- debug: + msg: "END ce_is_is_view import route policy resentd integration tests on connection={{ ansible_connection }}" diff --git a/test/integration/targets/ce_is_is_view/tests/netconf/test_isis_filter_import.yaml b/test/integration/targets/ce_is_is_view/tests/netconf/test_isis_filter_import.yaml new file mode 100644 index 00000000000..7a97d982d64 --- /dev/null +++ b/test/integration/targets/ce_is_is_view/tests/netconf/test_isis_filter_import.yaml @@ -0,0 +1,97 @@ +--- +- debug: + msg: "START ce_is_is_view EXPORTROUTE route policy presented integration tests on connection={{ ansible_connection }}" +- include_tasks: setup.yaml + +- name: present the provided configuration with the exisiting running configuration + ce_is_is_view: &present + instance_id: 100 + import_aclnumorname: 301 + import_ipprefix: ipprefix + import_routepolicyname: routepolicyname + register: result + +- name: Assert the configuration is reflected on host + assert: + that: + - "result['changed'] == true" + +- name: Get basic config by ce_netconf. + ce_netconf: &get_config + rpc: get + cfg_xml: " + + + + 100 + + + afIpv4 + 0 + + + + + + + + + + + + + " + register: result_xml + + +- name: present the provided configuration with the existing running configuration (IDEMPOTENT) + ce_is_is_view: *present + register: repeat + +- name: Assert that the previous task was idempotent + assert: + that: + - "repeat.changed == false" + - "'3001' in result_xml.end_state.result" + - "'ipprefix' in result_xml.end_state.result" + - "'routepolicyname' in result_xml.end_state.result" + +- name: present the provided configuration with the exisiting running configuration + ce_is_is_view: &absent + instance_id: 100 + defaultmode: always + cost: 10 + mode_tag: 10 + level_type: level_1 + avoid_learning: true + mode_routepolicyname: routepolicy_name + tag: 100 + state: absent + register: result + + +- name: Assert the configuration is reflected on host + assert: + that: + - "result['changed'] == true" + +- name: present the provided configuration with the existing running configuration (IDEMPOTENT) + ce_is_is_view: *absent + register: repeat + +- name: Get basic config by ce_netconf. + ce_netconf: *get_config + register: result_xml + +- name: Assert that the previous task was idempotent + assert: + that: + - "repeat.changed == false" + - "'3001' not in result_xml.end_state.result" + - "'ipprefix' not in result_xml.end_state.result" + - "'routepolicyname' not in result_xml.end_state.result" + +# after present, isis 100 should be deleted +- include_tasks: cleanup.yaml +- debug: + msg: "END ce_is_is_view EXPORTROUTE route policy resentd integration tests on connection={{ ansible_connection }}" diff --git a/test/integration/targets/ce_is_is_view/tests/netconf/test_isis_next_hop.yaml b/test/integration/targets/ce_is_is_view/tests/netconf/test_isis_next_hop.yaml new file mode 100644 index 00000000000..f18eeaf844e --- /dev/null +++ b/test/integration/targets/ce_is_is_view/tests/netconf/test_isis_next_hop.yaml @@ -0,0 +1,87 @@ +--- +- debug: + msg: "START ce_is_is_view next hop presented integration tests on connection={{ ansible_connection }}" +- include_tasks: setup.yaml + +- name: present the provided configuration with the exisiting running configuration + ce_is_is_view: &present + instance_id: 100 + ip_address: 1.1.1.1 + weight: 100 + register: result + +- name: Assert the configuration is reflected on host + assert: + that: + - "result['changed'] == true" + +- name: Get basic config by ce_netconf. + ce_netconf: &get_config + rpc: get + cfg_xml: " + + + + 100 + + + afIpv4 + 0 + + + + + + + + + + + + " + register: result_xml + + +- name: present the provided configuration with the existing running configuration (IDEMPOTENT) + ce_is_is_view: *present + register: repeat + +- name: Assert that the previous task was idempotent + assert: + that: + - "repeat.changed == false" + - "'1.1.1.1' in result_xml.end_state.result" + - "'100' in result_xml.end_state.result" + +- name: present the provided configuration with the exisiting running configuration + ce_is_is_view: &absent + instance_id: 100 + ip_address: 1.1.1.1 + weight: 100 + state: absent + register: result + + +- name: Assert the configuration is reflected on host + assert: + that: + - "result['changed'] == true" + +- name: present the provided configuration with the existing running configuration (IDEMPOTENT) + ce_is_is_view: *absent + register: repeat + +- name: Get basic config by ce_netconf. + ce_netconf: *get_config + register: result_xml + +- name: Assert that the previous task was idempotent + assert: + that: + - "repeat.changed == false" + - "'1.1.1.1' not in result_xml.end_state.result" + - "'100' not in result_xml.end_state.result" + # after present, isis 100 should be deleted +- include_tasks: cleanup.yaml +- debug: + msg: "END ce_is_is_view next hop resentd integration tests on connection={{ ansible_connection }}" diff --git a/test/units/modules/network/cloudengine/fixtures/ce_is_is_view/after.txt b/test/units/modules/network/cloudengine/fixtures/ce_is_is_view/after.txt new file mode 100644 index 00000000000..8da6a62e94a --- /dev/null +++ b/test/units/modules/network/cloudengine/fixtures/ce_is_is_view/after.txt @@ -0,0 +1,104 @@ + + + + + 100 + _public_ + ISIS + level_1 + narrow + true + 60 + 60 + 100 + true + true + + + netentity + + + + + afIpv4 + 0 + 100 + 100 + 10 + 32 + + + 100 + route + + + + + 1.1.1.1 + 100 + + + + + 3001 + ip + route + level_1 + + + + + ospf + 100 + level_1 + + + + + always + mode + 100 + 100 + level_1 + true + + + + + import + 100 + level_1 + 100 + 100 + level_1 + import + level_1 + 100 + true + + + + + 100 + route + 3001 + ip + true + true + + + + + 100 + route + 3001 + ip + true + + + + + + + + diff --git a/test/units/modules/network/cloudengine/fixtures/ce_is_is_view/before.txt b/test/units/modules/network/cloudengine/fixtures/ce_is_is_view/before.txt new file mode 100644 index 00000000000..abdb8e790f9 --- /dev/null +++ b/test/units/modules/network/cloudengine/fixtures/ce_is_is_view/before.txt @@ -0,0 +1,10 @@ + + + + + 100 + _public_ + + + + diff --git a/test/units/modules/network/cloudengine/test_ce_is_is_view.py b/test/units/modules/network/cloudengine/test_ce_is_is_view.py new file mode 100644 index 00000000000..ec2cda74d2f --- /dev/null +++ b/test/units/modules/network/cloudengine/test_ce_is_is_view.py @@ -0,0 +1,248 @@ +# (c) 2019 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 . + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) + +__metaclass__ = type + +from units.compat.mock import patch +from ansible.modules.network.cloudengine import ce_is_is_view +from units.modules.network.cloudengine.ce_module import TestCloudEngineModule, load_fixture +from units.modules.utils import set_module_args + + +class TestCloudEngineLacpModule(TestCloudEngineModule): + module = ce_is_is_view + + def setUp(self): + super(TestCloudEngineLacpModule, self).setUp() + + self.mock_get_config = patch('ansible.modules.network.cloudengine.ce_is_is_view.get_nc_config') + self.get_nc_config = self.mock_get_config.start() + + self.mock_set_config = patch('ansible.modules.network.cloudengine.ce_is_is_view.set_nc_config') + self.set_nc_config = self.mock_set_config.start() + self.set_nc_config.return_value = None + + self.before = load_fixture('ce_is_is_view', 'before.txt') + self.after = load_fixture('ce_is_is_view', 'after.txt') + + def tearDown(self): + super(TestCloudEngineLacpModule, self).tearDown() + self.mock_set_config.stop() + self.mock_get_config.stop() + + def test_ce_is_is_view_absent(self): + self.get_nc_config.side_effect = (self.after, self.before) + config = dict( + instance_id=100, + description='ISIS', + islevel='level_1', + coststyle='narrow', + stdlevel2cost=60, + stdbandwidth=100, + autocostenable=True, + autocostenablecompatible=True, + netentity='netentity', + preference_value=100, + route_policy_name='route', + max_load=32, + ip_address='1.1.1.1', + weight=100, + penetration_direct='level2-level1', + import_routepolicy_name='import', + tag=100, + allow_filter=True, + allow_up_down=True, + enablelevel1tolevel2=True, + defaultmode='always', + mode_routepolicyname='mode', + cost=100, + mode_tag=100, + level_type='level_1', + avoid_learning=True, + protocol='ospf', + processid=100, + cost_type='external', + import_cost=100, + import_tag=100, + import_route_policy='import', + impotr_leveltype='level_1', + inheritcost=True, + permitibgp=True, + export_protocol='ospf', + export_policytype='aclNumOrName', + export_processid=100, + export_ipprefix='export', + export_routepolicyname='export', + import_aclnumorname='acl', + import_routepolicyname='import', + bfd_min_rx=100, + bfd_min_tx=100, + bfd_multiplier_num=10, + state='absent' + ) + set_module_args(config) + self.execute_module(changed=True) + + def test_ce_is_is_view_present(self): + self.get_nc_config.side_effect = (self.before, self.after) + update = ['isis 100', + 'description ISIS', + 'is-level level_1', + 'cost-style narrow', + 'circuit-cost 60 level-2', + 'bandwidth-reference 100', + 'network-entity netentity', + 'preference 100 route-policy route', + 'maximum load-balancing 32', + 'nexthop 1.1.1.1 weight 100', + 'import-route isis level-2 into level-1 filter-policy route-policy import tag 100 direct allow-filter-policy allow-up-down-bit', + 'preference 100 route-policy route', + 'undo import-route isis level-1 into level-2 disable', + 'default-route-advertise always cost 100 tag 100 level-1 avoid-learning', + 'import-route isis level-2 into level-1 filter-policy route-policy import tag 100 direct allow-filter-policy allow-up-down-bit', + 'preference 100 route-policy route', + 'import-route ospf 100 inherit-cost cost-type external cost 100 tag 100 route-policy import level-1', + 'default-route-advertise always cost 100 tag 100 level-1 avoid-learning', + 'import-route isis level-2 into level-1 filter-policy route-policy import tag 100 direct allow-filter-policy allow-up-down-bit', + 'preference 100 route-policy route', + 'bfd all-interfaces enable', + 'bfd all-interfaces min-rx-interval 100 min-tx-interval 100 detect-multiplier 10', + 'import-route ospf 100 inherit-cost cost-type external cost 100 tag 100 route-policy import level-1', + 'default-route-advertise always cost 100 tag 100 level-1 avoid-learning', + 'import-route isis level-2 into level-1 filter-policy route-policy import tag 100 direct allow-filter-policy allow-up-down-bit', + 'preference 100 route-policy route', + 'filter-policy ip-prefix export route-policy export export ospf 100', + 'bfd all-interfaces min-rx-interval 100 min-tx-interval 100 detect-multiplier 10', + 'import-route ospf 100 inherit-cost cost-type external cost 100 tag 100 route-policy import level-1', + 'default-route-advertise always cost 100 tag 100 level-1 avoid-learning', + 'import-route isis level-2 into level-1 filter-policy route-policy import tag 100 direct allow-filter-policy allow-up-down-bit', + 'preference 100 route-policy route', + 'filter-policy acl-name acl route-policy importimport', + 'filter-policy ip-prefix export route-policy export export ospf 100', + 'bfd all-interfaces min-rx-interval 100 min-tx-interval 100 detect-multiplier 10', + 'import-route ospf 100 inherit-cost cost-type external cost 100 tag 100 route-policy import level-1', + 'default-route-advertise always cost 100 tag 100 level-1 avoid-learning', + 'import-route isis level-2 into level-1 filter-policy route-policy import tag 100 direct allow-filter-policy allow-up-down-bit', + 'preference 100 route-policy route', + 'auto-cost enable', + 'auto-cost enable compatible'] + + config = dict( + instance_id=100, + description='ISIS', + islevel='level_1', + coststyle='narrow', + stdlevel2cost=60, + stdbandwidth=100, + autocostenable=True, + autocostenablecompatible=True, + netentity='netentity', + preference_value=100, + route_policy_name='route', + max_load=32, + ip_address='1.1.1.1', + weight=100, + penetration_direct='level2-level1', + import_routepolicy_name='import', + tag=100, + allow_filter=True, + allow_up_down=True, + enablelevel1tolevel2=True, + defaultmode='always', + mode_routepolicyname='mode', + cost=100, + mode_tag=100, + level_type='level_1', + avoid_learning=True, + protocol='ospf', + processid=100, + cost_type='external', + import_cost=100, + import_tag=100, + import_route_policy='import', + impotr_leveltype='level_1', + inheritcost=True, + permitibgp=True, + export_protocol='ospf', + export_policytype='aclNumOrName', + export_processid=100, + export_ipprefix='export', + export_routepolicyname='export', + import_aclnumorname='acl', + import_routepolicyname='import', + bfd_min_rx=100, + bfd_min_tx=100, + bfd_multiplier_num=10 + ) + set_module_args(config) + result = self.execute_module(changed=True) + self.assertEquals(sorted(result['updates']), sorted(update)) + + def test_ce_is_is_view_no_changed(self): + self.get_nc_config.side_effect = (self.after, self.after) + config = dict( + instance_id=100, + description='ISIS', + islevel='level_1', + coststyle='narrow', + stdlevel2cost=60, + stdbandwidth=100, + autocostenable=True, + autocostenablecompatible=True, + netentity='netentity', + preference_value=100, + route_policy_name='route', + max_load=32, + ip_address='1.1.1.1', + weight=100, + penetration_direct='level2-level1', + import_routepolicy_name='import', + tag=100, + allow_filter=True, + allow_up_down=True, + enablelevel1tolevel2=True, + defaultmode='always', + mode_routepolicyname='mode', + cost=100, + mode_tag=100, + level_type='level_1', + avoid_learning=True, + protocol='ospf', + processid=100, + cost_type='external', + import_cost=100, + import_tag=100, + import_route_policy='import', + impotr_leveltype='level_1', + inheritcost=True, + permitibgp=True, + export_protocol='ospf', + export_policytype='aclNumOrName', + export_processid=100, + export_ipprefix='export', + export_routepolicyname='export', + import_aclnumorname='acl', + import_routepolicyname='import', + bfd_min_rx=100, + bfd_min_tx=100, + bfd_multiplier_num=10 + ) + set_module_args(config) + self.execute_module(changed=False)