mirror of
https://github.com/saltstack/salt.git
synced 2025-04-16 09:40:20 +00:00
Added sysfs state module to manage kernel objects
This commit is contained in:
parent
4206994aad
commit
d1932fa3c5
5 changed files with 197 additions and 0 deletions
1
changelog/60154.added
Normal file
1
changelog/60154.added
Normal file
|
@ -0,0 +1 @@
|
||||||
|
State module to manage SysFS attributes
|
|
@ -303,6 +303,7 @@ state modules
|
||||||
supervisord
|
supervisord
|
||||||
svn
|
svn
|
||||||
sysctl
|
sysctl
|
||||||
|
sysfs
|
||||||
syslog_ng
|
syslog_ng
|
||||||
sysrc
|
sysrc
|
||||||
telemetry_alert
|
telemetry_alert
|
||||||
|
|
5
doc/ref/states/all/salt.states.sysfs.rst
Normal file
5
doc/ref/states/all/salt.states.sysfs.rst
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
salt.states.sysfs
|
||||||
|
==================
|
||||||
|
|
||||||
|
.. automodule:: salt.states.sysfs
|
||||||
|
:members:
|
73
salt/states/sysfs.py
Normal file
73
salt/states/sysfs.py
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
"""
|
||||||
|
Configuration of the kernel using sysfs
|
||||||
|
=======================================
|
||||||
|
|
||||||
|
Control the kernel object attributes exported by sysfs
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
kernel/mm/transparent_hugepage/enabled
|
||||||
|
sysfs.present:
|
||||||
|
- value: never
|
||||||
|
|
||||||
|
.. versionadded: TBD
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
def __virtual__():
|
||||||
|
"""
|
||||||
|
This state is only available on Minions which support sysctl
|
||||||
|
"""
|
||||||
|
if "sysfs.attr" in __salt__:
|
||||||
|
return True
|
||||||
|
return (False, "sysfs module could not be loaded")
|
||||||
|
|
||||||
|
|
||||||
|
def present(name, value, config=None):
|
||||||
|
"""
|
||||||
|
Ensure that the named sysfs attribute is set with the defined value
|
||||||
|
|
||||||
|
name
|
||||||
|
The name of the sysfs attribute to edit
|
||||||
|
|
||||||
|
value
|
||||||
|
The sysfs value to apply
|
||||||
|
|
||||||
|
"""
|
||||||
|
ret = {"name": name, "result": True, "changes": {}, "comment": ""}
|
||||||
|
|
||||||
|
current = __salt__["sysfs.read"](name)
|
||||||
|
if current is False:
|
||||||
|
ret["result"] = False
|
||||||
|
ret["comment"] = "SysFS attribute {} doesn't exist.".format(name)
|
||||||
|
else:
|
||||||
|
# if the return is a dict, the "name" is an object not an attribute
|
||||||
|
if isinstance(current, dict):
|
||||||
|
ret["result"] = False
|
||||||
|
ret["comment"] = "{} is not a SysFS attribute.".format(name)
|
||||||
|
else:
|
||||||
|
# some attribute files lists all available options and the selected one between []
|
||||||
|
if isinstance(current, str):
|
||||||
|
current = re.sub(r"(.*\[|\].*)", "", current)
|
||||||
|
if value == current:
|
||||||
|
ret["result"] = True
|
||||||
|
ret["comment"] = "SysFS attribute {} is already set.".format(name)
|
||||||
|
else:
|
||||||
|
ret["result"] = None
|
||||||
|
|
||||||
|
if ret["result"] is None:
|
||||||
|
if __opts__["test"]:
|
||||||
|
ret["comment"] = "SysFS attribute {} set to be changed.".format(name)
|
||||||
|
else:
|
||||||
|
update = __salt__["sysfs.write"](name, value)
|
||||||
|
if not update:
|
||||||
|
ret["result"] = False
|
||||||
|
ret["comment"] = "Failed to set {} to {}".format(name, value)
|
||||||
|
else:
|
||||||
|
ret["result"] = True
|
||||||
|
ret["changes"] = {name: value}
|
||||||
|
ret["comment"] = "Updated SysFS attribute {} to {}".format(name, value)
|
||||||
|
|
||||||
|
return ret
|
117
tests/pytests/unit/states/test_sysfs.py
Normal file
117
tests/pytests/unit/states/test_sysfs.py
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
"""
|
||||||
|
:codeauthor: Piter Punk <piterpunk@slackware.com>
|
||||||
|
"""
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
import salt.states.sysfs as sysfs
|
||||||
|
from tests.support.mock import MagicMock, patch
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def configure_loader_modules():
|
||||||
|
return {sysfs: {}}
|
||||||
|
|
||||||
|
|
||||||
|
def test_if_the_sysfs_attribute_exists():
|
||||||
|
"""
|
||||||
|
Test sysfs.present for a non-existent attribute
|
||||||
|
"""
|
||||||
|
name = "block/sda/queue/this_does_not_exist"
|
||||||
|
value = "none"
|
||||||
|
comment = "SysFS attribute {} doesn't exist.".format(name)
|
||||||
|
ret = {"name": name, "result": False, "changes": {}, "comment": comment}
|
||||||
|
|
||||||
|
mock_read = MagicMock(return_value=False)
|
||||||
|
with patch.dict(sysfs.__salt__, {"sysfs.read": mock_read}):
|
||||||
|
assert sysfs.present(name, value) == ret
|
||||||
|
|
||||||
|
|
||||||
|
def test_name_is_an_object_and_not_an_attribute():
|
||||||
|
"""
|
||||||
|
Test sysfs.present targeting an object and not one of its attributes
|
||||||
|
"""
|
||||||
|
name = "block/sda/queue"
|
||||||
|
value = "none"
|
||||||
|
comment = "{} is not a SysFS attribute.".format(name)
|
||||||
|
ret = {"name": name, "result": False, "changes": {}, "comment": comment}
|
||||||
|
|
||||||
|
read_from_sysfs = {
|
||||||
|
"rotational": 1,
|
||||||
|
"rq_affinity": 1,
|
||||||
|
"scheduler": "[none] mq-deadline",
|
||||||
|
}
|
||||||
|
|
||||||
|
mock_read = MagicMock(return_value=read_from_sysfs)
|
||||||
|
with patch.dict(sysfs.__salt__, {"sysfs.read": mock_read}):
|
||||||
|
assert sysfs.present(name, value) == ret
|
||||||
|
|
||||||
|
|
||||||
|
def test_already_set():
|
||||||
|
"""
|
||||||
|
Test sysfs.present with equal old and new values
|
||||||
|
"""
|
||||||
|
name = "block/sda/queue"
|
||||||
|
value = "none"
|
||||||
|
comment = "SysFS attribute {} is already set.".format(name)
|
||||||
|
ret = {"name": name, "result": True, "changes": {}, "comment": comment}
|
||||||
|
|
||||||
|
read_from_sysfs = "[none] mq-deadline"
|
||||||
|
|
||||||
|
mock_read = MagicMock(return_value=read_from_sysfs)
|
||||||
|
with patch.dict(sysfs.__salt__, {"sysfs.read": mock_read}):
|
||||||
|
assert sysfs.present(name, value) == ret
|
||||||
|
|
||||||
|
|
||||||
|
def test_set_new_value_with_test_equals_true():
|
||||||
|
"""
|
||||||
|
Test sysfs.present setting a new value
|
||||||
|
"""
|
||||||
|
name = "devices/system/cpu/cpufreq/policy0"
|
||||||
|
value = "powersave"
|
||||||
|
comment = "SysFS attribute {} set to be changed.".format(name)
|
||||||
|
ret = {"name": name, "result": None, "changes": {}, "comment": comment}
|
||||||
|
|
||||||
|
read_from_sysfs = "performance"
|
||||||
|
|
||||||
|
mock_read = MagicMock(return_value=read_from_sysfs)
|
||||||
|
with patch.dict(sysfs.__opts__, {"test": True}):
|
||||||
|
with patch.dict(sysfs.__salt__, {"sysfs.read": mock_read}):
|
||||||
|
assert sysfs.present(name, value) == ret
|
||||||
|
|
||||||
|
|
||||||
|
def test_set_new_value_with_success():
|
||||||
|
"""
|
||||||
|
Test sysfs.present setting a new value
|
||||||
|
"""
|
||||||
|
name = "block/sda/queue/scheduler"
|
||||||
|
value = "mq-deadline"
|
||||||
|
comment = "Updated SysFS attribute {} to {}".format(name, value)
|
||||||
|
ret = {"name": name, "result": True, "changes": {name: value}, "comment": comment}
|
||||||
|
|
||||||
|
read_from_sysfs = "[none] mq-deadline"
|
||||||
|
|
||||||
|
mock_read = MagicMock(return_value=read_from_sysfs)
|
||||||
|
with patch.dict(sysfs.__opts__, {"test": False}):
|
||||||
|
with patch.dict(sysfs.__salt__, {"sysfs.read": mock_read}):
|
||||||
|
mock_write = MagicMock(return_value=True)
|
||||||
|
with patch.dict(sysfs.__salt__, {"sysfs.write": mock_write}):
|
||||||
|
assert sysfs.present(name, value) == ret
|
||||||
|
|
||||||
|
|
||||||
|
def test_set_new_value_with_failure():
|
||||||
|
"""
|
||||||
|
Test sysfs.present failure writing the value
|
||||||
|
"""
|
||||||
|
name = "block/sda/queue/scheduler"
|
||||||
|
value = "imaginary_scheduler"
|
||||||
|
comment = "Failed to set {} to {}".format(name, value)
|
||||||
|
ret = {"name": name, "result": False, "changes": {}, "comment": comment}
|
||||||
|
|
||||||
|
read_from_sysfs = "[none] mq-deadline"
|
||||||
|
|
||||||
|
mock_read = MagicMock(return_value=read_from_sysfs)
|
||||||
|
with patch.dict(sysfs.__opts__, {"test": False}):
|
||||||
|
with patch.dict(sysfs.__salt__, {"sysfs.read": mock_read}):
|
||||||
|
mock_write = MagicMock(return_value=False)
|
||||||
|
with patch.dict(sysfs.__salt__, {"sysfs.write": mock_write}):
|
||||||
|
assert sysfs.present(name, value) == ret
|
Loading…
Add table
Reference in a new issue