1#!/usr/bin/python 2# 3# This file is part of Ansible 4# 5# Ansible is free software: you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published by 7# the Free Software Foundation, either version 3 of the License, or 8# (at your option) any later version. 9# 10# Ansible is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# GNU General Public License for more details. 14# 15# You should have received a copy of the GNU General Public License 16# along with Ansible. If not, see <http://www.gnu.org/licenses/>. 17# 18ANSIBLE_METADATA = {'metadata_version': '1.1', 19 'status': ['preview'], 20 'supported_by': 'community'} 21 22DOCUMENTATION = """ 23--- 24module: ce_netstream_aging 25version_added: "2.4" 26short_description: Manages timeout mode of NetStream on HUAWEI CloudEngine switches. 27description: 28 - Manages timeout mode of NetStream on HUAWEI CloudEngine switches. 29author: YangYang (@QijunPan) 30notes: 31 - Recommended connection is C(network_cli). 32 - This module also works with C(local) connections for legacy playbooks. 33options: 34 timeout_interval: 35 description: 36 - Netstream timeout interval. 37 If is active type the interval is 1-60. 38 If is inactive ,the interval is 5-600. 39 default: 30 40 type: 41 description: 42 - Specifies the packet type of netstream timeout active interval. 43 choices: ['ip', 'vxlan'] 44 state: 45 description: 46 - Specify desired state of the resource. 47 choices: ['present', 'absent'] 48 default: present 49 timeout_type: 50 description: 51 - Netstream timeout type. 52 choices: ['active', 'inactive', 'tcp-session', 'manual'] 53 manual_slot: 54 description: 55 - Specifies the slot number of netstream manual timeout. 56""" 57 58EXAMPLES = ''' 59- name: netstream aging module test 60 hosts: cloudengine 61 connection: local 62 gather_facts: no 63 vars: 64 cli: 65 host: "{{ inventory_hostname }}" 66 port: "{{ ansible_ssh_port }}" 67 username: "{{ username }}" 68 password: "{{ password }}" 69 transport: cli 70 71 tasks: 72 73 - name: Configure netstream ip timeout active interval , the interval is 40 minutes. 74 ce_netstream_aging: 75 timeout_interval: 40 76 type: ip 77 timeout_type: active 78 state: present 79 provider: "{{ cli }}" 80 81 - name: Configure netstream vxlan timeout active interval , the interval is 40 minutes. 82 ce_netstream_aging: 83 timeout_interval: 40 84 type: vxlan 85 timeout_type: active 86 active_state: present 87 provider: "{{ cli }}" 88 89 - name: Delete netstream ip timeout active interval , set the ip timeout interval to 30 minutes. 90 ce_netstream_aging: 91 type: ip 92 timeout_type: active 93 state: absent 94 provider: "{{ cli }}" 95 96 - name: Delete netstream vxlan timeout active interval , set the vxlan timeout interval to 30 minutes. 97 ce_netstream_aging: 98 type: vxlan 99 timeout_type: active 100 state: absent 101 provider: "{{ cli }}" 102 103 - name: Enable netstream ip tcp session timeout. 104 ce_netstream_aging: 105 type: ip 106 timeout_type: tcp-session 107 state: present 108 provider: "{{ cli }}" 109 110 - name: Enable netstream vxlan tcp session timeout. 111 ce_netstream_aging: 112 type: vxlan 113 timeout_type: tcp-session 114 state: present 115 provider: "{{ cli }}" 116 117 - name: Disable netstream ip tcp session timeout. 118 ce_netstream_aging: 119 type: ip 120 timeout_type: tcp-session 121 state: absent 122 provider: "{{ cli }}" 123 124 - name: Disable netstream vxlan tcp session timeout. 125 ce_netstream_aging: 126 type: vxlan 127 timeout_type: tcp-session 128 state: absent 129 provider: "{{ cli }}" 130''' 131 132RETURN = ''' 133proposed: 134 description: k/v pairs of parameters passed into module 135 returned: verbose mode 136 type: dict 137 sample: {"timeout_interval": "40", 138 "type": "ip", 139 "state": "absent", 140 "timeout_type": active} 141existing: 142 description: k/v pairs of existing configuration 143 returned: verbose mode 144 type: dict 145 sample: {"active_timeout": [ 146 { 147 "ip": "40", 148 "vxlan": 30 149 } 150 ], 151 "inactive_timeout": [ 152 { 153 "ip": 30, 154 "vxlan": 30 155 } 156 ], 157 "tcp_timeout": [ 158 { 159 "ip": "disable", 160 "vxlan": "disable" 161 } 162 ]} 163end_state: 164 description: k/v pairs of configuration after module execution 165 returned: verbose mode 166 type: dict 167 sample: {"active_timeout": [ 168 { 169 "ip": 30, 170 "vxlan": 30 171 } 172 ], 173 "inactive_timeout": [ 174 { 175 "ip": 30, 176 "vxlan": 30 177 } 178 ], 179 "tcp_timeout": [ 180 { 181 "ip": "disable", 182 "vxlan": "disable" 183 } 184 ]} 185updates: 186 description: commands sent to the device 187 returned: always 188 type: list 189 sample: ["undo netstream timeout ip active 40"] 190changed: 191 description: check to see if a change was made on the device 192 returned: always 193 type: bool 194 sample: true 195''' 196 197import re 198from ansible.module_utils.basic import AnsibleModule 199from ansible.module_utils.network.cloudengine.ce import exec_command, load_config 200from ansible.module_utils.network.cloudengine.ce import ce_argument_spec 201 202 203class NetStreamAging(object): 204 """ 205 Manages netstream aging. 206 """ 207 208 def __init__(self, argument_spec): 209 self.spec = argument_spec 210 self.module = None 211 self.init_module() 212 213 # module input info 214 self.timeout_interval = self.module.params['timeout_interval'] 215 self.type = self.module.params['type'] 216 self.state = self.module.params['state'] 217 self.timeout_type = self.module.params['timeout_type'] 218 self.manual_slot = self.module.params['manual_slot'] 219 220 # host info 221 self.host = self.module.params['host'] 222 self.username = self.module.params['username'] 223 self.port = self.module.params['port'] 224 225 # state 226 self.changed = False 227 self.updates_cmd = list() 228 self.commands = list() 229 self.results = dict() 230 self.proposed = dict() 231 self.existing = dict() 232 self.end_state = dict() 233 234 # local parameters 235 self.existing["active_timeout"] = list() 236 self.existing["inactive_timeout"] = list() 237 self.existing["tcp_timeout"] = list() 238 self.end_state["active_timeout"] = list() 239 self.end_state["inactive_timeout"] = list() 240 self.end_state["tcp_timeout"] = list() 241 self.active_changed = False 242 self.inactive_changed = False 243 self.tcp_changed = False 244 245 def init_module(self): 246 """init module""" 247 248 self.module = AnsibleModule(argument_spec=self.spec, supports_check_mode=True) 249 250 def cli_load_config(self, commands): 251 """load config by cli""" 252 253 if not self.module.check_mode: 254 load_config(self.module, commands) 255 256 def cli_add_command(self, command, undo=False): 257 """add command to self.update_cmd and self.commands""" 258 259 if undo and command.lower() not in ["quit", "return"]: 260 cmd = "undo " + command 261 else: 262 cmd = command 263 264 self.commands.append(cmd) 265 if command.lower() not in ["quit", "return"]: 266 self.updates_cmd.append(cmd) 267 268 def get_exist_timer_out_para(self): 269 """Get exist netstream timeout parameters""" 270 271 active_tmp = dict() 272 inactive_tmp = dict() 273 tcp_tmp = dict() 274 active_tmp["ip"] = "30" 275 active_tmp["vxlan"] = "30" 276 inactive_tmp["ip"] = "30" 277 inactive_tmp["vxlan"] = "30" 278 tcp_tmp["ip"] = "absent" 279 tcp_tmp["vxlan"] = "absent" 280 281 cmd = "display current-configuration | include ^netstream timeout" 282 rc, out, err = exec_command(self.module, cmd) 283 if rc != 0: 284 self.module.fail_json(msg=err) 285 config = str(out).strip() 286 if config: 287 config = config.lstrip() 288 config_list = config.split('\n') 289 for config_mem in config_list: 290 config_mem = config_mem.lstrip() 291 config_mem_list = config_mem.split(' ') 292 if len(config_mem_list) > 4 and config_mem_list[2] == "ip": 293 if config_mem_list[3] == "active": 294 active_tmp["ip"] = config_mem_list[4] 295 if config_mem_list[3] == "inactive": 296 inactive_tmp["ip"] = config_mem_list[4] 297 if config_mem_list[3] == "tcp-session": 298 tcp_tmp["ip"] = "present" 299 if len(config_mem_list) > 4 and config_mem_list[2] == "vxlan": 300 if config_mem_list[4] == "active": 301 active_tmp["vxlan"] = config_mem_list[5] 302 if config_mem_list[4] == "inactive": 303 inactive_tmp["vxlan"] = config_mem_list[5] 304 if config_mem_list[4] == "tcp-session": 305 tcp_tmp["vxlan"] = "present" 306 self.existing["active_timeout"].append(active_tmp) 307 self.existing["inactive_timeout"].append(inactive_tmp) 308 self.existing["tcp_timeout"].append(tcp_tmp) 309 310 def get_end_timer_out_para(self): 311 """Get end netstream timeout parameters""" 312 313 active_tmp = dict() 314 inactive_tmp = dict() 315 tcp_tmp = dict() 316 active_tmp["ip"] = "30" 317 active_tmp["vxlan"] = "30" 318 inactive_tmp["ip"] = "30" 319 inactive_tmp["vxlan"] = "30" 320 tcp_tmp["ip"] = "absent" 321 tcp_tmp["vxlan"] = "absent" 322 cmd = "display current-configuration | include ^netstream timeout" 323 rc, out, err = exec_command(self.module, cmd) 324 if rc != 0: 325 self.module.fail_json(msg=err) 326 config = str(out).strip() 327 if config: 328 config = config.lstrip() 329 config_list = config.split('\n') 330 for config_mem in config_list: 331 config_mem = config_mem.lstrip() 332 config_mem_list = config_mem.split(' ') 333 if len(config_mem_list) > 4 and config_mem_list[2] == "ip": 334 if config_mem_list[3] == "active": 335 active_tmp["ip"] = config_mem_list[4] 336 if config_mem_list[3] == "inactive": 337 inactive_tmp["ip"] = config_mem_list[4] 338 if config_mem_list[3] == "tcp-session": 339 tcp_tmp["ip"] = "present" 340 if len(config_mem_list) > 4 and config_mem_list[2] == "vxlan": 341 if config_mem_list[4] == "active": 342 active_tmp["vxlan"] = config_mem_list[5] 343 if config_mem_list[4] == "inactive": 344 inactive_tmp["vxlan"] = config_mem_list[5] 345 if config_mem_list[4] == "tcp-session": 346 tcp_tmp["vxlan"] = "present" 347 self.end_state["active_timeout"].append(active_tmp) 348 self.end_state["inactive_timeout"].append(inactive_tmp) 349 self.end_state["tcp_timeout"].append(tcp_tmp) 350 351 def check_params(self): 352 """Check all input params""" 353 354 # interval check 355 if not str(self.timeout_interval).isdigit(): 356 self.module.fail_json( 357 msg='Error: Timeout interval should be numerical.') 358 if self.timeout_type == "active": 359 if int(self.timeout_interval) < 1 or int(self.timeout_interval) > 60: 360 self.module.fail_json( 361 msg="Error: Active interval should between 1 - 60 minutes.") 362 if self.timeout_type == "inactive": 363 if int(self.timeout_interval) < 5 or int(self.timeout_interval) > 600: 364 self.module.fail_json( 365 msg="Error: Inactive interval should between 5 - 600 seconds.") 366 if self.timeout_type == "manual": 367 if not self.manual_slot: 368 self.module.fail_json( 369 msg="Error: If use manual timeout mode,slot number is needed.") 370 if re.match(r'^\d+(\/\d*)?$', self.manual_slot) is None: 371 self.module.fail_json( 372 msg='Error: Slot number should be numerical.') 373 374 def get_proposed(self): 375 """get proposed info""" 376 377 if self.timeout_interval: 378 self.proposed["timeout_interval"] = self.timeout_interval 379 if self.timeout_type: 380 self.proposed["timeout_type"] = self.timeout_type 381 if self.type: 382 self.proposed["type"] = self.type 383 if self.state: 384 self.proposed["state"] = self.state 385 if self.manual_slot: 386 self.proposed["manual_slot"] = self.manual_slot 387 388 def get_existing(self): 389 """get existing info""" 390 active_tmp = dict() 391 inactive_tmp = dict() 392 tcp_tmp = dict() 393 394 self.get_exist_timer_out_para() 395 396 if self.timeout_type == "active": 397 for active_tmp in self.existing["active_timeout"]: 398 if self.state == "present": 399 if str(active_tmp[self.type]) != self.timeout_interval: 400 self.active_changed = True 401 else: 402 if self.timeout_interval != "30": 403 if str(active_tmp[self.type]) != "30": 404 if str(active_tmp[self.type]) != self.timeout_interval: 405 self.module.fail_json( 406 msg='Error: The specified active interval do not exist.') 407 if str(active_tmp[self.type]) != "30": 408 self.timeout_interval = active_tmp[self.type] 409 self.active_changed = True 410 if self.timeout_type == "inactive": 411 for inactive_tmp in self.existing["inactive_timeout"]: 412 if self.state == "present": 413 if str(inactive_tmp[self.type]) != self.timeout_interval: 414 self.inactive_changed = True 415 else: 416 if self.timeout_interval != "30": 417 if str(inactive_tmp[self.type]) != "30": 418 if str(inactive_tmp[self.type]) != self.timeout_interval: 419 self.module.fail_json( 420 msg='Error: The specified inactive interval do not exist.') 421 if str(inactive_tmp[self.type]) != "30": 422 self.timeout_interval = inactive_tmp[self.type] 423 self.inactive_changed = True 424 if self.timeout_type == "tcp-session": 425 for tcp_tmp in self.existing["tcp_timeout"]: 426 if str(tcp_tmp[self.type]) != self.state: 427 self.tcp_changed = True 428 429 def operate_time_out(self): 430 """configure timeout parameters""" 431 432 cmd = "" 433 if self.timeout_type == "manual": 434 if self.type == "ip": 435 self.cli_add_command("quit") 436 cmd = "reset netstream cache ip slot %s" % self.manual_slot 437 self.cli_add_command(cmd) 438 elif self.type == "vxlan": 439 self.cli_add_command("quit") 440 cmd = "reset netstream cache vxlan inner-ip slot %s" % self.manual_slot 441 self.cli_add_command(cmd) 442 443 if not self.active_changed and not self.inactive_changed and not self.tcp_changed: 444 if self.commands: 445 self.cli_load_config(self.commands) 446 self.changed = True 447 return 448 449 if self.active_changed or self.inactive_changed: 450 if self.type == "ip": 451 cmd = "netstream timeout ip %s %s" % (self.timeout_type, self.timeout_interval) 452 elif self.type == "vxlan": 453 cmd = "netstream timeout vxlan inner-ip %s %s" % (self.timeout_type, self.timeout_interval) 454 if self.state == "absent": 455 self.cli_add_command(cmd, undo=True) 456 else: 457 self.cli_add_command(cmd) 458 if self.timeout_type == "tcp-session" and self.tcp_changed: 459 if self.type == "ip": 460 if self.state == "present": 461 cmd = "netstream timeout ip tcp-session" 462 else: 463 cmd = "undo netstream timeout ip tcp-session" 464 465 elif self.type == "vxlan": 466 if self.state == "present": 467 cmd = "netstream timeout vxlan inner-ip tcp-session" 468 else: 469 cmd = "undo netstream timeout vxlan inner-ip tcp-session" 470 self.cli_add_command(cmd) 471 if self.commands: 472 self.cli_load_config(self.commands) 473 self.changed = True 474 475 def get_end_state(self): 476 """get end state info""" 477 478 self.get_end_timer_out_para() 479 480 def work(self): 481 """worker""" 482 483 self.check_params() 484 self.get_existing() 485 self.get_proposed() 486 self.operate_time_out() 487 self.get_end_state() 488 if self.existing == self.end_state: 489 self.changed = False 490 self.results['changed'] = self.changed 491 self.results['proposed'] = self.proposed 492 self.results['existing'] = self.existing 493 self.results['end_state'] = self.end_state 494 if self.changed: 495 self.results['updates'] = self.updates_cmd 496 else: 497 self.results['updates'] = list() 498 499 self.module.exit_json(**self.results) 500 501 502def main(): 503 """Module main""" 504 505 argument_spec = dict( 506 timeout_interval=dict(required=False, type='str', default='30'), 507 type=dict(required=False, choices=['ip', 'vxlan']), 508 state=dict(required=False, choices=['present', 'absent'], default='present'), 509 timeout_type=dict(required=False, choices=['active', 'inactive', 'tcp-session', 'manual']), 510 manual_slot=dict(required=False, type='str'), 511 ) 512 argument_spec.update(ce_argument_spec) 513 module = NetStreamAging(argument_spec) 514 module.work() 515 516 517if __name__ == '__main__': 518 main() 519