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 = r''' 12--- 13module: ce_is_is_instance 14version_added: '0.2.0' 15author: xuxiaowei0512 (@CloudEngine-Ansible) 16short_description: Manages isis process id 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 - This module requires the netconf system service be enabled on the remote device being managed. 21 - This module works with connection C(netconf). 22options: 23 instance_id: 24 description: 25 - Specifies the id of a isis process.The value is a number of 1 to 4294967295. 26 required: true 27 type: int 28 vpn_name: 29 description: 30 - VPN Instance, associate the VPN instance with the corresponding IS-IS process. 31 type: str 32 state: 33 description: 34 - Determines whether the config should be present or not on the device. 35 default: present 36 type: str 37 choices: ['present', 'absent'] 38''' 39 40EXAMPLES = r''' 41 - name: Set isis process 42 community.network.ce_is_is_instance: 43 instance_id: 3 44 state: present 45 46 - name: Unset isis process 47 community.network.ce_is_is_instance: 48 instance_id: 3 49 state: absent 50 51 - name: Check isis process 52 community.network.ce_is_is_instance: 53 instance_id: 4294967296 54 state: present 55 56 - name: Set vpn name 57 community.network.ce_is_is_instance: 58 instance_id: 22 59 vpn_name: vpn1 60 state: present 61 62 - name: Check vpn name 63 community.network.ce_is_is_instance: 64 instance_id: 22 65 vpn_name: vpn1234567896321452212221556asdasdasdasdsadvdv 66 state: present 67''' 68 69RETURN = r''' 70proposed: 71 description: k/v pairs of parameters passed into module 72 returned: always 73 type: dict 74 sample: { 75 "instance_id": 1, 76 "vpn_name": null 77 } 78existing: 79 description: k/v pairs of existing configuration 80 returned: always 81 type: dict 82 sample: { 83 "session": {} 84 } 85end_state: 86 description: k/v pairs of configuration after module execution 87 returned: always 88 type: dict 89 sample: { 90 "session": { 91 "instance_id": 1, 92 "vpn_name": null 93 } 94 } 95updates: 96 description: commands sent to the device 97 returned: always 98 type: list 99 sample: [ 100 "isis 1" 101 ] 102changed: 103 description: check to see if a change was made on the device 104 returned: always 105 type: bool 106 sample: true 107''' 108 109from xml.etree import ElementTree 110from ansible.module_utils.basic import AnsibleModule 111from ansible_collections.community.network.plugins.module_utils.network.cloudengine.ce import get_nc_config, set_nc_config 112 113CE_NC_GET_ISIS = """ 114 <filter type="subtree"> 115 <isiscomm xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0"> 116 %s 117 </isiscomm> 118 </filter> 119""" 120 121CE_NC_GET_ISIS_INSTANCE = """ 122 <isSites> 123 <isSite> 124 <instanceId>%s</instanceId> 125 <vpnName></vpnName> 126 </isSite> 127 </isSites> 128""" 129 130 131def is_valid_ip_vpn(vpname): 132 """check ip vpn""" 133 134 if not vpname: 135 return False 136 137 if vpname == "_public_": 138 return False 139 140 if len(vpname) < 1 or len(vpname) > 31: 141 return False 142 143 return True 144 145 146class ISIS_Instance(object): 147 """Manages ISIS Instance""" 148 149 def __init__(self, argument_spec): 150 self.spec = argument_spec 151 self.module = None 152 self.__init_module__() 153 154 # module input info 155 self.instance_id = self.module.params['instance_id'] 156 self.vpn_name = self.module.params['vpn_name'] 157 self.state = self.module.params['state'] 158 159 # state 160 self.changed = False 161 self.isis_dict = dict() 162 self.updates_cmd = list() 163 self.commands = list() 164 self.results = dict() 165 self.proposed = dict() 166 self.existing = dict() 167 self.end_state = dict() 168 169 def __init_module__(self): 170 """init module""" 171 self.module = AnsibleModule( 172 argument_spec=self.spec, supports_check_mode=True) 173 174 def get_isis_dict(self): 175 """isis config dict""" 176 isis_dict = dict() 177 isis_dict["instance"] = dict() 178 conf_str = CE_NC_GET_ISIS % ( 179 (CE_NC_GET_ISIS_INSTANCE % self.instance_id)) 180 181 xml_str = get_nc_config(self.module, conf_str) 182 if "<data/>" in xml_str: 183 return isis_dict 184 185 xml_str = xml_str.replace('\r', '').replace('\n', '').\ 186 replace('xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"', "").\ 187 replace('xmlns="http://www.huawei.com/netconf/vrp"', "") 188 root = ElementTree.fromstring(xml_str) 189 190 # get isis info 191 glb = root.find("isiscomm/isSites/isSite") 192 if glb: 193 for attr in glb: 194 isis_dict["instance"][attr.tag] = attr.text 195 196 return isis_dict 197 198 def config_session(self): 199 """configures isis""" 200 xml_str = "" 201 instance = self.isis_dict["instance"] 202 if not self.instance_id: 203 return xml_str 204 205 if self.state == "present": 206 xml_str = "<instanceId>%s</instanceId>" % self.instance_id 207 self.updates_cmd.append("isis %s" % self.instance_id) 208 209 if self.vpn_name: 210 xml_str += "<vpnName>%s</vpnName>" % self.vpn_name 211 self.updates_cmd.append("vpn-instance %s" % self.vpn_name) 212 else: 213 # absent 214 if self.instance_id and str(self.instance_id) == instance.get("instanceId"): 215 xml_str = "<instanceId>%s</instanceId>" % self.instance_id 216 self.updates_cmd.append("undo isis %s" % self.instance_id) 217 218 if self.state == "present": 219 return '<isSites><isSite operation="merge">' + xml_str + '</isSite></isSites>' 220 else: 221 if xml_str: 222 return '<isSites><isSite operation="delete">' + xml_str + '</isSite></isSites>' 223 224 def netconf_load_config(self, xml_str): 225 """load isis config by netconf""" 226 227 if not xml_str: 228 return 229 230 xml_cfg = """ 231 <config> 232 <isiscomm xmlns="http://www.huawei.com/netconf/vrp" content-version="1.0" format-version="1.0"> 233 %s 234 </isiscomm> 235 </config>""" % xml_str 236 set_nc_config(self.module, xml_cfg) 237 self.changed = True 238 239 def check_params(self): 240 """Check all input params""" 241 242 # check instance id 243 if not self.instance_id: 244 self.module.fail_json(msg="Error: Missing required arguments: instance_id.") 245 246 if self.instance_id: 247 if self.instance_id < 1 or self.instance_id > 4294967295: 248 self.module.fail_json(msg="Error: Instance id is not ranges from 1 to 4294967295.") 249 250 # check vpn_name 251 if self.vpn_name: 252 if not is_valid_ip_vpn(self.vpn_name): 253 self.module.fail_json(msg="Error: Session vpn_name is invalid.") 254 255 def get_proposed(self): 256 """get proposed info""" 257 # base config 258 self.proposed["instance_id"] = self.instance_id 259 self.proposed["vpn_name"] = self.vpn_name 260 self.proposed["state"] = self.state 261 262 def get_existing(self): 263 """get existing info""" 264 265 if not self.isis_dict: 266 self.existing["instance"] = None 267 268 self.existing["instance"] = self.isis_dict.get("instance") 269 270 def get_end_state(self): 271 """get end state info""" 272 273 isis_dict = self.get_isis_dict() 274 if not isis_dict: 275 self.end_state["instance"] = None 276 277 self.end_state["instance"] = isis_dict.get("instance") 278 279 if self.end_state == self.existing: 280 self.changed = False 281 282 def work(self): 283 """worker""" 284 self.check_params() 285 self.isis_dict = self.get_isis_dict() 286 self.get_existing() 287 self.get_proposed() 288 289 # deal present or absent 290 xml_str = '' 291 if self.instance_id: 292 cfg_str = self.config_session() 293 if cfg_str: 294 xml_str += cfg_str 295 296 # update to device 297 if xml_str: 298 self.netconf_load_config(xml_str) 299 self.changed = True 300 301 self.get_end_state() 302 self.results['changed'] = self.changed 303 self.results['proposed'] = self.proposed 304 self.results['existing'] = self.existing 305 self.results['end_state'] = self.end_state 306 if self.changed: 307 self.results['updates'] = self.updates_cmd 308 else: 309 self.results['updates'] = list() 310 311 self.module.exit_json(**self.results) 312 313 314def main(): 315 """Module main""" 316 argument_spec = dict( 317 instance_id=dict(required=True, type='int'), 318 vpn_name=dict(required=False, type='str'), 319 state=dict(required=False, default='present', choices=['present', 'absent']) 320 ) 321 322 module = ISIS_Instance(argument_spec) 323 module.work() 324 325 326if __name__ == '__main__': 327 main() 328