Added power cfg module and state for windows minions

- Allows you to set power settings on a windows minion for things like the monitor and disk
This commit is contained in:
Daniel Hobley 2015-05-12 14:49:48 +02:00
parent 3b0b55b888
commit 899ba78e79
7 changed files with 514 additions and 0 deletions

View file

@ -0,0 +1,6 @@
=========================
salt.modules.win_powercfg
=========================
.. automodule:: salt.modules.win_powercfg
:members:

View file

@ -0,0 +1,6 @@
========================
salt.states.win_powercfg
========================
.. automodule:: salt.states.win_powercfg
:members:

View file

@ -0,0 +1,189 @@
# -*- coding: utf-8 -*-
'''
This module allows you to control the power settings of a windows minion via
powercfg
.. code-block:: bash
salt '*' powercfg.set_monitor_timeout 0 power=dc
salt '*' powercfg.set_disk_timeout 120 power=ac
'''
# Import python libs
import re
import logging
# Import salt libs
log = logging.getLogger(__name__)
__virtualname__ = "powercfg"
def __virtual__():
'''
Only work on Windows
'''
if __grains__['os'] == 'Windows':
return __virtualname__
return False
def _get_current_scheme():
cmd = "powercfg /getactivescheme"
out = __salt__['cmd.run'](cmd, python_shell=False)
matches = re.search(r"GUID: (.*) \(", out)
return matches.groups()[0].strip()
def _get_powercfg_minute_values(scheme, guid, subguid):
'''
Returns the AC/DC values in an array for a guid and subguid for a the given scheme
'''
cmd = "powercfg /q {0} {1} {2}".format(scheme, guid, subguid)
out = __salt__['cmd.run'](cmd, python_shell=False)
raw_settings = re.findall(r"Power Setting Index: ([0-9a-fx]+)", out)
return {"ac": int(raw_settings[0], 0) / 60, "dc": int(raw_settings[1], 0) / 60}
def _set_powercfg_value(setting, power, value):
'''
Sets the value of a setting with a given power (ac/dc) to
the current scheme
'''
cmd = "powercfg /x {0}-{1} {2}".format(setting, power, value)
return __salt__['cmd.run'](cmd, python_shell=False)
def set_monitor_timeout(timeout, power="ac"):
'''
Set the monitor timeout in minutes for the current power scheme
CLI Example:
.. code-block:: bash
salt '*' powercfg.set_monitor_timeout 30 power=ac
timeout
The amount of time in minutes before the monitor will timeout
power
Should we set the value for AC or DC (battery)? Valid options ac,dc.
'''
return _set_powercfg_value("monitor-timeout", power, timeout)
def get_monitor_timeout():
'''
Get the current monitor timeout of the current scheme
CLI Example:
.. code-block:: bash
salt '*' powercfg.get_monitor_timeout
'''
return _get_powercfg_minute_values(_get_current_scheme(), "SUB_VIDEO", "VIDEOIDLE")
def set_disk_timeout(timeout, power="ac"):
'''
Set the disk timeout in minutes for the current power scheme
CLI Example:
.. code-block:: bash
salt '*' powercfg.set_disk_timeout 30 power=dc
timeout
The amount of time in minutes before the disk will timeout
power
Should we set the value for AC or DC (battery)? Valid options ac,dc.
'''
return _set_powercfg_value("disk-timeout", power, timeout)
def get_disk_timeout():
'''
Get the current disk timeout of the current scheme
CLI Example:
.. code-block:: bash
salt '*' powercfg.get_disk_timeout
'''
return _get_powercfg_minute_values(_get_current_scheme(), "SUB_DISK", "DISKIDLE")
def set_standby_timeout(timeout, power="ac"):
'''
Set the standby timeout in minutes for the current power scheme
CLI Example:
.. code-block:: bash
salt '*' powercfg.set_standby_timeout 30 power=dc
timeout
The amount of time in minutes before the computer sleeps
power
Should we set the value for AC or DC (battery)? Valid options ac,dc.
'''
return _set_powercfg_value("standby-timeout", power, timeout)
def get_standby_timeout():
'''
Get the current standby timeout of the current scheme
CLI Example:
.. code-block:: bash
salt '*' powercfg.get_standby_timeout
'''
return _get_powercfg_minute_values(_get_current_scheme(), "SUB_SLEEP", "STANDBYIDLE")
def set_hibernate_timeout(timeout, power="ac"):
'''
Set the hibernate timeout in minutes for the current power scheme
CLI Example:
.. code-block:: bash
salt '*' powercfg.set_hibernate_timeout 30 power=pc
timeout
The amount of time in minutes before the computer hibernates
power
Should we set the value for AC or DC (battery)? Valid options ac,dc.
'''
return _set_powercfg_value("hibernate-timeout", power, timeout)
def get_hibernate_timeout():
'''
Get the current hibernate timeout of the current scheme
CLI Example:
.. code-block:: bash
salt '*' powercfg.get_hibernate_timeout
'''
return _get_powercfg_minute_values(_get_current_scheme(), "SUB_SLEEP", "HIBERNATEIDLE")

View file

