mirror of
https://github.com/valitydev/salt.git
synced 2024-11-07 17:09:03 +00:00
Merge remote branch 'upstream/develop' into develop
This commit is contained in:
commit
e164562c90
@ -90,6 +90,12 @@
|
||||
# Set the directory used to hold unix sockets
|
||||
#sock_dir: /var/run/salt/master
|
||||
|
||||
# The master can take a while to start up when lspci and/or dmidecode is used
|
||||
# to populate the grains for the master. Enable if you want to see GPU hardware
|
||||
# data for your master.
|
||||
#
|
||||
# enable_gpu_grains: False
|
||||
|
||||
# The master maintains a job cache, while this is a great addition it can be
|
||||
# a burden on the master for larger deployments (over 5000 minions).
|
||||
# Disabling the job cache will make previously executed jobs unavailable to
|
||||
|
12
conf/minion
12
conf/minion
@ -182,6 +182,18 @@
|
||||
# often lower this value
|
||||
#loop_interval: 60
|
||||
|
||||
# The grains_refresh_every setting allows for a minion to periodically check
|
||||
# its grains to see if they have changed and, if so, to inform the master
|
||||
# of the new grains. This operation is moderately expensive, therefore
|
||||
# care should be taken not to set this value too low.
|
||||
#
|
||||
# Note: This value is expressed in __minutes__!
|
||||
#
|
||||
# A value of 10 minutes is a reasonable default.
|
||||
#
|
||||
# If the value is set to zero, this check is disabled.
|
||||
#grains_refresh_every = 1
|
||||
|
||||
# When healing, a dns_check is run. This is to make sure that the originally
|
||||
# resolved dns has not changed. If this is something that does not happen in
|
||||
# your environment, set this value to False.
|
||||
|
@ -70395,7 +70395,7 @@ settings for software packages that support that option.
|
||||
.sp
|
||||
In order to facilitate managing a Salt Windows software repo with Salt on a
|
||||
Standalone Minion on Windows, a new module named winrepo has been added to
|
||||
Salt. wirepo matches what is available in the salt runner and allows you to
|
||||
Salt. winrepo matches what is available in the salt runner and allows you to
|
||||
manage the Windows software repo contents. Example: \fBsalt \(aq*\(aq
|
||||
winrepo.genrepo\fP
|
||||
.SS Git Hosted Repo
|
||||
|
@ -20,8 +20,8 @@ Environments
|
||||
.. note::
|
||||
|
||||
Environments in Salt are very flexible, this section defines how the top
|
||||
file can be used to define what ststates from what environments are to be
|
||||
used fro specific minions.
|
||||
file can be used to define what states from what environments are to be
|
||||
used for specific minions.
|
||||
|
||||
If the intent is to bind minions to specific environments, then the
|
||||
`environment` option can be set in the minion configuration file.
|
||||
|
@ -237,7 +237,7 @@ Standalone Minion Salt Windows Repo Module
|
||||
|
||||
In order to facilitate managing a Salt Windows software repo with Salt on a
|
||||
Standalone Minion on Windows, a new module named winrepo has been added to
|
||||
Salt. wirepo matches what is available in the salt runner and allows you to
|
||||
Salt. winrepo matches what is available in the salt runner and allows you to
|
||||
manage the Windows software repo contents. Example: ``salt '*'
|
||||
winrepo.genrepo``
|
||||
|
||||
|
@ -33,7 +33,7 @@ Be advised that these security issues all apply to a small subset of Salt
|
||||
users and mostly apply to Salt SSH.
|
||||
|
||||
Insufficient Argument Validation
|
||||
-------------------------------
|
||||
--------------------------------
|
||||
|
||||
This issue allowed for a user with limited privileges to embed executions
|
||||
inside of routines to execute routines that should be restricted. This applies
|
||||
|
@ -9,13 +9,13 @@
|
||||
|
||||
%{!?python_sitelib: %global python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())")}
|
||||
%{!?python_sitearch: %global python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(1))")}
|
||||
%{!?pythonpath: %global pythonpath %(%{__python} -c "import os, sys; print(os.pathsep.join(sys.path))")}
|
||||
%{!?pythonpath: %global pythonpath %(%{__python} -c "import os, sys; print(os.pathsep.join(x for x in sys.path if x))")}
|
||||
|
||||
%define _salttesting SaltTesting
|
||||
%define _salttesting_ver 0.5.1
|
||||
|
||||
Name: salt
|
||||
Version: 0.17.0
|
||||
Version: 0.17.1
|
||||
Release: 1%{?dist}
|
||||
Summary: A parallel remote execution system
|
||||
|
||||
@ -50,6 +50,7 @@ BuildRequires: python26-devel
|
||||
BuildRequires: python26-jinja2
|
||||
BuildRequires: python26-m2crypto
|
||||
BuildRequires: python26-msgpack
|
||||
BuildRequires: python26-pip
|
||||
BuildRequires: python26-zmq
|
||||
BuildRequires: python26-PyYAML
|
||||
|
||||
@ -318,7 +319,10 @@ rm -rf $RPM_BUILD_ROOT
|
||||
%endif
|
||||
|
||||
%changelog
|
||||
* Mon Sep 30 2013 Erik Johnson <erik@saltstack.com> - 0.17.0-1
|
||||
* Thu Oct 17 2013 Erik Johnson <erik@saltstack.com> - 0.17.1-1
|
||||
- Update to bugfix release 0.17.1
|
||||
|
||||
* Thu Sep 26 2013 Erik Johnson <erik@saltstack.com> - 0.17.0-1
|
||||
- Update to feature release 0.17.0
|
||||
|
||||
* Wed Sep 11 2013 David Anderson <dave@dubkat.com>
|
||||
|
@ -12,6 +12,7 @@
|
||||
!include "nsDialogs.nsh"
|
||||
!include "LogicLib.nsh"
|
||||
!include "FileFunc.nsh"
|
||||
!include "nsProcess.nsh"; using plugin nsProcess
|
||||
|
||||
Var Dialog
|
||||
Var Label
|
||||
@ -126,11 +127,15 @@ ShowUnInstDetails show
|
||||
|
||||
Section "MainSection" SEC01
|
||||
|
||||
Exec "sc stop salt-minion" ;stopping service before upgrading
|
||||
${nsProcess::CloseProcess} "salt-minion.exe" $R0
|
||||
${nsProcess::Unload}
|
||||
SetOutPath "$INSTDIR\"
|
||||
SetOverwrite try
|
||||
CreateDirectory $INSTDIR\conf\pki\minion
|
||||
File /r "..\buildenv\"
|
||||
Exec 'icacls c:\salt /inheritance:r /grant:r "BUILTIN\Administrators":(OI)(CI)F /grant:r "NT AUTHORITY\SYSTEM":(OI)(CI)F'
|
||||
|
||||
|
||||
SectionEnd
|
||||
|
||||
@ -149,6 +154,7 @@ SectionEnd
|
||||
|
||||
Function .onInstSuccess
|
||||
Exec "nssm.exe install salt-minion $INSTDIR\salt-minion.exe -c $INSTDIR\conf -l quiet"
|
||||
RMDir /R "$INSTDIR\var\cache\salt" ; removing cache from old version
|
||||
Exec "sc start salt-minion"
|
||||
FunctionEnd
|
||||
|
||||
|
@ -341,7 +341,7 @@ class Resolver(object):
|
||||
|
||||
def mk_token(self, load):
|
||||
'''
|
||||
Request a token fromt he master
|
||||
Request a token from the master
|
||||
'''
|
||||
load['cmd'] = 'mk_token'
|
||||
sreq = salt.payload.SREQ(
|
||||
@ -354,7 +354,7 @@ class Resolver(object):
|
||||
|
||||
def get_token(self, token):
|
||||
'''
|
||||
Request a token fromt he master
|
||||
Request a token from the master
|
||||
'''
|
||||
load = {}
|
||||
load['token'] = token
|
||||
|
@ -8,6 +8,7 @@ import tarfile
|
||||
import tempfile
|
||||
import json
|
||||
import shutil
|
||||
from contextlib import closing
|
||||
|
||||
# Import salt libs
|
||||
import salt.client.ssh.shell
|
||||
@ -142,7 +143,7 @@ def prep_trans_tar(opts, chunks, file_refs):
|
||||
break
|
||||
cwd = os.getcwd()
|
||||
os.chdir(gendir)
|
||||
with tarfile.open(trans_tar, 'w:gz') as tfp:
|
||||
with closing(tarfile.open(trans_tar, 'w:gz')) as tfp:
|
||||
for root, dirs, files in os.walk(gendir):
|
||||
for name in files:
|
||||
full = os.path.join(root, name)
|
||||
|
@ -165,6 +165,8 @@ VALID_OPTS = {
|
||||
'win_repo_mastercachefile': str,
|
||||
'win_gitrepos': list,
|
||||
'modules_max_memory': int,
|
||||
'grains_refresh_every': int,
|
||||
'enable_lspci': bool,
|
||||
}
|
||||
|
||||
# default configurations
|
||||
@ -253,6 +255,7 @@ DEFAULT_MINION_OPTS = {
|
||||
'tcp_keepalive_cnt': -1,
|
||||
'tcp_keepalive_intvl': -1,
|
||||
'modules_max_memory': -1,
|
||||
'grains_refresh_every': 0,
|
||||
}
|
||||
|
||||
DEFAULT_MASTER_OPTS = {
|
||||
@ -345,6 +348,7 @@ DEFAULT_MASTER_OPTS = {
|
||||
'loop_interval': 60,
|
||||
'nodegroups': {},
|
||||
'cython_enable': False,
|
||||
'enable_gpu_grains': False,
|
||||
# XXX: Remove 'key_logfile' support in 0.18.0
|
||||
'key_logfile': os.path.join(syspaths.LOGS_DIR, 'key'),
|
||||
'verify_env': True,
|
||||
|
@ -357,10 +357,12 @@ class Client(object):
|
||||
if url_data.username is not None \
|
||||
and url_data.scheme in ('http', 'https'):
|
||||
_, netloc = url_data.netloc.split('@', 1)
|
||||
fixed_url = urlunparse((url_data.scheme, netloc, url_data.path,
|
||||
url_data.params, url_data.query, url_data.fragment))
|
||||
fixed_url = urlunparse(
|
||||
(url_data.scheme, netloc, url_data.path,
|
||||
url_data.params, url_data.query, url_data.fragment))
|
||||
passwd_mgr = url_passwd_mgr()
|
||||
passwd_mgr.add_password(None, fixed_url, url_data.username, url_data.password)
|
||||
passwd_mgr.add_password(
|
||||
None, fixed_url, url_data.username, url_data.password)
|
||||
auth_handler = url_auth_handler(passwd_mgr)
|
||||
opener = url_build_opener(auth_handler)
|
||||
url_install_opener(opener)
|
||||
@ -482,7 +484,9 @@ class LocalClient(Client):
|
||||
return ret
|
||||
prefix = prefix.strip('/')
|
||||
for path in self.opts['file_roots'][env]:
|
||||
for root, dirs, files in os.walk(os.path.join(path, prefix), followlinks=True):
|
||||
for root, dirs, files in os.walk(
|
||||
os.path.join(path, prefix), followlinks=True
|
||||
):
|
||||
for fname in files:
|
||||
ret.append(
|
||||
os.path.relpath(
|
||||
@ -502,7 +506,9 @@ class LocalClient(Client):
|
||||
if env not in self.opts['file_roots']:
|
||||
return ret
|
||||
for path in self.opts['file_roots'][env]:
|
||||
for root, dirs, files in os.walk(os.path.join(path, prefix), followlinks=True):
|
||||
for root, dirs, files in os.walk(
|
||||
os.path.join(path, prefix), followlinks=True
|
||||
):
|
||||
if len(dirs) == 0 and len(files) == 0:
|
||||
ret.append(os.path.relpath(root, path))
|
||||
return ret
|
||||
@ -517,7 +523,9 @@ class LocalClient(Client):
|
||||
return ret
|
||||
prefix = prefix.strip('/')
|
||||
for path in self.opts['file_roots'][env]:
|
||||
for root, dirs, files in os.walk(os.path.join(path, prefix), followlinks=True):
|
||||
for root, dirs, files in os.walk(
|
||||
os.path.join(path, prefix), followlinks=True
|
||||
):
|
||||
ret.append(os.path.relpath(root, path))
|
||||
return ret
|
||||
|
||||
@ -605,6 +613,26 @@ class RemoteClient(Client):
|
||||
self.auth = salt.crypt.SAuth(opts)
|
||||
self.sreq = salt.payload.SREQ(self.opts['master_uri'])
|
||||
|
||||
def _crypted_transfer(self, load, tries=3, timeout=60, payload='aes'):
|
||||
'''
|
||||
In case of authentication errors, try to renogiate authentication
|
||||
and retry the method.
|
||||
Indeed, we can fail too early in case of a master restart during a
|
||||
minion state executon call
|
||||
'''
|
||||
def _do_transfer():
|
||||
return self.auth.crypticle.loads(
|
||||
self.sreq.send(payload,
|
||||
self.auth.crypticle.dumps(load),
|
||||
tries,
|
||||
timeout)
|
||||
)
|
||||
try:
|
||||
return _do_transfer()
|
||||
except salt.crypt.AuthenticationError:
|
||||
self.auth = salt.crypt.SAuth(self.opts)
|
||||
return _do_transfer()
|
||||
|
||||
def get_file(self, path, dest='', makedirs=False, env='base', gzip=None):
|
||||
'''
|
||||
Get a single file from the salt-master
|
||||
@ -612,7 +640,8 @@ class RemoteClient(Client):
|
||||
dest is omitted, then the downloaded file will be placed in the minion
|
||||
cache
|
||||
'''
|
||||
#-- Hash compare local copy with master and skip download if no diference found.
|
||||
#-- Hash compare local copy with master and skip download
|
||||
# if no diference found.
|
||||
dest2check = dest
|
||||
if not dest2check:
|
||||
rel_path = self._check_proto(path)
|
||||
@ -623,7 +652,9 @@ class RemoteClient(Client):
|
||||
hash_local = self.hash_file(dest2check, env)
|
||||
hash_server = self.hash_file(path, env)
|
||||
if hash_local == hash_server:
|
||||
log.info('Fetching file ** skipped **, latest already in cache \'{0}\''.format(path))
|
||||
log.info(
|
||||
'Fetching file ** skipped **, '
|
||||
'latest already in cache \'{0}\''.format(path))
|
||||
return dest2check
|
||||
|
||||
log.debug('Fetching file ** attempting ** \'{0}\''.format(path))
|
||||
@ -651,12 +682,7 @@ class RemoteClient(Client):
|
||||
else:
|
||||
load['loc'] = fn_.tell()
|
||||
try:
|
||||
data = self.auth.crypticle.loads(
|
||||
self.sreq.send('aes',
|
||||
self.auth.crypticle.dumps(load),
|
||||
3,
|
||||
60)
|
||||
)
|
||||
data = self._crypted_transfer(load)
|
||||
except SaltReqTimeoutError:
|
||||
return ''
|
||||
|
||||
@ -707,12 +733,7 @@ class RemoteClient(Client):
|
||||
'prefix': prefix,
|
||||
'cmd': '_file_list'}
|
||||
try:
|
||||
return self.auth.crypticle.loads(
|
||||
self.sreq.send('aes',
|
||||
self.auth.crypticle.dumps(load),
|
||||
3,
|
||||
60)
|
||||
)
|
||||
return self._crypted_transfer(load)
|
||||
except SaltReqTimeoutError:
|
||||
return ''
|
||||
|
||||
@ -724,12 +745,7 @@ class RemoteClient(Client):
|
||||
'prefix': prefix,
|
||||
'cmd': '_file_list_emptydirs'}
|
||||
try:
|
||||
return self.auth.crypticle.loads(
|
||||
self.sreq.send('aes',
|
||||
self.auth.crypticle.dumps(load),
|
||||
3,
|
||||
60)
|
||||
)
|
||||
self._crypted_transfer(load)
|
||||
except SaltReqTimeoutError:
|
||||
return ''
|
||||
|
||||
@ -741,12 +757,7 @@ class RemoteClient(Client):
|
||||
'prefix': prefix,
|
||||
'cmd': '_dir_list'}
|
||||
try:
|
||||
return self.auth.crypticle.loads(
|
||||
self.sreq.send('aes',
|
||||
self.auth.crypticle.dumps(load),
|
||||
3,
|
||||
60)
|
||||
)
|
||||
return self._crypted_transfer(load)
|
||||
except SaltReqTimeoutError:
|
||||
return ''
|
||||
|
||||
@ -758,12 +769,7 @@ class RemoteClient(Client):
|
||||
'prefix': prefix,
|
||||
'cmd': '_symlink_list'}
|
||||
try:
|
||||
return self.auth.crypticle.loads(
|
||||
self.sreq.send('aes',
|
||||
self.auth.crypticle.dumps(load),
|
||||
3,
|
||||
60)
|
||||
)
|
||||
return self._crypted_transfer(load)
|
||||
except SaltReqTimeoutError:
|
||||
return ''
|
||||
|
||||
@ -782,19 +788,15 @@ class RemoteClient(Client):
|
||||
return {}
|
||||
else:
|
||||
ret = {}
|
||||
ret['hsum'] = salt.utils.get_hash(path, form='md5', chunk_size=4096)
|
||||
ret['hsum'] = salt.utils.get_hash(
|
||||
path, form='md5', chunk_size=4096)
|
||||
ret['hash_type'] = 'md5'
|
||||
return ret
|
||||
load = {'path': path,
|
||||
'env': env,
|
||||
'cmd': '_file_hash'}
|
||||
try:
|
||||
return self.auth.crypticle.loads(
|
||||
self.sreq.send('aes',
|
||||
self.auth.crypticle.dumps(load),
|
||||
3,
|
||||
60)
|
||||
)
|
||||
return self._crypted_transfer(load)
|
||||
except SaltReqTimeoutError:
|
||||
return ''
|
||||
|
||||
@ -805,12 +807,7 @@ class RemoteClient(Client):
|
||||
load = {'env': env,
|
||||
'cmd': '_file_list'}
|
||||
try:
|
||||
return self.auth.crypticle.loads(
|
||||
self.sreq.send('aes',
|
||||
self.auth.crypticle.dumps(load),
|
||||
3,
|
||||
60)
|
||||
)
|
||||
return self._crypted_transfer(load)
|
||||
except SaltReqTimeoutError:
|
||||
return ''
|
||||
|
||||
@ -820,12 +817,7 @@ class RemoteClient(Client):
|
||||
'''
|
||||
load = {'cmd': '_master_opts'}
|
||||
try:
|
||||
return self.auth.crypticle.loads(
|
||||
self.sreq.send('aes',
|
||||
self.auth.crypticle.dumps(load),
|
||||
3,
|
||||
60)
|
||||
)
|
||||
return self._crypted_transfer(load)
|
||||
except SaltReqTimeoutError:
|
||||
return ''
|
||||
|
||||
@ -839,11 +831,6 @@ class RemoteClient(Client):
|
||||
'opts': self.opts,
|
||||
'tok': self.auth.gen_token('salt')}
|
||||
try:
|
||||
return self.auth.crypticle.loads(
|
||||
self.sreq.send('aes',
|
||||
self.auth.crypticle.dumps(load),
|
||||
3,
|
||||
60)
|
||||
)
|
||||
return self._crypted_transfer(load)
|
||||
except SaltReqTimeoutError:
|
||||
return ''
|
||||
|
@ -143,6 +143,13 @@ def _linux_gpu_data():
|
||||
)
|
||||
return {}
|
||||
|
||||
elif not __opts__.get('enable_gpu_grains', None):
|
||||
log.info(
|
||||
'Skipping lspci call because enable_gpu_grains was set to False in the config. '
|
||||
'GPU grains will not be available.'
|
||||
)
|
||||
return {}
|
||||
|
||||
# dominant gpu vendors to search for (MUST be lowercase for matching below)
|
||||
known_vendors = ['nvidia', 'amd', 'ati', 'intel']
|
||||
|
||||
|
@ -501,6 +501,7 @@ class Minion(object):
|
||||
self.opts,
|
||||
self.functions,
|
||||
self.returners)
|
||||
self.grains_cache = self.opts['grains']
|
||||
|
||||
def __prep_mod_opts(self):
|
||||
'''
|
||||
@ -911,6 +912,24 @@ class Minion(object):
|
||||
data['arg'] = []
|
||||
self._handle_decoded_payload(data)
|
||||
|
||||
def _refresh_grains_watcher(self, refresh_interval_in_minutes):
|
||||
'''
|
||||
Create a loop that will fire a pillar refresh to inform a master about a change in the grains of this minion
|
||||
:param refresh_interval_in_minutes:
|
||||
:return: None
|
||||
'''
|
||||
if '__update_grains' not in self.opts.get('schedule', {}):
|
||||
if not 'schedule' in self.opts:
|
||||
self.opts['schedule'] = {}
|
||||
self.opts['schedule'].update({
|
||||
'__update_grains':
|
||||
{
|
||||
'function': 'event.fire',
|
||||
'args': [{}, "grains_refresh"],
|
||||
'minutes': refresh_interval_in_minutes
|
||||
}
|
||||
})
|
||||
|
||||
@property
|
||||
def master_pub(self):
|
||||
'''
|
||||
@ -982,6 +1001,7 @@ class Minion(object):
|
||||
def tune_in(self):
|
||||
'''
|
||||
Lock onto the publisher. This is the main event loop for the minion
|
||||
:rtype : None
|
||||
'''
|
||||
try:
|
||||
log.info(
|
||||
@ -1134,6 +1154,29 @@ class Minion(object):
|
||||
time.sleep(.5)
|
||||
|
||||
loop_interval = int(self.opts['loop_interval'])
|
||||
|
||||
try:
|
||||
if self.opts['grains_refresh_every']: # If exists and is not zero. In minutes, not seconds!
|
||||
if self.opts['grains_refresh_every'] > 1:
|
||||
log.debug(
|
||||
'Enabling the grains refresher. Will run every {0} minutes.'.format(
|
||||
self.opts['grains_refresh_every'])
|
||||
)
|
||||
else: # Clean up minute vs. minutes in log message
|
||||
log.debug(
|
||||
'Enabling the grains refresher. Will run every {0} minute.'.format(
|
||||
self.opts['grains_refresh_every'])
|
||||
|
||||
)
|
||||
self._refresh_grains_watcher(
|
||||
abs(self.opts['grains_refresh_every'])
|
||||
)
|
||||
except Exception as exc:
|
||||
log.error(
|
||||
'Exception occurred in attempt to initialize grain refresh routine during minion tune-in: {0}'.format(
|
||||
exc)
|
||||
)
|
||||
|
||||
while True:
|
||||
try:
|
||||
self.schedule.eval()
|
||||
@ -1164,6 +1207,10 @@ class Minion(object):
|
||||
self.module_refresh()
|
||||
elif package.startswith('pillar_refresh'):
|
||||
self.pillar_refresh()
|
||||
elif package.startswith('grains_refresh'):
|
||||
if self.grains_cache != self.opts['grains']:
|
||||
self.pillar_refresh()
|
||||
self.grains_cache = self.opts['grains']
|
||||
self.epub_sock.send(package)
|
||||
except Exception:
|
||||
pass
|
||||
|
@ -384,11 +384,10 @@ def install(name=None,
|
||||
if pkg_params is None or len(pkg_params) == 0:
|
||||
return {}
|
||||
elif pkg_type == 'file':
|
||||
cmd = 'dpkg -i {confold} {verify} {pkg}'.format(
|
||||
confold='--force-confold',
|
||||
verify='--force-bad-verify' if skip_verify else '',
|
||||
pkg=' '.join(pkg_params),
|
||||
)
|
||||
cmd = ['dpkg', '-i', '--force-confold']
|
||||
if skip_verify:
|
||||
cmd.append('--force-bad-verify')
|
||||
cmd.extend(pkg_params)
|
||||
elif pkg_type == 'repository':
|
||||
if pkgs is None and kwargs.get('version') and len(pkg_params) == 1:
|
||||
# Only use the 'version' param if 'name' was not specified as a
|
||||
|
@ -240,7 +240,7 @@ def cache_file(path, env='base'):
|
||||
_mk_client()
|
||||
if path.startswith('salt://|'):
|
||||
# Strip pipe. Windows doesn't allow pipes in filenames
|
||||
path = 'salt://{0}'.format(path.lstrip('salt://|'))
|
||||
path = 'salt://{0}'.format(path[8:])
|
||||
result = __context__['cp.fileclient'].cache_file(path, env)
|
||||
if not result:
|
||||
log.error(
|
||||
|
@ -1,8 +1,9 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Management of dockers: overview of this module
|
||||
==============================================
|
||||
Management of dockers
|
||||
=====================
|
||||
|
||||
.. versionadded:: Hydrogen
|
||||
|
||||
.. note::
|
||||
|
||||
|
@ -404,6 +404,12 @@ def list_all():
|
||||
'''
|
||||
Lists all ports available.
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' ports.list_all
|
||||
|
||||
.. warning::
|
||||
|
||||
Takes a while to run, and returns a **LOT** of output
|
||||
|
@ -3,6 +3,10 @@
|
||||
Module to provide MySQL compatibility to salt.
|
||||
|
||||
:depends: - MySQLdb Python module
|
||||
.. note::
|
||||
|
||||
On CentOS 5 (and possibly RHEL 5) both MySQL-python and python26-mysqldb need to be installed.
|
||||
|
||||
:configuration: In order to connect to MySQL, certain configuration is required
|
||||
in /etc/salt/minion on the relevant minions. Some sample configs might look
|
||||
like::
|
||||
@ -34,6 +38,9 @@ import sys
|
||||
# Import salt libs
|
||||
import salt.utils
|
||||
|
||||
#import shlex which should be distributed with Python
|
||||
import shlex
|
||||
|
||||
# Import third party libs
|
||||
try:
|
||||
import MySQLdb
|
||||
@ -148,6 +155,69 @@ def _connect(**kwargs):
|
||||
return dbc
|
||||
|
||||
|
||||
def _grant_to_tokens(grant):
|
||||
'''
|
||||
|
||||
This should correspond fairly closely to the YAML rendering of a mysql_grants state which comes out
|
||||
as follows:
|
||||
|
||||
OrderedDict([('whatever_identifier', OrderedDict([('mysql_grants.present',
|
||||
[OrderedDict([('database', 'testdb.*')]), OrderedDict([('user', 'testuser')]),
|
||||
OrderedDict([('grant', 'ALTER, SELECT, LOCK TABLES')]), OrderedDict([('host', 'localhost')])])]))])
|
||||
|
||||
:param grant: An un-parsed MySQL GRANT statement str, like
|
||||
"GRANT SELECT, ALTER, LOCK TABLES ON `testdb`.* TO 'testuser'@'localhost'"
|
||||
:return:
|
||||
A Python dict with the following keys/values:
|
||||
- user: MySQL User
|
||||
- host: MySQL host
|
||||
- grant: [grant1, grant2] (ala SELECT, USAGE, etc)
|
||||
- database: MySQL DB
|
||||
'''
|
||||
exploded_grant = shlex.split(grant)
|
||||
grant_tokens = []
|
||||
multiword_statement = []
|
||||
position_tracker = 1 # Skip the initial 'GRANT' word token
|
||||
phrase = 'grants'
|
||||
|
||||
for token in exploded_grant[position_tracker:]:
|
||||
|
||||
if token == 'ON':
|
||||
phrase = 'db'
|
||||
continue
|
||||
|
||||
elif token == 'TO':
|
||||
phrase = 'user'
|
||||
continue
|
||||
|
||||
if phrase == 'grants':
|
||||
if token.endswith(',') or exploded_grant[position_tracker+1] == 'ON': # Read-ahead
|
||||
cleaned_token = token.rstrip(',')
|
||||
if multiword_statement:
|
||||
multiword_statement.append(cleaned_token)
|
||||
grant_tokens.append(' '.join(multiword_statement))
|
||||
multiword_statement = []
|
||||
else:
|
||||
grant_tokens.append(cleaned_token)
|
||||
|
||||
elif token[-1:] != ',': # This is a multi-word, ala LOCK TABLES
|
||||
multiword_statement.append(token)
|
||||
|
||||
elif phrase == 'db':
|
||||
database = token.strip('`')
|
||||
phrase = 'tables'
|
||||
|
||||
elif phrase == 'user':
|
||||
user, host = token.split('@')
|
||||
|
||||
position_tracker += 1
|
||||
|
||||
return dict(user=user,
|
||||
host=host,
|
||||
grant=grant_tokens,
|
||||
database=database)
|
||||
|
||||
|
||||
def query(database, query, **connection_args):
|
||||
'''
|
||||
Run an arbitrary SQL query and return the results or
|
||||
@ -898,6 +968,15 @@ def user_remove(user,
|
||||
return False
|
||||
|
||||
|
||||
def tokenize_grant(grant):
|
||||
'''
|
||||
External wrapper function
|
||||
:param grant:
|
||||
:return: dict
|
||||
'''
|
||||
return _grant_to_tokens(grant)
|
||||
|
||||
|
||||
# Maintenance
|
||||
def db_check(name,
|
||||
table=None,
|
||||
@ -1072,17 +1151,30 @@ def grant_exists(grant,
|
||||
|
||||
salt '*' mysql.grant_exists 'SELECT,INSERT,UPDATE,...' 'database.*' 'frank' 'localhost'
|
||||
'''
|
||||
# TODO: This function is a bit tricky, since it requires the ordering to
|
||||
# be exactly the same. Perhaps should be replaced/reworked with a
|
||||
# better/cleaner solution.
|
||||
target = __grant_generate(
|
||||
grant, database, user, host, grant_option, escape
|
||||
)
|
||||
|
||||
grants = user_grants(user, host, **connection_args)
|
||||
if grants is not False and target in grants:
|
||||
log.debug('Grant exists.')
|
||||
return True
|
||||
|
||||
for grant in grants:
|
||||
try:
|
||||
target_tokens = None
|
||||
if not target_tokens: # Avoid the overhead of re-calc in loop
|
||||
target_tokens = _grant_to_tokens(target)
|
||||
grant_tokens = _grant_to_tokens(grant)
|
||||
if grant_tokens['user'] == target_tokens['user'] and \
|
||||
grant_tokens['database'] == target_tokens['database'] and \
|
||||
grant_tokens['host'] == target_tokens['host'] and \
|
||||
set(grant_tokens['grant']) == set(target_tokens['grant']):
|
||||
log.debug(grant_tokens)
|
||||
log.debug(target_tokens)
|
||||
return True
|
||||
|
||||
except Exception as exc: # Fallback to strict parsing
|
||||
if grants is not False and target in grants:
|
||||
log.debug('Grant exists.')
|
||||
return True
|
||||
|
||||
log.debug('Grant does not exist, or is perhaps not ordered properly?')
|
||||
return False
|
||||
|
@ -11,6 +11,7 @@ import shutil
|
||||
import time
|
||||
import logging
|
||||
import tarfile
|
||||
import datetime
|
||||
import tempfile
|
||||
|
||||
# Import salt libs
|
||||
@ -66,6 +67,8 @@ def _wait(jid):
|
||||
'''
|
||||
Wait for all previously started state jobs to finish running
|
||||
'''
|
||||
if jid is None:
|
||||
jid = '{0:%Y%m%d%H%M%S%f}'.format(datetime.datetime.now())
|
||||
states = _prior_running_states(jid)
|
||||
while states:
|
||||
time.sleep(1)
|
||||
@ -126,7 +129,7 @@ def low(data, queue=False, **kwargs):
|
||||
salt '*' state.low '{"state": "pkg", "fun": "installed", "name": "vi"}'
|
||||
'''
|
||||
if queue:
|
||||
_wait(kwargs['__pub_jid'])
|
||||
_wait(kwargs.get('__pub_jid'))
|
||||
else:
|
||||
conflict = running()
|
||||
if conflict:
|
||||
@ -157,7 +160,7 @@ def high(data, queue=False, **kwargs):
|
||||
salt '*' state.high '{"vim": {"pkg": ["installed"]}}'
|
||||
'''
|
||||
if queue:
|
||||
_wait(kwargs['__pub_jid'])
|
||||
_wait(kwargs.get('__pub_jid'))
|
||||
else:
|
||||
conflict = running()
|
||||
if conflict:
|
||||
@ -180,7 +183,7 @@ def template(tem, queue=False, **kwargs):
|
||||
salt '*' state.template '<Path to template on the minion>'
|
||||
'''
|
||||
if queue:
|
||||
_wait(kwargs['__pub_jid'])
|
||||
_wait(kwargs.get('__pub_jid'))
|
||||
else:
|
||||
conflict = running()
|
||||
if conflict:
|
||||
@ -203,7 +206,7 @@ def template_str(tem, queue=False, **kwargs):
|
||||
salt '*' state.template_str '<Template String>'
|
||||
'''
|
||||
if queue:
|
||||
_wait(kwargs['__pub_jid'])
|
||||
_wait(kwargs.get('__pub_jid'))
|
||||
else:
|
||||
conflict = running()
|
||||
if conflict:
|
||||
@ -229,7 +232,7 @@ def highstate(test=None, queue=False, **kwargs):
|
||||
salt '*' state.highstate exclude="[{'id': 'id_to_exclude'}, {'sls': 'sls_to_exclude'}]"
|
||||
'''
|
||||
if queue:
|
||||
_wait(kwargs['__pub_jid'])
|
||||
_wait(kwargs.get('__pub_jid'))
|
||||
else:
|
||||
conflict = running()
|
||||
if conflict:
|
||||
@ -296,7 +299,7 @@ def sls(mods, env='base', test=None, exclude=None, queue=False, **kwargs):
|
||||
'''
|
||||
|
||||
if queue:
|
||||
_wait(kwargs['__pub_jid'])
|
||||
_wait(kwargs.get('__pub_jid'))
|
||||
else:
|
||||
conflict = running()
|
||||
if conflict:
|
||||
@ -388,7 +391,7 @@ def top(topfn, test=None, queue=False, **kwargs):
|
||||
salt '*' state.top reverse_top.sls exclude="[{'id': 'id_to_exclude'}, {'sls': 'sls_to_exclude'}]"
|
||||
'''
|
||||
if queue:
|
||||
_wait(kwargs['__pub_jid'])
|
||||
_wait(kwargs.get('__pub_jid'))
|
||||
else:
|
||||
conflict = running()
|
||||
if conflict:
|
||||
@ -429,7 +432,7 @@ def show_highstate(queue=False, **kwargs):
|
||||
salt '*' state.show_highstate
|
||||
'''
|
||||
if queue:
|
||||
_wait(kwargs['__pub_jid'])
|
||||
_wait(kwargs.get('__pub_jid'))
|
||||
else:
|
||||
conflict = running()
|
||||
if conflict:
|
||||
@ -457,7 +460,7 @@ def show_lowstate(queue=False, **kwargs):
|
||||
salt '*' state.show_lowstate
|
||||
'''
|
||||
if queue:
|
||||
_wait(kwargs['__pub_jid'])
|
||||
_wait(kwargs.get('__pub_jid'))
|
||||
else:
|
||||
conflict = running()
|
||||
if conflict:
|
||||
@ -483,7 +486,7 @@ def show_low_sls(mods, env='base', test=None, queue=False, **kwargs):
|
||||
salt '*' state.show_low_sls foo
|
||||
'''
|
||||
if queue:
|
||||
_wait(kwargs['__pub_jid'])
|
||||
_wait(kwargs.get('__pub_jid'))
|
||||
else:
|
||||
conflict = running()
|
||||
if conflict:
|
||||
@ -521,7 +524,7 @@ def show_sls(mods, env='base', test=None, queue=False, **kwargs):
|
||||
salt '*' state.show_sls core,edit.vim dev
|
||||
'''
|
||||
if queue:
|
||||
_wait(kwargs['__pub_jid'])
|
||||
_wait(kwargs.get('__pub_jid'))
|
||||
else:
|
||||
conflict = running()
|
||||
if conflict:
|
||||
@ -558,7 +561,7 @@ def show_top(queue=False, **kwargs):
|
||||
salt '*' state.show_top
|
||||
'''
|
||||
if queue:
|
||||
_wait(kwargs['__pub_jid'])
|
||||
_wait(kwargs.get('__pub_jid'))
|
||||
else:
|
||||
conflict = running()
|
||||
if conflict:
|
||||
@ -593,7 +596,7 @@ def single(fun, name, test=None, queue=False, **kwargs):
|
||||
|
||||
'''
|
||||
if queue:
|
||||
_wait(kwargs['__pub_jid'])
|
||||
_wait(kwargs.get('__pub_jid'))
|
||||
else:
|
||||
conflict = running()
|
||||
if conflict:
|
||||
|
@ -39,7 +39,8 @@ def display_output(data, out, opts=None):
|
||||
ofh.write(display_data)
|
||||
ofh.write('\n')
|
||||
return
|
||||
print(display_data)
|
||||
if display_data:
|
||||
print(display_data)
|
||||
except IOError as exc:
|
||||
# Only raise if it's NOT a broken pipe
|
||||
if exc.errno != errno.EPIPE:
|
||||
|
@ -130,7 +130,7 @@ def ext_pillar(pillar,
|
||||
log.error('Virtualenv {} not a directory!'.format(path))
|
||||
return {}
|
||||
# load the virtualenv
|
||||
sys.path.append(virtualenv.path_locations(env)[1] + '/site-packages/')
|
||||
sys.path[0:0] = (virtualenv.path_locations(env)[1] + '/site-packages/',)
|
||||
|
||||
# load the django project
|
||||
sys.path.append(project_path)
|
||||
|
@ -2214,7 +2214,7 @@ class BaseHighState(object):
|
||||
statefiles = fnmatch.filter(self.avail[env], sls_match)
|
||||
if not statefiles:
|
||||
# No matching sls file was found! Output an error
|
||||
log.error(
|
||||
all_errors.append(
|
||||
'No matching sls found for \'{0}\' in env \'{1}\''
|
||||
.format(sls_match, env)
|
||||
)
|
||||
|
@ -69,6 +69,7 @@ def present(name,
|
||||
host='localhost',
|
||||
grant_option=False,
|
||||
escape=True,
|
||||
revoke_first=False,
|
||||
**connection_args):
|
||||
'''
|
||||
Ensure that the grant is present with the specified properties
|
||||
@ -93,6 +94,22 @@ def present(name,
|
||||
|
||||
escape
|
||||
Defines if the database value gets escaped or not. default: True
|
||||
|
||||
revoke_first
|
||||
By default, MySQL will not do anything if you issue a command to grant
|
||||
privileges that are more restrictive than what's already in place. This
|
||||
effectively means that you cannot downgrade permissions without first
|
||||
revoking permissions applied to a db.table/user pair first.
|
||||
|
||||
To have Salt forcibly revoke perms before applying a new grant, enable
|
||||
the 'revoke_first options.
|
||||
|
||||
WARNING: This will *remove* permissions for a database before attempting to apply
|
||||
new permissions. There is no guarantee that new permissions will be applied correctly
|
||||
which can leave your database security in an unknown and potentially dangerous state.
|
||||
Use with caution!
|
||||
|
||||
default: False
|
||||
'''
|
||||
comment = 'Grant {0} on {1} to {2}@{3} is already present'
|
||||
ret = {'name': name,
|
||||
@ -111,6 +128,19 @@ def present(name,
|
||||
ret['comment'] = err
|
||||
ret['result'] = False
|
||||
return ret
|
||||
if revoke_first:
|
||||
# for each grant, break into tokens and see if its on the same user/db as ours. (there is probably only one)
|
||||
for user_grant in __salt__['mysql.user_grants'](user, host, **connection_args):
|
||||
if __salt__['mysql.tokenize_grant'](user_grant)['database'].replace('`', '')\
|
||||
== database.replace('`', ''):
|
||||
grant_to_revoke = ','.join(__salt__['mysql.tokenize_grant'](user_grant)['grant']).rstrip(',')
|
||||
__salt__['mysql.grant_revoke'](grant_to_revoke,
|
||||
database,
|
||||
user,
|
||||
host=host,
|
||||
grant_option=grant_option,
|
||||
escape=escape,
|
||||
connection_args=connection_args) # Probably needs some ordering love
|
||||
|
||||
# The grant is not present, make it!
|
||||
if __opts__['test']:
|
||||
|
@ -8,7 +8,7 @@ controlled via the ssh_auth state. Defaults can be set by the enc, options,
|
||||
and comment keys. These defaults can be overridden by including them in the
|
||||
name.
|
||||
|
||||
Since the YAML specification limits the length of simple keys to 1024
|
||||
Since the YAML specification limits the length of simple keys to 1024
|
||||
characters, and since SSH keys are often longer than that, you may have
|
||||
to use a YAML 'explicit key', as demonstrated in the second example below.
|
||||
|
||||
|
@ -220,7 +220,7 @@ def daemonize(redirect_out=True):
|
||||
# not cleanly redirected and the parent process dies when the
|
||||
# multiprocessing process attempts to access stdout or err.
|
||||
if redirect_out:
|
||||
dev_null = open('/dev/null', 'rw')
|
||||
dev_null = open('/dev/null', 'w')
|
||||
os.dup2(dev_null.fileno(), sys.stdin.fileno())
|
||||
os.dup2(dev_null.fileno(), sys.stdout.fileno())
|
||||
os.dup2(dev_null.fileno(), sys.stderr.fileno())
|
||||
|
@ -1038,10 +1038,10 @@ class SaltCMDOptionParser(OptionParser, ConfigDirMixIn, MergeConfigMixIn,
|
||||
'minions to have running')
|
||||
)
|
||||
self.add_option(
|
||||
'-a', '--auth', '--eauth', '--extended-auth',
|
||||
'-a', '--auth', '--eauth', '--external-auth',
|
||||
default='',
|
||||
dest='eauth',
|
||||
help=('Specify an extended authentication system to use.')
|
||||
help=('Specify an external authentication system to use.')
|
||||
)
|
||||
self.add_option(
|
||||
'-T', '--make-token',
|
||||
@ -1080,10 +1080,16 @@ class SaltCMDOptionParser(OptionParser, ConfigDirMixIn, MergeConfigMixIn,
|
||||
)
|
||||
|
||||
def _mixin_after_parsed(self):
|
||||
# Catch invalid invocations of salt such as: salt run
|
||||
if len(self.args) <= 1 and not self.options.doc:
|
||||
self.print_help()
|
||||
self.exit(1)
|
||||
try:
|
||||
self.print_help()
|
||||
except Exception:
|
||||
# We get an argument that Python's optparser just can't deal
|
||||
# with. Perhaps stdout was redirected, or a file glob was
|
||||
# passed in. Regardless, we're in an unknown state here.
|
||||
sys.stdout.write('Invalid options passed. Please try -h for '
|
||||
'help.') # Try to warn if we can.
|
||||
sys.exit(1)
|
||||
|
||||
if self.options.doc:
|
||||
# Include the target
|
||||
@ -1102,41 +1108,44 @@ class SaltCMDOptionParser(OptionParser, ConfigDirMixIn, MergeConfigMixIn,
|
||||
else:
|
||||
self.config['tgt'] = self.args[0].split()
|
||||
else:
|
||||
self.config['tgt'] = self.args[0]
|
||||
|
||||
try:
|
||||
self.config['tgt'] = self.args[0]
|
||||
except IndexError:
|
||||
self.exit(42, '\nCannot execute command without defining a target.\n\n')
|
||||
# Detect compound command and set up the data for it
|
||||
if ',' in self.args[1]:
|
||||
self.config['fun'] = self.args[1].split(',')
|
||||
self.config['arg'] = [[]]
|
||||
cmd_index = 0
|
||||
if (self.args[2:].count(self.options.args_separator) ==
|
||||
len(self.config['fun']) - 1):
|
||||
# new style parsing: standalone argument separator
|
||||
for arg in self.args[2:]:
|
||||
if arg == self.options.args_separator:
|
||||
cmd_index += 1
|
||||
self.config['arg'].append([])
|
||||
else:
|
||||
self.config['arg'][cmd_index].append(arg)
|
||||
if self.args:
|
||||
if ',' in self.args[1]:
|
||||
self.config['fun'] = self.args[1].split(',')
|
||||
self.config['arg'] = [[]]
|
||||
cmd_index = 0
|
||||
if (self.args[2:].count(self.options.args_separator) ==
|
||||
len(self.config['fun']) - 1):
|
||||
# new style parsing: standalone argument separator
|
||||
for arg in self.args[2:]:
|
||||
if arg == self.options.args_separator:
|
||||
cmd_index += 1
|
||||
self.config['arg'].append([])
|
||||
else:
|
||||
self.config['arg'][cmd_index].append(arg)
|
||||
else:
|
||||
# old style parsing: argument separator can be inside args
|
||||
for arg in self.args[2:]:
|
||||
if self.options.args_separator in arg:
|
||||
sub_args = arg.split(self.options.args_separator)
|
||||
for sub_arg_index, sub_arg in enumerate(sub_args):
|
||||
if sub_arg:
|
||||
self.config['arg'][cmd_index].append(sub_arg)
|
||||
if sub_arg_index != len(sub_args) - 1:
|
||||
cmd_index += 1
|
||||
self.config['arg'].append([])
|
||||
else:
|
||||
self.config['arg'][cmd_index].append(arg)
|
||||
if len(self.config['fun']) != len(self.config['arg']):
|
||||
self.exit(42, 'Cannot execute compound command without '
|
||||
'defining all arguments.')
|
||||
else:
|
||||
# old style parsing: argument separator can be inside args
|
||||
for arg in self.args[2:]:
|
||||
if self.options.args_separator in arg:
|
||||
sub_args = arg.split(self.options.args_separator)
|
||||
for sub_arg_index, sub_arg in enumerate(sub_args):
|
||||
if sub_arg:
|
||||
self.config['arg'][cmd_index].append(sub_arg)
|
||||
if sub_arg_index != len(sub_args) - 1:
|
||||
cmd_index += 1
|
||||
self.config['arg'].append([])
|
||||
else:
|
||||
self.config['arg'][cmd_index].append(arg)
|
||||
if len(self.config['fun']) != len(self.config['arg']):
|
||||
self.exit(42, 'Cannot execute compound command without '
|
||||
'defining all arguments.')
|
||||
else:
|
||||
self.config['fun'] = self.args[1]
|
||||
self.config['arg'] = self.args[2:]
|
||||
self.config['fun'] = self.args[1]
|
||||
self.config['arg'] = self.args[2:]
|
||||
|
||||
def setup_config(self):
|
||||
return config.client_config(self.get_config_file_path())
|
||||
|
@ -12,21 +12,28 @@ from salttesting.helpers import (
|
||||
)
|
||||
ensure_in_syspath('../../')
|
||||
|
||||
# Import python libs
|
||||
import os
|
||||
import time
|
||||
|
||||
# Import salt libs
|
||||
import integration
|
||||
import salt.utils
|
||||
|
||||
_PKG_TARGETS = {
|
||||
'Arch': ['bzr', 'finch'],
|
||||
'Arch': ['python2-django', 'finch'],
|
||||
'Debian': ['python-plist', 'finch'],
|
||||
'RedHat': ['bzr', 'finch'],
|
||||
'RedHat': ['xz-devel', 'zsh-html'],
|
||||
'FreeBSD': ['aalib', 'pth'],
|
||||
'Suse': ['aalib', 'finch']
|
||||
}
|
||||
|
||||
_PKG_TARGETS_32 = {
|
||||
'CentOS': 'xz-devel.i686'
|
||||
}
|
||||
|
||||
@requires_salt_modules('pkg.latest_version')
|
||||
@requires_salt_modules('pkg.version')
|
||||
|
||||
@requires_salt_modules('pkg.version', 'pkg.latest_version')
|
||||
class PkgTest(integration.ModuleCase,
|
||||
integration.SaltReturnAssertsMixIn):
|
||||
'''
|
||||
@ -35,7 +42,7 @@ class PkgTest(integration.ModuleCase,
|
||||
@destructiveTest
|
||||
@skipIf(salt.utils.is_windows(), 'minion is windows')
|
||||
@requires_system_grains
|
||||
def test_pkg_installed(self, grains=None):
|
||||
def test_pkg_001_installed(self, grains=None):
|
||||
'''
|
||||
This is a destructive test as it installs and then removes a package
|
||||
'''
|
||||
@ -55,15 +62,57 @@ class PkgTest(integration.ModuleCase,
|
||||
# needs to not be installed before we run the states below
|
||||
self.assertFalse(version)
|
||||
|
||||
ret = self.run_state('pkg.installed', name=pkg_targets[0])
|
||||
ret = self.run_state('pkg.installed', name=target)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
ret = self.run_state('pkg.removed', name=pkg_targets[0])
|
||||
ret = self.run_state('pkg.removed', name=target)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
|
||||
@destructiveTest
|
||||
@skipIf(salt.utils.is_windows(), 'minion is windows')
|
||||
@requires_system_grains
|
||||
def test_pkg_installed_multipkg(self, grains=None):
|
||||
def test_pkg_002_installed_with_version(self, grains=None):
|
||||
'''
|
||||
This is a destructive test as it installs and then removes a package
|
||||
'''
|
||||
os_family = grains.get('os_family', '')
|
||||
pkg_targets = _PKG_TARGETS.get(os_family, [])
|
||||
|
||||
# Don't perform this test on FreeBSD since version specification is not
|
||||
# supported.
|
||||
if os_family == 'FreeBSD':
|
||||
return
|
||||
|
||||
# Make sure that we have targets that match the os_family. If this
|
||||
# fails then the _PKG_TARGETS dict above needs to have an entry added,
|
||||
# with two packages that are not installed before these tests are run
|
||||
self.assertTrue(pkg_targets)
|
||||
|
||||
if os_family == 'Arch':
|
||||
for idx in xrange(13):
|
||||
if idx == 12:
|
||||
raise Exception('Package database locked after 60 seconds, '
|
||||
'bailing out')
|
||||
if not os.path.isfile('/var/lib/pacman/db.lck'):
|
||||
break
|
||||
time.sleep(5)
|
||||
|
||||
target = pkg_targets[0]
|
||||
version = self.run_function('pkg.latest_version', [target])
|
||||
|
||||
# If this assert fails, we need to find new targets, this test needs to
|
||||
# be able to test successful installation of packages, so this package
|
||||
# needs to not be installed before we run the states below
|
||||
self.assertTrue(version)
|
||||
|
||||
ret = self.run_state('pkg.installed', name=target, version=version)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
ret = self.run_state('pkg.removed', name=target)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
|
||||
@destructiveTest
|
||||
@skipIf(salt.utils.is_windows(), 'minion is windows')
|
||||
@requires_system_grains
|
||||
def test_pkg_003_installed_multipkg(self, grains=None):
|
||||
'''
|
||||
This is a destructive test as it installs and then removes two packages
|
||||
'''
|
||||
@ -87,6 +136,116 @@ class PkgTest(integration.ModuleCase,
|
||||
ret = self.run_state('pkg.removed', name=None, pkgs=pkg_targets)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
|
||||
@destructiveTest
|
||||
@skipIf(salt.utils.is_windows(), 'minion is windows')
|
||||
@requires_system_grains
|
||||
def test_pkg_004_installed_multipkg_with_version(self, grains=None):
|
||||
'''
|
||||
This is a destructive test as it installs and then removes two packages
|
||||
'''
|
||||
os_family = grains.get('os_family', '')
|
||||
pkg_targets = _PKG_TARGETS.get(os_family, [])
|
||||
|
||||
# Don't perform this test on FreeBSD since version specification is not
|
||||
# supported.
|
||||
if os_family == 'FreeBSD':
|
||||
return
|
||||
|
||||
# Make sure that we have targets that match the os_family. If this
|
||||
# fails then the _PKG_TARGETS dict above needs to have an entry added,
|
||||
# with two packages that are not installed before these tests are run
|
||||
self.assertTrue(pkg_targets)
|
||||
|
||||
if os_family == 'Arch':
|
||||
for idx in xrange(13):
|
||||
if idx == 12:
|
||||
raise Exception('Package database locked after 60 seconds, '
|
||||
'bailing out')
|
||||
if not os.path.isfile('/var/lib/pacman/db.lck'):
|
||||
break
|
||||
time.sleep(5)
|
||||
|
||||
version = self.run_function('pkg.latest_version', [pkg_targets[0]])
|
||||
|
||||
# If this assert fails, we need to find new targets, this test needs to
|
||||
# be able to test successful installation of packages, so these
|
||||
# packages need to not be installed before we run the states below
|
||||
self.assertTrue(version)
|
||||
|
||||
pkgs = [{pkg_targets[0]: version}, pkg_targets[1]]
|
||||
|
||||
ret = self.run_state('pkg.installed', name=None, pkgs=pkgs)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
ret = self.run_state('pkg.removed', name=None, pkgs=pkg_targets)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
|
||||
@destructiveTest
|
||||
@skipIf(salt.utils.is_windows(), 'minion is windows')
|
||||
@requires_system_grains
|
||||
def test_pkg_005_installed_32bit(self, grains=None):
|
||||
'''
|
||||
This is a destructive test as it installs and then removes a package
|
||||
'''
|
||||
os_name = grains.get('os', '')
|
||||
target = _PKG_TARGETS_32.get(os_name, '')
|
||||
|
||||
# _PKG_TARGETS_32 is only populated for platforms for which Salt has to
|
||||
# munge package names for 32-bit-on-x86_64 (Currently only Ubuntu and
|
||||
# RHEL-based). Don't actually perform this test on other platforms.
|
||||
if target:
|
||||
# CentOS 5 has .i386 arch designation for 32-bit pkgs
|
||||
if os_name == 'CentOS' \
|
||||
and grains['osrelease'].startswith('5.'):
|
||||
target = target.replace('.i686', '.i386')
|
||||
|
||||
version = self.run_function('pkg.version', [target])
|
||||
|
||||
# If this assert fails, we need to find a new target. This test
|
||||
# needs to be able to test successful installation of packages, so
|
||||
# the target needs to not be installed before we run the states
|
||||
# below
|
||||
self.assertFalse(version)
|
||||
|
||||
ret = self.run_state('pkg.installed', name=target)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
ret = self.run_state('pkg.removed', name=target)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
|
||||
@destructiveTest
|
||||
@skipIf(salt.utils.is_windows(), 'minion is windows')
|
||||
@requires_system_grains
|
||||
def test_pkg_006_installed_32bit_with_version(self, grains=None):
|
||||
'''
|
||||
This is a destructive test as it installs and then removes a package
|
||||
'''
|
||||
os_name = grains.get('os', '')
|
||||
target = _PKG_TARGETS_32.get(os_name, '')
|
||||
|
||||
# _PKG_TARGETS_32 is only populated for platforms for which Salt has to
|
||||
# munge package names for 32-bit-on-x86_64 (Currently only Ubuntu and
|
||||
# RHEL-based). Don't actually perform this test on other platforms.
|
||||
if target:
|
||||
if grains.get('os_family', '') == 'Arch':
|
||||
self._wait_for_pkgdb_unlock()
|
||||
|
||||
# CentOS 5 has .i386 arch designation for 32-bit pkgs
|
||||
if os_name == 'CentOS' \
|
||||
and grains['osrelease'].startswith('5.'):
|
||||
target = target.replace('.i686', '.i386')
|
||||
|
||||
version = self.run_function('pkg.latest_version', [target])
|
||||
|
||||
# If this assert fails, we need to find a new target. This test
|
||||
# needs to be able to test successful installation of the package, so
|
||||
# the target needs to not be installed before we run the states
|
||||
# below
|
||||
self.assertTrue(version)
|
||||
|
||||
ret = self.run_state('pkg.installed', name=target, version=version)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
ret = self.run_state('pkg.removed', name=target)
|
||||
self.assertSaltTrueReturn(ret)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from integration import run_tests
|
||||
|
Loading…
Reference in New Issue
Block a user