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