-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
340 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
# -*- coding: utf-8 -*- | ||
''' | ||
s6 service module | ||
This module is compatible with the :mod:`service <salt.states.service>` states, | ||
so it can be used to maintain services using the ``provider`` argument: | ||
.. code-block:: yaml | ||
myservice: | ||
service: | ||
- running | ||
- provider: s6 | ||
Note that the ``enabled`` argument is not available with this provider. | ||
:codeauthor: :email:`Marek Skrobacki <skrobul@skrobul.com>` | ||
''' | ||
from __future__ import absolute_import | ||
|
||
# Import python libs | ||
import os | ||
import re | ||
|
||
# Import salt libs | ||
from salt.exceptions import CommandExecutionError | ||
|
||
__func_alias__ = { | ||
'reload_': 'reload' | ||
} | ||
|
||
VALID_SERVICE_DIRS = [ | ||
'/service', | ||
'/etc/service', | ||
] | ||
SERVICE_DIR = None | ||
for service_dir in VALID_SERVICE_DIRS: | ||
if os.path.exists(service_dir): | ||
SERVICE_DIR = service_dir | ||
break | ||
|
||
|
||
def _service_path(name): | ||
''' | ||
build service path | ||
''' | ||
if not SERVICE_DIR: | ||
raise CommandExecutionError("Could not find service directory.") | ||
return '{0}/{1}'.format(SERVICE_DIR, name) | ||
|
||
|
||
def start(name): | ||
''' | ||
Starts service via s6 | ||
CLI Example: | ||
.. code-block:: bash | ||
salt '*' s6.start <service name> | ||
''' | ||
cmd = 's6-svc -u {0}'.format(_service_path(name)) | ||
return not __salt__['cmd.retcode'](cmd) | ||
|
||
|
||
def stop(name): | ||
''' | ||
Stops service via s6 | ||
CLI Example: | ||
.. code-block:: bash | ||
salt '*' s6.stop <service name> | ||
''' | ||
cmd = 's6-svc -d {0}'.format(_service_path(name)) | ||
return not __salt__['cmd.retcode'](cmd) | ||
|
||
|
||
def term(name): | ||
''' | ||
Send a TERM to service via s6 | ||
CLI Example: | ||
.. code-block:: bash | ||
salt '*' s6.term <service name> | ||
''' | ||
cmd = 's6-svc -t {0}'.format(_service_path(name)) | ||
return not __salt__['cmd.retcode'](cmd) | ||
|
||
|
||
def reload_(name): | ||
''' | ||
Send a HUP to service via s6 | ||
CLI Example: | ||
.. code-block:: bash | ||
salt '*' s6.reload <service name> | ||
''' | ||
cmd = 's6-svc -h {0}'.format(_service_path(name)) | ||
return not __salt__['cmd.retcode'](cmd) | ||
|
||
|
||
def restart(name): | ||
''' | ||
Restart service via s6. This will stop/start service | ||
CLI Example: | ||
.. code-block:: bash | ||
salt '*' s6.restart <service name> | ||
''' | ||
cmd = 's6-svc -t {0}'.format(_service_path(name)) | ||
return not __salt__['cmd.retcode'](cmd) | ||
|
||
|
||
def full_restart(name): | ||
''' | ||
Calls s6.restart() function | ||
CLI Example: | ||
.. code-block:: bash | ||
salt '*' s6.full_restart <service name> | ||
''' | ||
restart(name) | ||
|
||
|
||
def status(name, sig=None): | ||
''' | ||
Return the status for a service via s6, return pid if running | ||
CLI Example: | ||
.. code-block:: bash | ||
salt '*' s6.status <service name> | ||
''' | ||
cmd = 's6-svstat {0}'.format(_service_path(name)) | ||
out = __salt__['cmd.run_stdout'](cmd) | ||
try: | ||
pid = re.search(r'up \(pid (\d+)\)', out).group(1) | ||
except AttributeError: | ||
pid = '' | ||
return pid | ||
|
||
|
||
def available(name): | ||
''' | ||
Returns ``True`` if the specified service is available, otherwise returns | ||
``False``. | ||
CLI Example: | ||
.. code-block:: bash | ||
salt '*' s6.available foo | ||
''' | ||
return name in get_all() | ||
|
||
|
||
def missing(name): | ||
''' | ||
The inverse of s6.available. | ||
Returns ``True`` if the specified service is not available, otherwise returns | ||
``False``. | ||
CLI Example: | ||
.. code-block:: bash | ||
salt '*' s6.missing foo | ||
''' | ||
return name not in get_all() | ||
|
||
|
||
def get_all(): | ||
''' | ||
Return a list of all available services | ||
CLI Example: | ||
.. code-block:: bash | ||
salt '*' s6.get_all | ||
''' | ||
if not SERVICE_DIR: | ||
raise CommandExecutionError("Could not find service directory.") | ||
service_list = [dirname for dirname | ||
in os.listdir(SERVICE_DIR) | ||
if not dirname.startswith('.')] | ||
return sorted(service_list) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
# -*- coding: utf-8 -*- | ||
''' | ||
:codeauthor: :email:`Marek Skrobacki <skrobul@skrobul.com>` | ||
''' | ||
|
||
# Import Python Libs | ||
from __future__ import absolute_import | ||
import os | ||
|
||
# Import Salt Testing Libs | ||
from salttesting import TestCase, skipIf | ||
from salttesting.mock import ( | ||
MagicMock, | ||
patch, | ||
NO_MOCK, | ||
NO_MOCK_REASON | ||
) | ||
|
||
from salttesting.helpers import ensure_in_syspath | ||
|
||
ensure_in_syspath('../../') | ||
|
||
# Import Salt Libs | ||
from salt.modules import s6 | ||
|
||
# Globals | ||
s6.__salt__ = {} | ||
s6.SERVICE_DIR = '/etc/service' | ||
|
||
|
||
@skipIf(NO_MOCK, NO_MOCK_REASON) | ||
class S6TestCase(TestCase): | ||
''' | ||
Test cases for salt.modules.s6 | ||
''' | ||
# 'start' function tests: 1 | ||
|
||
def test_start(self): | ||
''' | ||
Test if it starts service via s6-svc. | ||
''' | ||
mock_ret = MagicMock(return_value=False) | ||
with patch.dict(s6.__salt__, {'cmd.retcode': mock_ret}): | ||
self.assertTrue(s6.start('ssh')) | ||
|
||
# 'stop' function tests: 1 | ||
|
||
def test_stop(self): | ||
''' | ||
Test if it stops service via s6. | ||
''' | ||
mock_ret = MagicMock(return_value=False) | ||
with patch.dict(s6.__salt__, {'cmd.retcode': mock_ret}): | ||
self.assertTrue(s6.stop('ssh')) | ||
|
||
# 'term' function tests: 1 | ||
|
||
def test_term(self): | ||
''' | ||
Test if it send a TERM to service via s6. | ||
''' | ||
mock_ret = MagicMock(return_value=False) | ||
with patch.dict(s6.__salt__, {'cmd.retcode': mock_ret}): | ||
self.assertTrue(s6.term('ssh')) | ||
|
||
# 'reload_' function tests: 1 | ||
|
||
def test_reload(self): | ||
''' | ||
Test if it send a HUP to service via s6. | ||
''' | ||
mock_ret = MagicMock(return_value=False) | ||
with patch.dict(s6.__salt__, {'cmd.retcode': mock_ret}): | ||
self.assertTrue(s6.reload_('ssh')) | ||
|
||
# 'restart' function tests: 1 | ||
|
||
def test_restart(self): | ||
''' | ||
Test if it restart service via s6. This will stop/start service. | ||
''' | ||
mock_ret = MagicMock(return_value=False) | ||
with patch.dict(s6.__salt__, {'cmd.retcode': mock_ret}): | ||
self.assertTrue(s6.restart('ssh')) | ||
|
||
# 'full_restart' function tests: 1 | ||
|
||
def test_full_restart(self): | ||
''' | ||
Test if it calls s6.restart() function. | ||
''' | ||
mock_ret = MagicMock(return_value=False) | ||
with patch.dict(s6.__salt__, {'cmd.retcode': mock_ret}): | ||
self.assertIsNone(s6.full_restart('ssh')) | ||
|
||
# 'status' function tests: 1 | ||
|
||
def test_status(self): | ||
''' | ||
Test if it return the status for a service via s6, | ||
return pid if running. | ||
''' | ||
mock_run = MagicMock(return_value='salt') | ||
with patch.dict(s6.__salt__, {'cmd.run_stdout': mock_run}): | ||
self.assertEqual(s6.status('ssh'), '') | ||
|
||
# 'available' function tests: 1 | ||
|
||
def test_available(self): | ||
''' | ||
Test if it returns ``True`` if the specified service is available, | ||
otherwise returns ``False``. | ||
''' | ||
with patch.object(os, 'listdir', | ||
MagicMock(return_value=['/etc/service'])): | ||
self.assertTrue(s6.available('/etc/service')) | ||
|
||
# 'missing' function tests: 1 | ||
|
||
def test_missing(self): | ||
''' | ||
Test if it returns ``True`` if the specified service is not available, | ||
otherwise returns ``False``. | ||
''' | ||
with patch.object(os, 'listdir', | ||
MagicMock(return_value=['/etc/service'])): | ||
self.assertTrue(s6.missing('foo')) | ||
|
||
# 'get_all' function tests: 1 | ||
|
||
def test_get_all(self): | ||
''' | ||
Test if it return a list of all available services. | ||
''' | ||
with patch.object(os, 'listdir', | ||
MagicMock(return_value=['/etc/service'])): | ||
self.assertListEqual(s6.get_all(), ['/etc/service']) | ||
|
||
|
||
if __name__ == '__main__': | ||
from integration import run_tests | ||
run_tests(S6TestCase, needs_daemon=False) |