mirror of
https://github.com/valitydev/salt.git
synced 2024-11-07 17:09:03 +00:00
Merge remote-tracking branch 'upstream/develop' into sam_raet_43
This commit is contained in:
commit
bb925bee2b
@ -5,9 +5,10 @@ involves preparing the three listeners and the workers needed by the master.
|
||||
'''
|
||||
|
||||
# Import python libs
|
||||
import fnmatch
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import logging
|
||||
import time
|
||||
try:
|
||||
import pwd
|
||||
@ -76,7 +77,7 @@ def clean_fsbackend(opts):
|
||||
'''
|
||||
Clean out the old fileserver backends
|
||||
'''
|
||||
# Clear remote fileserver backend env cache so it gets recreated
|
||||
# Clear remote fileserver backend caches so they get recreated
|
||||
for backend in ('git', 'hg', 'svn'):
|
||||
if backend in opts['fileserver_backend']:
|
||||
env_cache = os.path.join(
|
||||
@ -94,6 +95,25 @@ def clean_fsbackend(opts):
|
||||
.format(env_cache, exc)
|
||||
)
|
||||
|
||||
file_lists_dir = os.path.join(
|
||||
opts['cachedir'],
|
||||
'file_lists',
|
||||
'{0}fs'.format(backend)
|
||||
)
|
||||
try:
|
||||
file_lists_caches = os.listdir(file_lists_dir)
|
||||
except OSError:
|
||||
continue
|
||||
for file_lists_cache in fnmatch.filter(file_lists_caches, '*.p'):
|
||||
cache_file = os.path.join(file_lists_dir, file_lists_cache)
|
||||
try:
|
||||
os.remove(cache_file)
|
||||
except (IOError, OSError) as exc:
|
||||
log.critical(
|
||||
'Unable to file_lists cache file {0}: {1}'
|
||||
.format(cache_file, exc)
|
||||
)
|
||||
|
||||
|
||||
def clean_expired_tokens(opts):
|
||||
'''
|
||||
@ -704,7 +724,7 @@ class RemoteFuncs(object):
|
||||
if 'jid' in minion:
|
||||
ret['__jid__'] = minion['jid']
|
||||
for key, val in self.local.get_cache_returns(ret['__jid__']).items():
|
||||
if not key in ret:
|
||||
if key not in ret:
|
||||
ret[key] = val
|
||||
if load.get('form', '') != 'full':
|
||||
ret.pop('__jid__')
|
||||
|
@ -590,6 +590,9 @@ def init():
|
||||
'hash': repo_hash,
|
||||
'cachedir': rp_
|
||||
})
|
||||
# Strip trailing slashes from the gitfs root as these cause
|
||||
# path searches to fail.
|
||||
repo_conf['root'] = repo_conf['root'].rstrip(os.path.sep)
|
||||
repos.append(repo_conf)
|
||||
|
||||
except Exception as exc:
|
||||
|
@ -1254,6 +1254,25 @@ class Minion(MinionBase):
|
||||
).compile_pillar()
|
||||
self.module_refresh()
|
||||
|
||||
def manage_schedule(self, package):
|
||||
'''
|
||||
Refresh the functions and returners.
|
||||
'''
|
||||
tag, data = salt.utils.event.MinionEvent.unpack(package)
|
||||
func = data.get('func', None)
|
||||
|
||||
if func == 'delete':
|
||||
job = data.get('job', None)
|
||||
self.schedule.delete_job(job)
|
||||
elif func == 'add':
|
||||
name = data.get('name', None)
|
||||
schedule = data.get('schedule', None)
|
||||
self.schedule.add_job(name, schedule)
|
||||
elif func == 'modify':
|
||||
name = data.get('name', None)
|
||||
schedule = data.get('schedule', None)
|
||||
self.schedule.modify_job(name, schedule)
|
||||
|
||||
def environ_setenv(self, package):
|
||||
'''
|
||||
Set the salt-minion main process environment according to
|
||||
@ -1400,6 +1419,8 @@ class Minion(MinionBase):
|
||||
self.module_refresh()
|
||||
elif package.startswith('pillar_refresh'):
|
||||
self.pillar_refresh()
|
||||
elif package.startswith('manage_schedule'):
|
||||
self.manage_schedule(package)
|
||||
elif package.startswith('grains_refresh'):
|
||||
if self.grains_cache != self.opts['grains']:
|
||||
self.pillar_refresh()
|
||||
|
@ -129,7 +129,7 @@ def available():
|
||||
for root, dirs, files in os.walk(mod_dir):
|
||||
for fn_ in files:
|
||||
if '.ko' in fn_:
|
||||
ret.append(fn_[:fn_.index('.ko')])
|
||||
ret.append(fn_[:fn_.index('.ko')].replace('-', '_'))
|
||||
return sorted(list(ret))
|
||||
|
||||
|
||||
|
289
salt/modules/schedule.py
Normal file
289
salt/modules/schedule.py
Normal file
@ -0,0 +1,289 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Module for manging the Salt schedule on a minion
|
||||
|
||||
.. versionadded:: Helium
|
||||
|
||||
'''
|
||||
|
||||
# Import Python libs
|
||||
import os
|
||||
import yaml
|
||||
|
||||
import salt.utils
|
||||
|
||||
__proxyenabled__ = ['*']
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
SCHEDULE_CONF = [
|
||||
'function',
|
||||
'splay',
|
||||
'range',
|
||||
'when',
|
||||
'returner',
|
||||
'jid_include',
|
||||
'args',
|
||||
'kwargs',
|
||||
'_seconds',
|
||||
'seconds',
|
||||
'minutes',
|
||||
'hours',
|
||||
'days'
|
||||
]
|
||||
|
||||
|
||||
def list():
|
||||
'''
|
||||
List the jobs currently scheduled on the minion
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' schedule.list
|
||||
'''
|
||||
|
||||
schedule = __opts__['schedule']
|
||||
for job in schedule.keys():
|
||||
if job.startswith('_'):
|
||||
del schedule[job]
|
||||
continue
|
||||
|
||||
for item in schedule[job].keys():
|
||||
if not item in SCHEDULE_CONF:
|
||||
del schedule[job][item]
|
||||
continue
|
||||
if schedule[job][item] == 'true':
|
||||
schedule[job][item] = True
|
||||
if schedule[job][item] == 'false':
|
||||
schedule[job][item] = False
|
||||
|
||||
if '_seconds' in schedule[job].keys():
|
||||
schedule[job]['seconds'] = schedule[job]['_seconds']
|
||||
del schedule[job]['_seconds']
|
||||
|
||||
if schedule:
|
||||
tmp = {'schedule': schedule}
|
||||
yaml_out = yaml.safe_dump(tmp, default_flow_style=False)
|
||||
return yaml_out
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def purge():
|
||||
'''
|
||||
Purge all the jobs currently scheduled on the minion
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' schedule.purge
|
||||
'''
|
||||
|
||||
ret = {'comment': [],
|
||||
'result': True}
|
||||
|
||||
schedule = __opts__['schedule']
|
||||
for job in schedule.keys():
|
||||
if job.startswith('_'):
|
||||
continue
|
||||
|
||||
out = __salt__['event.fire']({'job': job, 'func': 'delete'}, 'manage_schedule')
|
||||
if out:
|
||||
ret['comment'].append('Deleted job: {0} from schedule.'.format(job))
|
||||
else:
|
||||
ret['comment'].append('Failed to delete job {0} from schedule.'.format(job))
|
||||
ret['result'] = False
|
||||
return ret
|
||||
|
||||
|
||||
def delete(name):
|
||||
'''
|
||||
Delete a job from the minion's schedule
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' schedule.delete job1
|
||||
'''
|
||||
|
||||
ret = {'comment': [],
|
||||
'result': True}
|
||||
|
||||
if not name:
|
||||
ret['comment'] = 'Job name is required.'
|
||||
ret['result'] = False
|
||||
|
||||
if name in __opts__['schedule']:
|
||||
out = __salt__['event.fire']({'job': name, 'func': 'delete'}, 'manage_schedule')
|
||||
if out:
|
||||
ret['comment'] = 'Deleted Job {0} from schedule.'.format(name)
|
||||
else:
|
||||
ret['comment'] = 'Failed to delete job {0} from schedule.'.format(name)
|
||||
ret['result'] = False
|
||||
else:
|
||||
ret['comment'] = 'Job {0} does not exist.'.format(name)
|
||||
ret['result'] = False
|
||||
return ret
|
||||
|
||||
|
||||
def add(name, **kwargs):
|
||||
'''
|
||||
Add a job to the schedule
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' schedule.add job1 function='test.ping' seconds=3600
|
||||
'''
|
||||
|
||||
ret = {'comment': [],
|
||||
'result': True}
|
||||
|
||||
if name in __opts__['schedule']:
|
||||
ret['comment'] = 'Job {0} already exists in schedule.'.format(name)
|
||||
ret['result'] = True
|
||||
return ret
|
||||
|
||||
if not name:
|
||||
ret['comment'] = 'Job name is required.'
|
||||
ret['result'] = False
|
||||
|
||||
schedule = {'function': kwargs['function']}
|
||||
|
||||
time_conflict = False
|
||||
for item in ['seconds', 'minutes', 'hours', 'days']:
|
||||
if item in kwargs and 'when' in kwargs:
|
||||
time_conflict = True
|
||||
|
||||
if time_conflict:
|
||||
return 'Error: Unable to use "seconds", "minutes", "hours", or "days" with "when" option.'
|
||||
|
||||
for item in ['seconds', 'minutes', 'hours', 'days']:
|
||||
if item in kwargs:
|
||||
schedule[item] = kwargs[item]
|
||||
|
||||
if 'job_args' in kwargs:
|
||||
schedule['args'] = kwargs['job_args']
|
||||
|
||||
if 'job_kwargs' in kwargs:
|
||||
schedule['kwargs'] = kwargs['job_kwargs']
|
||||
|
||||
for item in ['splay', 'range', 'when', 'returner', 'jid_include']:
|
||||
if item in kwargs:
|
||||
schedule[item] = kwargs[item]
|
||||
|
||||
out = __salt__['event.fire']({'name': name, 'schedule': schedule, 'func': 'add'}, 'manage_schedule')
|
||||
if out:
|
||||
ret['comment'] = 'Added job: {0} to schedule.'.format(name)
|
||||
else:
|
||||
ret['comment'] = 'Failed to modify job {0} to schedule.'.format(name)
|
||||
ret['result'] = False
|
||||
return ret
|
||||
|
||||
|
||||
def modify(name, **kwargs):
|
||||
'''
|
||||
Modify an existing job in the schedule
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' schedule.modify job1 function='test.ping' seconds=3600
|
||||
'''
|
||||
|
||||
ret = {'comment': [],
|
||||
'result': True}
|
||||
|
||||
if not name in __opts__['schedule']:
|
||||
ret['comment'] = 'Job {0} does not exist in schedule.'.format(name)
|
||||
ret['result'] = False
|
||||
return ret
|
||||
|
||||
schedule = {'function': kwargs['function']}
|
||||
|
||||
time_conflict = False
|
||||
for item in ['seconds', 'minutes', 'hours', 'days']:
|
||||
if item in kwargs and 'when' in kwargs:
|
||||
time_conflict = True
|
||||
|
||||
if time_conflict:
|
||||
return 'Error: Unable to use "seconds", "minutes", "hours", or "days" with "when" option.'
|
||||
|
||||
for item in ['seconds', 'minutes', 'hours', 'days']:
|
||||
if item in kwargs:
|
||||
schedule[item] = kwargs[item]
|
||||
|
||||
if 'job_args' in kwargs:
|
||||
schedule['args'] = kwargs['job_args']
|
||||
|
||||
if 'job_kwargs' in kwargs:
|
||||
schedule['kwargs'] = kwargs['job_kwargs']
|
||||
|
||||
for item in ['splay', 'range', 'when', 'returner', 'jid_include']:
|
||||
if item in kwargs:
|
||||
schedule[item] = kwargs[item]
|
||||
|
||||
out = __salt__['event.fire']({'name': name, 'schedule': schedule, 'func': 'modify'}, 'manage_schedule')
|
||||
if out:
|
||||
ret['comment'] = 'Modified job: {0} in schedule.'.format(name)
|
||||
else:
|
||||
ret['comment'] = 'Failed to modify job {0} in schedule.'.format(name)
|
||||
ret['result'] = False
|
||||
return ret
|
||||
|
||||
|
||||
def save():
|
||||
'''
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' schedule.save
|
||||
'''
|
||||
|
||||
ret = {'comment': [],
|
||||
'result': True}
|
||||
|
||||
schedule = __opts__['schedule']
|
||||
for job in schedule.keys():
|
||||
if job.startswith('_'):
|
||||
del schedule[job]
|
||||
continue
|
||||
|
||||
for item in schedule[job].keys():
|
||||
if not item in SCHEDULE_CONF:
|
||||
del schedule[job][item]
|
||||
continue
|
||||
if schedule[job][item] == 'true':
|
||||
schedule[job][item] = True
|
||||
if schedule[job][item] == 'false':
|
||||
schedule[job][item] = False
|
||||
|
||||
if '_seconds' in schedule[job].keys():
|
||||
schedule[job]['seconds'] = schedule[job]['_seconds']
|
||||
del schedule[job]['_seconds']
|
||||
|
||||
# move this file into an configurable opt
|
||||
sfn = '{0}/{1}/schedule.conf'.format(__opts__['config_dir'], os.path.dirname(__opts__['default_include']))
|
||||
if schedule:
|
||||
tmp = {'schedule': schedule}
|
||||
yaml_out = yaml.safe_dump(tmp, default_flow_style=False)
|
||||
else:
|
||||
yaml_out = ''
|
||||
|
||||
try:
|
||||
with salt.utils.fopen(sfn, 'w+') as fp_:
|
||||
fp_.write(yaml_out)
|
||||
ret['comment'] = 'Schedule saved to {0}.'.format(sfn)
|
||||
except (IOError, OSError):
|
||||
ret['comment'] = 'Unable to write to schedule file at {0}. Check permissions.'.format(sfn)
|
||||
ret['result'] = False
|
||||
return ret
|
@ -169,6 +169,22 @@ def gen_password(password, crypt_salt=None, algorithm='sha512'):
|
||||
return salt.utils.pycrypto.gen_hash(crypt_salt, password, algorithm)
|
||||
|
||||
|
||||
def del_password(name):
|
||||
'''
|
||||
Delete the password from name user
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' shadow.del_password username
|
||||
'''
|
||||
cmd = 'passwd -d {0}'.format(name)
|
||||
__salt__['cmd.run'](cmd, output_loglevel='quiet')
|
||||
uinfo = info(name)
|
||||
return not uinfo['passwd']
|
||||
|
||||
|
||||
def set_password(name, password, use_usermod=False):
|
||||
'''
|
||||
Set the password for a named user. The password must be a properly defined
|
||||
|
@ -130,7 +130,7 @@ def _get_repo_options(**kwargs):
|
||||
repo_arg = ''
|
||||
if fromrepo:
|
||||
log.info('Restricting to repo {0!r}'.format(fromrepo))
|
||||
repo_arg = ('--disablerepo={0!r} --enablerepo={1!r}'
|
||||
repo_arg = ('--disablerepo={0!r} --enablerepo={1!r} '
|
||||
.format('*', fromrepo))
|
||||
else:
|
||||
repo_arg = ''
|
||||
@ -726,6 +726,10 @@ def install(name=None,
|
||||
Disable exclude from main, for a repo or for everything.
|
||||
(e.g., ``yum --disableexcludes='main'``)
|
||||
|
||||
branch
|
||||
Specifies the branch on YUM server.
|
||||
(e.g., ``yum --branch='test'``)
|
||||
|
||||
.. versionadded:: Helium
|
||||
|
||||
|
||||
@ -785,6 +789,10 @@ def install(name=None,
|
||||
'package targets')
|
||||
|
||||
repo_arg = _get_repo_options(fromrepo=fromrepo, **kwargs)
|
||||
# Support branch parameter for yum
|
||||
branch = kwargs.get('branch', '')
|
||||
if branch:
|
||||
repo_arg += '--branch={0!r}'.format(branch)
|
||||
exclude_arg = _get_excludes_option(**kwargs)
|
||||
|
||||
old = list_pkgs()
|
||||
|
@ -55,6 +55,7 @@ def _changes(name,
|
||||
createhome=True,
|
||||
password=None,
|
||||
enforce_password=True,
|
||||
empty_password=False,
|
||||
shell=None,
|
||||
fullname='',
|
||||
roomnumber='',
|
||||
@ -160,6 +161,7 @@ def present(name,
|
||||
createhome=True,
|
||||
password=None,
|
||||
enforce_password=True,
|
||||
empty_password=False,
|
||||
shell=None,
|
||||
unique=True,
|
||||
system=False,
|
||||
@ -229,6 +231,9 @@ def present(name,
|
||||
"password" field. This option will be ignored if "password" is not
|
||||
specified.
|
||||
|
||||
empty_password
|
||||
Set to True to enable no password-less login for user
|
||||
|
||||
shell
|
||||
The login shell, defaults to the system default shell
|
||||
|
||||
@ -325,6 +330,9 @@ def present(name,
|
||||
if gid_from_name:
|
||||
gid = __salt__['file.group_to_gid'](name)
|
||||
|
||||
if empty_password:
|
||||
__salt__['shadow.del_password'](name)
|
||||
|
||||
changes = _changes(name,
|
||||
uid,
|
||||
gid,
|
||||
@ -335,6 +343,7 @@ def present(name,
|
||||
createhome,
|
||||
password,
|
||||
enforce_password,
|
||||
empty_password,
|
||||
shell,
|
||||
fullname,
|
||||
roomnumber,
|
||||
@ -360,7 +369,7 @@ def present(name,
|
||||
lshad = __salt__['shadow.info'](name)
|
||||
pre = __salt__['user.info'](name)
|
||||
for key, val in changes.items():
|
||||
if key == 'passwd':
|
||||
if key == 'passwd' and not empty_password:
|
||||
__salt__['shadow.set_password'](name, password)
|
||||
continue
|
||||
if key == 'date':
|
||||
@ -419,6 +428,7 @@ def present(name,
|
||||
createhome,
|
||||
password,
|
||||
enforce_password,
|
||||
empty_password,
|
||||
shell,
|
||||
fullname,
|
||||
roomnumber,
|
||||
@ -464,7 +474,7 @@ def present(name,
|
||||
ret['comment'] = 'New user {0} created'.format(name)
|
||||
ret['changes'] = __salt__['user.info'](name)
|
||||
if 'shadow.info' in __salt__ and not salt.utils.is_windows():
|
||||
if password:
|
||||
if password and not empty_password:
|
||||
__salt__['shadow.set_password'](name, password)
|
||||
spost = __salt__['shadow.info'](name)
|
||||
if spost['passwd'] != password:
|
||||
|
@ -189,6 +189,23 @@ class Schedule(object):
|
||||
return self.functions['config.merge'](opt, {}, omit_master=True)
|
||||
return self.opts.get(opt, {})
|
||||
|
||||
def delete_job(self, name):
|
||||
# ensure job exists, then delete it
|
||||
if name in self.opts['schedule']:
|
||||
del self.opts['schedule'][name]
|
||||
|
||||
# remove from self.intervals
|
||||
if name in self.intervals:
|
||||
del self.intervals[name]
|
||||
|
||||
def add_job(self, name, schedule):
|
||||
self.opts['schedule'][name] = schedule
|
||||
|
||||
def modify_job(self, name, schedule):
|
||||
if name in self.opts['schedule']:
|
||||
self.delete_job(name)
|
||||
self.opts['schedule'][name] = schedule
|
||||
|
||||
def handle_func(self, func, data):
|
||||
'''
|
||||
Execute this method in a multiprocess or thread
|
||||
@ -311,6 +328,7 @@ class Schedule(object):
|
||||
Evaluate and execute the schedule
|
||||
'''
|
||||
schedule = self.option('schedule')
|
||||
#log.debug('calling eval {0}'.format(schedule))
|
||||
if not isinstance(schedule, dict):
|
||||
return
|
||||
for job, data in schedule.items():
|
||||
@ -335,8 +353,12 @@ class Schedule(object):
|
||||
when = 0
|
||||
seconds = 0
|
||||
|
||||
# clean this up
|
||||
if ('seconds' in data or 'hours' in data or 'minutes' in data or 'days' in data) and 'when' in data:
|
||||
time_conflict = False
|
||||
for item in ['seconds', 'minutes', 'hours', 'days']:
|
||||
if item in data and 'when' in data:
|
||||
time_conflict = True
|
||||
|
||||
if time_conflict:
|
||||
log.info('Unable to use "seconds", "minutes", "hours", or "days" with "when" option. Ignoring.')
|
||||
continue
|
||||
|
||||
@ -440,6 +462,7 @@ class Schedule(object):
|
||||
else:
|
||||
if now - self.intervals[job] >= seconds:
|
||||
run = True
|
||||
|
||||
else:
|
||||
if 'splay' in data:
|
||||
if 'when' in data:
|
||||
|
@ -282,7 +282,7 @@ class TestDaemon(object):
|
||||
self.pre_setup_minions()
|
||||
self.setup_minions()
|
||||
|
||||
if self.parser.options.ssh:
|
||||
if getattr(self.parser.options, 'ssh', False):
|
||||
self.prep_ssh()
|
||||
|
||||
if self.parser.options.sysinfo:
|
||||
|
@ -7,7 +7,7 @@
|
||||
from salttesting.unit import skipIf
|
||||
from salttesting.helpers import ensure_in_syspath
|
||||
from salttesting.mock import MagicMock, patch, NO_MOCK, NO_MOCK_REASON
|
||||
ensure_in_syspath('../')
|
||||
ensure_in_syspath('../..')
|
||||
|
||||
# Import salt libs
|
||||
import integration
|
||||
|
@ -8,7 +8,7 @@ from salttesting import skipIf
|
||||
from salttesting.helpers import ensure_in_syspath
|
||||
from salttesting.mock import patch, NO_MOCK, NO_MOCK_REASON
|
||||
|
||||
ensure_in_syspath('../')
|
||||
ensure_in_syspath('../..')
|
||||
|
||||
# Import Python libs
|
||||
import os
|
||||
@ -23,6 +23,10 @@ gitfs.__opts__ = {'gitfs_remotes': [''],
|
||||
'fileserver_backend': 'gitfs',
|
||||
'gitfs_base': 'master',
|
||||
'fileserver_events': True,
|
||||
'transport': 'zeromq',
|
||||
'gitfs_mountpoint': '',
|
||||
'gitfs_env_whitelist': [],
|
||||
'gitfs_env_blacklist': []
|
||||
}
|
||||
|
||||
load = {'saltenv': 'base'}
|
||||
@ -88,7 +92,11 @@ class GitFSTest(integration.ModuleCase):
|
||||
'gitfs_remotes': ['file://' + self.tmp_repo_git],
|
||||
'sock_dir': self.master_opts['sock_dir']}):
|
||||
ret = gitfs.find_file('testfile')
|
||||
expected_ret = {'path': '/tmp/salttest/cache/gitfs/refs/master/testfile',
|
||||
expected_ret = {'path': os.path.join(self.master_opts['cachedir'],
|
||||
'gitfs',
|
||||
'refs',
|
||||
'base',
|
||||
'testfile'),
|
||||
'rel': 'testfile'}
|
||||
|
||||
self.assertDictEqual(ret, expected_ret)
|
||||
@ -140,8 +148,18 @@ class GitFSTest(integration.ModuleCase):
|
||||
|
||||
ret = gitfs.serve_file(load, fnd)
|
||||
self.assertDictEqual({
|
||||
'data': 'Scene 24\n\n \n OLD MAN: Ah, hee he he ha!\n ARTHUR: And this enchanter of whom you speak, he has seen the grail?\n OLD MAN: Ha ha he he he he!\n ARTHUR: Where does he live? Old man, where does he live?\n OLD MAN: He knows of a cave, a cave which no man has entered.\n ARTHUR: And the Grail... The Grail is there?\n OLD MAN: Very much danger, for beyond the cave lies the Gorge\n of Eternal Peril, which no man has ever crossed.\n ARTHUR: But the Grail! Where is the Grail!?\n OLD MAN: Seek you the Bridge of Death.\n ARTHUR: The Bridge of Death, which leads to the Grail?\n OLD MAN: Hee hee ha ha!\n\n',
|
||||
'dest': 'testfile'}, ret)
|
||||
'data': 'Scene 24\n\n \n OLD MAN: Ah, hee he he ha!\n ARTHUR: '
|
||||
'And this enchanter of whom you speak, he has seen the grail?\n '
|
||||
'OLD MAN: Ha ha he he he he!\n ARTHUR: Where does he live? '
|
||||
'Old man, where does he live?\n OLD MAN: He knows of a cave, '
|
||||
'a cave which no man has entered.\n ARTHUR: And the Grail... '
|
||||
'The Grail is there?\n OLD MAN: Very much danger, for beyond '
|
||||
'the cave lies the Gorge\n of Eternal Peril, which no man '
|
||||
'has ever crossed.\n ARTHUR: But the Grail! Where is the Grail!?\n '
|
||||
'OLD MAN: Seek you the Bridge of Death.\n ARTHUR: The Bridge of '
|
||||
'Death, which leads to the Grail?\n OLD MAN: Hee hee ha ha!\n\n',
|
||||
'dest': 'testfile'},
|
||||
ret)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
@ -7,7 +7,7 @@
|
||||
from salttesting import skipIf
|
||||
from salttesting.helpers import ensure_in_syspath
|
||||
from salttesting.mock import patch, NO_MOCK, NO_MOCK_REASON
|
||||
ensure_in_syspath('../')
|
||||
ensure_in_syspath('../..')
|
||||
|
||||
# Import salt libs
|
||||
import integration
|
||||
@ -22,11 +22,15 @@ import os
|
||||
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
class RootsTest(integration.ModuleCase):
|
||||
|
||||
def setUp(self):
|
||||
self.master_opts['file_roots']['base'] = [os.path.join(integration.FILES, 'file', 'base')]
|
||||
if integration.TMP_STATE_TREE not in self.master_opts['file_roots']['base']:
|
||||
# We need to setup the file roots
|
||||
self.master_opts['file_roots']['base'] = [os.path.join(integration.FILES, 'file', 'base')]
|
||||
|
||||
def test_file_list(self):
|
||||
with patch.dict(roots.__opts__, {'file_roots': self.master_opts['file_roots'],
|
||||
with patch.dict(roots.__opts__, {'cachedir': self.master_opts['cachedir'],
|
||||
'file_roots': self.master_opts['file_roots'],
|
||||
'fileserver_ignoresymlinks': False,
|
||||
'fileserver_followsymlinks': False,
|
||||
'file_ignore_regex': False,
|
||||
@ -102,7 +106,10 @@ class RootsTest(integration.ModuleCase):
|
||||
self.assertDictEqual(ret, {'hsum': '98aa509006628302ce38ce521a7f805f', 'hash_type': 'md5'})
|
||||
|
||||
def test_file_list_emptydirs(self):
|
||||
with patch.dict(roots.__opts__, {'file_roots': self.master_opts['file_roots'],
|
||||
if integration.TMP_STATE_TREE not in self.master_opts['file_roots']['base']:
|
||||
self.skipTest('This test fails when using tests/runtests.py. salt-runtests will be available soon.')
|
||||
with patch.dict(roots.__opts__, {'cachedir': self.master_opts['cachedir'],
|
||||
'file_roots': self.master_opts['file_roots'],
|
||||
'fileserver_ignoresymlinks': False,
|
||||
'fileserver_followsymlinks': False,
|
||||
'file_ignore_regex': False,
|
||||
@ -111,11 +118,14 @@ class RootsTest(integration.ModuleCase):
|
||||
self.assertIn('empty_dir', ret)
|
||||
|
||||
def test_dir_list(self):
|
||||
with patch.dict(roots.__opts__, {'file_roots': self.master_opts['file_roots'],
|
||||
'fileserver_ignoresymlinks': False,
|
||||
'fileserver_followsymlinks': False,
|
||||
'file_ignore_regex': False,
|
||||
'file_ignore_glob': False}):
|
||||
if integration.TMP_STATE_TREE not in self.master_opts['file_roots']['base']:
|
||||
self.skipTest('This test fails when using tests/runtests.py. salt-runtests will be available soon.')
|
||||
with patch.dict(roots.__opts__, {'cachedir': self.master_opts['cachedir'],
|
||||
'file_roots': self.master_opts['file_roots'],
|
||||
'fileserver_ignoresymlinks': False,
|
||||
'fileserver_followsymlinks': False,
|
||||
'file_ignore_regex': False,
|
||||
'file_ignore_glob': False}):
|
||||
ret = roots.dir_list({'saltenv': 'base'})
|
||||
self.assertIn('empty_dir', ret)
|
||||
|
||||
|
@ -85,34 +85,8 @@ class CallTest(integration.ShellCase, integration.ShellCaseCommonTestsMixIn):
|
||||
|
||||
@skipIf(sys.platform.startswith('win'), 'This test does not apply on Win')
|
||||
def test_return(self):
|
||||
config_dir = '/tmp/salttest'
|
||||
minion_config_file = os.path.join(config_dir, 'minion')
|
||||
minion_config = {
|
||||
'id': 'minion_test_issue_2731',
|
||||
'master': 'localhost',
|
||||
'master_port': 64506,
|
||||
'root_dir': '/tmp/salttest',
|
||||
'pki_dir': 'pki',
|
||||
'cachedir': 'cachedir',
|
||||
'sock_dir': 'minion_sock',
|
||||
'open_mode': True,
|
||||
'log_file': '/tmp/salttest/minion_test_issue_2731',
|
||||
'log_level': 'quiet',
|
||||
'log_level_logfile': 'info'
|
||||
}
|
||||
|
||||
# Remove existing logfile
|
||||
if os.path.isfile('/tmp/salttest/minion_test_issue_2731'):
|
||||
os.unlink('/tmp/salttest/minion_test_issue_2731')
|
||||
|
||||
# Let's first test with a master running
|
||||
open(minion_config_file, 'w').write(
|
||||
yaml.dump(minion_config, default_flow_style=False)
|
||||
)
|
||||
out = self.run_call('-c {0} cmd.run "echo returnTOmaster"'.format(
|
||||
os.path.join(integration.INTEGRATION_TEST_DIR, 'files', 'conf')))
|
||||
jobs = [a for a in self.run_run('-c {0} jobs.list_jobs'.format(
|
||||
os.path.join(integration.INTEGRATION_TEST_DIR, 'files', 'conf')))]
|
||||
self.run_call('-c {0} cmd.run "echo returnTOmaster"'.format(self.get_config_dir()))
|
||||
jobs = [a for a in self.run_run('-c {0} jobs.list_jobs'.format(self.get_config_dir()))]
|
||||
|
||||
self.assertTrue(True in ['returnTOmaster' in j for j in jobs])
|
||||
# lookback jid
|
||||
@ -129,38 +103,43 @@ class CallTest(integration.ShellCase, integration.ShellCaseCommonTestsMixIn):
|
||||
assert idx > 0
|
||||
assert jid
|
||||
master_out = [
|
||||
a for a in self.run_run('-c {0} jobs.lookup_jid {1}'.format(
|
||||
os.path.join(integration.INTEGRATION_TEST_DIR,
|
||||
'files',
|
||||
'conf'),
|
||||
jid))]
|
||||
a for a in self.run_run('-c {0} jobs.lookup_jid {1}'.format(self.get_config_dir(), jid))
|
||||
]
|
||||
self.assertTrue(True in ['returnTOmaster' in a for a in master_out])
|
||||
|
||||
@skipIf(sys.platform.startswith('win'), 'This test does not apply on Win')
|
||||
def test_issue_2731_masterless(self):
|
||||
config_dir = '/tmp/salttest'
|
||||
root_dir = os.path.join(integration.TMP, 'issue-2731')
|
||||
config_dir = os.path.join(root_dir, 'conf')
|
||||
minion_config_file = os.path.join(config_dir, 'minion')
|
||||
logfile = os.path.join(root_dir, 'minion_test_issue_2731')
|
||||
|
||||
if not os.path.isdir(config_dir):
|
||||
os.makedirs(config_dir)
|
||||
|
||||
master_config = yaml.load(open(self.get_config_file_path('master')).read())
|
||||
master_root_dir = master_config['root_dir']
|
||||
this_minion_key = os.path.join(
|
||||
config_dir, 'pki', 'minions', 'minion_test_issue_2731'
|
||||
master_root_dir, 'pki', 'minions', 'minion_test_issue_2731'
|
||||
)
|
||||
|
||||
minion_config = {
|
||||
'id': 'minion_test_issue_2731',
|
||||
'master': 'localhost',
|
||||
'master_port': 64506,
|
||||
'root_dir': '/tmp/salttest',
|
||||
'root_dir': master_root_dir,
|
||||
'pki_dir': 'pki',
|
||||
'cachedir': 'cachedir',
|
||||
'sock_dir': 'minion_sock',
|
||||
'open_mode': True,
|
||||
'log_file': '/tmp/salttest/minion_test_issue_2731',
|
||||
'log_file': logfile,
|
||||
'log_level': 'quiet',
|
||||
'log_level_logfile': 'info'
|
||||
}
|
||||
|
||||
# Remove existing logfile
|
||||
if os.path.isfile('/tmp/salttest/minion_test_issue_2731'):
|
||||
os.unlink('/tmp/salttest/minion_test_issue_2731')
|
||||
if os.path.isfile(logfile):
|
||||
os.unlink(logfile)
|
||||
|
||||
start = datetime.now()
|
||||
# Let's first test with a master running
|
||||
|
@ -109,6 +109,13 @@ class SaltTestsuiteParser(SaltCoverageTestingParser):
|
||||
action='store_true',
|
||||
help='Run unit tests'
|
||||
)
|
||||
self.test_selection_group.add_option(
|
||||
'--fileserver-tests',
|
||||
dest='fileserver',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help='Run Fileserver tests'
|
||||
)
|
||||
self.test_selection_group.add_option(
|
||||
'-o',
|
||||
'--outputter',
|
||||
@ -137,7 +144,8 @@ class SaltTestsuiteParser(SaltCoverageTestingParser):
|
||||
self.options.module, self.options.client, self.options.shell,
|
||||
self.options.unit, self.options.state, self.options.runner,
|
||||
self.options.loader, self.options.name, self.options.outputter,
|
||||
os.geteuid() != 0, not self.options.run_destructive)):
|
||||
self.options.fileserver, os.geteuid() != 0,
|
||||
not self.options.run_destructive)):
|
||||
self.error(
|
||||
'No sense in generating the tests coverage report when '
|
||||
'not running the full test suite, including the '
|
||||
@ -149,7 +157,8 @@ class SaltTestsuiteParser(SaltCoverageTestingParser):
|
||||
if not any((self.options.module, self.options.client,
|
||||
self.options.shell, self.options.unit, self.options.state,
|
||||
self.options.runner, self.options.loader,
|
||||
self.options.name, self.options.outputter)):
|
||||
self.options.name, self.options.outputter,
|
||||
self.options.fileserver)):
|
||||
self.options.module = True
|
||||
self.options.client = True
|
||||
self.options.shell = True
|
||||
@ -158,6 +167,7 @@ class SaltTestsuiteParser(SaltCoverageTestingParser):
|
||||
self.options.state = True
|
||||
self.options.loader = True
|
||||
self.options.outputter = True
|
||||
self.options.fileserver = True
|
||||
|
||||
self.start_coverage(
|
||||
branch=True,
|
||||
@ -192,6 +202,7 @@ class SaltTestsuiteParser(SaltCoverageTestingParser):
|
||||
self.options.client or
|
||||
self.options.loader or
|
||||
self.options.outputter or
|
||||
self.options.fileserver or
|
||||
named_tests):
|
||||
# We're either not running any of runner, state, module and client
|
||||
# tests, or, we're only running unittests by passing --unit or by
|
||||
@ -240,7 +251,8 @@ class SaltTestsuiteParser(SaltCoverageTestingParser):
|
||||
if not any([self.options.client, self.options.module,
|
||||
self.options.runner, self.options.shell,
|
||||
self.options.state, self.options.loader,
|
||||
self.options.outputter, self.options.name]):
|
||||
self.options.outputter, self.options.name,
|
||||
self.options.fileserver]):
|
||||
return status
|
||||
|
||||
with TestDaemon(self):
|
||||
@ -264,6 +276,8 @@ class SaltTestsuiteParser(SaltCoverageTestingParser):
|
||||
status.append(self.run_integration_suite('shell', 'Shell'))
|
||||
if self.options.outputter:
|
||||
status.append(self.run_integration_suite('output', 'Outputter'))
|
||||
if self.options.fileserver:
|
||||
status.append(self.run_integration_suite('fileserver', 'Fileserver'))
|
||||
return status
|
||||
|
||||
def run_unit_tests(self):
|
||||
|
@ -14,7 +14,7 @@ ensure_in_syspath('../')
|
||||
|
||||
# Import Salt libs
|
||||
import integration
|
||||
from salt import client
|
||||
from salt import client, config
|
||||
from salt.exceptions import EauthAuthenticationError, SaltInvocationError
|
||||
|
||||
|
||||
@ -22,15 +22,14 @@ from salt.exceptions import EauthAuthenticationError, SaltInvocationError
|
||||
class LocalClientTestCase(TestCase,
|
||||
integration.AdaptedConfigurationTestCaseMixIn):
|
||||
def setUp(self):
|
||||
if not os.path.exists('/tmp/salttest'):
|
||||
# This path is hardcoded in the configuration file
|
||||
os.makedirs('/tmp/salttest/cache')
|
||||
master_config_path = self.get_config_file_path('master')
|
||||
master_config = config.master_config(master_config_path)
|
||||
if not os.path.exists(master_config['cachedir']):
|
||||
os.makedirs(master_config['cachedir'])
|
||||
if not os.path.exists(integration.TMP_CONF_DIR):
|
||||
os.makedirs(integration.TMP_CONF_DIR)
|
||||
|
||||
self.local_client = client.LocalClient(
|
||||
self.get_config_file_path('master')
|
||||
)
|
||||
self.local_client = client.LocalClient(mopts=master_config)
|
||||
|
||||
def test_create_local_client(self):
|
||||
local_client = client.LocalClient(self.get_config_file_path('master'))
|
||||
|
@ -93,7 +93,7 @@ def _fopen_side_effect_etc_hosts(filename):
|
||||
_unhandled_mock_read(filename)
|
||||
|
||||
|
||||
class ConfigTestCase(TestCase):
|
||||
class ConfigTestCase(TestCase, integration.AdaptedConfigurationTestCaseMixIn):
|
||||
def test_proper_path_joining(self):
|
||||
fpath = tempfile.mktemp()
|
||||
try:
|
||||
@ -335,31 +335,28 @@ class ConfigTestCase(TestCase):
|
||||
shutil.rmtree(tempdir)
|
||||
|
||||
def test_syndic_config(self):
|
||||
syndic_conf_path = os.path.join(
|
||||
integration.INTEGRATION_TEST_DIR, 'files', 'conf', 'syndic'
|
||||
)
|
||||
minion_config_path = os.path.join(
|
||||
integration.INTEGRATION_TEST_DIR, 'files', 'conf', 'minion'
|
||||
)
|
||||
syndic_conf_path = self.get_config_file_path('syndic')
|
||||
minion_conf_path = self.get_config_file_path('minion')
|
||||
syndic_opts = sconfig.syndic_config(
|
||||
syndic_conf_path, minion_config_path
|
||||
syndic_conf_path, minion_conf_path
|
||||
)
|
||||
syndic_opts.update(salt.minion.resolve_dns(syndic_opts))
|
||||
root_dir = syndic_opts['root_dir']
|
||||
# id & pki dir are shared & so configured on the minion side
|
||||
self.assertEqual(syndic_opts['id'], 'minion')
|
||||
self.assertEqual(syndic_opts['pki_dir'], '/tmp/salttest/pki')
|
||||
self.assertEqual(syndic_opts['pki_dir'], os.path.join(root_dir, 'pki'))
|
||||
# the rest is configured master side
|
||||
self.assertEqual(syndic_opts['master_uri'], 'tcp://127.0.0.1:54506')
|
||||
self.assertEqual(syndic_opts['master_port'], 54506)
|
||||
self.assertEqual(syndic_opts['master_ip'], '127.0.0.1')
|
||||
self.assertEqual(syndic_opts['master'], 'localhost')
|
||||
self.assertEqual(syndic_opts['sock_dir'], '/tmp/salttest/minion_sock')
|
||||
self.assertEqual(syndic_opts['cachedir'], '/tmp/salttest/cachedir')
|
||||
self.assertEqual(syndic_opts['log_file'], '/tmp/salttest/osyndic.log')
|
||||
self.assertEqual(syndic_opts['pidfile'], '/tmp/salttest/osyndic.pid')
|
||||
self.assertEqual(syndic_opts['sock_dir'], os.path.join(root_dir, 'minion_sock'))
|
||||
self.assertEqual(syndic_opts['cachedir'], os.path.join(root_dir, 'cachedir'))
|
||||
self.assertEqual(syndic_opts['log_file'], os.path.join(root_dir, 'osyndic.log'))
|
||||
self.assertEqual(syndic_opts['pidfile'], os.path.join(root_dir, 'osyndic.pid'))
|
||||
# Show that the options of localclient that repub to local master
|
||||
# are not merged with syndic ones
|
||||
self.assertEqual(syndic_opts['_master_conf_file'], minion_config_path)
|
||||
self.assertEqual(syndic_opts['_master_conf_file'], minion_conf_path)
|
||||
self.assertEqual(syndic_opts['_minion_conf_file'], syndic_conf_path)
|
||||
|
||||
def test_check_dns_deprecation_warning(self):
|
||||
|
Loading…
Reference in New Issue
Block a user