mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
Contributing lib/ansible/modules/network/cloudengine/ce_interface_ospf.py module to manage HUAWEI data center CloudEngine (#22051)
* add ce_interface_ospf add ce_interface_ospf * upgrade Interface OSPF * fix CI issues
This commit is contained in:
parent
7c78a86338
commit
16bea773b8
1 changed files with 810 additions and 0 deletions
810
lib/ansible/modules/network/cloudengine/ce_interface_ospf.py
Normal file
810
lib/ansible/modules/network/cloudengine/ce_interface_ospf.py
Normal file
|
@ -0,0 +1,810 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'metadata_version': '1.0'}
|
||||
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ce_interface_ospf
|
||||
version_added: "2.4"
|
||||
short_description: Manages configuration of an OSPF interface instanceon HUAWEI CloudEngine switches.
|
||||
description:
|
||||
- Manages configuration of an OSPF interface instanceon HUAWEI CloudEngine switches.
|
||||
author: QijunPan (@CloudEngine-Ansible)
|
||||
options:
|
||||
interface:
|
||||
description:
|
||||
- Full name of interface, i.e. 40GE1/0/10.
|
||||
required: true
|
||||
process_id:
|
||||
description:
|
||||
- Specifies a process ID.
|
||||
The value is an integer ranging from 1 to 4294967295.
|
||||
required: true
|
||||
area:
|
||||
description:
|
||||
- Ospf area associated with this ospf process.
|
||||
Valid values are a string, formatted as an IP address
|
||||
(i.e. "0.0.0.0") or as an integer between 1 and 4294967295.
|
||||
required: true
|
||||
cost:
|
||||
description:
|
||||
- The cost associated with this interface.
|
||||
Valid values are an integer in the range from 1 to 65535.
|
||||
required: false
|
||||
default: null
|
||||
hello_interval:
|
||||
description:
|
||||
- Time between sending successive hello packets.
|
||||
Valid values are an integer in the range from 1 to 65535.
|
||||
required: false
|
||||
default: null
|
||||
dead_interval:
|
||||
description:
|
||||
- Time interval an ospf neighbor waits for a hello
|
||||
packet before tearing down adjacencies. Valid values are an
|
||||
integer in the range from 1 to 235926000.
|
||||
required: false
|
||||
default: null
|
||||
silent_interface:
|
||||
description:
|
||||
- Setting to true will prevent this interface from receiving
|
||||
HELLO packets. Valid values are 'true' and 'false'.
|
||||
required: false
|
||||
default: false
|
||||
auth_mode:
|
||||
description:
|
||||
- Specifies the authentication type.
|
||||
required: false
|
||||
choices: ['none', 'null', 'hmac-sha256', 'md5', 'hmac-md5', 'simple']
|
||||
default: null
|
||||
auth_text_simple:
|
||||
description:
|
||||
- Specifies a password for simple authentication.
|
||||
The value is a string of 1 to 8 characters.
|
||||
required: false
|
||||
default: null
|
||||
auth_key_id:
|
||||
description:
|
||||
- Authentication key id when C(auth_mode) is 'hmac-sha256', 'md5' or 'hmac-md5.
|
||||
Valid value is an integer is in the range from 1 to 255.
|
||||
required: false
|
||||
default: null
|
||||
auth_text_md5:
|
||||
description:
|
||||
- Specifies a password for MD5, HMAC-MD5, or HMAC-SHA256 authentication.
|
||||
The value is a string of 1 to 255 case-sensitive characters, spaces not supported.
|
||||
required: false
|
||||
default: null
|
||||
state:
|
||||
description:
|
||||
- Determines whether the config should be present or not
|
||||
on the device.
|
||||
required: false
|
||||
default: present
|
||||
choices: ['present','absent']
|
||||
"""
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: eth_trunk module test
|
||||
hosts: cloudengine
|
||||
connection: local
|
||||
gather_facts: no
|
||||
vars:
|
||||
cli:
|
||||
host: "{{ inventory_hostname }}"
|
||||
port: "{{ ansible_ssh_port }}"
|
||||
username: "{{ username }}"
|
||||
password: "{{ password }}"
|
||||
transport: cli
|
||||
|
||||
tasks:
|
||||
- name: Enables OSPF and sets the cost on an interface
|
||||
ce_interface_ospf:
|
||||
interface: 10GE1/0/30
|
||||
process_id: 1
|
||||
area: 100
|
||||
cost: 100
|
||||
provider: '{{ cli }}'
|
||||
|
||||
- name: Sets the dead interval of the OSPF neighbor
|
||||
ce_interface_ospf:
|
||||
interface: 10GE1/0/30
|
||||
process_id: 1
|
||||
area: 100
|
||||
dead_interval: 100
|
||||
provider: '{{ cli }}'
|
||||
|
||||
- name: Sets the interval for sending Hello packets on an interface
|
||||
ce_interface_ospf:
|
||||
interface: 10GE1/0/30
|
||||
process_id: 1
|
||||
area: 100
|
||||
hello_interval: 2
|
||||
provider: '{{ cli }}'
|
||||
|
||||
- name: Disables an interface from receiving and sending OSPF packets
|
||||
ce_interface_ospf:
|
||||
interface: 10GE1/0/30
|
||||
process_id: 1
|
||||
area: 100
|
||||
silent_interface: true
|
||||
provider: '{{ cli }}'
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
proposed:
|
||||
description: k/v pairs of parameters passed into module
|
||||
returned: verbose mode
|
||||
type: dict
|
||||
sample: {"process_id": "1", "area": "0.0.0.100", "interface": "10GE1/0/30", "cost": "100"}
|
||||
existing:
|
||||
description: k/v pairs of existing configuration
|
||||
returned: verbose mode
|
||||
type: dict
|
||||
sample: {"process_id": "1", "area": "0.0.0.100"}
|
||||
end_state:
|
||||
description: k/v pairs of configuration after module execution
|
||||
returned: verbose mode
|
||||
type: dict
|
||||
sample: {"process_id": "1", "area": "0.0.0.100", "interface": "10GE1/0/30",
|
||||
"cost": "100", "dead_interval": "40", "hello_interval": "10",
|
||||
"process_id": "6", "silent_interface": "false", "auth_mode": "none"}
|
||||
updates:
|
||||
description: commands sent to the device
|
||||
returned: always
|
||||
type: list
|
||||
sample: ["interface 10GE1/0/30",
|
||||
"ospf enable 1 area 0.0.0.100",
|
||||
"ospf cost 100"]
|
||||
changed:
|
||||
description: check to see if a change was made on the device
|
||||
returned: always
|
||||
type: boolean
|
||||
sample: true
|
||||
'''
|
||||
|
||||
from xml.etree import ElementTree
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.ce import get_nc_config, set_nc_config, ce_argument_spec
|
||||
|
||||
CE_NC_GET_OSPF = """
|
||||
<filter type="subtree">
|
||||
<ospfv2 xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0">
|
||||
<ospfv2comm>
|
||||
<ospfSites>
|
||||
<ospfSite>
|
||||
<processId>%s</processId>
|
||||
<routerId></routerId>
|
||||
<vrfName></vrfName>
|
||||
<areas>
|
||||
<area>
|
||||
<areaId>%s</areaId>
|
||||
<interfaces>
|
||||
<interface>
|
||||
<ifName>%s</ifName>
|
||||
<networkType></networkType>
|
||||
<helloInterval></helloInterval>
|
||||
<deadInterval></deadInterval>
|
||||
<silentEnable></silentEnable>
|
||||
<configCost></configCost>
|
||||
<authenticationMode></authenticationMode>
|
||||
<authTextSimple></authTextSimple>
|
||||
<keyId></keyId>
|
||||
<authTextMd5></authTextMd5>
|
||||
</interface>
|
||||
</interfaces>
|
||||
</area>
|
||||
</areas>
|
||||
</ospfSite>
|
||||
</ospfSites>
|
||||
</ospfv2comm>
|
||||
</ospfv2>
|
||||
</filter>
|
||||
"""
|
||||
|
||||
CE_NC_XML_BUILD_PROCESS = """
|
||||
<config>
|
||||
<ospfv2 xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0">
|
||||
<ospfv2comm>
|
||||
<ospfSites>
|
||||
<ospfSite>
|
||||
<processId>%s</processId>
|
||||
<areas>
|
||||
<area>
|
||||
<areaId>%s</areaId>
|
||||
%s
|
||||
</area>
|
||||
</areas>
|
||||
</ospfSite>
|
||||
</ospfSites>
|
||||
</ospfv2comm>
|
||||
</ospfv2>
|
||||
</config>
|
||||
"""
|
||||
|
||||
CE_NC_XML_BUILD_MERGE_INTF = """
|
||||
<interfaces>
|
||||
<interface operation="merge">
|
||||
%s
|
||||
</interface>
|
||||
</interfaces>
|
||||
"""
|
||||
|
||||
CE_NC_XML_BUILD_DELETE_INTF = """
|
||||
<interfaces>
|
||||
<interface operation="delete">
|
||||
%s
|
||||
</interface>
|
||||
</interfaces>
|
||||
"""
|
||||
CE_NC_XML_SET_IF_NAME = """
|
||||
<ifName>%s</ifName>
|
||||
"""
|
||||
|
||||
CE_NC_XML_SET_HELLO = """
|
||||
<helloInterval>%s</helloInterval>
|
||||
"""
|
||||
|
||||
CE_NC_XML_SET_DEAD = """
|
||||
<deadInterval>%s</deadInterval>
|
||||
"""
|
||||
|
||||
CE_NC_XML_SET_SILENT = """
|
||||
<silentEnable>%s</silentEnable>
|
||||
"""
|
||||
|
||||
CE_NC_XML_SET_COST = """
|
||||
<configCost>%s</configCost>
|
||||
"""
|
||||
|
||||
CE_NC_XML_SET_AUTH_MODE = """
|
||||
<authenticationMode>%s</authenticationMode>
|
||||
"""
|
||||
|
||||
|
||||
CE_NC_XML_SET_AUTH_TEXT_SIMPLE = """
|
||||
<authTextSimple>%s</authTextSimple>
|
||||
"""
|
||||
|
||||
CE_NC_XML_SET_AUTH_MD5 = """
|
||||
<keyId>%s</keyId>
|
||||
<authTextMd5>%s</authTextMd5>
|
||||
"""
|
||||
|
||||
|
||||
def get_interface_type(interface):
|
||||
"""Gets the type of interface, such as 10GE, ETH-TRUNK, VLANIF..."""
|
||||
|
||||
if interface is None:
|
||||
return None
|
||||
|
||||
iftype = 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()
|
||||
|
||||
|
||||
def is_valid_v4addr(addr):
|
||||
"""check is ipv4 addr is valid"""
|
||||
|
||||
if not addr:
|
||||
return False
|
||||
|
||||
if addr.find('.') != -1:
|
||||
addr_list = addr.split('.')
|
||||
if len(addr_list) != 4:
|
||||
return False
|
||||
for each_num in addr_list:
|
||||
if not each_num.isdigit():
|
||||
return False
|
||||
if int(each_num) > 255:
|
||||
return False
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
class InterfaceOSPF(object):
|
||||
"""
|
||||
Manages configuration of an OSPF interface instance.
|
||||
"""
|
||||
|
||||
def __init__(self, argument_spec):
|
||||
self.spec = argument_spec
|
||||
self.module = None
|
||||
self.init_module()
|
||||
|
||||
# module input info
|
||||
self.interface = self.module.params['interface']
|
||||
self.process_id = self.module.params['process_id']
|
||||
self.area = self.module.params['area']
|
||||
self.cost = self.module.params['cost']
|
||||
self.hello_interval = self.module.params['hello_interval']
|
||||
self.dead_interval = self.module.params['dead_interval']
|
||||
self.silent_interface = self.module.params['silent_interface']
|
||||
self.auth_mode = self.module.params['auth_mode']
|
||||
self.auth_text_simple = self.module.params['auth_text_simple']
|
||||
self.auth_key_id = self.module.params['auth_key_id']
|
||||
self.auth_text_md5 = self.module.params['auth_text_md5']
|
||||
self.state = self.module.params['state']
|
||||
|
||||
# ospf info
|
||||
self.ospf_info = dict()
|
||||
|
||||
# state
|
||||
self.changed = False
|
||||
self.updates_cmd = list()
|
||||
self.results = dict()
|
||||
self.proposed = dict()
|
||||
self.existing = dict()
|
||||
self.end_state = dict()
|
||||
|
||||
def init_module(self):
|
||||
"""init module"""
|
||||
|
||||
self.module = AnsibleModule(
|
||||
argument_spec=self.spec, supports_check_mode=True)
|
||||
|
||||
def netconf_set_config(self, xml_str, xml_name):
|
||||
"""netconf set config"""
|
||||
|
||||
rcv_xml = set_nc_config(self.module, xml_str)
|
||||
if "<ok/>" not in rcv_xml:
|
||||
self.module.fail_json(msg='Error: %s failed.' % xml_name)
|
||||
|
||||
def get_area_ip(self):
|
||||
"""convert integer to ip address"""
|
||||
|
||||
if not self.area.isdigit():
|
||||
return self.area
|
||||
|
||||
addr_int = ['0'] * 4
|
||||
addr_int[0] = str(((int(self.area) & 0xFF000000) >> 24) & 0xFF)
|
||||
addr_int[1] = str(((int(self.area) & 0x00FF0000) >> 16) & 0xFF)
|
||||
addr_int[2] = str(((int(self.area) & 0x0000FF00) >> 8) & 0XFF)
|
||||
addr_int[3] = str(int(self.area) & 0xFF)
|
||||
|
||||
return '.'.join(addr_int)
|
||||
|
||||
def get_ospf_dict(self):
|
||||
""" get one ospf attributes dict."""
|
||||
|
||||
ospf_info = dict()
|
||||
conf_str = CE_NC_GET_OSPF % (
|
||||
self.process_id, self.get_area_ip(), self.interface)
|
||||
rcv_xml = get_nc_config(self.module, conf_str)
|
||||
|
||||
if "<data/>" in rcv_xml:
|
||||
return ospf_info
|
||||
|
||||
xml_str = rcv_xml.replace('\r', '').replace('\n', '').\
|
||||
replace('xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"', "").\
|
||||
replace('xmlns="http://www.huawei.com/netconf/vrp"', "")
|
||||
|
||||
# get process base info
|
||||
root = ElementTree.fromstring(xml_str)
|
||||
ospfsite = root.find("data/ospfv2/ospfv2comm/ospfSites/ospfSite")
|
||||
if not ospfsite:
|
||||
self.module.fail_json(msg="Error: ospf process does not exist.")
|
||||
|
||||
for site in ospfsite:
|
||||
if site.tag in ["processId", "routerId", "vrfName"]:
|
||||
ospf_info[site.tag] = site.text
|
||||
|
||||
# get areas info
|
||||
ospf_info["areaId"] = ""
|
||||
areas = root.find(
|
||||
"data/ospfv2/ospfv2comm/ospfSites/ospfSite/areas/area")
|
||||
if areas:
|
||||
for area in areas:
|
||||
if area.tag == "areaId":
|
||||
ospf_info["areaId"] = area.text
|
||||
break
|
||||
|
||||
# get interface info
|
||||
ospf_info["interface"] = dict()
|
||||
intf = root.find(
|
||||
"data/ospfv2/ospfv2comm/ospfSites/ospfSite/areas/area/interfaces/interface")
|
||||
if intf:
|
||||
for attr in intf:
|
||||
if attr.tag in ["ifName", "networkType",
|
||||
"helloInterval", "deadInterval",
|
||||
"silentEnable", "configCost",
|
||||
"authenticationMode", "authTextSimple",
|
||||
"keyId", "authTextMd5"]:
|
||||
ospf_info["interface"][attr.tag] = attr.text
|
||||
|
||||
return ospf_info
|
||||
|
||||
def set_ospf_interface(self):
|
||||
"""set interface ospf enable, and set its ospf attributes"""
|
||||
|
||||
xml_intf = CE_NC_XML_SET_IF_NAME % self.interface
|
||||
|
||||
# ospf view
|
||||
self.updates_cmd.append("ospf %s" % self.process_id)
|
||||
self.updates_cmd.append("area %s" % self.get_area_ip())
|
||||
if self.silent_interface:
|
||||
xml_intf += CE_NC_XML_SET_SILENT % str(self.silent_interface).lower()
|
||||
if self.silent_interface:
|
||||
self.updates_cmd.append("silent-interface %s" % self.interface)
|
||||
else:
|
||||
self.updates_cmd.append("undo silent-interface %s" % self.interface)
|
||||
|
||||
# interface view
|
||||
self.updates_cmd.append("interface %s" % self.interface)
|
||||
self.updates_cmd.append("ospf enable process %s area %s" % (
|
||||
self.process_id, self.get_area_ip()))
|
||||
if self.cost:
|
||||
xml_intf += CE_NC_XML_SET_COST % self.cost
|
||||
self.updates_cmd.append("ospf cost %s" % self.cost)
|
||||
if self.hello_interval:
|
||||
xml_intf += CE_NC_XML_SET_HELLO % self.hello_interval
|
||||
self.updates_cmd.append("ospf timer hello %s" %
|
||||
self.hello_interval)
|
||||
if self.dead_interval:
|
||||
xml_intf += CE_NC_XML_SET_DEAD % self.dead_interval
|
||||
self.updates_cmd.append("ospf timer dead %s" % self.dead_interval)
|
||||
if self.auth_mode:
|
||||
xml_intf += CE_NC_XML_SET_AUTH_MODE % self.auth_mode
|
||||
if self.auth_mode == "none":
|
||||
self.updates_cmd.append("undo ospf authentication-mode")
|
||||
else:
|
||||
self.updates_cmd.append("ospf authentication-mode %s" % self.auth_mode)
|
||||
if self.auth_mode == "simple" and self.auth_text_simple:
|
||||
xml_intf += CE_NC_XML_SET_AUTH_TEXT_SIMPLE % self.auth_text_simple
|
||||
self.updates_cmd.pop()
|
||||
self.updates_cmd.append("ospf authentication-mode %s %s"
|
||||
% (self.auth_mode, self.auth_text_simple))
|
||||
elif self.auth_mode in ["hmac-sha256", "md5", "hmac-md5"] and self.auth_key_id:
|
||||
xml_intf += CE_NC_XML_SET_AUTH_MD5 % (
|
||||
self.auth_key_id, self.auth_text_md5)
|
||||
self.updates_cmd.pop()
|
||||
self.updates_cmd.append("ospf authentication-mode %s %s %s"
|
||||
% (self.auth_mode, self.auth_key_id, self.auth_text_md5))
|
||||
else:
|
||||
pass
|
||||
|
||||
xml_str = CE_NC_XML_BUILD_PROCESS % (self.process_id,
|
||||
self.get_area_ip(),
|
||||
(CE_NC_XML_BUILD_MERGE_INTF % xml_intf))
|
||||
self.netconf_set_config(xml_str, "SET_INTERFACE_OSPF")
|
||||
self.changed = True
|
||||
|
||||
def merge_ospf_interface(self):
|
||||
"""merge interface ospf attributes"""
|
||||
|
||||
intf_dict = self.ospf_info["interface"]
|
||||
|
||||
# ospf view
|
||||
xml_ospf = ""
|
||||
if intf_dict.get("silentEnable") != str(self.silent_interface).lower():
|
||||
xml_ospf += CE_NC_XML_SET_SILENT % str(self.silent_interface).lower()
|
||||
self.updates_cmd.append("ospf %s" % self.process_id)
|
||||
self.updates_cmd.append("area %s" % self.get_area_ip())
|
||||
if self.silent_interface:
|
||||
self.updates_cmd.append("silent-interface %s" % self.interface)
|
||||
else:
|
||||
self.updates_cmd.append("undo silent-interface %s" % self.interface)
|
||||
|
||||
# interface view
|
||||
xml_intf = ""
|
||||
self.updates_cmd.append("interface %s" % self.interface)
|
||||
if self.cost and intf_dict.get("configCost") != self.cost:
|
||||
xml_intf += CE_NC_XML_SET_COST % self.cost
|
||||
self.updates_cmd.append("ospf cost %s" % self.cost)
|
||||
if self.hello_interval and intf_dict.get("helloInterval") != self.hello_interval:
|
||||
xml_intf += CE_NC_XML_SET_HELLO % self.hello_interval
|
||||
self.updates_cmd.append("ospf timer hello %s" %
|
||||
self.hello_interval)
|
||||
if self.dead_interval and intf_dict.get("deadInterval") != self.dead_interval:
|
||||
xml_intf += CE_NC_XML_SET_DEAD % self.dead_interval
|
||||
self.updates_cmd.append("ospf timer dead %s" % self.dead_interval)
|
||||
if self.auth_mode:
|
||||
# NOTE: for security, authentication config will always be update
|
||||
xml_intf += CE_NC_XML_SET_AUTH_MODE % self.auth_mode
|
||||
if self.auth_mode == "none":
|
||||
self.updates_cmd.append("undo ospf authentication-mode")
|
||||
else:
|
||||
self.updates_cmd.append("ospf authentication-mode %s" % self.auth_mode)
|
||||
if self.auth_mode == "simple" and self.auth_text_simple:
|
||||
xml_intf += CE_NC_XML_SET_AUTH_TEXT_SIMPLE % self.auth_text_simple
|
||||
self.updates_cmd.pop()
|
||||
self.updates_cmd.append("ospf authentication-mode %s %s"
|
||||
% (self.auth_mode, self.auth_text_simple))
|
||||
elif self.auth_mode in ["hmac-sha256", "md5", "hmac-md5"] and self.auth_key_id:
|
||||
xml_intf += CE_NC_XML_SET_AUTH_MD5 % (
|
||||
self.auth_key_id, self.auth_text_md5)
|
||||
self.updates_cmd.pop()
|
||||
self.updates_cmd.append("ospf authentication-mode %s %s %s"
|
||||
% (self.auth_mode, self.auth_key_id, self.auth_text_md5))
|
||||
else:
|
||||
pass
|
||||
if not xml_intf:
|
||||
self.updates_cmd.pop() # remove command: interface
|
||||
|
||||
if not xml_ospf and not xml_intf:
|
||||
return
|
||||
|
||||
xml_sum = CE_NC_XML_SET_IF_NAME % self.interface
|
||||
xml_sum += xml_ospf + xml_intf
|
||||
xml_str = CE_NC_XML_BUILD_PROCESS % (self.process_id,
|
||||
self.get_area_ip(),
|
||||
(CE_NC_XML_BUILD_MERGE_INTF % xml_sum))
|
||||
self.netconf_set_config(xml_str, "MERGE_INTERFACE_OSPF")
|
||||
self.changed = True
|
||||
|
||||
def unset_ospf_interface(self):
|
||||
"""set interface ospf disable, and all its ospf attributes will be removed"""
|
||||
|
||||
intf_dict = self.ospf_info["interface"]
|
||||
xml_sum = ""
|
||||
xml_intf = CE_NC_XML_SET_IF_NAME % self.interface
|
||||
if intf_dict.get("silentEnable") == "true":
|
||||
xml_sum += CE_NC_XML_BUILD_MERGE_INTF % (
|
||||
xml_intf + (CE_NC_XML_SET_SILENT % "false"))
|
||||
self.updates_cmd.append("ospf %s" % self.process_id)
|
||||
self.updates_cmd.append("area %s" % self.get_area_ip())
|
||||
self.updates_cmd.append(
|
||||
"undo silent-interface %s" % self.interface)
|
||||
|
||||
xml_sum += CE_NC_XML_BUILD_DELETE_INTF % xml_intf
|
||||
xml_str = CE_NC_XML_BUILD_PROCESS % (self.process_id,
|
||||
self.get_area_ip(),
|
||||
xml_sum)
|
||||
self.netconf_set_config(xml_str, "DELETE_INTERFACE_OSPF")
|
||||
self.updates_cmd.append("undo ospf cost")
|
||||
self.updates_cmd.append("undo ospf timer hello")
|
||||
self.updates_cmd.append("undo ospf timer dead")
|
||||
self.updates_cmd.append("undo ospf authentication-mode")
|
||||
self.updates_cmd.append("undo ospf enable %s area %s" % (
|
||||
self.process_id, self.get_area_ip()))
|
||||
self.changed = True
|
||||
|
||||
def check_params(self):
|
||||
"""Check all input params"""
|
||||
|
||||
self.interface = self.interface.replace(" ", "").upper()
|
||||
|
||||
# interface check
|
||||
if not get_interface_type(self.interface):
|
||||
self.module.fail_json(msg="Error: interface is invalid.")
|
||||
|
||||
# process_id check
|
||||
if not self.process_id.isdigit():
|
||||
self.module.fail_json(msg="Error: process_id is not digit.")
|
||||
if int(self.process_id) < 1 or int(self.process_id) > 4294967295:
|
||||
self.module.fail_json(msg="Error: process_id must be an integer between 1 and 4294967295.")
|
||||
|
||||
# area check
|
||||
if self.area.isdigit():
|
||||
if int(self.area) < 0 or int(self.area) > 4294967295:
|
||||
self.module.fail_json(msg="Error: area id (Integer) must be between 0 and 4294967295.")
|
||||
else:
|
||||
if not is_valid_v4addr(self.area):
|
||||
self.module.fail_json(msg="Error: area id is invalid.")
|
||||
|
||||
# area authentication check
|
||||
if self.state == "present":
|
||||
if self.auth_mode:
|
||||
if self.auth_mode == "simple":
|
||||
if self.auth_text_simple and len(self.auth_text_simple) > 8:
|
||||
self.module.fail_json(
|
||||
msg="Error: auth_text_simple is not in the range from 1 to 8.")
|
||||
if self.auth_mode in ["hmac-sha256", "hmac-sha256", "md5"]:
|
||||
if self.auth_key_id and not self.auth_text_md5:
|
||||
self.module.fail_json(
|
||||
msg='Error: auth_key_id and auth_text_md5 should be set at the same time.')
|
||||
if not self.auth_key_id and self.auth_text_md5:
|
||||
self.module.fail_json(
|
||||
msg='Error: auth_key_id and auth_text_md5 should be set at the same time.')
|
||||
if self.auth_key_id:
|
||||
if not self.auth_key_id.isdigit():
|
||||
self.module.fail_json(
|
||||
msg="Error: auth_key_id is not digit.")
|
||||
if int(self.auth_key_id) < 1 or int(self.auth_key_id) > 255:
|
||||
self.module.fail_json(
|
||||
msg="Error: auth_key_id is not in the range from 1 to 255.")
|
||||
if self.auth_text_md5 and len(self.auth_text_md5) > 255:
|
||||
self.module.fail_json(
|
||||
msg="Error: auth_text_md5 is not in the range from 1 to 255.")
|
||||
# cost check
|
||||
if self.cost:
|
||||
if not self.cost.isdigit():
|
||||
self.module.fail_json(msg="Error: cost is not digit.")
|
||||
if int(self.cost) < 1 or int(self.cost) > 65535:
|
||||
self.module.fail_json(
|
||||
msg="Error: cost is not in the range from 1 to 65535")
|
||||
|
||||
# hello_interval check
|
||||
if self.hello_interval:
|
||||
if not self.hello_interval.isdigit():
|
||||
self.module.fail_json(
|
||||
msg="Error: hello_interval is not digit.")
|
||||
if int(self.hello_interval) < 1 or int(self.hello_interval) > 65535:
|
||||
self.module.fail_json(
|
||||
msg="Error: hello_interval is not in the range from 1 to 65535")
|
||||
|
||||
# dead_interval check
|
||||
if self.dead_interval:
|
||||
if not self.dead_interval.isdigit():
|
||||
self.module.fail_json(msg="Error: dead_interval is not digit.")
|
||||
if int(self.dead_interval) < 1 or int(self.dead_interval) > 235926000:
|
||||
self.module.fail_json(
|
||||
msg="Error: dead_interval is not in the range from 1 to 235926000")
|
||||
|
||||
def get_proposed(self):
|
||||
"""get proposed info"""
|
||||
|
||||
self.proposed["interface"] = self.interface
|
||||
self.proposed["process_id"] = self.process_id
|
||||
self.proposed["area"] = self.get_area_ip()
|
||||
self.proposed["cost"] = self.cost
|
||||
self.proposed["hello_interval"] = self.hello_interval
|
||||
self.proposed["dead_interval"] = self.dead_interval
|
||||
self.proposed["silent_interface"] = self.silent_interface
|
||||
if self.auth_mode:
|
||||
self.proposed["auth_mode"] = self.auth_mode
|
||||
if self.auth_mode == "simple":
|
||||
self.proposed["auth_text_simple"] = self.auth_text_simple
|
||||
if self.auth_mode in ["hmac-sha256", "hmac-sha256", "md5"]:
|
||||
self.proposed["auth_key_id"] = self.auth_key_id
|
||||
self.proposed["auth_text_md5"] = self.auth_text_md5
|
||||
self.proposed["state"] = self.state
|
||||
|
||||
def get_existing(self):
|
||||
"""get existing info"""
|
||||
|
||||
if not self.ospf_info:
|
||||
return
|
||||
|
||||
if self.ospf_info["interface"]:
|
||||
self.existing["interface"] = self.interface
|
||||
self.existing["cost"] = self.ospf_info["interface"].get("configCost")
|
||||
self.existing["hello_interval"] = self.ospf_info["interface"].get("helloInterval")
|
||||
self.existing["dead_interval"] = self.ospf_info["interface"].get("deadInterval")
|
||||
self.existing["silent_interface"] = self.ospf_info["interface"].get("silentEnable")
|
||||
self.existing["auth_mode"] = self.ospf_info["interface"].get("authenticationMode")
|
||||
self.existing["auth_text_simple"] = self.ospf_info["interface"].get("authTextSimple")
|
||||
self.existing["auth_key_id"] = self.ospf_info["interface"].get("keyId")
|
||||
self.existing["auth_text_md5"] = self.ospf_info["interface"].get("authTextMd5")
|
||||
self.existing["process_id"] = self.ospf_info["processId"]
|
||||
self.existing["area"] = self.ospf_info["areaId"]
|
||||
|
||||
def get_end_state(self):
|
||||
"""get end state info"""
|
||||
|
||||
ospf_info = self.get_ospf_dict()
|
||||
if not ospf_info:
|
||||
return
|
||||
|
||||
if ospf_info["interface"]:
|
||||
self.end_state["interface"] = self.interface
|
||||
self.end_state["cost"] = ospf_info["interface"].get("configCost")
|
||||
self.end_state["hello_interval"] = ospf_info["interface"].get("helloInterval")
|
||||
self.end_state["dead_interval"] = ospf_info["interface"].get("deadInterval")
|
||||
self.end_state["silent_interface"] = ospf_info["interface"].get("silentEnable")
|
||||
self.end_state["auth_mode"] = ospf_info["interface"].get("authenticationMode")
|
||||
self.end_state["auth_text_simple"] = ospf_info["interface"].get("authTextSimple")
|
||||
self.end_state["auth_key_id"] = ospf_info["interface"].get("keyId")
|
||||
self.end_state["auth_text_md5"] = ospf_info["interface"].get("authTextMd5")
|
||||
self.end_state["process_id"] = ospf_info["processId"]
|
||||
self.end_state["area"] = ospf_info["areaId"]
|
||||
|
||||
def work(self):
|
||||
"""worker"""
|
||||
|
||||
self.check_params()
|
||||
self.ospf_info = self.get_ospf_dict()
|
||||
self.get_existing()
|
||||
self.get_proposed()
|
||||
|
||||
# deal present or absent
|
||||
if self.state == "present":
|
||||
if not self.ospf_info or not self.ospf_info["interface"]:
|
||||
# create ospf area and set interface config
|
||||
self.set_ospf_interface()
|
||||
else:
|
||||
# merge interface ospf area config
|
||||
self.merge_ospf_interface()
|
||||
else:
|
||||
if self.ospf_info and self.ospf_info["interface"]:
|
||||
# delete interface ospf area config
|
||||
self.unset_ospf_interface()
|
||||
|
||||
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(
|
||||
interface=dict(required=True, type='str'),
|
||||
process_id=dict(required=True, type='str'),
|
||||
area=dict(required=True, type='str'),
|
||||
cost=dict(required=False, type='str'),
|
||||
hello_interval=dict(required=False, type='str'),
|
||||
dead_interval=dict(required=False, type='str'),
|
||||
silent_interface=dict(required=False, default=False, type='bool'),
|
||||
auth_mode=dict(required=False,
|
||||
choices=['none', 'null', 'hmac-sha256', 'md5', 'hmac-md5', 'simple'], type='str'),
|
||||
auth_text_simple=dict(required=False, type='str', no_log=True),
|
||||
auth_key_id=dict(required=False, type='str'),
|
||||
auth_text_md5=dict(required=False, type='str', no_log=True),
|
||||
state=dict(required=False, default='present',
|
||||
choices=['present', 'absent'])
|
||||
)
|
||||
|
||||
argument_spec.update(ce_argument_spec)
|
||||
module = InterfaceOSPF(argument_spec)
|
||||
module.work()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Loading…
Reference in a new issue