1#!/usr/local/bin/python3.8
2# -*- coding: utf-8 -*-
3# Copyright 2019 Red Hat
4# GNU General Public License v3.0+
5# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
6#
7
8from __future__ import (absolute_import, division, print_function)
9__metaclass__ = type
10
11DOCUMENTATION = '''
12---
13module: ce_is_is_interface
14version_added: '0.2.0'
15author: xuxiaowei0512 (@CloudEngine-Ansible)
16short_description: Manages isis interface configuration on HUAWEI CloudEngine devices.
17description:
18  - Manages isis process id, creates a isis instance id or deletes a process id on HUAWEI CloudEngine devices.
19notes:
20  - Interface must already be a L3 port when using this module.
21  - This module requires the netconf system service be enabled on the remote device being managed.
22  - This module works with connection C(netconf).
23options:
24  instance_id:
25    description:
26      - Specifies the id of a isis process.
27        The value is a number of 1 to 4294967295.
28    required: true
29    type: int
30  ifname:
31    description:
32      - A L3 interface.
33    required: true
34    type: str
35  leveltype:
36    description:
37      - level type for three types.
38    type: str
39    choices: ['level_1', 'level_2', 'level_1_2']
40  level1dispriority:
41    description:
42      - the dispriority of the level1.
43        The value is a number of 1 to 127.
44    type: int
45  level2dispriority:
46    description:
47      - the dispriority of the level1.
48        The value is a number of 1 to 127.
49    type: int
50  silentenable:
51    description:
52      - enable the interface can send isis message.
53        The value is a bool type.
54    type: bool
55  silentcost:
56    description:
57      - Specifies whether the routing cost of the silent interface is 0.
58        The value is a bool type.
59    type: bool
60  typep2penable:
61    description:
62      - Simulate the network type of the interface as P2P.
63        The value is a bool type.
64    type: bool
65  snpacheck:
66    description:
67      - Enable SNPA check for LSPs and SNPs.
68        The value is a bool type.
69    type: bool
70  p2pnegotiationmode:
71    description:
72       - Set the P2P neighbor negotiation type.
73    type: str
74    choices: ['2_way', '3_way', '3_wayonly']
75  p2ppeeripignore:
76    description:
77      - When the P2P hello packet is received, no IP address check is performed.
78        The value is a bool type.
79    type: bool
80  ppposicpcheckenable:
81    description:
82      - Interface for setting PPP link protocol to check OSICP negotiation status.
83        The value is a bool type.
84    type: bool
85  level1cost:
86    description:
87      - Specifies the link cost of the interface when performing Level-1 SPF calculation.
88        The value is a number of 0 to 16777215.
89    type: int
90  level2cost:
91    description:
92      - Specifies the link cost of the interface when performing Level-2 SPF calculation.
93        The value is a number of 0 to 16777215.
94    type: int
95  bfdstaticen:
96    description:
97      - Configure static BFD on a specific interface enabled with ISIS.
98        The value is a bool type.
99    type: bool
100  bfdblocken:
101    description:
102      - Blocking interfaces to dynamically create BFD features.
103        The value is a bool type.
104    type: bool
105  state:
106    description:
107      - Determines whether the config should be present or not on the device.
108    type: str
109    default: 'present'
110    choices: ['present', 'absent']
111'''
112
113EXAMPLES = '''
114  - name: "create vlan and config vlanif"
115    ce_config:
116      lines: 'vlan {{ test_vlan_id }},quit,interface {{test_intf_vlanif}},ip address {{test_vlanif_ip}} 24'
117      match: none
118
119  - name: "create eth-trunk and config eth-trunk"
120    ce_config:
121      lines: 'interface {{test_intf_trunk}},undo portswitch,ip address {{test_trunk_ip}} 24'
122      match: none
123
124  - name: "create vpn instance"
125    ce_config:
126      lines: 'ip vpn-instance {{test_vpn}},ipv4-family'
127      match: none
128
129  - name: Set isis circuit-level
130    community.network.ce_is_is_interface:
131      instance_id: 3
132      ifname: Eth-Trunk10
133      leveltype: level_1_2
134      state: present
135
136  - name: Set isis level1dispriority
137    community.network.ce_is_is_interface:
138      instance_id: 3
139      ifname: Eth-Trunk10
140      level1dispriority: 0
141      state: present
142
143  - name: Set isis level2dispriority
144    community.network.ce_is_is_interface:
145      instance_id: 3
146      ifname: Eth-Trunk10
147      level2dispriority: 0
148      state: present
149
150  - name: Set isis silentenable
151    community.network.ce_is_is_interface:
152      instance_id: 3
153      ifname: Eth-Trunk10
154      silentenable: true
155      state: present
156
157  - name: Set vpn name
158    ce_is_is_instance:
159      instance_id: 22
160      vpn_name: vpn1
161      state: present
162'''
163
164RETURN = '''
165proposed:
166    description: k/v pairs of parameters passed into module
167    returned: always
168    type: dict
169    sample: {
170        "addr_type": null,
171        "create_type": null,
172        "dest_addr": null,
173        "out_if_name": "10GE1/0/1",
174        "session_name": "bfd_l2link",
175        "src_addr": null,
176        "state": "present",
177        "use_default_ip": true,
178        "vrf_name": null
179    }
180existing:
181    description: k/v pairs of existing configuration
182    returned: always
183    type: dict
184    sample: {
185        "session": {}
186    }
187end_state:
188    description: k/v pairs of configuration after module execution
189    returned: always
190    type: dict
191    sample: {
192        "session": {
193            "addrType": "IPV4",
194            "createType": "SESS_STATIC",
195            "destAddr": null,
196            "outIfName": "10GE1/0/1",
197            "sessName": "bfd_l2link",
198            "srcAddr": null,
199            "useDefaultIp": "true",
200            "vrfName": null
201        }
202    }
203updates:
204    description: commands sent to the device
205    returned: always
206    type: list
207    sample: [
208        "bfd bfd_l2link bind peer-ip default-ip interface 10ge1/0/1"
209    ]
210changed:
211    description: check to see if a change was made on the device
212    returned: always
213    type: bool
214    sample: true
215'''
216
217import sys
218import socket
219from xml.etree import ElementTree
220from ansible.module_utils.basic import AnsibleModule
221from ansible_collections.community.network.plugins.module_utils.network.cloudengine.ce import get_nc_config, set_nc_config
222
223CE_NC_GET_ISIS = """
224    <filter type="subtree">
225      <isiscomm xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0">
226      %s
227      </isiscomm>
228    </filter>
229"""
230
231CE_NC_GET_ISIS_INTERFACE = """
232        <isSites>
233          <isSite>
234            <instanceId>%s</instanceId>
235            <isCircuits>
236              <isCircuit>
237                <ifName></ifName>
238                <circuitLevelType></circuitLevelType>
239                <level1DisPriority></level1DisPriority>
240                <level2DisPriority></level2DisPriority>
241                <silentEnable></silentEnable>
242                <silentCost></silentCost>
243                <typeP2pEnable></typeP2pEnable>
244                <snpaCheck></snpaCheck>
245                <p2pNegotiationMode></p2pNegotiationMode>
246                <p2pPeerIPIgnore></p2pPeerIPIgnore>
247                <pPPOsicpCheckEnable></pPPOsicpCheckEnable>
248                <level1Cost></level1Cost>
249                <level2Cost></level2Cost>
250              </isCircuit>
251            </isCircuits>
252          </isSite>
253        </isSites>
254"""
255
256CE_NC_MERGE_ISIS_INTERFACE = """
257        <isSites>
258          <isSite>
259            <instanceId>%s</instanceId>
260            <isCircuits>
261              <isCircuit operation="merge">
262              %s
263              </isCircuit>
264            </isCircuits>
265          </isSite>
266        </isSites>
267"""
268
269CE_NC_DELETE_ISIS_INTERFACE = """
270        <isSites>
271          <isSite>
272            <instanceId>%s</instanceId>
273            <isCircuits>
274              <isCircuit operation="delete">
275              %s
276              </isCircuit>
277            </isCircuits>
278          </isSite>
279        </isSites>
280"""
281
282CE_NC_GET_ISIS_BFDINTERFACE = """
283        <isSites>
284          <isSite>
285            <instanceId>%s</instanceId>
286            <isSiteMTs>
287              <isSiteMT>
288                <addressFamily>afIpv4</addressFamily>
289                <mtId>0</mtId>
290                <isCircMts>
291                  <isCircMt>
292                    <bfdStaticEn></bfdStaticEn>
293                    <bfdBlockEn></bfdBlockEn>
294                  </isCircMt>
295                </isCircMts>
296              </isSiteMT>
297            </isSiteMTs>
298          </isSite>
299        </isSites>
300"""
301
302CE_NC_MERGE_ISIS_BFDINTERFACE = """
303        <isSites>
304          <isSite>
305            <instanceId>%s</instanceId>
306            <isSiteMTs>
307              <isSiteMT>
308                <addressFamily>afIpv4</addressFamily>
309                <mtId>0</mtId>
310                <isCircMts>
311                  <isCircMt operation="merge">
312                  %s
313                  </isCircMt>
314                </isCircMts>
315              </isSiteMT>
316            </isSiteMTs>
317          </isSite>
318        </isSites>
319"""
320
321CE_NC_DELETE_ISIS_BFDINTERFACE = """
322        <isSites>
323          <isSite>
324            <instanceId>%s</instanceId>
325            <isSiteMTs>
326              <isSiteMT>
327                <addressFamily>afIpv4</addressFamily>
328                <mtId>0</mtId>
329                <isCircMts>
330                  <isCircMt operation="delete">
331                  %s
332                  </isCircMt>
333                </isCircMts>
334              </isSiteMT>
335            </isSiteMTs>
336          </isSite>
337        </isSites>
338"""
339
340
341def is_valid_ip_vpn(vpname):
342    """check ip vpn"""
343
344    if not vpname:
345        return False
346
347    if vpname == "_public_":
348        return False
349
350    if len(vpname) < 1 or len(vpname) > 31:
351        return False
352
353    return True
354
355
356def check_ip_addr(ipaddr):
357    """check ip address, Supports IPv4 and IPv6"""
358
359    if not ipaddr or '\x00' in ipaddr:
360        return False
361
362    try:
363        res = socket.getaddrinfo(ipaddr, 0, socket.AF_UNSPEC,
364                                 socket.SOCK_STREAM,
365                                 0, socket.AI_NUMERICHOST)
366        return bool(res)
367    except socket.gaierror:
368        err = sys.exc_info()[1]
369        if err.args[0] == socket.EAI_NONAME:
370            return False
371        raise
372
373    return True
374
375
376def check_default_ip(ipaddr):
377    """check the default multicast IP address"""
378
379    # The value ranges from 224.0.0.107 to 224.0.0.250
380    if not check_ip_addr(ipaddr):
381        return False
382
383    if ipaddr.count(".") != 3:
384        return False
385
386    ips = ipaddr.split(".")
387    if ips[0] != "224" or ips[1] != "0" or ips[2] != "0":
388        return False
389
390    if not ips[3].isdigit() or int(ips[3]) < 107 or int(ips[3]) > 250:
391        return False
392
393    return True
394
395
396def get_interface_type(interface):
397    """get the type of interface, such as 10GE, ETH-TRUNK, VLANIF..."""
398
399    if interface.upper().startswith('GE'):
400        return 'ge'
401    elif interface.upper().startswith('10GE'):
402        return '10ge'
403    elif interface.upper().startswith('25GE'):
404        return '25ge'
405    elif interface.upper().startswith('4X10GE'):
406        return '4x10ge'
407    elif interface.upper().startswith('40GE'):
408        return '40ge'
409    elif interface.upper().startswith('100GE'):
410        return '100ge'
411    elif interface.upper().startswith('VLANIF'):
412        return 'vlanif'
413    elif interface.upper().startswith('LOOPBACK'):
414        return 'loopback'
415    elif interface.upper().startswith('METH'):
416        return 'meth'
417    elif interface.upper().startswith('ETH-TRUNK'):
418        return 'eth-trunk'
419    elif interface.upper().startswith('VBDIF'):
420        return 'vbdif'
421    elif interface.upper().startswith('NVE'):
422        return 'nve'
423    elif interface.upper().startswith('TUNNEL'):
424        return 'tunnel'
425    elif interface.upper().startswith('ETHERNET'):
426        return 'ethernet'
427    elif interface.upper().startswith('FCOE-PORT'):
428        return 'fcoe-port'
429    elif interface.upper().startswith('FABRIC-PORT'):
430        return 'fabric-port'
431    elif interface.upper().startswith('STACK-PORT'):
432        return 'stack-port'
433    elif interface.upper().startswith('NULL'):
434        return 'null'
435    else:
436        return None
437
438
439class ISIS_Instance(object):
440    """Manages ISIS Instance"""
441
442    def __init__(self, argument_spec):
443        self.spec = argument_spec
444        self.module = None
445        self.__init_module__()
446
447        # module input info
448        self.instance_id = self.module.params['instance_id']
449        self.ifname = self.module.params['ifname']
450        self.leveltype = self.module.params['leveltype']
451        self.level1dispriority = self.module.params['level1dispriority']
452        self.level2dispriority = self.module.params['level2dispriority']
453        self.silentenable = self.module.params['silentenable']
454        self.silentcost = self.module.params['silentcost']
455        self.typep2penable = self.module.params['typep2penable']
456        self.snpacheck = self.module.params['snpacheck']
457        self.p2pnegotiationmode = self.module.params['p2pnegotiationmode']
458        self.p2ppeeripignore = self.module.params['p2ppeeripignore']
459        self.ppposicpcheckenable = self.module.params['ppposicpcheckenable']
460        self.level1cost = self.module.params['level1cost']
461        self.level2cost = self.module.params['level2cost']
462        self.bfdstaticen = self.module.params['bfdstaticen']
463        self.bfdblocken = self.module.params['bfdblocken']
464        self.state = self.module.params['state']
465
466        # state
467        self.changed = False
468        self.isis_dict = dict()
469        self.updates_cmd = list()
470        self.commands = list()
471        self.results = dict()
472        self.proposed = dict()
473        self.existing = dict()
474        self.end_state = dict()
475
476    def __init_module__(self):
477        """init module"""
478        mutually_exclusive = [["level1dispriority", "level2dispriority"],
479                              ["level1cost", "level2cost"]]
480        self.module = AnsibleModule(
481            argument_spec=self.spec,
482            mutually_exclusive=mutually_exclusive,
483            supports_check_mode=True)
484
485    def get_isis_dict(self):
486        """bfd config dict"""
487
488        isis_dict = dict()
489        isis_dict["instance"] = dict()
490        conf_str = CE_NC_GET_ISIS % (
491            (CE_NC_GET_ISIS_INTERFACE % self.instance_id))
492        if self.bfdstaticen or self.bfdblocken:
493            conf_str = CE_NC_GET_ISIS % (
494                (CE_NC_GET_ISIS_BFDINTERFACE % self.instance_id))
495
496        xml_str = get_nc_config(self.module, conf_str)
497        if "<data/>" in xml_str:
498            return isis_dict
499
500        xml_str = xml_str.replace('\r', '').replace('\n', '').\
501            replace('xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"', "").\
502            replace('xmlns="http://www.huawei.com/netconf/vrp"', "")
503        root = ElementTree.fromstring(xml_str)
504
505        #
506        glb = root.find("isiscomm/isSites/isSite/isCircuits/isCircuit")
507        if self.bfdstaticen or self.bfdblocken:
508            glb = root.find("isiscomm/isSites/isSite/isSiteMTs/isSiteMT/isCircMts/isCircMt")
509        if glb:
510            for attr in glb:
511                isis_dict["instance"][attr.tag] = attr.text
512
513        return isis_dict
514
515    def config_session(self):
516        """configures bfd session"""
517
518        xml_str = ""
519        instance = self.isis_dict["instance"]
520        if not self.instance_id:
521            return xml_str
522        if self.ifname:
523            xml_str = "<ifName>%s</ifName>" % self.ifname
524            self.updates_cmd.append("interface %s" % self.ifname)
525        if self.state == "present":
526            self.updates_cmd.append("isis enable %s" % self.instance_id)
527
528            if self.leveltype:
529                if self.leveltype == "level_1":
530                    xml_str += "<circuitLevelType>level_1</circuitLevelType>"
531                    self.updates_cmd.append("isis circuit-level level-1")
532                elif self.leveltype == "level_2":
533                    xml_str += "<circuitLevelType>level_2</circuitLevelType>"
534                    self.updates_cmd.append("isis circuit-level level-2")
535                elif self.leveltype == "level_1_2":
536                    xml_str += "<circuitLevelType>level_1_2</circuitLevelType>"
537                    self.updates_cmd.append("isis circuit-level level-1-2")
538            if self.level1dispriority is not None:
539                xml_str += "<level1DisPriority>%s</level1DisPriority>" % self.level1dispriority
540                self.updates_cmd.append("isis dis-priority %s level-1" % self.level1dispriority)
541            if self.level2dispriority is not None:
542                xml_str += "<level2DisPriority>%s</level2DisPriority>" % self.level2dispriority
543                self.updates_cmd.append("isis dis-priority %s level-2" % self.level2dispriority)
544            if self.p2pnegotiationmode:
545                if self.p2pnegotiationmode == "2_way":
546                    xml_str += "<p2pNegotiationMode>2_way</p2pNegotiationMode>"
547                    self.updates_cmd.append("isis ppp-negotiation 2-way")
548                elif self.p2pnegotiationmode == "3_way":
549                    xml_str += "<p2pNegotiationMode>3_way</p2pNegotiationMode>"
550                    self.updates_cmd.append("isis ppp-negotiation 3-way")
551                elif self.p2pnegotiationmode == "3_wayonly":
552                    xml_str += "<p2pNegotiationMode>3_wayonly</p2pNegotiationMode>"
553                    self.updates_cmd.append("isis ppp-negotiation only")
554            if self.level1cost is not None:
555                xml_str += "<level1Cost>%s</level1Cost>" % self.level1cost
556                self.updates_cmd.append("isis cost %s level-1" % self.level1cost)
557            if self.level2cost is not None:
558                xml_str += "<level2Cost>%s</level2Cost>" % self.level2cost
559                self.updates_cmd.append("isis cost %s level-2" % self.level2cost)
560
561        else:
562            # absent
563            self.updates_cmd.append("undo isis enable")
564            if self.leveltype and self.leveltype == instance.get("circuitLevelType"):
565                xml_str += "<circuitLevelType>level_1_2</circuitLevelType>"
566                self.updates_cmd.append("undo isis circuit-level")
567            if self.level1dispriority is not None and self.level1dispriority == instance.get("level1DisPriority"):
568                xml_str += "<level1DisPriority>64</level1DisPriority>"
569                self.updates_cmd.append("undo isis dis-priority %s level-1" % self.level1dispriority)
570            if self.level2dispriority is not None and self.level2dispriority == instance.get("level2dispriority"):
571                xml_str += "<level2dispriority>64</level2dispriority>"
572                self.updates_cmd.append("undo isis dis-priority %s level-2" % self.level2dispriority)
573            if self.p2pnegotiationmode and self.p2pnegotiationmode == instance.get("p2pNegotiationMode"):
574                xml_str += "<p2pNegotiationMode/>"
575                self.updates_cmd.append("undo isis ppp-negotiation")
576            if self.level1cost is not None and self.level1cost == instance.get("level1Cost"):
577                xml_str += "<level1Cost/>"
578                self.updates_cmd.append("undo isis cost %s level-1" % self.level1cost)
579            if self.level2cost is not None and self.level2cost == instance.get("level2Cost"):
580                xml_str += "<level2Cost/>"
581                self.updates_cmd.append("undo isis cost %s level-2" % self.level2cost)
582
583        if self.silentenable and instance.get("silentEnable", "false") == "false":
584            xml_str += "<silentEnable>true</silentEnable>"
585            self.updates_cmd.append("isis silent")
586        elif not self.silentenable and instance.get("silentEnable", "false") == "true":
587            xml_str += "<silentEnable>false</silentEnable>"
588            self.updates_cmd.append("undo isis silent")
589
590        if self.silentcost and instance.get("silentCost", "false") == "false":
591            xml_str += "<silentCost>true</silentCost>"
592            self.updates_cmd.append("isis silent advertise-zero-cost")
593        elif not self.silentcost and instance.get("silentCost", "false") == "true":
594            xml_str += "<silentCost>false</silentCost>"
595
596        if self.typep2penable and instance.get("typeP2pEnable", "false") == "false":
597            xml_str += "<typeP2pEnable>true</typeP2pEnable>"
598            self.updates_cmd.append("isis circuit-type p2p")
599        elif not self.typep2penable and instance.get("typeP2pEnable", "false") == "true":
600            xml_str += "<typeP2pEnable>false</typeP2pEnable>"
601            self.updates_cmd.append("undo isis circuit-type")
602
603        if self.snpacheck and instance.get("snpaCheck", "false") == "false":
604            xml_str += "<snpaCheck>true</snpaCheck>"
605            self.updates_cmd.append("isis circuit-type p2p strict-snpa-check")
606        elif not self.snpacheck and instance.get("snpaCheck", "false") == "true":
607            xml_str += "<snpaCheck>false</snpaCheck>"
608
609        if self.p2ppeeripignore and instance.get("p2pPeerIPIgnore", "false") == "false":
610            xml_str += "<p2pPeerIPIgnore>true</p2pPeerIPIgnore>"
611            self.updates_cmd.append("isis peer-ip-ignore")
612        elif not self.p2ppeeripignore and instance.get("p2pPeerIPIgnore", "false") == "true":
613            xml_str += "<p2pPeerIPIgnore>false</p2pPeerIPIgnore>"
614            self.updates_cmd.append("undo isis peer-ip-ignore")
615
616        if self.ppposicpcheckenable and instance.get("pPPOsicpCheckEnable", "false") == "false":
617            xml_str += "<pPPOsicpCheckEnable>true</pPPOsicpCheckEnable>"
618            self.updates_cmd.append("isis ppp-osicp-check")
619        elif not self.ppposicpcheckenable and instance.get("pPPOsicpCheckEnable", "false") == "true":
620            xml_str += "<pPPOsicpCheckEnable>false</pPPOsicpCheckEnable>"
621            self.updates_cmd.append("undo isis ppp-osicp-check")
622        if self.bfdstaticen and instance.get("bfdStaticEn", "false") == "false":
623            xml_str += "<bfdStaticEn>true</bfdStaticEn>"
624            self.updates_cmd.append("isis bfd static")
625        elif not self.bfdstaticen and instance.get("bfdStaticEn", "false") == "true":
626            xml_str += "<bfdStaticEn>false</bfdStaticEn>"
627            self.updates_cmd.append("undo isis bfd static")
628        if self.bfdblocken and instance.get("bfdBlockEn", "false") == "false":
629            xml_str += "<bfdBlockEn>true</bfdBlockEn>"
630            self.updates_cmd.append("isis bfd block")
631        elif not self.bfdblocken and instance.get("bfdBlockEn", "false") == "true":
632            xml_str += "<bfdBlockEn>false</bfdBlockEn>"
633            self.updates_cmd.append("undo isis bfd block")
634
635        if self.state == "present":
636            if self.bfdstaticen is not None or self.bfdblocken is not None:
637                return CE_NC_MERGE_ISIS_BFDINTERFACE % (self.instance_id, xml_str)
638            return CE_NC_MERGE_ISIS_INTERFACE % (self.instance_id, xml_str)
639        else:
640            if self.bfdstaticen is not None or self.bfdblocken is not None:
641                return CE_NC_DELETE_ISIS_BFDINTERFACE % (self.instance_id, xml_str)
642            return CE_NC_DELETE_ISIS_INTERFACE % (self.instance_id, xml_str)
643
644    def netconf_load_config(self, xml_str):
645        """load bfd config by netconf"""
646
647        if not xml_str:
648            return
649
650        xml_cfg = """
651            <config>
652            <isiscomm xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0">
653            %s
654            </isiscomm>
655            </config>""" % xml_str
656        set_nc_config(self.module, xml_cfg)
657        self.changed = True
658
659    def check_params(self):
660        """Check all input params"""
661
662        # check instance id
663        if not self.instance_id:
664            self.module.fail_json(msg="Error: Missing required arguments: instance_id.")
665
666        if self.instance_id:
667            if self.instance_id < 1 or self.instance_id > 4294967295:
668                self.module.fail_json(msg="Error: Instance id is not ranges from 1 to 4294967295.")
669
670        # check level1dispriority
671        if self.level1dispriority is not None:
672            if self.level1dispriority < 0 or self.level1dispriority > 127:
673                self.module.fail_json(msg="Error: level1dispriority is not ranges from 0 to 127.")
674
675        if self.level2dispriority is not None:
676            if self.level2dispriority < 0 or self.level2dispriority > 127:
677                self.module.fail_json(msg="Error: level2dispriority is not ranges from 0 to 127.")
678
679        if self.level1cost is not None:
680            if self.level1cost < 0 or self.level1cost > 16777215:
681                self.module.fail_json(msg="Error: level1cost is not ranges from 0 to 16777215.")
682
683        if self.level2cost is not None:
684            if self.level2cost < 0 or self.level2cost > 16777215:
685                self.module.fail_json(msg="Error: level2cost is not ranges from 0 to 16777215.")
686
687    def get_proposed(self):
688        """get proposed info"""
689        self.proposed["instance_id"] = self.instance_id
690        self.proposed["ifname"] = self.ifname
691        self.proposed["leveltype"] = self.leveltype
692        self.proposed["level1dispriority"] = self.level1dispriority
693        self.proposed["level2dispriority"] = self.level2dispriority
694        self.proposed["silentenable"] = self.silentenable
695        self.proposed["silentcost"] = self.silentcost
696        self.proposed["typep2penable"] = self.typep2penable
697        self.proposed["snpacheck"] = self.snpacheck
698        self.proposed["p2pnegotiationmode"] = self.p2pnegotiationmode
699        self.proposed["p2ppeeripignore"] = self.p2ppeeripignore
700        self.proposed["ppposicpcheckenable"] = self.ppposicpcheckenable
701        self.proposed["level1cost"] = self.level1cost
702        self.proposed["level2cost"] = self.level2cost
703        self.proposed["bfdstaticen"] = self.bfdstaticen
704        self.proposed["bfdblocken"] = self.bfdblocken
705        self.proposed["state"] = self.state
706
707    def get_existing(self):
708        """get existing info"""
709
710        if not self.isis_dict:
711            self.existing["instance"] = None
712        else:
713            self.existing["instance"] = self.isis_dict.get("instance")
714
715    def get_end_state(self):
716        """get end state info"""
717
718        isis_dict = self.get_isis_dict()
719        if not isis_dict:
720            self.end_state["instance"] = None
721        else:
722            self.end_state["instance"] = isis_dict.get("instance")
723        if self.existing == self.end_state:
724            self.changed = False
725
726    def work(self):
727        """worker"""
728
729        self.check_params()
730        self.isis_dict = self.get_isis_dict()
731        self.get_existing()
732        self.get_proposed()
733
734        # deal present or absent
735        xml_str = ''
736        if self.instance_id:
737            xml_str += self.config_session()
738
739        # update to device
740        if xml_str:
741            self.netconf_load_config(xml_str)
742            self.changed = True
743
744        self.get_end_state()
745        self.results['changed'] = self.changed
746        self.results['proposed'] = self.proposed
747        self.results['existing'] = self.existing
748        self.results['end_state'] = self.end_state
749        if self.changed:
750            self.results['updates'] = self.updates_cmd
751        else:
752            self.results['updates'] = list()
753
754        self.module.exit_json(**self.results)
755
756
757def main():
758    """Module main"""
759
760    argument_spec = dict(
761        instance_id=dict(required=True, type='int'),
762        ifname=dict(required=True, type='str'),
763        leveltype=dict(required=False, type='str', choices=['level_1', 'level_2', 'level_1_2']),
764        level1dispriority=dict(required=False, type='int'),
765        level2dispriority=dict(required=False, type='int'),
766        silentenable=dict(required=False, type='bool'),
767        silentcost=dict(required=False, type='bool'),
768        typep2penable=dict(required=False, type='bool'),
769        snpacheck=dict(required=False, type='bool'),
770        p2pnegotiationmode=dict(required=False, type='str', choices=['2_way', '3_way', '3_wayonly']),
771        p2ppeeripignore=dict(required=False, type='bool'),
772        ppposicpcheckenable=dict(required=False, type='bool'),
773        level1cost=dict(required=False, type='int'),
774        level2cost=dict(required=False, type='int'),
775        bfdstaticen=dict(required=False, type='bool'),
776        bfdblocken=dict(required=False, type='bool'),
777        state=dict(required=False, default='present', choices=['present', 'absent'])
778    )
779
780    module = ISIS_Instance(argument_spec)
781    module.work()
782
783
784if __name__ == '__main__':
785    main()
786