mirror of
https://github.com/valitydev/salt.git
synced 2024-11-08 17:33:54 +00:00
Merge branch 'develop' of https://github.com/saltstack/salt into develop
This commit is contained in:
commit
4edefcdfec
26
HACKING
Normal file
26
HACKING
Normal file
@ -0,0 +1,26 @@
|
||||
Hacking on Salt
|
||||
===============
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
||||
TODO
|
||||
|
||||
|
||||
Running Tests
|
||||
-------------
|
||||
|
||||
To run the full suite, you'll need mock:
|
||||
|
||||
`pip install mock`
|
||||
|
||||
On Python < 2.7, unittest compatibility is provided by unittest2
|
||||
|
||||
`pip install unittest2`
|
||||
|
||||
|
||||
Community
|
||||
---------
|
||||
|
||||
The #salt irc channel is on irc.freenode.net
|
||||
|
@ -15,12 +15,19 @@ Get started with Salt
|
||||
|
||||
.. _`presentations and interviews on Salt`: http://saltstack.org/presentations/
|
||||
|
||||
Salt is a **remote execution** and **configuration management** tool.
|
||||
Salt is an open source tool to manage your infrastructure. Easy enough to get
|
||||
running in minutes and fast enough to manage tens of thousands of servers (and
|
||||
still get a response back in *seconds*).
|
||||
|
||||
Salt is designed to be secure using **AES encryption** and **public-key
|
||||
authentication**; incredibly scalable using an advanced **ZeroMQ** topology;
|
||||
fast and efficient using **msgpack**; and extensible using small and simple
|
||||
**Python** modules.
|
||||
Execute arbitrary shell commands or choose from dozens of pre-built modules of
|
||||
common (or complex) commands. Target individual servers or groups of servers
|
||||
based on name, defined roles, or a variety of system information such as
|
||||
hardware, software, operating system, current version, current environment, and
|
||||
many more.
|
||||
|
||||
Bring your servers up to a known configured state by writing simple lists of
|
||||
items and defining attributes on those lists—no need to learn yet another
|
||||
language.
|
||||
|
||||
Read the :doc:`Salt overview <topics/index>` for a more thorough description.
|
||||
|
||||
|
@ -4,6 +4,7 @@ Manage Django sites
|
||||
|
||||
import os
|
||||
|
||||
|
||||
def _get_django_admin(bin_env):
|
||||
'''
|
||||
Return the django admin
|
||||
@ -11,7 +12,7 @@ def _get_django_admin(bin_env):
|
||||
if not bin_env:
|
||||
da = 'django-admin.py'
|
||||
else:
|
||||
# try to get pip bin from env
|
||||
# try to get django-admin.py bin from env
|
||||
if os.path.exists(os.path.join(bin_env, 'bin', 'django-admin.py')):
|
||||
da = os.path.join(bin_env, 'bin', 'django-admin.py')
|
||||
else:
|
||||
@ -39,7 +40,6 @@ def command(settings_module,
|
||||
for key, value in kwargs.items():
|
||||
if not key.startswith('__'):
|
||||
cmd = '{0} --{1}={2}'.format(cmd, key, value)
|
||||
|
||||
return __salt__['cmd.run'](cmd)
|
||||
|
||||
|
||||
@ -60,17 +60,20 @@ def syncdb(settings_module,
|
||||
|
||||
salt '*' django.syncdb settings.py
|
||||
'''
|
||||
da = _get_django_admin(bin_env)
|
||||
cmd = '{0} syncdb --settings={1}'.format(da, settings_module)
|
||||
args = []
|
||||
kwargs = {}
|
||||
if migrate:
|
||||
cmd = '{0} --migrate'.format(cmd)
|
||||
args.append('migrate')
|
||||
if database:
|
||||
cmd = '{0} --database={1}'.format(cmd, database)
|
||||
if pythonpath:
|
||||
cmd = '{0} --pythonpath={1}'.format(cmd, pythonpath)
|
||||
kwargs['database'] = database
|
||||
if noinput:
|
||||
cmd = '{0} --noinput'.format(cmd)
|
||||
return __salt__['cmd.run'](cmd)
|
||||
args.append('noinput')
|
||||
|
||||
return command(settings_module,
|
||||
'syncdb',
|
||||
bin_env,
|
||||
pythonpath,
|
||||
*args, **kwargs)
|
||||
|
||||
|
||||
def createsuperuser(settings_module,
|
||||
@ -88,14 +91,18 @@ def createsuperuser(settings_module,
|
||||
|
||||
salt '*' django.createsuperuser settings.py user user@example.com
|
||||
'''
|
||||
da = _get_django_admin(bin_env)
|
||||
cmd = "{0} createsuperuser --settings={1} --noinput --email='{2}' --username={3}".format(
|
||||
da, settings_module, email, username)
|
||||
args = ['noinput']
|
||||
kwargs = dict(
|
||||
email=email,
|
||||
username=username,
|
||||
)
|
||||
if database:
|
||||
cmd = '{0} --database={1}'.format(cmd, database)
|
||||
if pythonpath:
|
||||
cmd = '{0} --pythonpath={1}'.format(cmd, pythonpath)
|
||||
return __salt__['cmd.run'](cmd)
|
||||
kwargs['database'] = database
|
||||
return command(settings_module,
|
||||
'createsuperuser',
|
||||
bin_env,
|
||||
pythonpath,
|
||||
*args, **kwargs)
|
||||
|
||||
|
||||
def loaddata(settings_module,
|
||||
@ -138,25 +145,26 @@ def collectstatic(settings_module,
|
||||
that can easily be served in production.
|
||||
|
||||
CLI Example::
|
||||
|
||||
|
||||
salt '*' django.collectstatic settings.py
|
||||
'''
|
||||
da = _get_django_admin(bin_env)
|
||||
cmd = '{0} collectstatic --settings={1} --noinput'.format(
|
||||
da, settings_module)
|
||||
args = []
|
||||
kwargs = {}
|
||||
if no_post_process:
|
||||
cmd = '{0} --no-post-process'.format(cmd)
|
||||
args.append('no-post-process')
|
||||
if ignore:
|
||||
cmd = '{0} --ignore='.format(cmd, ignore)
|
||||
kwargs['ignore'] = ignore
|
||||
if dry_run:
|
||||
cmd = '{0} --dry-run'.format(cmd)
|
||||
args.append('dry-run')
|
||||
if clear:
|
||||
cmd = '{0} --clear'.format(cmd)
|
||||
args.append('clear')
|
||||
if link:
|
||||
cmd = '{0} --link'.format(cmd)
|
||||
args.append('link')
|
||||
if no_default_ignore:
|
||||
cmd = '{0} --no-default-ignore'.format(cmd)
|
||||
if pythonpath:
|
||||
cmd = '{0} --pythonpath={1}'.format(cmd, pythonpath)
|
||||
args.append('no-default-ignore')
|
||||
|
||||
return __salt__['cmd.run'](cmd)
|
||||
return command(settings_module,
|
||||
'collectstatic',
|
||||
bin_env,
|
||||
pythonpath,
|
||||
*args, **kwargs)
|
||||
|
44
salt/modules/monit.py
Normal file
44
salt/modules/monit.py
Normal file
@ -0,0 +1,44 @@
|
||||
'''
|
||||
Monit service module. This module will create a monit type
|
||||
service watcher.
|
||||
'''
|
||||
|
||||
import os
|
||||
|
||||
def start(name):
|
||||
'''
|
||||
|
||||
CLI Example::
|
||||
salt '*' monit.start <service name>
|
||||
'''
|
||||
cmd = "monit start {0}".format(name)
|
||||
|
||||
return not __salt__['cmd.retcode'](cmd)
|
||||
|
||||
|
||||
def stop(name):
|
||||
'''
|
||||
Stops service via monit
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' monit.stop <service name>
|
||||
'''
|
||||
cmd = "monit stop {0}".format(name)
|
||||
|
||||
|
||||
return not __salt__['cmd.retcode'](cmd)
|
||||
|
||||
|
||||
def restart(name):
|
||||
'''
|
||||
Restart service via monit
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' monit.restart <service name>
|
||||
'''
|
||||
cmd = "monit restart {0}".format(name)
|
||||
|
||||
return not __salt__['cmd.retcode'](cmd)
|
||||
|
@ -168,7 +168,7 @@ class ModuleCase(TestCase):
|
||||
Run a single salt function and condition the return down to match the
|
||||
behavior of the raw function call
|
||||
'''
|
||||
orig = self.client.cmd('minion', function, arg, kwarg=kwargs)
|
||||
orig = self.client.cmd('minion', function, arg, timeout=5, kwarg=kwargs)
|
||||
return orig['minion']
|
||||
|
||||
def state_result(self, ret):
|
||||
@ -183,6 +183,7 @@ class ModuleCase(TestCase):
|
||||
'''
|
||||
return self.run_function('state.single', [function], **kwargs)
|
||||
|
||||
@property
|
||||
def minion_opts(self):
|
||||
'''
|
||||
Return the options used for the minion
|
||||
@ -194,6 +195,7 @@ class ModuleCase(TestCase):
|
||||
)
|
||||
)
|
||||
|
||||
@property
|
||||
def master_opts(self):
|
||||
'''
|
||||
Return the options used for the minion
|
||||
|
92
tests/integration/modules/django.py
Normal file
92
tests/integration/modules/django.py
Normal file
@ -0,0 +1,92 @@
|
||||
'''
|
||||
Test the django module
|
||||
'''
|
||||
# Import python libs
|
||||
import sys
|
||||
|
||||
# Import Salt libs
|
||||
from saltunittest import TestLoader, TextTestRunner
|
||||
import integration
|
||||
from integration import TestDaemon
|
||||
from salt.modules import django
|
||||
django.__salt__ = {}
|
||||
|
||||
from mock import MagicMock, patch
|
||||
|
||||
|
||||
class DjangoModuleTest(integration.ModuleCase):
|
||||
'''
|
||||
Test the django module
|
||||
'''
|
||||
|
||||
def test_command(self):
|
||||
mock = MagicMock()
|
||||
with patch.dict(django.__salt__,
|
||||
{'cmd.run': mock}):
|
||||
django.command('settings.py', 'runserver')
|
||||
mock.assert_called_once_with('django-admin.py runserver --settings=settings.py')
|
||||
|
||||
def test_command_with_args(self):
|
||||
mock = MagicMock()
|
||||
with patch.dict(django.__salt__,
|
||||
{'cmd.run': mock}):
|
||||
django.command('settings.py', 'runserver', None, None, 'noinput', 'somethingelse')
|
||||
mock.assert_called_once_with('django-admin.py runserver --settings=settings.py --noinput --somethingelse')
|
||||
|
||||
def test_command_with_kwargs(self):
|
||||
mock = MagicMock()
|
||||
with patch.dict(django.__salt__,
|
||||
{'cmd.run': mock}):
|
||||
django.command('settings.py', 'runserver', None, None, database='something')
|
||||
mock.assert_called_once_with('django-admin.py runserver --settings=settings.py --database=something')
|
||||
|
||||
def test_command_with_kwargs_ignore_dunder(self):
|
||||
mock = MagicMock()
|
||||
with patch.dict(django.__salt__,
|
||||
{'cmd.run': mock}):
|
||||
django.command('settings.py', 'runserver', None, None, __ignore='something')
|
||||
mock.assert_called_once_with('django-admin.py runserver --settings=settings.py')
|
||||
|
||||
def test_syncdb(self):
|
||||
mock = MagicMock()
|
||||
with patch.dict(django.__salt__,
|
||||
{'cmd.run': mock}):
|
||||
django.syncdb('settings.py')
|
||||
mock.assert_called_once_with('django-admin.py syncdb --settings=settings.py --noinput')
|
||||
|
||||
def test_syncdb_migrate(self):
|
||||
mock = MagicMock()
|
||||
with patch.dict(django.__salt__,
|
||||
{'cmd.run': mock}):
|
||||
django.syncdb('settings.py', migrate=True)
|
||||
mock.assert_called_once_with('django-admin.py syncdb --settings=settings.py --migrate --noinput')
|
||||
|
||||
def test_createsuperuser(self):
|
||||
mock = MagicMock()
|
||||
with patch.dict(django.__salt__,
|
||||
{'cmd.run': mock}):
|
||||
django.createsuperuser('settings.py', 'testuser', 'user@example.com')
|
||||
mock.assert_called_once_with('django-admin.py createsuperuser --settings=settings.py --noinput --username=testuser --email=user@example.com')
|
||||
|
||||
def test_loaddata(self):
|
||||
mock = MagicMock()
|
||||
with patch.dict(django.__salt__,
|
||||
{'cmd.run': mock}):
|
||||
django.loaddata('settings.py', 'app1,app2')
|
||||
mock.assert_called_once_with('django-admin.py loaddata --settings=settings.py app1 app2')
|
||||
|
||||
def test_collectstatic(self):
|
||||
mock = MagicMock()
|
||||
with patch.dict(django.__salt__,
|
||||
{'cmd.run': mock}):
|
||||
django.collectstatic('settings.py', None, True, 'something', True, True, True, True)
|
||||
mock.assert_called_once_with('django-admin.py collectstatic --settings=settings.py --no-post-process --dry-run --clear --link --no-default-ignore --ignore=something')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
loader = TestLoader()
|
||||
tests = loader.loadTestsFromTestCase(DjangoModuleTest)
|
||||
print('Setting up Salt daemons to execute tests')
|
||||
with TestDaemon():
|
||||
runner = TextTestRunner(verbosity=1).run(tests)
|
||||
sys.exit(runner.wasSuccessful())
|
@ -18,14 +18,14 @@ class TestModulesGrains(integration.ModuleCase):
|
||||
'''
|
||||
grains.items
|
||||
'''
|
||||
opts = self.minion_opts()
|
||||
opts = self.minion_opts
|
||||
self.assertEqual(self.run_function('grains.items')['test_grain'], opts['grains']['test_grain'])
|
||||
|
||||
def test_item(self):
|
||||
'''
|
||||
grains.item
|
||||
'''
|
||||
opts = self.minion_opts()
|
||||
opts = self.minion_opts
|
||||
self.assertEqual(self.run_function('grains.item', ['test_grain']), opts['grains']['test_grain'])
|
||||
|
||||
def test_ls(self):
|
||||
|
@ -13,21 +13,19 @@ HFILE = os.path.join(integration.TMP, 'hosts')
|
||||
|
||||
|
||||
class HostTest(integration.ModuleCase):
|
||||
def setUp(self):
|
||||
shutil.copy(os.path.join(
|
||||
integration.INTEGRATION_TEST_DIR, 'files', 'hosts'),
|
||||
self.master_opts['hosts.file'])
|
||||
shutil.copy(os.path.join(
|
||||
integration.INTEGRATION_TEST_DIR, 'files', 'hosts'),
|
||||
self.minion_opts['hosts.file'])
|
||||
|
||||
def tearDown(self):
|
||||
os.remove(self.master_opts['hosts.file'])
|
||||
os.remove(self.minion_opts['hosts.file'])
|
||||
|
||||
'''
|
||||
Validate the host state
|
||||
'''
|
||||
|
||||
def setUp(self):
|
||||
shutil.copyfile(os.path.join(integration.FILES, 'hosts'), HFILE)
|
||||
super(HostTest, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
if os.path.exists(HFILE):
|
||||
os.remove(HFILE)
|
||||
super(HostTest, self).tearDown()
|
||||
|
||||
def test_present(self):
|
||||
'''
|
||||
host.present
|
||||
|
50
tests/unit/utils/verify_test.py
Normal file
50
tests/unit/utils/verify_test.py
Normal file
@ -0,0 +1,50 @@
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import stat
|
||||
import tempfile
|
||||
|
||||
from saltunittest import skipIf, TestCase
|
||||
|
||||
from salt.utils.verify import (
|
||||
check_user,
|
||||
verify_env,
|
||||
verify_socket,
|
||||
zmq_version,
|
||||
)
|
||||
|
||||
|
||||
class TestVerify(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.logger = logging.getLogger(__name__)
|
||||
|
||||
def test_zmq_verify(self):
|
||||
self.assertTrue(zmq_version())
|
||||
|
||||
def test_zmq_verify_insuficient(self):
|
||||
import zmq
|
||||
zmq.__version__ = '2.1.0'
|
||||
self.assertFalse(zmq_version())
|
||||
|
||||
def test_user(self):
|
||||
self.assertTrue(check_user(os.getlogin(), self.logger))
|
||||
|
||||
def test_no_user(self):
|
||||
self.assertFalse(check_user('nouser', self.logger))
|
||||
|
||||
@skipIf(sys.platform.startswith('win'), 'No verify_env Windows')
|
||||
def test_verify_env(self):
|
||||
root_dir = tempfile.mkdtemp()
|
||||
var_dir = os.path.join(root_dir, 'var', 'log', 'salt')
|
||||
verify_env([var_dir], os.getlogin())
|
||||
self.assertTrue(os.path.exists(var_dir))
|
||||
dir_stat = os.stat(var_dir)
|
||||
self.assertEqual(dir_stat.st_uid, os.getuid())
|
||||
self.assertEqual(dir_stat.st_gid, os.getgid())
|
||||
self.assertEqual(dir_stat.st_mode & stat.S_IRWXU, stat.S_IRWXU)
|
||||
self.assertEqual(dir_stat.st_mode & stat.S_IRWXG, 0)
|
||||
self.assertEqual(dir_stat.st_mode & stat.S_IRWXO, 0)
|
||||
|
||||
def test_verify_socket(self):
|
||||
self.assertTrue(verify_socket('', 18000, 18001))
|
Loading…
Reference in New Issue
Block a user