mirror of
https://github.com/saltstack/salt.git
synced 2025-04-16 09:40:20 +00:00
fixes saltstack/salt#63128 add ethtool execution and state module functions for pause
This commit is contained in:
parent
b7da9d2ef2
commit
553dfd2fe2
5 changed files with 545 additions and 1 deletions
1
changelog/63128.added
Normal file
1
changelog/63128.added
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Add ethtool execution and state module functions for pause
|
|
@ -9,8 +9,11 @@ Module for running ethtool command
|
||||||
:platform: linux
|
:platform: linux
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
import salt.utils.path
|
||||||
|
from salt.exceptions import CommandExecutionError
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import ethtool
|
import ethtool
|
||||||
|
@ -299,3 +302,136 @@ def set_offload(devname, **kwargs):
|
||||||
return "Not supported"
|
return "Not supported"
|
||||||
|
|
||||||
return show_offload(devname)
|
return show_offload(devname)
|
||||||
|
|
||||||
|
|
||||||
|
def _ethtool_command(devname, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Helper function to build an ethtool command
|
||||||
|
"""
|
||||||
|
ethtool = salt.utils.path.which("ethtool")
|
||||||
|
if not ethtool:
|
||||||
|
raise CommandExecutionError("Command 'ethtool' cannot be found")
|
||||||
|
switches = " ".join(arg for arg in args)
|
||||||
|
params = " ".join("{} {}".format(key, val) for key, val in kwargs.items())
|
||||||
|
cmd = "{} {} {} {}".format(ethtool, switches, devname, params).strip()
|
||||||
|
ret = __salt__["cmd.run"](cmd, ignore_retcode=True).splitlines()
|
||||||
|
if ret and ret[0].startswith("Cannot"):
|
||||||
|
raise CommandExecutionError(ret[0])
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_params(valid_params, kwargs):
|
||||||
|
"""
|
||||||
|
Helper function to validate parameters to ethtool commands. Boolean values
|
||||||
|
will be transformed into ``on`` and ``off`` to match expected syntax.
|
||||||
|
"""
|
||||||
|
validated = {}
|
||||||
|
for key, val in kwargs.items():
|
||||||
|
key = key.lower()
|
||||||
|
if key in valid_params:
|
||||||
|
if val is True:
|
||||||
|
val = "on"
|
||||||
|
elif val is False:
|
||||||
|
val = "off"
|
||||||
|
validated[key] = val
|
||||||
|
if not validated:
|
||||||
|
raise CommandExecutionError(
|
||||||
|
"None of the valid parameters were provided: {}".format(valid_params)
|
||||||
|
)
|
||||||
|
return validated
|
||||||
|
|
||||||
|
|
||||||
|
def show_pause(devname):
|
||||||
|
"""
|
||||||
|
Queries the specified network device for associated pause information
|
||||||
|
|
||||||
|
CLI Example:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
salt '*' ethtool.show_pause <devname>
|
||||||
|
"""
|
||||||
|
data = {}
|
||||||
|
|
||||||
|
content = _ethtool_command(devname, "-a")
|
||||||
|
|
||||||
|
for line in content[1:]:
|
||||||
|
if line.strip():
|
||||||
|
(key, value) = (s.strip() for s in line.split(":", 1))
|
||||||
|
data[key] = value == "on"
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def set_pause(devname, **kwargs):
|
||||||
|
"""
|
||||||
|
Changes the pause parameters of the specified network device
|
||||||
|
|
||||||
|
CLI Example:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
salt '*' ethtool.set_pause <devname> autoneg=off rx=off tx=off
|
||||||
|
"""
|
||||||
|
valid_params = ["autoneg", "rx", "tx"]
|
||||||
|
params = _validate_params(valid_params, kwargs)
|
||||||
|
ret = _ethtool_command(devname, "-A", **params)
|
||||||
|
if not ret:
|
||||||
|
return True
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
def show_features(devname):
|
||||||
|
"""
|
||||||
|
Queries the specified network device for associated feature information
|
||||||
|
|
||||||
|
CLI Example:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
salt '*' ethtool.show_feature <devname>
|
||||||
|
"""
|
||||||
|
data = {}
|
||||||
|
|
||||||
|
content = _ethtool_command(devname, "-k")
|
||||||
|
|
||||||
|
for line in content[1:]:
|
||||||
|
if ":" in line:
|
||||||
|
key, value = (s.strip() for s in line.strip().split(":", 1))
|
||||||
|
fixed = "fixed" in value
|
||||||
|
if fixed:
|
||||||
|
value = value.split()[0].strip()
|
||||||
|
data[key.strip()] = {"on": value == "on", "fixed": fixed}
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def set_feature(devname, **kwargs):
|
||||||
|
"""
|
||||||
|
Changes the feature parameters of the specified network device
|
||||||
|
|
||||||
|
CLI Example:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
salt '*' ethtool.set_feature <devname> sg=off
|
||||||
|
"""
|
||||||
|
valid_params = [
|
||||||
|
"rx",
|
||||||
|
"tx",
|
||||||
|
"sg",
|
||||||
|
"tso",
|
||||||
|
"ufo",
|
||||||
|
"gso",
|
||||||
|
"gro",
|
||||||
|
"lro",
|
||||||
|
"rxvlan",
|
||||||
|
"txvlan",
|
||||||
|
"ntuple",
|
||||||
|
"rxhash",
|
||||||
|
]
|
||||||
|
params = _validate_params(valid_params, kwargs)
|
||||||
|
ret = _ethtool_command(devname, "-K", **params)
|
||||||
|
if not ret:
|
||||||
|
return True
|
||||||
|
return os.linesep.join(ret)
|
||||||
|
|
|
@ -32,6 +32,8 @@ Configuration of network device
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from salt.exceptions import CommandExecutionError
|
||||||
|
|
||||||
# Set up logging
|
# Set up logging
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -310,3 +312,83 @@ def offload(name, **kwargs):
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
def pause(name, **kwargs):
|
||||||
|
"""
|
||||||
|
Manage pause parameters of network device
|
||||||
|
|
||||||
|
name
|
||||||
|
Interface name to apply pause parameters
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
eth0:
|
||||||
|
ethtool.pause:
|
||||||
|
- name: eth0
|
||||||
|
- autoneg: off
|
||||||
|
- rx: off
|
||||||
|
- tx: off
|
||||||
|
|
||||||
|
"""
|
||||||
|
ret = {
|
||||||
|
"name": name,
|
||||||
|
"changes": {},
|
||||||
|
"result": True,
|
||||||
|
"comment": "Network device {} pause parameters are up to date.".format(name),
|
||||||
|
}
|
||||||
|
apply_pause = False
|
||||||
|
|
||||||
|
# Get current pause parameters
|
||||||
|
try:
|
||||||
|
old = __salt__["ethtool.show_pause"](name)
|
||||||
|
except CommandExecutionError:
|
||||||
|
ret["result"] = False
|
||||||
|
ret["comment"] = "Device {} pause parameters are not supported".format(name)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
# map ethtool command input to output text
|
||||||
|
pause_map = {
|
||||||
|
"autoneg": "Autonegotiate",
|
||||||
|
"rx": "RX",
|
||||||
|
"tx": "RX",
|
||||||
|
}
|
||||||
|
|
||||||
|
# Process changes
|
||||||
|
new = {}
|
||||||
|
diff = []
|
||||||
|
|
||||||
|
for key, value in kwargs.items():
|
||||||
|
key = key.lower()
|
||||||
|
if key in pause_map:
|
||||||
|
if value != old[pause_map[key]]:
|
||||||
|
new.update({key: value})
|
||||||
|
if value is True:
|
||||||
|
value = "on"
|
||||||
|
elif value is False:
|
||||||
|
value = "off"
|
||||||
|
diff.append("{}: {}".format(key, value))
|
||||||
|
|
||||||
|
if not new:
|
||||||
|
return ret
|
||||||
|
|
||||||
|
# Dry run
|
||||||
|
if __opts__["test"]:
|
||||||
|
ret["result"] = None
|
||||||
|
ret["comment"] = "Device {} pause parameters are set to be updated:\n{}".format(
|
||||||
|
name, "\n".join(diff)
|
||||||
|
)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
# Apply pause parameters
|
||||||
|
try:
|
||||||
|
__salt__["ethtool.set_pause"](name, **new)
|
||||||
|
# Prepare return output
|
||||||
|
ret["comment"] = "Device {} pause parameters updated.".format(name)
|
||||||
|
ret["changes"]["ethtool_pause"] = "\n".join(diff)
|
||||||
|
except CommandExecutionError as exc:
|
||||||
|
ret["result"] = False
|
||||||
|
ret["comment"] = str(exc)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
248
tests/pytests/unit/modules/test_ethtool.py
Normal file
248
tests/pytests/unit/modules/test_ethtool.py
Normal file
|
@ -0,0 +1,248 @@
|
||||||
|
from textwrap import dedent
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
import salt.modules.ethtool as ethtool
|
||||||
|
from salt.exceptions import CommandExecutionError
|
||||||
|
from tests.support.mock import MagicMock, patch
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def configure_loader_modules():
|
||||||
|
return {
|
||||||
|
ethtool: {
|
||||||
|
"__salt__": {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def pause_ret():
|
||||||
|
cmdret = dedent(
|
||||||
|
"""Pause parameters for eth0:
|
||||||
|
Autonegotiate: on
|
||||||
|
RX: on
|
||||||
|
TX: on
|
||||||
|
RX negotiated: off
|
||||||
|
TX negotiated: off"""
|
||||||
|
)
|
||||||
|
return cmdret
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def features_ret():
|
||||||
|
cmdret = dedent(
|
||||||
|
"""Features for eth0:
|
||||||
|
rx-checksumming: on [fixed]
|
||||||
|
tx-checksumming: on
|
||||||
|
tx-checksum-ipv4: off [fixed]
|
||||||
|
tx-checksum-ip-generic: on
|
||||||
|
tx-checksum-ipv6: off [fixed]
|
||||||
|
tx-checksum-fcoe-crc: off [fixed]
|
||||||
|
tx-checksum-sctp: off [fixed]
|
||||||
|
scatter-gather: on
|
||||||
|
tx-scatter-gather: on
|
||||||
|
tx-scatter-gather-fraglist: off [fixed]
|
||||||
|
tcp-segmentation-offload: on
|
||||||
|
tx-tcp-segmentation: on
|
||||||
|
tx-tcp-ecn-segmentation: on
|
||||||
|
tx-tcp-mangleid-segmentation: off
|
||||||
|
tx-tcp6-segmentation: on
|
||||||
|
udp-fragmentation-offload: off
|
||||||
|
generic-segmentation-offload: on
|
||||||
|
generic-receive-offload: on
|
||||||
|
large-receive-offload: off [fixed]
|
||||||
|
rx-vlan-offload: off [fixed]
|
||||||
|
tx-vlan-offload: off [fixed]
|
||||||
|
ntuple-filters: off [fixed]
|
||||||
|
receive-hashing: off [fixed]
|
||||||
|
highdma: on [fixed]
|
||||||
|
rx-vlan-filter: on [fixed]
|
||||||
|
vlan-challenged: off [fixed]
|
||||||
|
tx-lockless: off [fixed]
|
||||||
|
netns-local: off [fixed]
|
||||||
|
tx-gso-robust: on [fixed]
|
||||||
|
tx-fcoe-segmentation: off [fixed]
|
||||||
|
tx-gre-segmentation: off [fixed]
|
||||||
|
tx-gre-csum-segmentation: off [fixed]
|
||||||
|
tx-ipxip4-segmentation: off [fixed]
|
||||||
|
tx-ipxip6-segmentation: off [fixed]
|
||||||
|
tx-udp_tnl-segmentation: off [fixed]
|
||||||
|
tx-udp_tnl-csum-segmentation: off [fixed]
|
||||||
|
tx-gso-partial: off [fixed]
|
||||||
|
tx-sctp-segmentation: off [fixed]
|
||||||
|
tx-esp-segmentation: off [fixed]
|
||||||
|
tx-udp-segmentation: off [fixed]
|
||||||
|
fcoe-mtu: off [fixed]
|
||||||
|
tx-nocache-copy: off
|
||||||
|
loopback: off [fixed]
|
||||||
|
rx-fcs: off [fixed]
|
||||||
|
rx-all: off [fixed]
|
||||||
|
tx-vlan-stag-hw-insert: off [fixed]
|
||||||
|
rx-vlan-stag-hw-parse: off [fixed]
|
||||||
|
rx-vlan-stag-filter: off [fixed]
|
||||||
|
l2-fwd-offload: off [fixed]
|
||||||
|
hw-tc-offload: off [fixed]
|
||||||
|
esp-hw-offload: off [fixed]
|
||||||
|
esp-tx-csum-hw-offload: off [fixed]
|
||||||
|
rx-udp_tunnel-port-offload: off [fixed]
|
||||||
|
tls-hw-tx-offload: off [fixed]
|
||||||
|
tls-hw-rx-offload: off [fixed]
|
||||||
|
rx-gro-hw: off [fixed]
|
||||||
|
tls-hw-record: off [fixed]"""
|
||||||
|
)
|
||||||
|
return cmdret
|
||||||
|
|
||||||
|
|
||||||
|
def test_ethtool__ethtool_command_which_fail():
|
||||||
|
with patch("salt.utils.path.which", MagicMock(return_value=None)):
|
||||||
|
with pytest.raises(CommandExecutionError):
|
||||||
|
ethtool._ethtool_command("eth0")
|
||||||
|
|
||||||
|
|
||||||
|
def test_ethtool__ethtool_command_operation_not_supported():
|
||||||
|
mock_cmd_run = MagicMock(
|
||||||
|
side_effect=[
|
||||||
|
"Pause parameters for eth0:\nCannot get device pause settings: Operation not supported",
|
||||||
|
"Cannot get device pause settings: Operation not supported",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
with patch(
|
||||||
|
"salt.utils.path.which", MagicMock(return_value="/sbin/ethtool")
|
||||||
|
), patch.dict(ethtool.__salt__, {"cmd.run": mock_cmd_run}):
|
||||||
|
with pytest.raises(CommandExecutionError):
|
||||||
|
ethtool._ethtool_command("eth0", "-a")
|
||||||
|
ethtool._ethtool_command("eth0", "-A", autoneg="off", rx="off", tx="off")
|
||||||
|
|
||||||
|
|
||||||
|
def test_ethtool__ethtool_command(pause_ret):
|
||||||
|
mock_cmd_run = MagicMock(return_value=pause_ret)
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"salt.utils.path.which", MagicMock(return_value="/sbin/ethtool")
|
||||||
|
), patch.dict(ethtool.__salt__, {"cmd.run": mock_cmd_run}):
|
||||||
|
ret = ethtool._ethtool_command("eth0", "-A", autoneg="off", rx="off", tx="off")
|
||||||
|
|
||||||
|
mock_cmd_run.assert_called_once_with(
|
||||||
|
"/sbin/ethtool -A eth0 autoneg off rx off tx off", ignore_retcode=True
|
||||||
|
)
|
||||||
|
assert pause_ret.splitlines() == ret
|
||||||
|
|
||||||
|
|
||||||
|
def test_ethtool__validate_params():
|
||||||
|
with pytest.raises(CommandExecutionError):
|
||||||
|
ethtool._validate_params(["not_found"], {"eth": "tool"})
|
||||||
|
assert ethtool._validate_params(["eth"], {"eth": "tool"}) == {"eth": "tool"}
|
||||||
|
assert ethtool._validate_params(["eth", "not_found"], {"eth": "tool"}) == {
|
||||||
|
"eth": "tool"
|
||||||
|
}
|
||||||
|
assert ethtool._validate_params(["eth", "salt"], {"eth": True, "salt": False}) == {
|
||||||
|
"eth": "on",
|
||||||
|
"salt": "off",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_ethtool_show_pause(pause_ret):
|
||||||
|
expected = {
|
||||||
|
"Autonegotiate": True,
|
||||||
|
"RX": True,
|
||||||
|
"RX negotiated": False,
|
||||||
|
"TX": True,
|
||||||
|
"TX negotiated": False,
|
||||||
|
}
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"salt.modules.ethtool._ethtool_command",
|
||||||
|
MagicMock(return_value=pause_ret.splitlines()),
|
||||||
|
):
|
||||||
|
ret = ethtool.show_pause("eth0")
|
||||||
|
|
||||||
|
assert expected == ret
|
||||||
|
|
||||||
|
|
||||||
|
def test_ethtool_show_features(features_ret):
|
||||||
|
expected = {
|
||||||
|
"esp-hw-offload": {"fixed": True, "on": False},
|
||||||
|
"esp-tx-csum-hw-offload": {"fixed": True, "on": False},
|
||||||
|
"fcoe-mtu": {"fixed": True, "on": False},
|
||||||
|
"generic-receive-offload": {"fixed": False, "on": True},
|
||||||
|
"generic-segmentation-offload": {"fixed": False, "on": True},
|
||||||
|
"highdma": {"fixed": True, "on": True},
|
||||||
|
"hw-tc-offload": {"fixed": True, "on": False},
|
||||||
|
"l2-fwd-offload": {"fixed": True, "on": False},
|
||||||
|
"large-receive-offload": {"fixed": True, "on": False},
|
||||||
|
"loopback": {"fixed": True, "on": False},
|
||||||
|
"netns-local": {"fixed": True, "on": False},
|
||||||
|
"ntuple-filters": {"fixed": True, "on": False},
|
||||||
|
"receive-hashing": {"fixed": True, "on": False},
|
||||||
|
"rx-all": {"fixed": True, "on": False},
|
||||||
|
"rx-checksumming": {"fixed": True, "on": True},
|
||||||
|
"rx-fcs": {"fixed": True, "on": False},
|
||||||
|
"rx-gro-hw": {"fixed": True, "on": False},
|
||||||
|
"rx-udp_tunnel-port-offload": {"fixed": True, "on": False},
|
||||||
|
"rx-vlan-filter": {"fixed": True, "on": True},
|
||||||
|
"rx-vlan-offload": {"fixed": True, "on": False},
|
||||||
|
"rx-vlan-stag-filter": {"fixed": True, "on": False},
|
||||||
|
"rx-vlan-stag-hw-parse": {"fixed": True, "on": False},
|
||||||
|
"scatter-gather": {"fixed": False, "on": True},
|
||||||
|
"tcp-segmentation-offload": {"fixed": False, "on": True},
|
||||||
|
"tls-hw-record": {"fixed": True, "on": False},
|
||||||
|
"tls-hw-rx-offload": {"fixed": True, "on": False},
|
||||||
|
"tls-hw-tx-offload": {"fixed": True, "on": False},
|
||||||
|
"tx-checksum-fcoe-crc": {"fixed": True, "on": False},
|
||||||
|
"tx-checksum-ip-generic": {"fixed": False, "on": True},
|
||||||
|
"tx-checksum-ipv4": {"fixed": True, "on": False},
|
||||||
|
"tx-checksum-ipv6": {"fixed": True, "on": False},
|
||||||
|
"tx-checksum-sctp": {"fixed": True, "on": False},
|
||||||
|
"tx-checksumming": {"fixed": False, "on": True},
|
||||||
|
"tx-esp-segmentation": {"fixed": True, "on": False},
|
||||||
|
"tx-fcoe-segmentation": {"fixed": True, "on": False},
|
||||||
|
"tx-gre-csum-segmentation": {"fixed": True, "on": False},
|
||||||
|
"tx-gre-segmentation": {"fixed": True, "on": False},
|
||||||
|
"tx-gso-partial": {"fixed": True, "on": False},
|
||||||
|
"tx-gso-robust": {"fixed": True, "on": True},
|
||||||
|
"tx-ipxip4-segmentation": {"fixed": True, "on": False},
|
||||||
|
"tx-ipxip6-segmentation": {"fixed": True, "on": False},
|
||||||
|
"tx-lockless": {"fixed": True, "on": False},
|
||||||
|
"tx-nocache-copy": {"fixed": False, "on": False},
|
||||||
|
"tx-scatter-gather": {"fixed": False, "on": True},
|
||||||
|
"tx-scatter-gather-fraglist": {"fixed": True, "on": False},
|
||||||
|
"tx-sctp-segmentation": {"fixed": True, "on": False},
|
||||||
|
"tx-tcp-ecn-segmentation": {"fixed": False, "on": True},
|
||||||
|
"tx-tcp-mangleid-segmentation": {"fixed": False, "on": False},
|
||||||
|
"tx-tcp-segmentation": {"fixed": False, "on": True},
|
||||||
|
"tx-tcp6-segmentation": {"fixed": False, "on": True},
|
||||||
|
"tx-udp-segmentation": {"fixed": True, "on": False},
|
||||||
|
"tx-udp_tnl-csum-segmentation": {"fixed": True, "on": False},
|
||||||
|
"tx-udp_tnl-segmentation": {"fixed": True, "on": False},
|
||||||
|
"tx-vlan-offload": {"fixed": True, "on": False},
|
||||||
|
"tx-vlan-stag-hw-insert": {"fixed": True, "on": False},
|
||||||
|
"udp-fragmentation-offload": {"fixed": False, "on": False},
|
||||||
|
"vlan-challenged": {"fixed": True, "on": False},
|
||||||
|
}
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"salt.modules.ethtool._ethtool_command",
|
||||||
|
MagicMock(return_value=features_ret.splitlines()),
|
||||||
|
):
|
||||||
|
ret = ethtool.show_features("eth0")
|
||||||
|
|
||||||
|
assert expected == ret
|
||||||
|
|
||||||
|
|
||||||
|
def test_ethtool_set_pause():
|
||||||
|
with patch("salt.modules.ethtool._ethtool_command", MagicMock(return_value="")):
|
||||||
|
with pytest.raises(CommandExecutionError):
|
||||||
|
ethtool.set_pause("eth0", not_there=False)
|
||||||
|
ret = ethtool.set_pause("eth0", autoneg=False)
|
||||||
|
|
||||||
|
assert ret is True
|
||||||
|
|
||||||
|
|
||||||
|
def test_ethtool_set_feature():
|
||||||
|
with patch("salt.modules.ethtool._ethtool_command", MagicMock(return_value="")):
|
||||||
|
with pytest.raises(CommandExecutionError):
|
||||||
|
ethtool.set_feature("eth0", not_there=False)
|
||||||
|
ret = ethtool.set_feature("eth0", sg=False)
|
||||||
|
|
||||||
|
assert ret is True
|
77
tests/pytests/unit/states/test_ethtool.py
Normal file
77
tests/pytests/unit/states/test_ethtool.py
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
import salt.states.ethtool as ethtool
|
||||||
|
from salt.exceptions import CommandExecutionError
|
||||||
|
from tests.support.mock import MagicMock, patch
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def configure_loader_modules():
|
||||||
|
return {
|
||||||
|
ethtool: {
|
||||||
|
"__opts__": {"test": False},
|
||||||
|
"__salt__": {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_ethtool_pause():
|
||||||
|
expected = {
|
||||||
|
"changes": {},
|
||||||
|
"comment": "Network device eth0 pause parameters are up to date.",
|
||||||
|
"name": "eth0",
|
||||||
|
"result": True,
|
||||||
|
}
|
||||||
|
show_ret = {
|
||||||
|
"Autonegotiate": True,
|
||||||
|
"RX": True,
|
||||||
|
"RX negotiated": False,
|
||||||
|
"TX": True,
|
||||||
|
"TX negotiated": False,
|
||||||
|
}
|
||||||
|
mock_show = MagicMock(return_value=show_ret)
|
||||||
|
mock_set = MagicMock(return_value=True)
|
||||||
|
with patch.dict(
|
||||||
|
ethtool.__salt__,
|
||||||
|
{"ethtool.set_pause": mock_set, "ethtool.show_pause": mock_show},
|
||||||
|
):
|
||||||
|
# clean
|
||||||
|
ret = ethtool.pause("eth0", autoneg=True, rx=True, tx=True)
|
||||||
|
assert ret == expected
|
||||||
|
|
||||||
|
# changes
|
||||||
|
expected["changes"] = {"ethtool_pause": "autoneg: off\nrx: off\ntx: off"}
|
||||||
|
expected["comment"] = "Device eth0 pause parameters updated."
|
||||||
|
ret = ethtool.pause("eth0", autoneg=False, rx=False, tx=False)
|
||||||
|
assert ret == expected
|
||||||
|
mock_set.assert_called_once_with("eth0", autoneg=False, rx=False, tx=False)
|
||||||
|
|
||||||
|
# changes, test mode
|
||||||
|
mock_set.reset_mock()
|
||||||
|
with patch.dict(ethtool.__opts__, {"test": True}):
|
||||||
|
expected["result"] = None
|
||||||
|
expected["changes"] = {}
|
||||||
|
expected[
|
||||||
|
"comment"
|
||||||
|
] = "Device eth0 pause parameters are set to be updated:\nautoneg: off\nrx: off\ntx: off"
|
||||||
|
ret = ethtool.pause("eth0", autoneg=False, rx=False, tx=False)
|
||||||
|
assert ret == expected
|
||||||
|
mock_set.assert_not_called()
|
||||||
|
|
||||||
|
# exceptions
|
||||||
|
with patch.dict(
|
||||||
|
ethtool.__salt__,
|
||||||
|
{
|
||||||
|
"ethtool.set_pause": MagicMock(side_effect=CommandExecutionError("blargh")),
|
||||||
|
"ethtool.show_pause": MagicMock(
|
||||||
|
side_effect=[CommandExecutionError, show_ret]
|
||||||
|
),
|
||||||
|
},
|
||||||
|
):
|
||||||
|
expected["comment"] = "Device eth0 pause parameters are not supported"
|
||||||
|
expected["result"] = False
|
||||||
|
ret = ethtool.pause("eth0", autoneg=False, rx=False, tx=False)
|
||||||
|
assert ret == expected
|
||||||
|
ret = ethtool.pause("eth0", autoneg=False, rx=False, tx=False)
|
||||||
|
expected["comment"] = "blargh"
|
||||||
|
assert ret == expected
|
Loading…
Add table
Reference in a new issue