1#!/usr/local/bin/python3.8
2#
3# Copyright: Ansible Project
4# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
5
6from __future__ import absolute_import, division, print_function
7__metaclass__ = type
8
9DOCUMENTATION = '''
10---
11module: onyx_protocol
12author: "Samer Deeb (@samerd)"
13short_description: Enables/Disables protocols on Mellanox ONYX network devices
14description:
15  - This module provides a mechanism for enabling and disabling protocols
16    Mellanox on ONYX network devices.
17notes:
18  - Tested on ONYX 3.6.4000
19options:
20  mlag:
21    description: MLAG protocol
22    choices: ['enabled', 'disabled']
23  magp:
24    description: MAGP protocol
25    choices: ['enabled', 'disabled']
26  spanning_tree:
27    description: Spanning Tree support
28    choices: ['enabled', 'disabled']
29  dcb_pfc:
30    description: DCB priority flow control
31    choices: ['enabled', 'disabled']
32  igmp_snooping:
33    description: IP IGMP snooping
34    choices: ['enabled', 'disabled']
35  lacp:
36    description: LACP protocol
37    choices: ['enabled', 'disabled']
38  ip_l3:
39    description: IP L3 support
40    choices: ['enabled', 'disabled']
41  ip_routing:
42    description: IP routing support
43    choices: ['enabled', 'disabled']
44  lldp:
45    description: LLDP protocol
46    choices: ['enabled', 'disabled']
47  bgp:
48    description: BGP protocol
49    choices: ['enabled', 'disabled']
50  ospf:
51    description: OSPF protocol
52    choices: ['enabled', 'disabled']
53  nve:
54    description: nve protocol
55    choices: ['enabled', 'disabled']
56  bfd:
57    description: bfd protocol
58    choices: ['enabled', 'disabled']
59    version_added: '0.2.0'
60'''
61
62EXAMPLES = """
63- name: Enable protocols for MLAG
64  onyx_protocol:
65    lacp: enabled
66    spanning_tree: disabled
67    ip_routing: enabled
68    mlag: enabled
69    dcb_pfc: enabled
70"""
71
72RETURN = """
73commands:
74  description: The list of configuration mode commands to send to the device.
75  returned: always
76  type: list
77  sample:
78    - no spanning-tree
79    - protocol mlag
80"""
81
82from ansible.module_utils.basic import AnsibleModule
83from ansible.module_utils.six import iteritems
84
85from ansible_collections.mellanox.onyx.plugins.module_utils.network.onyx.onyx import BaseOnyxModule
86from ansible_collections.mellanox.onyx.plugins.module_utils.network.onyx.onyx import show_cmd
87
88
89class OnyxProtocolModule(BaseOnyxModule):
90
91    PROTOCOL_MAPPING = dict(
92        mlag=dict(name="mlag", enable="protocol mlag",
93                  disable="no protocol mlag"),
94        magp=dict(name="magp", enable="protocol magp",
95                  disable="no protocol magp"),
96        spanning_tree=dict(name="spanning-tree", enable="spanning-tree",
97                           disable="no spanning-tree"),
98        dcb_pfc=dict(name="priority-flow-control",
99                     enable="dcb priority-flow-control enable force",
100                     disable="no dcb priority-flow-control enable force"),
101        igmp_snooping=dict(name="igmp-snooping", enable="ip igmp snooping",
102                           disable="no ip igmp snooping"),
103        lacp=dict(name="lacp", enable="lacp", disable="no lacp"),
104        ip_l3=dict(name="IP L3", enable="ip l3",
105                        disable="no ip l3"),
106        ip_routing=dict(name="IP routing", enable="ip routing",
107                        disable="no ip routing"),
108        lldp=dict(name="lldp", enable="lldp", disable="no lldp"),
109        bgp=dict(name="bgp", enable="protocol bgp", disable="no protocol bgp"),
110        ospf=dict(name="ospf", enable="protocol ospf",
111                  disable="no protocol ospf"),
112        nve=dict(name="nve", enable="protocol nve",
113                 disable="no protocol nve"),
114        bfd=dict(name="bfd", enable="protocol bfd",
115                 disable="no protocol bfd"),
116    )
117
118    @classmethod
119    def _get_element_spec(cls):
120        element_spec = dict()
121        for protocol in cls.PROTOCOL_MAPPING:
122            element_spec[protocol] = dict(choices=['enabled', 'disabled'])
123        return element_spec
124
125    def init_module(self):
126        """ Ansible module initialization
127        """
128        element_spec = self._get_element_spec()
129        argument_spec = dict()
130        argument_spec.update(element_spec)
131        self._module = AnsibleModule(
132            argument_spec=argument_spec,
133            supports_check_mode=True
134        )
135
136    def get_required_config(self):
137        self._required_config = dict()
138        module_params = self._module.params
139        for key, val in iteritems(module_params):
140            if key in self.PROTOCOL_MAPPING and val is not None:
141                self._required_config[key] = val
142
143    def _get_protocols(self):
144        return show_cmd(self._module, "show protocols")
145
146    def _get_ip_routing(self):
147        return show_cmd(self._module, 'show ip routing | include "IP routing"',
148                        json_fmt=False)
149
150    def load_current_config(self):
151        self._current_config = dict()
152        protocols_config = self._get_protocols()
153        if not protocols_config:
154            protocols_config = dict()
155        ip_config = self._get_ip_routing()
156        if ip_config:
157            lines = ip_config.split('\n')
158            for line in lines:
159                line = line.strip()
160                line_attr = line.split(':')
161                if len(line_attr) == 2:
162                    attr = line_attr[0].strip()
163                    val = line_attr[1].strip()
164                    protocols_config[attr] = val
165        for protocol, protocol_metadata in iteritems(self.PROTOCOL_MAPPING):
166            protocol_json_attr = protocol_metadata['name']
167            val = protocols_config.get(protocol_json_attr, 'disabled')
168            if val not in ('enabled', 'disabled'):
169                val = 'enabled'
170            self._current_config[protocol] = val
171
172    def generate_commands(self):
173        for protocol, req_val in iteritems(self._required_config):
174            protocol_metadata = self.PROTOCOL_MAPPING[protocol]
175            curr_val = self._current_config.get(protocol, 'disabled')
176            if curr_val != req_val:
177                if req_val == 'disabled':
178                    command = protocol_metadata['disable']
179                else:
180                    command = protocol_metadata['enable']
181                self._commands.append(command)
182
183
184def main():
185    """ main entry point for module execution
186    """
187    OnyxProtocolModule.main()
188
189
190if __name__ == '__main__':
191    main()
192