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_global 25version_added: "2.4" 26short_description: Manages global parameters of NetStream on HUAWEI CloudEngine switches. 27description: 28 - Manages global parameters 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 type: 35 description: 36 - Specifies the type of netstream global. 37 choices: ['ip', 'vxlan'] 38 default: 'ip' 39 state: 40 description: 41 - Specify desired state of the resource. 42 choices: ['present', 'absent'] 43 default: present 44 interface: 45 description: 46 - Netstream global interface. 47 required: true 48 sampler_interval: 49 description: 50 - Specifies the netstream sampler interval, length is 1 - 65535. 51 sampler_direction: 52 description: 53 - Specifies the netstream sampler direction. 54 choices: ['inbound', 'outbound'] 55 statistics_direction: 56 description: 57 - Specifies the netstream statistic direction. 58 choices: ['inbound', 'outbound'] 59 statistics_record: 60 description: 61 - Specifies the flexible netstream statistic record, length is 1 - 32. 62 index_switch: 63 description: 64 - Specifies the netstream index-switch. 65 choices: ['16', '32'] 66 default: '16' 67""" 68 69EXAMPLES = ''' 70- name: netstream global module test 71 hosts: cloudengine 72 connection: local 73 gather_facts: no 74 vars: 75 cli: 76 host: "{{ inventory_hostname }}" 77 port: "{{ ansible_ssh_port }}" 78 username: "{{ username }}" 79 password: "{{ password }}" 80 transport: cli 81 82 tasks: 83 84 - name: Configure a netstream sampler at interface 10ge1/0/2, direction is outbound,interval is 30. 85 ce_netstream_global: 86 interface: 10ge1/0/2 87 type: ip 88 sampler_interval: 30 89 sampler_direction: outbound 90 state: present 91 provider: "{{ cli }}" 92 - name: Configure a netstream flexible statistic at interface 10ge1/0/2, record is test1, type is ip. 93 ce_netstream_global: 94 type: ip 95 interface: 10ge1/0/2 96 statistics_record: test1 97 provider: "{{ cli }}" 98 - name: Set the vxlan index-switch to 32. 99 ce_netstream_global: 100 type: vxlan 101 interface: all 102 index_switch: 32 103 provider: "{{ cli }}" 104''' 105 106RETURN = ''' 107proposed: 108 description: k/v pairs of parameters passed into module 109 returned: verbose mode 110 type: dict 111 sample: {"index_switch": "16", 112 "interface": "10ge1/0/2", 113 "state": "present", 114 "statistics_record": "test", 115 "type": "vxlan"} 116existing: 117 description: k/v pairs of existing configuration 118 returned: verbose mode 119 type: dict 120 sample: {"flexible_statistic": [ 121 { 122 "interface": "10ge1/0/2", 123 "statistics_record": [], 124 "type": "ip" 125 }, 126 { 127 "interface": "10ge1/0/2", 128 "statistics_record": [], 129 "type": "vxlan" 130 } 131 ], 132 "index-switch": [ 133 { 134 "index-switch": "16", 135 "type": "ip" 136 }, 137 { 138 "index-switch": "16", 139 "type": "vxlan" 140 } 141 ], 142 "ip_record": [ 143 "test", 144 "test1" 145 ], 146 "sampler": [ 147 { 148 "interface": "all", 149 "sampler_direction": "null", 150 "sampler_interval": "null" 151 } 152 ], 153 "statistic": [ 154 { 155 "interface": "10ge1/0/2", 156 "statistics_direction": [], 157 "type": "null" 158 } 159 ], 160 "vxlan_record": [ 161 "test" 162 ]} 163end_state: 164 description: k/v pairs of configuration after module execution 165 returned: verbose mode 166 type: dict 167 sample: {"flexible_statistic": [ 168 { 169 "interface": "10ge1/0/2", 170 "statistics_record": [], 171 "type": "ip" 172 }, 173 { 174 "interface": "10ge1/0/2", 175 "statistics_record": [ 176 "test" 177 ], 178 "type": "vxlan" 179 } 180 ], 181 "index-switch": [ 182 { 183 "index-switch": "16", 184 "type": "ip" 185 }, 186 { 187 "index-switch": "16", 188 "type": "vxlan" 189 } 190 ], 191 "sampler": [ 192 { 193 "interface": "all", 194 "sampler_direction": "null", 195 "sampler_interval": "null" 196 } 197 ], 198 "statistic": [ 199 { 200 "interface": "10ge1/0/2", 201 "statistics_direction": [], 202 "type": "null" 203 } 204 ]} 205updates: 206 description: commands sent to the device 207 returned: always 208 type: list 209 sample: ["interface 10ge1/0/2", 210 "netstream record test vxlan inner-ip"] 211changed: 212 description: check to see if a change was made on the device 213 returned: always 214 type: bool 215 sample: true 216''' 217 218import re 219from ansible.module_utils.basic import AnsibleModule 220from ansible.module_utils.network.cloudengine.ce import load_config 221from ansible.module_utils.network.cloudengine.ce import get_connection, rm_config_prefix 222from ansible.module_utils.network.cloudengine.ce import ce_argument_spec 223 224 225def get_interface_type(interface): 226 """Gets the type of interface, such as 10GE, ETH-TRUNK...""" 227 228 if interface is None: 229 return None 230 231 iftype = None 232 233 if interface.upper().startswith('GE'): 234 iftype = 'ge' 235 elif interface.upper().startswith('10GE'): 236 iftype = '10ge' 237 elif interface.upper().startswith('25GE'): 238 iftype = '25ge' 239 elif interface.upper().startswith('4X10GE'): 240 iftype = '4x10ge' 241 elif interface.upper().startswith('40GE'): 242 iftype = '40ge' 243 elif interface.upper().startswith('100GE'): 244 iftype = '100ge' 245 elif interface.upper().startswith('ETH-TRUNK'): 246 iftype = 'eth-trunk' 247 elif interface.upper().startswith('ALL'): 248 iftype = 'all' 249 else: 250 return None 251 252 return iftype.lower() 253 254 255def get_config(module, flags): 256 257 """Retrieves the current config from the device or cache 258 """ 259 time_stamp_regex = re.compile(r'\s*\d{4}-\d{1,2}-\d{1,2}\s+\d{2}\:\d{2}\:\d{2}\.\d+\s*') 260 flags = [] if flags is None else flags 261 if isinstance(flags, str): 262 flags = [flags] 263 elif not isinstance(flags, list): 264 flags = [] 265 266 cmd = 'display current-configuration ' 267 cmd += ' '.join(flags) 268 cmd = cmd.strip() 269 conn = get_connection(module) 270 rc, out, err = conn.exec_command(cmd) 271 if rc != 0: 272 module.fail_json(msg=err) 273 cfg = str(out).strip() 274 # remove default configuration prefix '~' 275 for flag in flags: 276 if "include-default" in flag: 277 cfg = rm_config_prefix(cfg) 278 break 279 lines = cfg.split('\n') 280 lines = [l for l in lines if time_stamp_regex.match(l) is None] 281 if cfg.startswith('display'): 282 if len(lines) > 1: 283 lines.pop(0) 284 else: 285 return '' 286 return '\n'.join(lines) 287 288 289class NetStreamGlobal(object): 290 """ 291 Manages netstream global parameters. 292 """ 293 294 def __init__(self, argument_spec): 295 self.spec = argument_spec 296 self.module = None 297 self.init_module() 298 299 # module input info 300 self.type = self.module.params['type'] 301 self.interface = self.module.params['interface'] 302 self.sampler_interval = self.module.params['sampler_interval'] 303 self.sampler_direction = self.module.params['sampler_direction'] 304 self.statistics_direction = self.module.params['statistics_direction'] 305 self.statistics_record = self.module.params['statistics_record'] 306 self.index_switch = self.module.params['index_switch'] 307 self.state = self.module.params['state'] 308 309 # host info 310 self.host = self.module.params['host'] 311 self.username = self.module.params['username'] 312 self.port = self.module.params['port'] 313 314 # state 315 self.changed = False 316 self.updates_cmd = list() 317 self.commands = list() 318 self.results = dict() 319 self.proposed = dict() 320 self.existing = dict() 321 self.end_state = dict() 322 323 # local parameters 324 self.existing["sampler"] = list() 325 self.existing["statistic"] = list() 326 self.existing["flexible_statistic"] = list() 327 self.existing["index-switch"] = list() 328 self.existing["ip_record"] = list() 329 self.existing["vxlan_record"] = list() 330 self.end_state["sampler"] = list() 331 self.end_state["statistic"] = list() 332 self.end_state["flexible_statistic"] = list() 333 self.end_state["index-switch"] = list() 334 self.sampler_changed = False 335 self.statistic_changed = False 336 self.flexible_changed = False 337 self.index_switch_changed = False 338 339 def init_module(self): 340 """init module""" 341 342 self.module = AnsibleModule( 343 argument_spec=self.spec, supports_check_mode=True) 344 345 def cli_load_config(self, commands): 346 """load config by cli""" 347 348 if not self.module.check_mode: 349 load_config(self.module, commands) 350 351 def cli_add_command(self, command, undo=False): 352 """add command to self.update_cmd and self.commands""" 353 354 if undo and command.lower() not in ["quit", "return"]: 355 cmd = "undo " + command 356 else: 357 cmd = command 358 359 self.commands.append(cmd) 360 if command.lower() not in ["quit", "return"]: 361 self.updates_cmd.append(cmd) 362 363 def get_exist_sampler_interval(self): 364 """get exist netstream sampler interval""" 365 366 sampler_tmp = dict() 367 sampler_tmp1 = dict() 368 flags = list() 369 exp = " | ignore-case include ^netstream sampler random-packets" 370 flags.append(exp) 371 config = get_config(self.module, flags) 372 if not config: 373 sampler_tmp["sampler_interval"] = "null" 374 sampler_tmp["sampler_direction"] = "null" 375 sampler_tmp["interface"] = "null" 376 else: 377 config_list = config.split(' ') 378 config_num = len(config_list) 379 sampler_tmp["sampler_direction"] = config_list[config_num - 1] 380 sampler_tmp["sampler_interval"] = config_list[config_num - 2] 381 sampler_tmp["interface"] = "all" 382 self.existing["sampler"].append(sampler_tmp) 383 if self.interface != "all": 384 flags = list() 385 exp = r" | ignore-case section include ^#\s+interface %s" \ 386 r" | include netstream sampler random-packets" % self.interface 387 flags.append(exp) 388 config = get_config(self.module, flags) 389 if not config: 390 sampler_tmp1["sampler_interval"] = "null" 391 sampler_tmp1["sampler_direction"] = "null" 392 else: 393 config = config.lstrip() 394 config_list = config.split('\n') 395 for config_mem in config_list: 396 sampler_tmp1 = dict() 397 config_mem_list = config_mem.split(' ') 398 config_num = len(config_mem_list) 399 if config_num > 1: 400 sampler_tmp1["sampler_direction"] = config_mem_list[ 401 config_num - 1] 402 sampler_tmp1["sampler_interval"] = config_mem_list[ 403 config_num - 2] 404 sampler_tmp1["interface"] = self.interface 405 self.existing["sampler"].append(sampler_tmp1) 406 407 def get_exist_statistic_record(self): 408 """get exist netstream statistic record parameter""" 409 410 if self.statistics_record and self.statistics_direction: 411 self.module.fail_json( 412 msg='Error: The statistic direction and record can not exist at the same time.') 413 statistic_tmp = dict() 414 statistic_tmp1 = dict() 415 statistic_tmp["statistics_record"] = list() 416 statistic_tmp["interface"] = self.interface 417 statistic_tmp1["statistics_record"] = list() 418 statistic_tmp1["interface"] = self.interface 419 flags = list() 420 exp = r" | ignore-case section include ^#\s+interface %s" \ 421 r" | include netstream record"\ 422 % (self.interface) 423 flags.append(exp) 424 config = get_config(self.module, flags) 425 if not config: 426 statistic_tmp["type"] = "ip" 427 self.existing["flexible_statistic"].append(statistic_tmp) 428 statistic_tmp1["type"] = "vxlan" 429 self.existing["flexible_statistic"].append(statistic_tmp1) 430 else: 431 config = config.lstrip() 432 config_list = config.split('\n') 433 for config_mem in config_list: 434 config_mem = config_mem.lstrip() 435 statistic_tmp["statistics_record"] = list() 436 config_mem_list = config_mem.split(' ') 437 if len(config_mem_list) > 3 and str(config_mem_list[3]) == "ip": 438 statistic_tmp["statistics_record"].append( 439 str(config_mem_list[2])) 440 statistic_tmp["type"] = "ip" 441 self.existing["flexible_statistic"].append(statistic_tmp) 442 for config_mem in config_list: 443 statistic_tmp1["statistics_record"] = list() 444 config_mem = config_mem.lstrip() 445 config_mem_list = config_mem.split(' ') 446 if len(config_mem_list) > 3 and str(config_mem_list[3]) == "vxlan": 447 statistic_tmp1["statistics_record"].append( 448 str(config_mem_list[2])) 449 statistic_tmp1["type"] = "vxlan" 450 self.existing["flexible_statistic"].append(statistic_tmp1) 451 452 def get_exist_interface_statistic(self): 453 """get exist netstream interface statistic parameter""" 454 455 statistic_tmp1 = dict() 456 statistic_tmp1["statistics_direction"] = list() 457 flags = list() 458 exp = r" | ignore-case section include ^#\s+interface %s" \ 459 r" | include netstream inbound|outbound"\ 460 % self.interface 461 flags.append(exp) 462 config = get_config(self.module, flags) 463 if not config: 464 statistic_tmp1["type"] = "null" 465 else: 466 statistic_tmp1["type"] = "ip" 467 config = config.lstrip() 468 config_list = config.split('\n') 469 for config_mem in config_list: 470 config_mem = config_mem.lstrip() 471 config_mem_list = config_mem.split(' ') 472 if len(config_mem_list) > 1: 473 statistic_tmp1["statistics_direction"].append( 474 str(config_mem_list[1])) 475 statistic_tmp1["interface"] = self.interface 476 self.existing["statistic"].append(statistic_tmp1) 477 478 def get_exist_index_switch(self): 479 """get exist netstream index-switch""" 480 481 index_switch_tmp = dict() 482 index_switch_tmp1 = dict() 483 index_switch_tmp["index-switch"] = "16" 484 index_switch_tmp["type"] = "ip" 485 index_switch_tmp1["index-switch"] = "16" 486 index_switch_tmp1["type"] = "vxlan" 487 flags = list() 488 exp = " | ignore-case include index-switch" 489 flags.append(exp) 490 config = get_config(self.module, flags) 491 if not config: 492 self.existing["index-switch"].append(index_switch_tmp) 493 self.existing["index-switch"].append(index_switch_tmp1) 494 else: 495 config = config.lstrip() 496 config_list = config.split('\n') 497 for config_mem in config_list: 498 config_mem_list = config_mem.split(' ') 499 if len(config_mem_list) > 2 and str(config_mem_list[2]) == "ip": 500 index_switch_tmp["index-switch"] = "32" 501 index_switch_tmp["type"] = "ip" 502 if len(config_mem_list) > 2 and str(config_mem_list[2]) == "vxlan": 503 index_switch_tmp1["index-switch"] = "32" 504 index_switch_tmp1["type"] = "vxlan" 505 self.existing["index-switch"].append(index_switch_tmp) 506 self.existing["index-switch"].append(index_switch_tmp1) 507 508 def get_exist_record(self): 509 """get exist netstream record""" 510 511 flags = list() 512 exp = " | ignore-case include netstream record" 513 flags.append(exp) 514 config = get_config(self.module, flags) 515 if config: 516 config = config.lstrip() 517 config_list = config.split('\n') 518 for config_mem in config_list: 519 config_mem_list = config_mem.split(' ') 520 if len(config_mem_list) > 3 and config_mem_list[3] == "ip": 521 self.existing["ip_record"].append(config_mem_list[2]) 522 if len(config_mem_list) > 3 and config_mem_list[3] == "vxlan": 523 self.existing["vxlan_record"].append(config_mem_list[2]) 524 525 def get_end_sampler_interval(self): 526 """get end netstream sampler interval""" 527 528 sampler_tmp = dict() 529 sampler_tmp1 = dict() 530 flags = list() 531 exp = " | ignore-case include ^netstream sampler random-packets" 532 flags.append(exp) 533 config = get_config(self.module, flags) 534 if not config: 535 sampler_tmp["sampler_interval"] = "null" 536 sampler_tmp["sampler_direction"] = "null" 537 else: 538 config_list = config.split(' ') 539 config_num = len(config_list) 540 if config_num > 1: 541 sampler_tmp["sampler_direction"] = config_list[config_num - 1] 542 sampler_tmp["sampler_interval"] = config_list[config_num - 2] 543 sampler_tmp["interface"] = "all" 544 self.end_state["sampler"].append(sampler_tmp) 545 if self.interface != "all": 546 flags = list() 547 exp = r" | ignore-case section include ^#\s+interface %s" \ 548 r" | include netstream sampler random-packets" % self.interface 549 flags.append(exp) 550 config = get_config(self.module, flags) 551 if not config: 552 sampler_tmp1["sampler_interval"] = "null" 553 sampler_tmp1["sampler_direction"] = "null" 554 else: 555 config = config.lstrip() 556 config_list = config.split('\n') 557 for config_mem in config_list: 558 sampler_tmp1 = dict() 559 config_mem_list = config_mem.split(' ') 560 config_num = len(config_mem_list) 561 if config_num > 1: 562 sampler_tmp1["sampler_direction"] = config_mem_list[ 563 config_num - 1] 564 sampler_tmp1["sampler_interval"] = config_mem_list[ 565 config_num - 2] 566 sampler_tmp1["interface"] = self.interface 567 self.end_state["sampler"].append(sampler_tmp1) 568 569 def get_end_statistic_record(self): 570 """get end netstream statistic record parameter""" 571 572 if self.statistics_record and self.statistics_direction: 573 self.module.fail_json( 574 msg='Error: The statistic direction and record can not exist at the same time.') 575 statistic_tmp = dict() 576 statistic_tmp1 = dict() 577 statistic_tmp["statistics_record"] = list() 578 statistic_tmp["interface"] = self.interface 579 statistic_tmp1["statistics_record"] = list() 580 statistic_tmp1["interface"] = self.interface 581 flags = list() 582 exp = r" | ignore-case section include ^#\s+interface %s" \ 583 r" | include netstream record"\ 584 % (self.interface) 585 flags.append(exp) 586 config = get_config(self.module, flags) 587 if not config: 588 statistic_tmp["type"] = "ip" 589 self.end_state["flexible_statistic"].append(statistic_tmp) 590 statistic_tmp1["type"] = "vxlan" 591 self.end_state["flexible_statistic"].append(statistic_tmp1) 592 else: 593 config = config.lstrip() 594 config_list = config.split('\n') 595 for config_mem in config_list: 596 config_mem = config_mem.lstrip() 597 statistic_tmp["statistics_record"] = list() 598 config_mem_list = config_mem.split(' ') 599 if len(config_mem_list) > 3 and str(config_mem_list[3]) == "ip": 600 statistic_tmp["statistics_record"].append( 601 str(config_mem_list[2])) 602 statistic_tmp["type"] = "ip" 603 self.end_state["flexible_statistic"].append(statistic_tmp) 604 for config_mem in config_list: 605 statistic_tmp1["statistics_record"] = list() 606 config_mem = config_mem.lstrip() 607 config_mem_list = config_mem.split(' ') 608 if len(config_mem_list) > 3 and str(config_mem_list[3]) == "vxlan": 609 statistic_tmp1["statistics_record"].append( 610 str(config_mem_list[2])) 611 statistic_tmp1["type"] = "vxlan" 612 self.end_state["flexible_statistic"].append(statistic_tmp1) 613 614 def get_end_interface_statistic(self): 615 """get end netstream interface statistic parameters""" 616 617 statistic_tmp1 = dict() 618 statistic_tmp1["statistics_direction"] = list() 619 flags = list() 620 exp = r" | ignore-case section include ^#\s+interface %s" \ 621 r" | include netstream inbound|outbound"\ 622 % self.interface 623 flags.append(exp) 624 config = get_config(self.module, flags) 625 if not config: 626 statistic_tmp1["type"] = "null" 627 else: 628 statistic_tmp1["type"] = "ip" 629 config = config.lstrip() 630 config_list = config.split('\n') 631 for config_mem in config_list: 632 config_mem = config_mem.lstrip() 633 config_mem_list = config_mem.split(' ') 634 if len(config_mem_list) > 1: 635 statistic_tmp1["statistics_direction"].append( 636 str(config_mem_list[1])) 637 statistic_tmp1["interface"] = self.interface 638 self.end_state["statistic"].append(statistic_tmp1) 639 640 def get_end_index_switch(self): 641 """get end netstream index switch""" 642 643 index_switch_tmp = dict() 644 index_switch_tmp1 = dict() 645 index_switch_tmp["index-switch"] = "16" 646 index_switch_tmp["type"] = "ip" 647 index_switch_tmp1["index-switch"] = "16" 648 index_switch_tmp1["type"] = "vxlan" 649 flags = list() 650 exp = " | ignore-case include index-switch" 651 flags.append(exp) 652 config = get_config(self.module, flags) 653 if not config: 654 self.end_state["index-switch"].append(index_switch_tmp) 655 self.end_state["index-switch"].append(index_switch_tmp1) 656 else: 657 config = config.lstrip() 658 config_list = config.split('\n') 659 for config_mem in config_list: 660 config_mem_list = config_mem.split(' ') 661 if len(config_mem_list) > 2 and str(config_mem_list[2]) == "ip": 662 index_switch_tmp["index-switch"] = "32" 663 index_switch_tmp["type"] = "ip" 664 if len(config_mem_list) > 2 and str(config_mem_list[2]) == "vxlan": 665 index_switch_tmp1["index-switch"] = "32" 666 index_switch_tmp1["type"] = "vxlan" 667 self.end_state["index-switch"].append(index_switch_tmp) 668 self.end_state["index-switch"].append(index_switch_tmp1) 669 670 def check_params(self): 671 """check all input params""" 672 673 # netstream parameters check 674 if not get_interface_type(self.interface): 675 self.module.fail_json( 676 msg='Error: Interface name of %s is error.' % self.interface) 677 if self.sampler_interval: 678 if not str(self.sampler_interval).isdigit(): 679 self.module.fail_json( 680 msg='Error: Active interval should be numerical.') 681 if int(self.sampler_interval) < 1 or int(self.sampler_interval) > 65535: 682 self.module.fail_json( 683 msg="Error: Sampler interval should between 1 - 65535.") 684 if self.statistics_record: 685 if len(self.statistics_record) < 1 or len(self.statistics_record) > 32: 686 self.module.fail_json( 687 msg="Error: Statistic record length should between 1 - 32.") 688 if self.interface == "all": 689 if self.statistics_record or self.statistics_direction: 690 self.module.fail_json( 691 msg="Error: Statistic function should be used at interface.") 692 if self.statistics_direction: 693 if self.type == "vxlan": 694 self.module.fail_json( 695 msg="Error: Vxlan do not support inbound or outbound statistic.") 696 if (self.sampler_interval and not self.sampler_direction) \ 697 or (self.sampler_direction and not self.sampler_interval): 698 self.module.fail_json( 699 msg="Error: Sampler interval and direction must be set at the same time.") 700 701 if self.statistics_record and not self.type: 702 self.module.fail_json( 703 msg="Error: Statistic type and record must be set at the same time.") 704 705 self.get_exist_record() 706 if self.statistics_record: 707 if self.type == "ip": 708 if self.statistics_record not in self.existing["ip_record"]: 709 self.module.fail_json( 710 msg="Error: The statistic record is not exist.") 711 if self.type == "vxlan": 712 if self.statistics_record not in self.existing["vxlan_record"]: 713 self.module.fail_json( 714 msg="Error: The statistic record is not exist.") 715 716 def get_proposed(self): 717 """get proposed info""" 718 719 if self.type: 720 self.proposed["type"] = self.type 721 if self.interface: 722 self.proposed["interface"] = self.interface 723 if self.sampler_interval: 724 self.proposed["sampler_interval"] = self.sampler_interval 725 if self.sampler_direction: 726 self.proposed["sampler_direction"] = self.sampler_direction 727 if self.statistics_direction: 728 self.proposed["statistics_direction"] = self.statistics_direction 729 if self.statistics_record: 730 self.proposed["statistics_record"] = self.statistics_record 731 if self.index_switch: 732 self.proposed["index_switch"] = self.index_switch 733 if self.state: 734 self.proposed["state"] = self.state 735 736 def get_existing(self): 737 """get existing info""" 738 sampler_tmp = dict() 739 statistic_tmp = dict() 740 statistic_tmp1 = dict() 741 index_tmp = dict() 742 temp = False 743 744 self.get_exist_sampler_interval() 745 self.get_exist_interface_statistic() 746 self.get_exist_statistic_record() 747 self.get_exist_index_switch() 748 749 if self.state == "present": 750 for sampler_tmp in self.existing["sampler"]: 751 if self.interface == str(sampler_tmp["interface"]): 752 temp = True 753 if (self.sampler_interval and str(sampler_tmp["sampler_interval"]) != self.sampler_interval) \ 754 or (self.sampler_direction and 755 str(sampler_tmp["sampler_direction"]) != self.sampler_direction): 756 self.sampler_changed = True 757 if not temp: 758 if self.sampler_direction or self.sampler_interval: 759 self.sampler_changed = True 760 for statistic_tmp in self.existing["statistic"]: 761 if str(statistic_tmp["interface"]) == self.interface and self.interface != "all": 762 if self.type == "vxlan": 763 if statistic_tmp["statistics_direction"] \ 764 and 'outbound' in statistic_tmp["statistics_direction"]: 765 self.module.fail_json( 766 msg='Error: The NetStream record vxlan ' 767 'cannot be configured because the port has been configured NetStream outbound ip.') 768 if statistic_tmp["statistics_direction"] and self.statistics_direction: 769 if self.statistics_direction not in statistic_tmp["statistics_direction"]: 770 self.statistic_changed = True 771 else: 772 if self.statistics_direction: 773 self.statistic_changed = True 774 for statistic_tmp1 in self.existing["flexible_statistic"]: 775 if self.interface != "all" \ 776 and self.type == str(statistic_tmp1["type"]) \ 777 and self.interface == str(statistic_tmp1["interface"]): 778 if statistic_tmp1["statistics_record"] and self.statistics_record: 779 if self.statistics_record not in statistic_tmp1["statistics_record"]: 780 self.flexible_changed = True 781 else: 782 if self.statistics_record: 783 self.flexible_changed = True 784 for index_tmp in self.existing["index-switch"]: 785 if self.type == str(index_tmp["type"]): 786 if self.index_switch != str(index_tmp["index-switch"]): 787 self.index_switch_changed = True 788 else: 789 for sampler_tmp in self.existing["sampler"]: 790 if self.interface == str(sampler_tmp["interface"]): 791 if (self.sampler_interval and str(sampler_tmp["sampler_interval"]) == self.sampler_interval) \ 792 and (self.sampler_direction and str(sampler_tmp["sampler_direction"]) == self.sampler_direction): 793 self.sampler_changed = True 794 for statistic_tmp in self.existing["statistic"]: 795 if str(statistic_tmp["interface"]) == self.interface and self.interface != "all": 796 if len(statistic_tmp["statistics_direction"]) and self.statistics_direction: 797 if self.statistics_direction in statistic_tmp["statistics_direction"]: 798 self.statistic_changed = True 799 for statistic_tmp1 in self.existing["flexible_statistic"]: 800 if self.interface != "all" \ 801 and self.type == str(statistic_tmp1["type"]) \ 802 and self.interface == str(statistic_tmp1["interface"]): 803 if len(statistic_tmp1["statistics_record"]) and self.statistics_record: 804 if self.statistics_record in statistic_tmp1["statistics_record"]: 805 self.flexible_changed = True 806 for index_tmp in self.existing["index-switch"]: 807 if self.type == str(index_tmp["type"]): 808 if self.index_switch == str(index_tmp["index-switch"]): 809 if self.index_switch != "16": 810 self.index_switch_changed = True 811 812 def operate_ns_gloabl(self): 813 """configure netstream global parameters""" 814 815 cmd = "" 816 if not self.sampler_changed and not self.statistic_changed \ 817 and not self.flexible_changed and not self.index_switch_changed: 818 self.changed = False 819 return 820 821 if self.sampler_changed is True: 822 if self.type == "vxlan": 823 self.module.fail_json( 824 msg="Error: Netstream do not support vxlan sampler.") 825 if self.interface != "all": 826 cmd = "interface %s" % self.interface 827 self.cli_add_command(cmd) 828 cmd = "netstream sampler random-packets %s %s" % ( 829 self.sampler_interval, self.sampler_direction) 830 if self.state == "present": 831 self.cli_add_command(cmd) 832 else: 833 self.cli_add_command(cmd, undo=True) 834 if self.interface != "all": 835 cmd = "quit" 836 self.cli_add_command(cmd) 837 if self.statistic_changed is True: 838 if self.interface != "all": 839 cmd = "interface %s" % self.interface 840 self.cli_add_command(cmd) 841 cmd = "netstream %s ip" % self.statistics_direction 842 if self.state == "present": 843 self.cli_add_command(cmd) 844 else: 845 self.cli_add_command(cmd, undo=True) 846 if self.interface != "all": 847 cmd = "quit" 848 self.cli_add_command(cmd) 849 if self.flexible_changed is True: 850 if self.interface != "all": 851 cmd = "interface %s" % self.interface 852 self.cli_add_command(cmd) 853 if self.state == "present": 854 for statistic_tmp in self.existing["flexible_statistic"]: 855 tmp_list = statistic_tmp["statistics_record"] 856 if self.type == statistic_tmp["type"]: 857 if self.type == "ip": 858 if len(tmp_list) > 0: 859 cmd = "netstream record %s ip" % tmp_list[0] 860 self.cli_add_command(cmd, undo=True) 861 cmd = "netstream record %s ip" % self.statistics_record 862 self.cli_add_command(cmd) 863 if self.type == "vxlan": 864 if len(tmp_list) > 0: 865 cmd = "netstream record %s vxlan inner-ip" % tmp_list[ 866 0] 867 self.cli_add_command(cmd, undo=True) 868 cmd = "netstream record %s vxlan inner-ip" % self.statistics_record 869 self.cli_add_command(cmd) 870 else: 871 if self.type == "ip": 872 cmd = "netstream record %s ip" % self.statistics_record 873 self.cli_add_command(cmd, undo=True) 874 if self.type == "vxlan": 875 cmd = "netstream record %s vxlan inner-ip" % self.statistics_record 876 self.cli_add_command(cmd, undo=True) 877 if self.interface != "all": 878 cmd = "quit" 879 self.cli_add_command(cmd) 880 if self.index_switch_changed is True: 881 if self.interface != "all": 882 self.module.fail_json( 883 msg="Error: Index-switch function should be used globally.") 884 if self.type == "ip": 885 cmd = "netstream export ip index-switch %s" % self.index_switch 886 else: 887 cmd = "netstream export vxlan inner-ip index-switch %s" % self.index_switch 888 if self.state == "present": 889 self.cli_add_command(cmd) 890 else: 891 self.cli_add_command(cmd, undo=True) 892 893 if self.commands: 894 self.cli_load_config(self.commands) 895 self.changed = True 896 897 def get_end_state(self): 898 """get end state info""" 899 900 self.get_end_sampler_interval() 901 self.get_end_interface_statistic() 902 self.get_end_statistic_record() 903 self.get_end_index_switch() 904 905 def work(self): 906 """worker""" 907 908 self.check_params() 909 self.get_existing() 910 self.get_proposed() 911 self.operate_ns_gloabl() 912 self.get_end_state() 913 self.results['changed'] = self.changed 914 self.results['proposed'] = self.proposed 915 self.results['existing'] = self.existing 916 self.results['end_state'] = self.end_state 917 if self.changed: 918 self.results['updates'] = self.updates_cmd 919 else: 920 self.results['updates'] = list() 921 922 self.module.exit_json(**self.results) 923 924 925def main(): 926 """Module main""" 927 928 argument_spec = dict( 929 type=dict(required=False, choices=['ip', 'vxlan'], default='ip'), 930 interface=dict(required=True, type='str'), 931 sampler_interval=dict(required=False, type='str'), 932 sampler_direction=dict(required=False, choices=['inbound', 'outbound']), 933 statistics_direction=dict(required=False, choices=['inbound', 'outbound']), 934 statistics_record=dict(required=False, type='str'), 935 index_switch=dict(required=False, choices=['16', '32'], default='16'), 936 state=dict(required=False, choices=['present', 'absent'], default='present'), 937 ) 938 argument_spec.update(ce_argument_spec) 939 module = NetStreamGlobal(argument_spec) 940 module.work() 941 942 943if __name__ == '__main__': 944 main() 945