@ -0,0 +1,95 @@
# -*- coding: utf-8 -*-
'''
This module allows you to control the power settings of a windows minion via
powercfg
.. code-block:: yaml
monitor:
powercfg.set_timeout:
- value: 30
- power: dc
'''
# Import python libs
import logging
# Import salt libs
log = logging.getLogger(__name__)
__virtualname__ = "powercfg"
def __virtual__():
'''
Only work on Windows
'''
if __grains__['os'] == 'Windows':
return __virtualname__
return False
def _check_or_set(check_func, set_func, value, power):
values = check_func()
if values[power] == value:
return True
else:
set_func(value, power)
return False
def set_timeout(name, value, power="ac"):
'''
Set the sleep timeouts of specific items such as disk, monitor.
CLI Example:
.. code-block:: yaml
monitor:
powercfg.set_timeout:
- value: 30
- power: dc
disk:
powercfg.set_timeout:
- value: 12
- power: ac
name
The setting to change, can be one of the following: monitor, disk, standby, hibernate
timeout
The amount of time in minutes before the item will timeout i.e the monitor
power
Should we set the value for AC or DC (battery)? Valid options ac,dc.
'''
ret = {'name': name,
'result': True,
'comment': '',
'changes': {}}
comment = []
if name not in ["monitor", "disk", "standby", "hibernate"]:
ret["result"] = False
comment.append("{0} is not a valid setting".format(name))
elif power not in ["ac", "dc"]:
ret["result"] = False
comment.append("{0} is not a power type".format(power))
else:
check_func = __salt__["powercfg.get_{0}_timeout".format(name)]
set_func = __salt__["powercfg.set_{0}_timeout".format(name)]
values = check_func()
if values[power] == value:
comment.append ("{0} {1} is already set with the value {2}.".format(name, power, value))
else:
ret['changes'] = {name: {power: value}}
set_func(value, power)
ret['comment'] = ' '.join(comment)
return ret

0
tests/runtests.py Normal file → Executable file
View file

View file

@ -0,0 +1,150 @@
# -*- coding: utf-8 -*-
# Import Python libs
from __future__ import absolute_import
# Import Salt Libs
from salt.modules import win_powercfg as powercfg
# Import Salt Testing Libs
from salttesting import skipIf, TestCase
from salttesting.helpers import ensure_in_syspath
from salttesting.mock import (
NO_MOCK,
NO_MOCK_REASON,
MagicMock,
patch,
call
)
ensure_in_syspath('../../')
powercfg.__salt__ = {}
@skipIf(NO_MOCK, NO_MOCK_REASON)
class PowerCfgTestCase(TestCase):
query_ouput = '''Subgroup GUID: 238c9fa8-0aad-41ed-83f4-97be242c8f20 (Hibernate)
GUID Alias: SUB_SLEEP
Power Setting GUID: 29f6c1db-86da-48c5-9fdb-f2b67b1f44da (Hibernate after)
GUID Alias: HIBERNATEIDLE
Minimum Possible Setting: 0x00000000
Maximum Possible Setting: 0xffffffff
Possible Settings increment: 0x00000001
Possible Settings units: Seconds
Current AC Power Setting Index: 0x00000708
Current DC Power Setting Index: 0x00000384'''
'''
Validate the powercfg state
'''
def test_set_monitor_timeout(self):
'''
Test to make sure we can set the monitor timeout value
'''
mock = MagicMock(return_value="")
with patch.dict(powercfg.__salt__, {'cmd.run': mock}):
powercfg.set_monitor_timeout(0, "dc")
mock.assert_called_once_with('powercfg /x monitor-timeout-dc 0', python_shell=False)
def test_set_disk_timeout(self):
'''
Test to make sure we can set the disk timeout value
'''
mock = MagicMock(return_value="")
with patch.dict(powercfg.__salt__, {'cmd.run': mock}):
powercfg.set_disk_timeout(0, "dc")
mock.assert_called_once_with('powercfg /x disk-timeout-dc 0', python_shell=False)
def test_set_standby_timeout(self):
'''
Test to make sure we can set the standby timeout value
'''
mock = MagicMock(return_value="")
with patch.dict(powercfg.__salt__, {'cmd.run': mock}):
powercfg.set_standby_timeout(0, "dc")
mock.assert_called_once_with('powercfg /x standby-timeout-dc 0', python_shell=False)
def test_set_hibernate_timeout(self):
'''
Test to make sure we can set the hibernate timeout value
'''
mock = MagicMock(return_value="")
with patch.dict(powercfg.__salt__, {'cmd.run': mock}):
powercfg.set_hibernate_timeout(0, "dc")
mock.assert_called_once_with('powercfg /x hibernate-timeout-dc 0', python_shell=False)
def test_get_monitor_timeout(self):
'''
Test to make sure we can get the monitor timeout value
'''
mock = MagicMock()
mock.side_effect = ["Power Scheme GUID: 381b4222-f694-41f0-9685-ff5bb260df2e (Balanced)", self.query_ouput]
with patch.dict(powercfg.__salt__, {'cmd.run': mock}):
ret = powercfg.get_monitor_timeout()
calls = [
call('powercfg /getactivescheme', python_shell=False),
call('powercfg /q 381b4222-f694-41f0-9685-ff5bb260df2e SUB_VIDEO VIDEOIDLE', python_shell=False)
]
mock.assert_has_calls(calls)
self.assertEqual({'ac': 30, 'dc': 15}, ret)
def test_get_disk_timeout(self):
'''
Test to make sure we can get the disk timeout value
'''
mock = MagicMock()
mock.side_effect = ["Power Scheme GUID: 381b4222-f694-41f0-9685-ff5bb260df2e (Balanced)", self.query_ouput]
with patch.dict(powercfg.__salt__, {'cmd.run': mock}):
ret = powercfg.get_disk_timeout()
calls = [
call('powercfg /getactivescheme', python_shell=False),
call('powercfg /q 381b4222-f694-41f0-9685-ff5bb260df2e SUB_DISK DISKIDLE', python_shell=False)
]
mock.assert_has_calls(calls)
self.assertEqual({'ac': 30, 'dc': 15}, ret)
def test_get_standby_timeout(self):
'''
Test to make sure we can get the standby timeout value
'''
mock = MagicMock()
mock.side_effect = ["Power Scheme GUID: 381b4222-f694-41f0-9685-ff5bb260df2e (Balanced)", self.query_ouput]
with patch.dict(powercfg.__salt__, {'cmd.run': mock}):
ret = powercfg.get_standby_timeout()
calls = [
call('powercfg /getactivescheme', python_shell=False),
call('powercfg /q 381b4222-f694-41f0-9685-ff5bb260df2e SUB_SLEEP STANDBYIDLE', python_shell=False)
]
mock.assert_has_calls(calls)
self.assertEqual({'ac': 30, 'dc': 15}, ret)
def test_get_hibernate_timeout(self):
'''
Test to make sure we can get the hibernate timeout value
'''
mock = MagicMock()
mock.side_effect = ["Power Scheme GUID: 381b4222-f694-41f0-9685-ff5bb260df2e (Balanced)", self.query_ouput]
with patch.dict(powercfg.__salt__, {'cmd.run': mock}):
ret = powercfg.get_hibernate_timeout()
calls = [
call('powercfg /getactivescheme', python_shell=False),
call('powercfg /q 381b4222-f694-41f0-9685-ff5bb260df2e SUB_SLEEP HIBERNATEIDLE', python_shell=False)
]
mock.assert_has_calls(calls)
self.assertEqual({'ac': 30, 'dc': 15}, ret)
if __name__ == '__main__':
from integration import run_tests
run_tests(PowerCfgTestCase, needs_daemon=False)

