summaryrefslogtreecommitdiff
path: root/lib/ansible/modules/network/onyx/onyx_ptp_interface.py
blob: 15b6b2c27ae2707d8b3e85b053305383758055a2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
#!/usr/bin/python
#
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

from __future__ import absolute_import, division, print_function
__metaclass__ = type

ANSIBLE_METADATA = {'metadata_version': '1.1',
                    'status': ['preview'],
                    'supported_by': 'community'}

DOCUMENTATION = """
---
module: onyx_ptp_interface
version_added: '2.8'
author: 'Anas Badaha (@anasb)'
short_description: 'Configures PTP on interface'
description:
    - "This module provides declarative management of PTP interfaces configuration\non Mellanox ONYX network devices."
notes:
    - 'Tested on ONYX 3.6.8130'
    - 'PTP Protocol must be enabled on switch.'
    - 'Interface must not be a switch port interface.'
options:
    name:
        description:
            - 'ethernet or vlan interface name that we want to configure PTP on it'
        required: true
    state:
        description:
            - 'Enable/Disable PTP on Interface'
        default: enabled
        choices:
            - enabled
            - disabled
    delay_request:
        description:
            - 'configure PTP delay request interval, Range 0-5'
    announce_interval:
        description:
            - 'configure PTP announce setting for interval, Range -3-1'
    announce_timeout:
        description:
            - 'configure PTP announce setting for timeout, Range 2-10'
    sync_interval:
        description:
            - 'configure PTP sync interval, Range -7--1'
"""

EXAMPLES = """
- name: configure PTP interface
  onyx_ptp_interface:
    state: enabled
    name: Eth1/1
    delay_request: 0
    announce_interval: -2
    announce_timeout: 3
"""

RETURN = """
commands:
  description: The list of configuration mode commands to send to the device.
  returned: always
  type: list
  sample:
    - interface ethernet 1/16 ptp enable
    - interface ethernet 1/16 ptp delay-req interval 0
    - interface ethernet 1/16 ptp announce interval -1
"""

import re

from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.six import iteritems
from ansible.module_utils.network.onyx.onyx import show_cmd
from ansible.module_utils.network.onyx.onyx import BaseOnyxModule


