mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-06-28 11:10:21 -07:00
Adding Support for Traffic Class in Onyx Switches (#55577)
* Adding Support for Traffic Class in Onyx Switches Signed-off-by: Anas Badaha <anasb@mellanox.com> * Enhancing the code and elemenating code duplicate Signed-off-by: Anas Badaha <anasb@mellanox.com>
This commit is contained in:
parent
7e6be4e634
commit
031655def0
4 changed files with 579 additions and 0 deletions
326
lib/ansible/modules/network/onyx/onyx_traffic_class.py
Normal file
326
lib/ansible/modules/network/onyx/onyx_traffic_class.py
Normal file
|
@ -0,0 +1,326 @@
|
||||||
|
#!/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_traffic_class
|
||||||
|
version_added: "2.9"
|
||||||
|
author: "Anas Badaha (@anasb)"
|
||||||
|
short_description: Configures Traffic Class
|
||||||
|
description:
|
||||||
|
- This module provides declarative management of Traffic Class configuration
|
||||||
|
on Mellanox ONYX network devices.
|
||||||
|
options:
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- enable congestion control on interface.
|
||||||
|
choices: ['enabled', 'disabled']
|
||||||
|
default: enabled
|
||||||
|
interfaces:
|
||||||
|
description:
|
||||||
|
- list of interfaces name.
|
||||||
|
required: true
|
||||||
|
tc:
|
||||||
|
description:
|
||||||
|
- traffic class, range 0-7.
|
||||||
|
required: true
|
||||||
|
congestion_control:
|
||||||
|
description:
|
||||||
|
- configure congestion control on interface.
|
||||||
|
suboptions:
|
||||||
|
control:
|
||||||
|
description:
|
||||||
|
- congestion control type.
|
||||||
|
choices: ['red', 'ecn', 'both']
|
||||||
|
required: true
|
||||||
|
threshold_mode:
|
||||||
|
description:
|
||||||
|
- congestion control threshold mode.
|
||||||
|
choices: ['absolute', 'relative']
|
||||||
|
required: true
|
||||||
|
min_threshold:
|
||||||
|
description:
|
||||||
|
- Set minimum-threshold value (in KBs) for marking traffic-class queue.
|
||||||
|
required: true
|
||||||
|
max_threshold:
|
||||||
|
description:
|
||||||
|
- Set maximum-threshold value (in KBs) for marking traffic-class queue.
|
||||||
|
required: true
|
||||||
|
dcb:
|
||||||
|
description:
|
||||||
|
- configure dcb control on interface.
|
||||||
|
suboptions:
|
||||||
|
mode:
|
||||||
|
description:
|
||||||
|
- dcb control mode.
|
||||||
|
choices: ['strict', 'wrr']
|
||||||
|
required: true
|
||||||
|
weight:
|
||||||
|
description:
|
||||||
|
- Relevant only for wrr mode.
|
||||||
|
"""
|
||||||
|
|
||||||
|
EXAMPLES = """
|
||||||
|
- name: configure traffic class
|
||||||
|
onyx_traffic_class:
|
||||||
|
interfaces:
|
||||||
|
- Eth1/1
|
||||||
|
- Eth1/2
|
||||||
|
tc: 3
|
||||||
|
congestion_control:
|
||||||
|
control: ecn
|
||||||
|
threshold_mode: absolute
|
||||||
|
min_threshold: 500
|
||||||
|
max_threshold: 1500
|
||||||
|
dcb:
|
||||||
|
mode: strict
|
||||||
|
"""
|
||||||
|
|
||||||
|
RETURN = """
|
||||||
|
commands:
|
||||||
|
description: The list of configuration mode commands to send to the device.
|
||||||
|
returned: always
|
||||||
|
type: list
|
||||||
|
sample:
|
||||||
|
- interface ethernet 1/15 traffic-class 3 congestion-control ecn minimum-absolute 150 maximum-absolute 1500
|
||||||
|
- interface ethernet 1/16 traffic-class 3 congestion-control ecn minimum-absolute 150 maximum-absolute 1500
|
||||||
|
- interface mlag-port-channel 7 traffic-class 3 congestion-control ecn minimum-absolute 150 maximum-absolute 1500
|
||||||
|
- interface port-channel 1 traffic-class 3 congestion-control ecn minimum-absolute 150 maximum-absolute 1500
|
||||||
|
- interface ethernet 1/15 traffic-class 3 dcb ets strict
|
||||||
|
- interface ethernet 1/16 traffic-class 3 dcb ets strict
|
||||||
|
- interface mlag-port-channel 7 traffic-class 3 dcb ets strict
|
||||||
|
- interface port-channel 1 traffic-class 3 dcb ets strict
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
from ansible.module_utils.six import iteritems
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible.module_utils.network.onyx.onyx import show_cmd
|
||||||
|
from ansible.module_utils.network.onyx.onyx import BaseOnyxModule
|
||||||
|
|
||||||
|
|
||||||
|
class OnyxTrafficClassModule(BaseOnyxModule):
|
||||||
|
|
||||||
|
IF_ETH_REGEX = re.compile(r"^Eth(\d+\/\d+|Eth\d+\/\d+\d+)$")
|
||||||
|
IF_PO_REGEX = re.compile(r"^Po(\d+)$")
|
||||||
|
MLAG_NAME_REGEX = re.compile(r"^Mpo(\d+)$")
|
||||||
|
|
||||||
|
IF_TYPE_ETH = "ethernet"
|
||||||
|
PORT_CHANNEL = "port-channel"
|
||||||
|
MLAG_PORT_CHANNEL = "mlag-port-channel"
|
||||||
|
|
||||||
|
IF_TYPE_MAP = {
|
||||||
|
IF_TYPE_ETH: IF_ETH_REGEX,
|
||||||
|
PORT_CHANNEL: IF_PO_REGEX,
|
||||||
|
MLAG_PORT_CHANNEL: MLAG_NAME_REGEX
|
||||||
|
}
|
||||||
|
|
||||||
|
def init_module(self):
|
||||||
|
""" initialize module
|
||||||
|
"""
|
||||||
|
congestion_control_spec = dict(control=dict(choices=['red', 'ecn', 'both'], required=True),
|
||||||
|
threshold_mode=dict(choices=['absolute', 'relative'], required=True),
|
||||||
|
min_threshold=dict(type=int, required=True),
|
||||||
|
max_threshold=dict(type=int, required=True))
|
||||||
|
|
||||||
|
dcb_spec = dict(mode=dict(choices=['strict', 'wrr'], required=True),
|
||||||
|
weight=dict(type=int))
|
||||||
|
|
||||||
|
element_spec = dict(
|
||||||
|
interfaces=dict(type='list', required=True),
|
||||||
|
tc=dict(type=int, required=True),
|
||||||
|
congestion_control=dict(type='dict', options=congestion_control_spec),
|
||||||
|
dcb=dict(type='dict', options=dcb_spec),
|
||||||
|
state=dict(choices=['enabled', 'disabled'], default='enabled'))
|
||||||
|
|
||||||
|
argument_spec = dict()
|
||||||
|
argument_spec.update(element_spec)
|
||||||
|
self._module = AnsibleModule(
|
||||||
|
argument_spec=argument_spec,
|
||||||
|
supports_check_mode=True)
|
||||||
|
|
||||||
|
def get_required_config(self):
|
||||||
|
module_params = self._module.params
|
||||||
|
self._required_config = dict(module_params)
|
||||||
|
self.validate_param_values(self._required_config)
|
||||||
|
|
||||||
|
def validate_tc(self, value):
|
||||||
|
if value and not 0 <= int(value) <= 7:
|
||||||
|
self._module.fail_json(msg='tc value must be between 0 and 7')
|
||||||
|
|
||||||
|
def validate_param_values(self, obj, param=None):
|
||||||
|
dcb = obj.get("dcb")
|
||||||
|
if dcb is not None:
|
||||||
|
dcb_mode = dcb.get("mode")
|
||||||
|
weight = dcb.get("weight")
|
||||||
|
if dcb_mode == "wrr" and weight is None:
|
||||||
|
self._module.fail_json(msg='User should send weight attribute when dcb mode is wrr')
|
||||||
|
super(OnyxTrafficClassModule, self).validate_param_values(obj, param)
|
||||||
|
|
||||||
|
def _get_interface_type(self, if_name):
|
||||||
|
if_type = None
|
||||||
|
if_id = None
|
||||||
|
for interface_type, interface_regex in iteritems(self.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_interface_congestion_control_config(self, interface_congestion_control_config,
|
||||||
|
interface, if_type, if_id):
|
||||||
|
tc = self._required_config.get("tc")
|
||||||
|
interface_dcb_ets = self._show_interface_dcb_ets(if_type, if_id)[0].get(interface)
|
||||||
|
if interface_dcb_ets is None:
|
||||||
|
dcb = dict()
|
||||||
|
else:
|
||||||
|
ets_per_tc = interface_dcb_ets[2].get("ETS per TC")
|
||||||
|
tc_config = ets_per_tc[0].get(str(tc))
|
||||||
|
dcb_mode = tc_config[0].get("S.Mode")
|
||||||
|
dcb_weight = int(tc_config[0].get("W"))
|
||||||
|
dcb = dict(mode=dcb_mode.lower(), weight=dcb_weight)
|
||||||
|
|
||||||
|
interface_congestion_control_config = interface_congestion_control_config[tc + 1]
|
||||||
|
mode = interface_congestion_control_config.get("Mode")
|
||||||
|
if mode == "none":
|
||||||
|
self._current_config[interface] = dict(state="disabled", dcb=dcb, if_type=if_type, if_id=if_id)
|
||||||
|
return
|
||||||
|
|
||||||
|
threshold_mode = interface_congestion_control_config.get("Threshold mode")
|
||||||
|
max_threshold = interface_congestion_control_config.get("Maximum threshold")
|
||||||
|
min_threshold = interface_congestion_control_config.get("Minimum threshold")
|
||||||
|
|
||||||
|
if threshold_mode == "absolute":
|
||||||
|
delimiter = ' '
|
||||||
|
else:
|
||||||
|
delimiter = '%'
|
||||||
|
min_value = int(min_threshold.split(delimiter)[0])
|
||||||
|
max_malue = int(max_threshold.split(delimiter)[0])
|
||||||
|
congestion_control = dict(control=mode.lower(), threshold_mode=threshold_mode,
|
||||||
|
min_threshold=min_value, max_threshold=max_malue)
|
||||||
|
|
||||||
|
self._current_config[interface] = dict(state="enabled", congestion_control=congestion_control,
|
||||||
|
dcb=dcb, if_type=if_type, if_id=if_id)
|
||||||
|
|
||||||
|
def _show_interface_congestion_control(self, if_type, interface):
|
||||||
|
cmd = "show interfaces {0} {1} congestion-control".format(if_type, interface)
|
||||||
|
return show_cmd(self._module, cmd, json_fmt=True, fail_on_error=False)
|
||||||
|
|
||||||
|
def _show_interface_dcb_ets(self, if_type, interface):
|
||||||
|
cmd = "show dcb ets interface {0} {1}".format(if_type, interface)
|
||||||
|
return show_cmd(self._module, cmd, json_fmt=True, fail_on_error=False)
|
||||||
|
|
||||||
|
def load_current_config(self):
|
||||||
|
self._current_config = dict()
|
||||||
|
for interface in self._required_config.get("interfaces"):
|
||||||
|
if_type, if_id = self._get_interface_type(interface)
|
||||||
|
if not if_id:
|
||||||
|
self._module.fail_json(
|
||||||
|
msg='unsupported interface: {0}'.format(interface))
|
||||||
|
interface_congestion_control_config = self._show_interface_congestion_control(if_type, if_id)
|
||||||
|
if interface_congestion_control_config is not None:
|
||||||
|
self._set_interface_congestion_control_config(interface_congestion_control_config,
|
||||||
|
interface, if_type, if_id)
|
||||||
|
else:
|
||||||
|
self._module.fail_json(
|
||||||
|
msg='Interface {0} does not exist on switch'.format(interface))
|
||||||
|
|
||||||
|
def generate_commands(self):
|
||||||
|
state = self._required_config.get("state")
|
||||||
|
tc = self._required_config.get("tc")
|
||||||
|
interfaces = self._required_config.get("interfaces")
|
||||||
|
for interface in interfaces:
|
||||||
|
current_interface = self._current_config.get(interface)
|
||||||
|
current_state = current_interface.get("state")
|
||||||
|
if_type = current_interface.get("if_type")
|
||||||
|
if_id = current_interface.get("if_id")
|
||||||
|
if state == "disabled":
|
||||||
|
if current_state == "enabled":
|
||||||
|
self._commands.append('interface {0} {1} no traffic-class {2} congestion-control'.format(if_type, if_id, tc))
|
||||||
|
continue
|
||||||
|
|
||||||
|
congestion_control = self._required_config.get("congestion_control")
|
||||||
|
|
||||||
|
if congestion_control is not None:
|
||||||
|
control = congestion_control.get("control")
|
||||||
|
current_congestion_control = current_interface.get("congestion_control")
|
||||||
|
threshold_mode = congestion_control.get("threshold_mode")
|
||||||
|
min_threshold = congestion_control.get("min_threshold")
|
||||||
|
max_threshold = congestion_control.get("max_threshold")
|
||||||
|
if current_congestion_control is None:
|
||||||
|
self._threshold_mode_generate_cmds_mappers(threshold_mode, if_type, if_id, tc,
|
||||||
|
control, min_threshold, max_threshold)
|
||||||
|
else:
|
||||||
|
current_control = current_congestion_control.get("control")
|
||||||
|
curr_threshold_mode = current_congestion_control.get("threshold_mode")
|
||||||
|
curr_min_threshold = current_congestion_control.get("min_threshold")
|
||||||
|
curr_max_threshold = current_congestion_control.get("max_threshold")
|
||||||
|
|
||||||
|
if control != current_control:
|
||||||
|
self._threshold_mode_generate_cmds_mappers(threshold_mode, if_type, if_id, tc,
|
||||||
|
control, min_threshold, max_threshold)
|
||||||
|
else:
|
||||||
|
if threshold_mode != curr_threshold_mode:
|
||||||
|
self._threshold_mode_generate_cmds_mappers(threshold_mode, if_type, if_id, tc,
|
||||||
|
control, min_threshold, max_threshold)
|
||||||
|
elif min_threshold != curr_min_threshold or max_threshold != curr_max_threshold:
|
||||||
|
self._threshold_mode_generate_cmds_mappers(threshold_mode, if_type, if_id, tc,
|
||||||
|
control, min_threshold, max_threshold)
|
||||||
|
|
||||||
|
dcb = self._required_config.get("dcb")
|
||||||
|
if dcb is not None:
|
||||||
|
dcb_mode = dcb.get("mode")
|
||||||
|
current_dcb = current_interface.get("dcb")
|
||||||
|
current_dcb_mode = current_dcb.get("mode")
|
||||||
|
if dcb_mode == "strict" and dcb_mode != current_dcb_mode:
|
||||||
|
self._commands.append('interface {0} {1} traffic-class {2} '
|
||||||
|
'dcb ets {3}'.format(if_type, if_id, tc, dcb_mode))
|
||||||
|
elif dcb_mode == "wrr":
|
||||||
|
weight = dcb.get("weight")
|
||||||
|
current_weight = current_dcb.get("weight")
|
||||||
|
if dcb_mode != current_dcb_mode or weight != current_weight:
|
||||||
|
self._commands.append('interface {0} {1} traffic-class {2} '
|
||||||
|
'dcb ets {3} {4}'.format(if_type, if_id, tc, dcb_mode, weight))
|
||||||
|
|
||||||
|
def _threshold_mode_generate_cmds_mappers(self, threshold_mode, if_type, if_id, tc,
|
||||||
|
control, min_threshold, max_threshold):
|
||||||
|
if threshold_mode == 'absolute':
|
||||||
|
self._generate_congestion_control_absolute_cmds(if_type, if_id, tc, control,
|
||||||
|
min_threshold, max_threshold)
|
||||||
|
else:
|
||||||
|
self._generate_congestion_control_relative_cmds(if_type, if_id, tc, control,
|
||||||
|
min_threshold, max_threshold)
|
||||||
|
|
||||||
|
def _generate_congestion_control_absolute_cmds(self, if_type, if_id, tc, control,
|
||||||
|
min_absolute, max_absolute):
|
||||||
|
self._commands.append('interface {0} {1} traffic-class {2} '
|
||||||
|
'congestion-control {3} minimum-absolute {4} '
|
||||||
|
'maximum-absolute {5}'.format(if_type, if_id, tc, control,
|
||||||
|
min_absolute, max_absolute))
|
||||||
|
|
||||||
|
def _generate_congestion_control_relative_cmds(self, if_type, if_id, tc, control,
|
||||||
|
min_relative, max_relative):
|
||||||
|
self._commands.append('interface {0} {1} traffic-class {2} '
|
||||||
|
'congestion-control {3} minimum-relative {4} '
|
||||||
|
'maximum-relative {5}'.format(if_type, if_id, tc, control,
|
||||||
|
min_relative, max_relative))
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
""" main entry point for module execution
|
||||||
|
"""
|
||||||
|
OnyxTrafficClassModule.main()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
|
@ -0,0 +1,99 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"Eth1/1": [
|
||||||
|
{
|
||||||
|
"Multicast unaware mapping": "disabled",
|
||||||
|
"Interface Bandwidth Shape [Mbps]": "N/A"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Flags": [
|
||||||
|
{
|
||||||
|
"S.Mode": "Scheduling Mode [Strict/WRR]",
|
||||||
|
"Bw.Sh": "Bandwidth Shaper",
|
||||||
|
"D": "-",
|
||||||
|
"W": "Weight",
|
||||||
|
"Bw.Gr": "Bandwidth Guaranteed"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ETS per TC": [
|
||||||
|
{
|
||||||
|
"1": [
|
||||||
|
{
|
||||||
|
"S.Mode": "WRR",
|
||||||
|
"BW Sh.(Mbps)": "N/A",
|
||||||
|
"W(%)": "17",
|
||||||
|
"BW Gr.(Mbps)": "0",
|
||||||
|
"W": "13"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"0": [
|
||||||
|
{
|
||||||
|
"S.Mode": "WRR",
|
||||||
|
"BW Sh.(Mbps)": "N/A",
|
||||||
|
"W(%)": "17",
|
||||||
|
"BW Gr.(Mbps)": "0",
|
||||||
|
"W": "12"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"3": [
|
||||||
|
{
|
||||||
|
"S.Mode": "Strict",
|
||||||
|
"BW Sh.(Mbps)": "N/A",
|
||||||
|
"W(%)": "0",
|
||||||
|
"BW Gr.(Mbps)": "0",
|
||||||
|
"W": "0"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"2": [
|
||||||
|
{
|
||||||
|
"S.Mode": "Strict",
|
||||||
|
"BW Sh.(Mbps)": "N/A",
|
||||||
|
"W(%)": "0",
|
||||||
|
"BW Gr.(Mbps)": "0",
|
||||||
|
"W": "0"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"5": [
|
||||||
|
{
|
||||||
|
"S.Mode": "WRR",
|
||||||
|
"BW Sh.(Mbps)": "N/A",
|
||||||
|
"W(%)": "17",
|
||||||
|
"BW Gr.(Mbps)": "0",
|
||||||
|
"W": "13"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"4": [
|
||||||
|
{
|
||||||
|
"S.Mode": "WRR",
|
||||||
|
"BW Sh.(Mbps)": "N/A",
|
||||||
|
"W(%)": "16",
|
||||||
|
"BW Gr.(Mbps)": "0",
|
||||||
|
"W": "12"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"7": [
|
||||||
|
{
|
||||||
|
"S.Mode": "WRR",
|
||||||
|
"BW Sh.(Mbps)": "N/A",
|
||||||
|
"W(%)": "17",
|
||||||
|
"BW Gr.(Mbps)": "0",
|
||||||
|
"W": "13"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"6": [
|
||||||
|
{
|
||||||
|
"S.Mode": "WRR",
|
||||||
|
"BW Sh.(Mbps)": "N/A",
|
||||||
|
"W(%)": "16",
|
||||||
|
"BW Gr.(Mbps)": "0",
|
||||||
|
"W": "12"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
|
@ -0,0 +1,46 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"Interface ethernet": "1/1",
|
||||||
|
"ECN marked packets": "0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"header": "TC-0",
|
||||||
|
"Mode": "none"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"header": "TC-1",
|
||||||
|
"Mode": "none"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Threshold mode": "relative",
|
||||||
|
"RED dropped packets": "0",
|
||||||
|
"header": "TC-2",
|
||||||
|
"Mode": "RED",
|
||||||
|
"Maximum threshold": "90%",
|
||||||
|
"Minimum threshold": "9%"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Threshold mode": "absolute",
|
||||||
|
"RED dropped packets": "0",
|
||||||
|
"header": "TC-3",
|
||||||
|
"Mode": "ECN",
|
||||||
|
"Maximum threshold": "1550 KB",
|
||||||
|
"Minimum threshold": "500 KB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"header": "TC-4",
|
||||||
|
"Mode": "none"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"header": "TC-5",
|
||||||
|
"Mode": "none"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"header": "TC-6",
|
||||||
|
"Mode": "none"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"header": "TC-7",
|
||||||
|
"Mode": "none"
|
||||||
|
}
|
||||||
|
]
|
108
test/units/modules/network/onyx/test_onyx_traffic_class.py
Normal file
108
test/units/modules/network/onyx/test_onyx_traffic_class.py
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
#
|
||||||
|
# Copyright: Ansible Project
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
# Make coding more python3-ish
|
||||||
|
from __future__ import (absolute_import, division, print_function)
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
from units.compat.mock import patch
|
||||||
|
from ansible.modules.network.onyx import onyx_traffic_class
|
||||||
|
from units.modules.utils import set_module_args
|
||||||
|
from .onyx_module import TestOnyxModule, load_fixture
|
||||||
|
|
||||||
|
|
||||||
|
class TestOnyxTrafficClassModule(TestOnyxModule):
|
||||||
|
|
||||||
|
module = onyx_traffic_class
|
||||||
|
arp_suppression = True
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestOnyxTrafficClassModule, self).setUp()
|
||||||
|
self.mock_get_congestion_control_config = patch.object(
|
||||||
|
onyx_traffic_class.OnyxTrafficClassModule, "_show_interface_congestion_control")
|
||||||
|
self.get_congestion_control_config = self.mock_get_congestion_control_config.start()
|
||||||
|
|
||||||
|
self.mock_load_config = patch(
|
||||||
|
'ansible.module_utils.network.onyx.onyx.load_config')
|
||||||
|
self.load_config = self.mock_load_config.start()
|
||||||
|
|
||||||
|
self.mock_get_dcb_config = patch.object(
|
||||||
|
onyx_traffic_class.OnyxTrafficClassModule, "_show_interface_dcb_ets")
|
||||||
|
self.get_dcb_config = self.mock_get_dcb_config.start()
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
super(TestOnyxTrafficClassModule, self).tearDown()
|
||||||
|
self.mock_get_congestion_control_config.stop()
|
||||||
|
self.mock_load_config.stop()
|
||||||
|
self.mock_get_dcb_config.stop()
|
||||||
|
|
||||||
|
def load_fixtures(self, commands=None, transport='cli'):
|
||||||
|
interfaces_congestion_control_config_file = 'onyx_show_interface_congestion_control.cfg'
|
||||||
|
interfaces_dcb_config_file = 'onyx_show_dcb_ets_interface.cfg'
|
||||||
|
interfaces_congestion_control_data = load_fixture(interfaces_congestion_control_config_file)
|
||||||
|
interfaces_dcb_config_data = load_fixture(interfaces_dcb_config_file)
|
||||||
|
self.get_congestion_control_config.return_value = interfaces_congestion_control_data
|
||||||
|
self.get_dcb_config.return_value = interfaces_dcb_config_data
|
||||||
|
self.load_config.return_value = None
|
||||||
|
|
||||||
|
def test_configure_congestion_control_disabled_with_change(self):
|
||||||
|
set_module_args(dict(interfaces=["Eth1/1"], tc=1,
|
||||||
|
congestion_control=dict(control="ecn", threshold_mode="absolute",
|
||||||
|
min_threshold=500, max_threshold=1500)))
|
||||||
|
commands = [
|
||||||
|
"interface ethernet 1/1 traffic-class 1 congestion-control ecn minimum-absolute 500 maximum-absolute 1500"
|
||||||
|
]
|
||||||
|
self.execute_module(changed=True, commands=commands)
|
||||||
|
|
||||||
|
def test_configure_congestion_control_disabled_with_no_change(self):
|
||||||
|
set_module_args(dict(state="disabled", interfaces=["Eth1/1"], tc=0))
|
||||||
|
|
||||||
|
self.execute_module(changed=False)
|
||||||
|
|
||||||
|
def test_configure_congestion_control_with_change(self):
|
||||||
|
set_module_args(dict(interfaces=["Eth1/1"], tc=2,
|
||||||
|
congestion_control=dict(control="ecn", threshold_mode="relative",
|
||||||
|
min_threshold=9, max_threshold=88)))
|
||||||
|
commands = [
|
||||||
|
"interface ethernet 1/1 traffic-class 2 congestion-control ecn minimum-relative 9 maximum-relative 88"
|
||||||
|
]
|
||||||
|
self.execute_module(changed=True, commands=commands)
|
||||||
|
|
||||||
|
def test_configure_congestion_control_absolute_with_change(self):
|
||||||
|
set_module_args(dict(interfaces=["Eth1/1"], tc=3,
|
||||||
|
congestion_control=dict(control="ecn", threshold_mode="absolute",
|
||||||
|
min_threshold=500, max_threshold=1500)))
|
||||||
|
commands = [
|
||||||
|
"interface ethernet 1/1 traffic-class 3 congestion-control ecn minimum-absolute 500 maximum-absolute 1500"
|
||||||
|
]
|
||||||
|
self.execute_module(changed=True, commands=commands)
|
||||||
|
|
||||||
|
def test_configure_congestion_control_with_no_change(self):
|
||||||
|
set_module_args(dict(interfaces=["Eth1/1"], tc=3,
|
||||||
|
congestion_control=dict(control="ecn", threshold_mode="absolute",
|
||||||
|
min_threshold=500, max_threshold=1550)))
|
||||||
|
self.execute_module(changed=False)
|
||||||
|
|
||||||
|
def test_configure_dcb_mode_with_no_change(self):
|
||||||
|
set_module_args(dict(interfaces=["Eth1/1"], tc=3, dcb=dict(mode="strict")))
|
||||||
|
self.execute_module(changed=False)
|
||||||
|
|
||||||
|
def test_configure_dcb_strict_mode_with_change(self):
|
||||||
|
set_module_args(dict(interfaces=["Eth1/1"], tc=1, dcb=dict(mode="strict")))
|
||||||
|
commands = [
|
||||||
|
"interface ethernet 1/1 traffic-class 1 dcb ets strict"
|
||||||
|
]
|
||||||
|
self.execute_module(changed=True, commands=commands)
|
||||||
|
|
||||||
|
def test_configure_dcb_wrr_mode_with_change(self):
|
||||||
|
set_module_args(dict(interfaces=["Eth1/1"], tc=0, dcb=dict(mode="wrr", weight=10)))
|
||||||
|
commands = [
|
||||||
|
"interface ethernet 1/1 traffic-class 0 dcb ets wrr 10"
|
||||||
|
]
|
||||||
|
self.execute_module(changed=True, commands=commands)
|
||||||
|
|
||||||
|
def test_configure_dcb_wrr_mode_with_no_change(self):
|
||||||
|
set_module_args(dict(interfaces=["Eth1/1"], tc=0, dcb=dict(mode="wrr", weight=12)))
|
||||||
|
|
||||||
|
self.execute_module(changed=False)
|
Loading…
Add table
Add a link
Reference in a new issue