View file

@ -0,0 +1,68 @@
# -*- coding: utf-8 -*-
# Import Python libs
from __future__ import absolute_import
# Import Salt Libs
from salt.states import win_powercfg as powercfg
# Import Salt Testing Libs
from salttesting import skipIf, TestCase
from salttesting.helpers import ensure_in_syspath
from salttesting.mock import (
NO_MOCK,
NO_MOCK_REASON,
MagicMock,
patch
)
ensure_in_syspath('../../')
powercfg.__salt__ = {}
@skipIf(NO_MOCK, NO_MOCK_REASON)
class PowerCfgTestCase(TestCase):
'''
Validate the powercfg state
'''
def test_set_monitor(self):
'''
Test to make sure we can set the monitor timeout value
'''
ret = {'changes': {'monitor': {'ac': 0}}, 'comment': '', 'name': 'monitor', 'result': True}
monitor_val = {"ac": 45, "dc": 22}
with patch.dict(powercfg.__salt__, {"powercfg.get_monitor_timeout": MagicMock(return_value=monitor_val),
"powercfg.set_monitor_timeout": MagicMock(return_value=True)}):
self.assertEqual(powercfg.set_timeout("monitor", 0), ret)
def test_set_monitor_already_set(self):
'''
Test to make sure we can set the monitor timeout value
'''
ret = {'changes': {}, 'comment': 'monitor ac is already set with the value 0.', 'name': 'monitor', 'result': True}
monitor_val = {"ac": 0, "dc": 0}
with patch.dict(powercfg.__salt__, {"powercfg.get_monitor_timeout": MagicMock(return_value=monitor_val),
"powercfg.set_monitor_timeout": MagicMock(return_value=True)}):
self.assertEqual(powercfg.set_timeout("monitor", 0), ret)
def test_fail_invalid_setting(self):
'''
Test to make sure we can set the monitor timeout value
'''
ret = {'changes': {}, 'comment': 'fakesetting is not a valid setting', 'name': 'fakesetting', 'result': False}
self.assertEqual(powercfg.set_timeout("fakesetting", 0), ret)
def test_fail_invalid_power(self):
'''
Test to make sure we can set the monitor timeout value
'''
ret = {'changes': {}, 'comment': 'fakepower is not a power type', 'name': 'monitor', 'result': False}
self.assertEqual(powercfg.set_timeout("monitor", 0, power="fakepower"), ret)
if __name__ == '__main__':
from integration import run_tests
run_tests(PowerCfgTestCase, needs_daemon=False)