class OnyxPtpInterfaceModule(BaseOnyxModule):
    IF_ETH_REGEX = re.compile(r"^Eth(\d+\/\d+|Eth\d+\/\d+\d+)$")
    IF_VLAN_REGEX = re.compile(r"^Vlan (\d+)$")

    IF_TYPE_ETH = "ethernet"
    IF_TYPE_VLAN = "vlan"

    IF_TYPE_MAP = {
        IF_TYPE_ETH: IF_ETH_REGEX,
        IF_TYPE_VLAN: IF_VLAN_REGEX
    }

    RANGE_ATTR = {
        "delay_request": (0, 5),
        "announce_interval": (-3, -1),
        "announce_timeout": (2, 10),
        "sync_interval": (-7, -1)
    }

    _interface_type = None
    _interface_id = None

    def init_module(self):
        """ initialize module
        """
        element_spec = dict(
            name=dict(required=True),
            state=dict(choices=['enabled', 'disabled'], default='enabled'),
            delay_request=dict(type=int),
            announce_interval=dict(type=int),
            announce_timeout=dict(type=int),
            sync_interval=dict(type=int)
        )
        argument_spec = dict()
        argument_spec.update(element_spec)
        self._module = AnsibleModule(
            argument_spec=argument_spec,
            supports_check_mode=True)

    @classmethod
    def _get_interface_type(cls, if_name):
        if_type = None
        if_id = None
        for interface_type, interface_regex in iteritems(cls.IF_TYPE_MAP):
            match = interface_regex.match(if_name)
            if match:
                if_type = interface_type
                if_id = match.group(1)
                break
        return if_type, if_id

    def _set_if_type(self, module_params):
        if_name = module_params['name']
        self._interface_type, self._interface_id = self._get_interface_type(if_name)
        if not self._interface_id:
            self._module.fail_json(
                msg='unsupported interface name/type: %s' % if_name)

    def get_required_config(self):
        module_params = self._module.params
        self._required_config = dict(module_params)
        self._set_if_type(self._required_config)
        self.validate_param_values(self._required_config)

    def _validate_attr_is_not_none(self, attr_name, attr_value):
        if attr_value is not None:
            self._module.fail_json(msg='Can not set %s value on switch while state is disabled' % attr_name)

    def validate_param_values(self, obj, param=None):
        if obj['state'] == 'disabled':
            for attr_name in self.RANGE_ATTR:
                self._validate_attr_is_not_none(attr_name, obj[attr_name])
        super(OnyxPtpInterfaceModule, self).validate_param_values(obj, param)

    def _validate_range(self, value, attr_name):
        min_value, max_value = self.RANGE_ATTR[attr_name]
        if value and not min_value <= int(value) <= max_value:
            self._module.fail_json(msg='%s value must be between %d and %d' % (attr_name, min_value, max_value))

    def validate_delay_request(self, value):
        self._validate_range(value, "delay_request")

    def validate_announce_interval(self, value):
        self._validate_range(value, "announce_interval")

    def validate_announce_timeout(self, value):
        self._validate_range(value, "announce_timeout")

    def validate_sync_interval(self, value):
        self._validate_range(value, "sync_interval")

    def _set_ptp_interface_config(self, ptp_interface_config):
        if ptp_interface_config is None:
            self._current_config['state'] = 'disabled'
            return
        ptp_interface_config = ptp_interface_config[0]
        self._current_config['state'] = 'enabled'
        self._current_config['delay_request'] = int(ptp_interface_config['Delay request interval(log mean)'])
        self._current_config['announce_interval'] = int(ptp_interface_config['Announce interval(log mean)'])
        self._current_config['announce_timeout'] = int(ptp_interface_config['Announce receipt time out'])
        self._current_config['sync_interval'] = int(ptp_interface_config['Sync interval(log mean)'])

    def _show_ptp_interface_config(self):
        cmd = "show ptp interface %s %s" % (self._interface_type, self._interface_id)
        return show_cmd(self._module, cmd, json_fmt=True, fail_on_error=False)

    def load_current_config(self):
        self._current_config = dict()
        ptp_interface_config = self._show_ptp_interface_config()
        self._set_ptp_interface_config(ptp_interface_config)

    def _generate_attr_command(self, attr_name, attr_cmd_name):
        attr_val = self._required_config.get(attr_name)
        if attr_val is not None:
            curr_val = self._current_config.get(attr_name)
            if attr_val != curr_val:
                self._commands.append(
                    'interface %s %s ptp %s %d' % (self._interface_type, self._interface_id, attr_cmd_name, attr_val))

    def generate_commands(self):
        state = self._required_config.get("state", "enabled")
        self._gen_ptp_commands(state)

        self._generate_attr_command("delay_request", "delay-req interval")
        self._generate_attr_command("announce_interval", "announce interval")
        self._generate_attr_command("announce_timeout", "announce timeout")
        self._generate_attr_command("sync_interval", "sync interval")

    def _add_if_ptp_cmd(self, req_state):
        if req_state == 'enabled':
            if_ptp_cmd = 'interface %s %s ptp enable' % (self._interface_type, self._interface_id)
        else:
            if_ptp_cmd = 'no interface %s %s ptp enable' % (self._interface_type, self._interface_id)
        self._commands.append(if_ptp_cmd)

    def _gen_ptp_commands(self, req_state):
        curr_state = self._current_config.get('state')
        if curr_state != req_state:
            self._add_if_ptp_cmd(req_state)


def main():
    """ main entry point for module execution
    """
    OnyxPtpInterfaceModule.main()


if __name__ == '__main__':
    main()