mirror of
https://github.com/valitydev/salt.git
synced 2024-11-08 01:18:58 +00:00
Merge remote-tracking branch 'upstream/develop' into unify-api
This commit is contained in:
commit
a841b5f452
@ -167,16 +167,20 @@
|
||||
# - cmd
|
||||
|
||||
# The external auth system uses the Salt auth modules to authenticate and
|
||||
# validate users to access areas of the Salt system
|
||||
# validate users to access areas of the Salt system.
|
||||
#
|
||||
# external_auth:
|
||||
# pam:
|
||||
# fred:
|
||||
# - test.*
|
||||
#
|
||||
|
||||
# Time (in seconds) for a newly generated token to live. Default: 12 hours
|
||||
# token_expire: 43200
|
||||
|
||||
# Allow minions to push files to the master. This is disabled by default, for
|
||||
# security purposes.
|
||||
# file_recv: False
|
||||
|
||||
##### Master Module Management #####
|
||||
##########################################
|
||||
|
@ -11941,7 +11941,7 @@ salt \(aq*\(aq cp.is_cached salt://path/to/file
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B salt.modules.cp.list_master(env=\(aqbase\(aq)
|
||||
.B salt.modules.cp.list_master(env=\(aqbase\(aq, prefix=\(aq\(aq)
|
||||
List all of the files stored on the master
|
||||
.sp
|
||||
CLI Example:
|
||||
@ -11954,7 +11954,7 @@ salt \(aq*\(aq cp.list_master
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B salt.modules.cp.list_master_dirs(env=\(aqbase\(aq)
|
||||
.B salt.modules.cp.list_master_dirs(env=\(aqbase\(aq, prefix=\(aq\(aq)
|
||||
List all of the directories stored on the master
|
||||
.sp
|
||||
CLI Example:
|
||||
|
@ -305,7 +305,7 @@ insecure!
|
||||
``client_acl``
|
||||
--------------
|
||||
|
||||
Default: {}
|
||||
Default: ``{}``
|
||||
|
||||
Enable user accounts on the master to execute specific modules. These modules
|
||||
can be expressed as regular expressions
|
||||
@ -317,6 +317,74 @@ can be expressed as regular expressions
|
||||
- test.ping
|
||||
- pkg.*
|
||||
|
||||
.. conf_master:: client_acl_blacklist
|
||||
|
||||
``client_acl_blacklist``
|
||||
------------------------
|
||||
|
||||
Default: ``{}``
|
||||
|
||||
Blacklist users or modules
|
||||
|
||||
This example would blacklist all non sudo users, including root from
|
||||
running any commands. It would also blacklist any use of the "cmd"
|
||||
module.
|
||||
|
||||
This is completely disabled by default.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
client_acl_blacklist:
|
||||
users:
|
||||
- root
|
||||
- '^(?!sudo_).*$' # all non sudo users
|
||||
modules:
|
||||
- cmd
|
||||
|
||||
.. conf_master:: external_auth
|
||||
|
||||
``external_auth``
|
||||
-----------------
|
||||
|
||||
Default: ``{}``
|
||||
|
||||
The external auth system uses the Salt auth modules to authenticate and
|
||||
validate users to access areas of the Salt system.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
external_auth:
|
||||
pam:
|
||||
fred:
|
||||
- test.*
|
||||
|
||||
.. conf_master:: token_expire
|
||||
|
||||
``token_expire``
|
||||
----------------
|
||||
|
||||
Default: ``43200``
|
||||
|
||||
Time (in seconds) for a newly generated token to live. Default: 12 hours
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
token_expire: 43200
|
||||
|
||||
.. conf_master:: file_recv
|
||||
|
||||
``file_recv``
|
||||
-------------
|
||||
|
||||
Default: ``False``
|
||||
|
||||
Allow minions to push files to the master. This is disabled by default, for
|
||||
security purposes.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
file_recv: False
|
||||
|
||||
|
||||
Master Module Management
|
||||
------------------------
|
||||
|
@ -110,3 +110,9 @@ To execute the manage.up runner:
|
||||
.. code-block:: bash
|
||||
|
||||
# salt-call publish.runner manage.up
|
||||
|
||||
To match minions using other matchers, use ``expr_form``:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# salt-call publish.publish 'webserv* and not G@os:Ubuntu' test.ping expr_form='compound'
|
||||
|
@ -204,3 +204,16 @@ class Resolver(object):
|
||||
except (IOError, OSError):
|
||||
pass
|
||||
return tdata
|
||||
|
||||
def request_token(self, load):
|
||||
'''
|
||||
Request a token fromt he master
|
||||
'''
|
||||
load['cmd'] = 'mk_token'
|
||||
sreq = salt.payload.SREQ(
|
||||
'tcp://{0[interface]}:{0[ret_port]}'.format(self.opts),
|
||||
)
|
||||
tdata = sreq.send('clear', load)
|
||||
if 'token' not in tdata:
|
||||
return tdata
|
||||
return tdata
|
||||
|
@ -129,6 +129,7 @@ VALID_OPTS = {
|
||||
'client_acl_blacklist': dict,
|
||||
'external_auth': dict,
|
||||
'token_expire': int,
|
||||
'file_recv': bool,
|
||||
'file_ignore_regex': bool,
|
||||
'file_ignore_glob': bool,
|
||||
'fileserver_backend': list,
|
||||
@ -271,6 +272,7 @@ DEFAULT_MASTER_OPTS = {
|
||||
'client_acl_blacklist': {},
|
||||
'external_auth': {},
|
||||
'token_expire': 43200,
|
||||
'file_recv': False,
|
||||
'file_buffer_size': 1048576,
|
||||
'file_ignore_regex': None,
|
||||
'file_ignore_glob': None,
|
||||
|
@ -102,7 +102,7 @@ class Client(object):
|
||||
'''
|
||||
raise NotImplementedError
|
||||
|
||||
def file_list_emptydirs(self, env='base'):
|
||||
def file_list_emptydirs(self, env='base', prefix=''):
|
||||
'''
|
||||
List the empty dirs
|
||||
'''
|
||||
@ -207,13 +207,13 @@ class Client(object):
|
||||
ldest = self._file_local_list(localfilesdest)
|
||||
return sorted(fdest.union(ldest))
|
||||
|
||||
def file_list(self, env='base'):
|
||||
def file_list(self, env='base', prefix=''):
|
||||
'''
|
||||
This function must be overwritten
|
||||
'''
|
||||
return []
|
||||
|
||||
def dir_list(self, env='base'):
|
||||
def dir_list(self, env='base', prefix=''):
|
||||
'''
|
||||
This function must be overwritten
|
||||
'''
|
||||
@ -461,47 +461,56 @@ class LocalClient(Client):
|
||||
return ''
|
||||
return fnd['path']
|
||||
|
||||
def file_list(self, env='base'):
|
||||
def file_list(self, env='base', prefix=''):
|
||||
'''
|
||||
Return a list of files in the given environment
|
||||
with optional relative prefix path to limit directory traversal
|
||||
'''
|
||||
ret = []
|
||||
if env not in self.opts['file_roots']:
|
||||
return ret
|
||||
for path in self.opts['file_roots'][env]:
|
||||
if prefix:
|
||||
path = os.path.join(path, prefix)
|
||||
for root, dirs, files in os.walk(path, followlinks=True):
|
||||
for fname in files:
|
||||
ret.append(
|
||||
os.path.relpath(
|
||||
os.path.join(root, fname),
|
||||
os.path.join(root, prefix, fname),
|
||||
path
|
||||
)
|
||||
)
|
||||
return ret
|
||||
|
||||
def file_list_emptydirs(self, env='base'):
|
||||
def file_list_emptydirs(self, env='base', prefix=''):
|
||||
'''
|
||||
List the empty dirs in the file_roots
|
||||
with optional relative prefix path to limit directory traversal
|
||||
'''
|
||||
ret = []
|
||||
if env not in self.opts['file_roots']:
|
||||
return ret
|
||||
for path in self.opts['file_roots'][env]:
|
||||
if prefix:
|
||||
path = os.path.join(path, prefix)
|
||||
for root, dirs, files in os.walk(path, followlinks=True):
|
||||
if len(dirs) == 0 and len(files) == 0:
|
||||
ret.append(os.path.relpath(root, path))
|
||||
ret.append(os.path.relpath(root, os.path.join(prefix, path)))
|
||||
return ret
|
||||
|
||||
def dir_list(self, env='base'):
|
||||
def dir_list(self, env='base', prefix=''):
|
||||
'''
|
||||
List the dirs in the file_roots
|
||||
with optional relative prefix path to limit directory traversal
|
||||
'''
|
||||
ret = []
|
||||
if env not in self.opts['file_roots']:
|
||||
return ret
|
||||
for path in self.opts['file_roots'][env]:
|
||||
if prefix:
|
||||
path = os.path.join(path, prefix)
|
||||
for root, dirs, files in os.walk(path, followlinks=True):
|
||||
ret.append(os.path.relpath(root, path))
|
||||
ret.append(os.path.relpath(root, os.path.join(prefix, path)))
|
||||
return ret
|
||||
|
||||
def hash_file(self, path, env='base'):
|
||||
@ -667,11 +676,12 @@ class RemoteClient(Client):
|
||||
fn_.close()
|
||||
return dest
|
||||
|
||||
def file_list(self, env='base'):
|
||||
def file_list(self, env='base', prefix=''):
|
||||
'''
|
||||
List the files on the master
|
||||
'''
|
||||
load = {'env': env,
|
||||
'prefix': prefix,
|
||||
'cmd': '_file_list'}
|
||||
try:
|
||||
return self.auth.crypticle.loads(
|
||||
@ -683,11 +693,12 @@ class RemoteClient(Client):
|
||||
except SaltReqTimeoutError:
|
||||
return ''
|
||||
|
||||
def file_list_emptydirs(self, env='base'):
|
||||
def file_list_emptydirs(self, env='base', prefix=''):
|
||||
'''
|
||||
List the empty dirs on the master
|
||||
'''
|
||||
load = {'env': env,
|
||||
'prefix': prefix,
|
||||
'cmd': '_file_list_emptydirs'}
|
||||
try:
|
||||
return self.auth.crypticle.loads(
|
||||
@ -699,11 +710,12 @@ class RemoteClient(Client):
|
||||
except SaltReqTimeoutError:
|
||||
return ''
|
||||
|
||||
def dir_list(self, env='base'):
|
||||
def dir_list(self, env='base', prefix=''):
|
||||
'''
|
||||
List the dirs on the master
|
||||
'''
|
||||
load = {'env': env,
|
||||
'prefix': prefix,
|
||||
'cmd': '_dir_list'}
|
||||
try:
|
||||
return self.auth.crypticle.loads(
|
||||
|
@ -99,10 +99,11 @@ def file_list(load):
|
||||
return ret
|
||||
|
||||
for path in __opts__['file_roots'][load['env']]:
|
||||
path = os.path.join(path, load['prefix'])
|
||||
for root, dirs, files in os.walk(path, followlinks=True):
|
||||
for fname in files:
|
||||
rel_fn = os.path.relpath(
|
||||
os.path.join(root, fname),
|
||||
os.path.join(root, load['prefix'], fname),
|
||||
path
|
||||
)
|
||||
if not salt.fileserver.is_file_ignored(__opts__, rel_fn):
|
||||
@ -118,11 +119,12 @@ def file_list_emptydirs(load):
|
||||
if load['env'] not in __opts__['file_roots']:
|
||||
return ret
|
||||
for path in __opts__['file_roots'][load['env']]:
|
||||
path = os.path.join(path, load['prefix'])
|
||||
for root, dirs, files in os.walk(path, followlinks=True):
|
||||
if len(dirs) == 0 and len(files) == 0:
|
||||
rel_fn = os.path.relpath(root, path)
|
||||
if not salt.fileserver.is_file_ignored(__opts__, rel_fn):
|
||||
ret.append(rel_fn)
|
||||
ret.append(os.path.join(load['prefix'], rel_fn))
|
||||
return ret
|
||||
|
||||
|
||||
@ -134,6 +136,7 @@ def dir_list(load):
|
||||
if load['env'] not in __opts__['file_roots']:
|
||||
return ret
|
||||
for path in __opts__['file_roots'][load['env']]:
|
||||
path = os.path.join(path, load['prefix'])
|
||||
for root, dirs, files in os.walk(path, followlinks=True):
|
||||
ret.append(os.path.relpath(root, path))
|
||||
ret.append(os.path.relpath(root, os.path.join(load['prefix'], path)))
|
||||
return ret
|
||||
|
114
salt/master.py
114
salt/master.py
@ -743,10 +743,10 @@ class AESFuncs(object):
|
||||
# The minion is not who it says it is!
|
||||
# We don't want to listen to it!
|
||||
log.warn(
|
||||
('Minion id {0} is not who it says it is and is attempting '
|
||||
'to issue a peer command').format(
|
||||
clear_load['id']
|
||||
)
|
||||
(
|
||||
'Minion id {0} is not who it says it is and is attempting '
|
||||
'to issue a peer command'
|
||||
).format(clear_load['id'])
|
||||
)
|
||||
return False
|
||||
perms = []
|
||||
@ -1324,10 +1324,10 @@ class AESFuncs(object):
|
||||
# The minion is not who it says it is!
|
||||
# We don't want to listen to it!
|
||||
log.warn(
|
||||
('Minion id {0} is not who it says it is and is attempting '
|
||||
'to revoke the key for {0}').format(
|
||||
load['id']
|
||||
)
|
||||
(
|
||||
'Minion id {0} is not who it says it is and is attempting '
|
||||
'to revoke the key for {0}'
|
||||
).format(load['id'])
|
||||
)
|
||||
return False
|
||||
keyapi = salt.key.Key(self.opts)
|
||||
@ -1753,6 +1753,94 @@ class ClearFuncs(object):
|
||||
self.event.fire_event(eload, 'auth')
|
||||
return ret
|
||||
|
||||
def runner(self, clear_load):
|
||||
'''
|
||||
Send a master control function back to the wheel system
|
||||
'''
|
||||
# All wheel ops pass through eauth
|
||||
if 'token' in clear_load:
|
||||
try:
|
||||
token = self.loadauth.get_tok(clear_load['token'])
|
||||
except Exception as exc:
|
||||
log.error(
|
||||
'Exception occurred when generating auth token: {0}'.format(
|
||||
exc
|
||||
)
|
||||
)
|
||||
return ''
|
||||
if not token:
|
||||
log.warning('Authentication failure of type "token" occurred.')
|
||||
return ''
|
||||
if token['eauth'] not in self.opts['external_auth']:
|
||||
log.warning('Authentication failure of type "token" occurred.')
|
||||
return ''
|
||||
if token['name'] not in self.opts['external_auth'][token['eauth']]:
|
||||
log.warning('Authentication failure of type "token" occurred.')
|
||||
return ''
|
||||
good = self.ckminions.runner_check(
|
||||
self.opts['external_auth'][clear_load['eauth']][token['name']] if token['name'] in self.opts['external_auth'][clear_load['eauth']] else self.opts['external_auth'][token['eauth']]['*'],
|
||||
clear_load['fun'])
|
||||
if not good:
|
||||
msg = ('Authentication failure of type "eauth" occurred for '
|
||||
'user {0}.').format(clear_load.get('username', 'UNKNOWN'))
|
||||
log.warning(msg)
|
||||
return ''
|
||||
|
||||
try:
|
||||
fun = clear_load.pop('fun')
|
||||
return self.wheel_.call_func(fun, **clear_load)
|
||||
except Exception as exc:
|
||||
log.error('Exception occurred while '
|
||||
'introspecting {0}: {1}'.format(fun, exc))
|
||||
return ''
|
||||
|
||||
if 'eauth' not in clear_load:
|
||||
msg = ('Authentication failure of type "eauth" occurred for '
|
||||
'user {0}.').format(clear_load.get('username', 'UNKNOWN'))
|
||||
log.warning(msg)
|
||||
return ''
|
||||
if clear_load['eauth'] not in self.opts['external_auth']:
|
||||
# The eauth system is not enabled, fail
|
||||
msg = ('Authentication failure of type "eauth" occurred for '
|
||||
'user {0}.').format(clear_load.get('username', 'UNKNOWN'))
|
||||
log.warning(msg)
|
||||
return ''
|
||||
|
||||
try:
|
||||
name = self.loadauth.load_name(clear_load)
|
||||
if not ((name in self.opts['external_auth'][clear_load['eauth']]) | ('*' in self.opts['external_auth'][clear_load['eauth']])):
|
||||
msg = ('Authentication failure of type "eauth" occurred for '
|
||||
'user {0}.').format(clear_load.get('username', 'UNKNOWN'))
|
||||
log.warning(msg)
|
||||
return ''
|
||||
if not self.loadauth.time_auth(clear_load):
|
||||
msg = ('Authentication failure of type "eauth" occurred for '
|
||||
'user {0}.').format(clear_load.get('username', 'UNKNOWN'))
|
||||
log.warning(msg)
|
||||
return ''
|
||||
good = self.ckminions.runner_check(
|
||||
self.opts['external_auth'][clear_load['eauth']][name] if name in self.opts['external_auth'][clear_load['eauth']] else self.opts['external_auth'][token['eauth']]['*'],
|
||||
clear_load['fun'])
|
||||
if not good:
|
||||
msg = ('Authentication failure of type "eauth" occurred for '
|
||||
'user {0}.').format(clear_load.get('username', 'UNKNOWN'))
|
||||
log.warning(msg)
|
||||
return ''
|
||||
|
||||
try:
|
||||
fun = clear_load.pop('fun')
|
||||
return self.wheel_.call_func(fun, **clear_load)
|
||||
except Exception as exc:
|
||||
log.error('Exception occurred while '
|
||||
'introspecting {0}: {1}'.format(fun, exc))
|
||||
return ''
|
||||
|
||||
except Exception as exc:
|
||||
log.error(
|
||||
'Exception occurred in the wheel system: {0}'.format(exc)
|
||||
)
|
||||
return ''
|
||||
|
||||
def wheel(self, clear_load):
|
||||
'''
|
||||
Send a master control function back to the wheel system
|
||||
@ -1777,6 +1865,14 @@ class ClearFuncs(object):
|
||||
if token['name'] not in self.opts['external_auth'][token['eauth']]:
|
||||
log.warning('Authentication failure of type "token" occurred.')
|
||||
return ''
|
||||
good = self.ckminions.wheel_check(
|
||||
self.opts['external_auth'][clear_load['eauth']][token['name']] if token['name'] in self.opts['external_auth'][clear_load['eauth']] else self.opts['external_auth'][token['eauth']]['*'],
|
||||
clear_load['fun'])
|
||||
if not good:
|
||||
msg = ('Authentication failure of type "eauth" occurred for '
|
||||
'user {0}.').format(clear_load.get('username', 'UNKNOWN'))
|
||||
log.warning(msg)
|
||||
return ''
|
||||
|
||||
try:
|
||||
fun = clear_load.pop('fun')
|
||||
@ -2060,7 +2156,7 @@ class ClearFuncs(object):
|
||||
self.opts['hash_type']
|
||||
)
|
||||
|
||||
# Announce the job on the event bus
|
||||
# Announce the job on the event bus
|
||||
self.event.fire_event(clear_load, 'new_job')
|
||||
|
||||
# Verify the jid dir
|
||||
|
@ -150,8 +150,13 @@ def latest_version(*names, **kwargs):
|
||||
# If there are no installed versions that are greater than or equal
|
||||
# to the install candidate, then the candidate is an upgrade, so
|
||||
# add it to the return dict
|
||||
if not any([compare(pkg1=x, oper='>=', pkg2=candidate)
|
||||
for x in installed]):
|
||||
if not any(
|
||||
(salt.utils.compare_versions(ver1=x,
|
||||
oper='>=',
|
||||
ver2=candidate,
|
||||
cmp_func=version_cmp)
|
||||
for x in installed)
|
||||
):
|
||||
ret[name] = candidate
|
||||
|
||||
# Return a string if only one package name passed
|
||||
@ -629,7 +634,7 @@ def upgrade_available(name):
|
||||
return latest_version(name) != ''
|
||||
|
||||
|
||||
def perform_cmp(pkg1='', pkg2=''):
|
||||
def version_cmp(pkg1, pkg2):
|
||||
'''
|
||||
Do a cmp-style comparison on two packages. Return -1 if pkg1 < pkg2, 0 if
|
||||
pkg1 == pkg2, and 1 if pkg1 > pkg2. Return None if there was a problem
|
||||
@ -637,8 +642,7 @@ def perform_cmp(pkg1='', pkg2=''):
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' pkg.perform_cmp '0.2.4-0ubuntu1' '0.2.4.1-0ubuntu1'
|
||||
salt '*' pkg.perform_cmp pkg1='0.2.4-0ubuntu1' pkg2='0.2.4.1-0ubuntu1'
|
||||
salt '*' pkg.version_cmp '0.2.4-0ubuntu1' '0.2.4.1-0ubuntu1'
|
||||
'''
|
||||
try:
|
||||
for oper, ret in (('lt', -1), ('eq', 0), ('gt', 1)):
|
||||
@ -651,18 +655,6 @@ def perform_cmp(pkg1='', pkg2=''):
|
||||
return None
|
||||
|
||||
|
||||
def compare(pkg1='', oper='==', pkg2=''):
|
||||
'''
|
||||
Compare two version strings.
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' pkg.compare '0.2.4-0' '<' '0.2.4.1-0'
|
||||
salt '*' pkg.compare pkg1='0.2.4-0' oper='<' pkg2='0.2.4.1-0'
|
||||
'''
|
||||
return __salt__['pkg_resource.compare'](pkg1=pkg1, oper=oper, pkg2=pkg2)
|
||||
|
||||
|
||||
def _split_repo_str(repo):
|
||||
split = sourceslist.SourceEntry(repo)
|
||||
return split.type, split.uri, split.dist, split.comps
|
||||
|
@ -278,29 +278,3 @@ def upgrade_available(pkg):
|
||||
salt '*' pkg.upgrade_available <package name>
|
||||
'''
|
||||
return pkg in list_upgrades()
|
||||
|
||||
|
||||
def perform_cmp(pkg1='', pkg2=''):
|
||||
'''
|
||||
Do a cmp-style comparison on two packages. Return -1 if pkg1 < pkg2, 0 if
|
||||
pkg1 == pkg2, and 1 if pkg1 > pkg2. Return None if there was a problem
|
||||
making the comparison.
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' pkg.perform_cmp '0.2.4-0' '0.2.4.1-0'
|
||||
salt '*' pkg.perform_cmp pkg1='0.2.4-0' pkg2='0.2.4.1-0'
|
||||
'''
|
||||
return __salt__['pkg_resource.perform_cmp'](pkg1=pkg1, pkg2=pkg2)
|
||||
|
||||
|
||||
def compare(pkg1='', oper='==', pkg2=''):
|
||||
'''
|
||||
Compare two version strings.
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' pkg.compare '0.2.4-0' '<' '0.2.4.1-0'
|
||||
salt '*' pkg.compare pkg1='0.2.4-0' oper='<' pkg2='0.2.4.1-0'
|
||||
'''
|
||||
return __salt__['pkg_resource.compare'](pkg1=pkg1, oper=oper, pkg2=pkg2)
|
||||
|
@ -312,7 +312,7 @@ def list_states(env='base'):
|
||||
return __context__['cp.fileclient'].list_states(env)
|
||||
|
||||
|
||||
def list_master(env='base'):
|
||||
def list_master(env='base', prefix=''):
|
||||
'''
|
||||
List all of the files stored on the master
|
||||
|
||||
@ -321,10 +321,10 @@ def list_master(env='base'):
|
||||
salt '*' cp.list_master
|
||||
'''
|
||||
_mk_client()
|
||||
return __context__['cp.fileclient'].file_list(env)
|
||||
return __context__['cp.fileclient'].file_list(env, prefix)
|
||||
|
||||
|
||||
def list_master_dirs(env='base'):
|
||||
def list_master_dirs(env='base', prefix=''):
|
||||
'''
|
||||
List all of the directories stored on the master
|
||||
|
||||
@ -333,7 +333,7 @@ def list_master_dirs(env='base'):
|
||||
salt '*' cp.list_master_dirs
|
||||
'''
|
||||
_mk_client()
|
||||
return __context__['cp.fileclient'].dir_list(env)
|
||||
return __context__['cp.fileclient'].dir_list(env, prefix)
|
||||
|
||||
|
||||
def list_minion(env='base'):
|
||||
@ -379,12 +379,12 @@ def push(path):
|
||||
'''
|
||||
Push a file from the minion up to the master, the file will be saved to
|
||||
the salt master in the master's minion files cachedir
|
||||
(defaults to /var/cache/salt/master/minions/files)
|
||||
(defaults to ``/var/cache/salt/master/minions/minion-id/files``)
|
||||
|
||||
Since this feature allows a minion to push a file up to the master server
|
||||
it is disabled by default for security purposes. To enable add the option:
|
||||
file_recv: True
|
||||
to the master configuration and restart the master
|
||||
it is disabled by default for security purposes. To enable, set
|
||||
``file_recv`` to ``True`` in the master configuration file, and restart the
|
||||
master.
|
||||
|
||||
CLI Example::
|
||||
|
||||
|
@ -132,7 +132,11 @@ def latest_version(*names, **kwargs):
|
||||
installed = _cpv_to_version(_vartree().dep_bestmatch(name))
|
||||
avail = _cpv_to_version(_porttree().dep_bestmatch(name))
|
||||
if avail:
|
||||
if not installed or compare(pkg1=installed, oper='<', pkg2=avail):
|
||||
if not installed \
|
||||
or salt.utils.compare_versions(ver1=installed,
|
||||
oper='<',
|
||||
ver2=avail,
|
||||
cmp_func=version_cmp):
|
||||
ret[name] = avail
|
||||
|
||||
# Return a string if only one package name passed
|
||||
@ -221,8 +225,8 @@ def porttree_matches(name):
|
||||
'''
|
||||
matches = []
|
||||
for category in _porttree().dbapi.categories:
|
||||
if _porttree().dbapi.cp_list(category+"/"+name):
|
||||
matches.append(category+"/"+name)
|
||||
if _porttree().dbapi.cp_list(category + "/" + name):
|
||||
matches.append(category + "/" + name)
|
||||
return matches
|
||||
|
||||
|
||||
@ -276,7 +280,8 @@ def refresh_db():
|
||||
if 'makeconf.features_contains'in __salt__ and __salt__['makeconf.features_contains']('webrsync-gpg'):
|
||||
# GPG sign verify is supported only for "webrsync"
|
||||
cmd = 'emerge-webrsync -q'
|
||||
if salt.utils.which('emerge-delta-webrsync'): # We prefer 'delta-webrsync' to 'webrsync'
|
||||
# We prefer 'delta-webrsync' to 'webrsync'
|
||||
if salt.utils.which('emerge-delta-webrsync'):
|
||||
cmd = 'emerge-delta-webrsync -q'
|
||||
return __salt__['cmd.retcode'](cmd) == 0
|
||||
else:
|
||||
@ -284,7 +289,8 @@ def refresh_db():
|
||||
return True
|
||||
# We fall back to "webrsync" if "rsync" fails for some reason
|
||||
cmd = 'emerge-webrsync -q'
|
||||
if salt.utils.which('emerge-delta-webrsync'): # We prefer 'delta-webrsync' to 'webrsync'
|
||||
# We prefer 'delta-webrsync' to 'webrsync'
|
||||
if salt.utils.which('emerge-delta-webrsync'):
|
||||
cmd = 'emerge-delta-webrsync -q'
|
||||
return __salt__['cmd.retcode'](cmd) == 0
|
||||
|
||||
@ -413,7 +419,7 @@ def install(name=None,
|
||||
for param, version_num in pkg_params.iteritems():
|
||||
original_param = param
|
||||
param = _p_to_cp(param)
|
||||
if param == None:
|
||||
if param is None:
|
||||
raise portage.dep.InvalidAtom(original_param)
|
||||
|
||||
if version_num is None:
|
||||
@ -442,12 +448,12 @@ def install(name=None,
|
||||
__salt__['portage_config.append_use_flags'](target[1:-1])
|
||||
new = __salt__['portage_config.get_flags_from_package_conf']('use', target[1:-1])
|
||||
if old != new:
|
||||
changes[param+'-USE'] = {'old': old, 'new': new}
|
||||
changes[param + '-USE'] = {'old': old, 'new': new}
|
||||
target = target[:target.rfind('[')] + '"'
|
||||
|
||||
if keyword != None:
|
||||
if keyword is not None:
|
||||
__salt__['portage_config.append_to_package_conf']('accept_keywords', target[1:-1], ['~ARCH'])
|
||||
changes[param+'-ACCEPT_KEYWORD'] = {'old': '', 'new': '~ARCH'}
|
||||
changes[param + '-ACCEPT_KEYWORD'] = {'old': '', 'new': '~ARCH'}
|
||||
|
||||
targets.append(target)
|
||||
else:
|
||||
@ -571,7 +577,7 @@ def remove(name=None, slot=None, fromrepo=None, pkgs=None, **kwargs):
|
||||
targets = ['{0}:{1}'.format(fullatom, slot)]
|
||||
if fromrepo is not None:
|
||||
targets = ['{0}::{1}'.format(fullatom, fromrepo)]
|
||||
targets = [ fullatom ]
|
||||
targets = [fullatom]
|
||||
else:
|
||||
targets = [x for x in pkg_params if x in old]
|
||||
|
||||
@ -656,7 +662,7 @@ def depclean(name=None, slot=None, fromrepo=None, pkgs=None):
|
||||
targets = ['{0}:{1}'.format(fullatom, slot)]
|
||||
if fromrepo is not None:
|
||||
targets = ['{0}::{1}'.format(fullatom, fromrepo)]
|
||||
targets = [ fullatom ]
|
||||
targets = [fullatom]
|
||||
else:
|
||||
targets = [x for x in pkg_params if x in old]
|
||||
|
||||
@ -667,7 +673,7 @@ def depclean(name=None, slot=None, fromrepo=None, pkgs=None):
|
||||
return __salt__['pkg_resource.find_changes'](old, new)
|
||||
|
||||
|
||||
def perform_cmp(pkg1='', pkg2=''):
|
||||
def version_cmp(pkg1, pkg2):
|
||||
'''
|
||||
Do a cmp-style comparison on two packages. Return -1 if pkg1 < pkg2, 0 if
|
||||
pkg1 == pkg2, and 1 if pkg1 > pkg2. Return None if there was a problem
|
||||
@ -675,8 +681,7 @@ def perform_cmp(pkg1='', pkg2=''):
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' pkg.perform_cmp '0.2.4-0' '0.2.4.1-0'
|
||||
salt '*' pkg.perform_cmp pkg1='0.2.4-0' pkg2='0.2.4.1-0'
|
||||
salt '*' pkg.version_cmp '0.2.4-0' '0.2.4.1-0'
|
||||
'''
|
||||
regex = r'^~?([^:\[]+):?[^\[]*\[?.*$'
|
||||
ver1 = re.match(regex, pkg1)
|
||||
@ -687,18 +692,6 @@ def perform_cmp(pkg1='', pkg2=''):
|
||||
return None
|
||||
|
||||
|
||||
def compare(pkg1='', oper='==', pkg2=''):
|
||||
'''
|
||||
Compare two version strings.
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' pkg.compare '0.2.4-0' '<' '0.2.4.1-0'
|
||||
salt '*' pkg.compare pkg1='0.2.4-0' oper='<' pkg2='0.2.4.1-0'
|
||||
'''
|
||||
return __salt__['pkg_resource.compare'](pkg1=pkg1, oper=oper, pkg2=pkg2)
|
||||
|
||||
|
||||
def version_clean(version):
|
||||
'''
|
||||
Clean the version string removing extra data.
|
||||
@ -752,7 +745,8 @@ def check_extra_requirements(pkgname, pkgver):
|
||||
|
||||
des_uses = set(portage.dep.dep_getusedeps(atom))
|
||||
cur_use = cur_use.split()
|
||||
if len([ x for x in des_uses.difference(cur_use) if x[0]!='-' or x[1:] in cur_use ]) > 0:
|
||||
if len([x for x in des_uses.difference(cur_use)
|
||||
if x[0] != '-' or x[1:] in cur_use]) > 0:
|
||||
return False
|
||||
|
||||
if keyword:
|
||||
|
@ -391,32 +391,6 @@ def rehash():
|
||||
__salt__['cmd.run_all']('rehash')
|
||||
|
||||
|
||||
def perform_cmp(pkg1='', pkg2=''):
|
||||
'''
|
||||
Do a cmp-style comparison on two packages. Return -1 if pkg1 < pkg2, 0 if
|
||||
pkg1 == pkg2, and 1 if pkg1 > pkg2. Return None if there was a problem
|
||||
making the comparison.
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' pkg.perform_cmp '0.2.4-0' '0.2.4.1-0'
|
||||
salt '*' pkg.perform_cmp pkg1='0.2.4-0' pkg2='0.2.4.1-0'
|
||||
'''
|
||||
return __salt__['pkg_resource.perform_cmp'](pkg1=pkg1, pkg2=pkg2)
|
||||
|
||||
|
||||
def compare(pkg1='', oper='==', pkg2=''):
|
||||
'''
|
||||
Compare two version strings.
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' pkg.compare '0.2.4-0' '<' '0.2.4.1-0'
|
||||
salt '*' pkg.compare pkg1='0.2.4-0' oper='<' pkg2='0.2.4.1-0'
|
||||
'''
|
||||
return __salt__['pkg_resource.compare'](pkg1=pkg1, oper=oper, pkg2=pkg2)
|
||||
|
||||
|
||||
def file_list(*packages):
|
||||
'''
|
||||
List the files that belong to a package. Not specifying any packages will
|
||||
|
@ -216,3 +216,30 @@ def ls(): # pylint: disable=C0103
|
||||
salt '*' grains.ls
|
||||
'''
|
||||
return sorted(__grains__)
|
||||
|
||||
|
||||
def filter_by(lookup_dict, grain='os_family'):
|
||||
'''
|
||||
Look up the given grain in a given dictionary for the current OS and return
|
||||
the result
|
||||
|
||||
Although this may occasionally be useful at the CLI, the primary intent of
|
||||
this function is for use in Jinja to make short work of creating lookup
|
||||
tables for OS-specific data. For example::
|
||||
|
||||
{% set pkg_table = {
|
||||
'Debian': {'name': 'apache2'},
|
||||
'RedHat': {'name': 'httpd'},
|
||||
} %}
|
||||
{% set pkg = salt['grains.filter_by'](pkg_table) %}
|
||||
|
||||
myapache:
|
||||
pkg:
|
||||
- installed
|
||||
- name: {{ pkg.name }}
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' grains.filter_by '{Debian: Debheads rule, RedHat: I love my hat}'
|
||||
'''
|
||||
return lookup_dict.get(__grains__[grain], None)
|
||||
|
@ -222,29 +222,3 @@ def purge(name=None, pkgs=None, **kwargs):
|
||||
salt '*' pkg.purge pkgs='["foo", "bar"]'
|
||||
'''
|
||||
return remove(name=name, pkgs=pkgs)
|
||||
|
||||
|
||||
def perform_cmp(pkg1='', pkg2=''):
|
||||
'''
|
||||
Do a cmp-style comparison on two packages. Return -1 if pkg1 < pkg2, 0 if
|
||||
pkg1 == pkg2, and 1 if pkg1 > pkg2. Return None if there was a problem
|
||||
making the comparison.
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' pkg.perform_cmp '0.2.4' '0.2.4.1'
|
||||
salt '*' pkg.perform_cmp pkg1='0.2.4' pkg2='0.2.4.1'
|
||||
'''
|
||||
return __salt__['pkg_resource.perform_cmp'](pkg1=pkg1, pkg2=pkg2)
|
||||
|
||||
|
||||
def compare(pkg1='', oper='==', pkg2=''):
|
||||
'''
|
||||
Compare two version strings.
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' pkg.compare '0.2.4' '<' '0.2.4.1'
|
||||
salt '*' pkg.compare pkg1='0.2.4' oper='<' pkg2='0.2.4.1'
|
||||
'''
|
||||
return __salt__['pkg_resource.compare'](pkg1=pkg1, oper=oper, pkg2=pkg2)
|
||||
|
@ -396,32 +396,6 @@ def purge(name=None, pkgs=None, **kwargs):
|
||||
return _uninstall(action='purge', name=name, pkgs=pkgs)
|
||||
|
||||
|
||||
def perform_cmp(pkg1='', pkg2=''):
|
||||
'''
|
||||
Do a cmp-style comparison on two packages. Return -1 if pkg1 < pkg2, 0 if
|
||||
pkg1 == pkg2, and 1 if pkg1 > pkg2. Return None if there was a problem
|
||||
making the comparison.
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' pkg.perform_cmp '0.2.4-0' '0.2.4.1-0'
|
||||
salt '*' pkg.perform_cmp pkg1='0.2.4-0' pkg2='0.2.4.1-0'
|
||||
'''
|
||||
return __salt__['pkg_resource.perform_cmp'](pkg1=pkg1, pkg2=pkg2)
|
||||
|
||||
|
||||
def compare(pkg1='', oper='==', pkg2=''):
|
||||
'''
|
||||
Compare two version strings.
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' pkg.compare '0.2.4-0' '<' '0.2.4.1-0'
|
||||
salt '*' pkg.compare pkg1='0.2.4-0' oper='<' pkg2='0.2.4.1-0'
|
||||
'''
|
||||
return __salt__['pkg_resource.compare'](pkg1=pkg1, oper=oper, pkg2=pkg2)
|
||||
|
||||
|
||||
def file_list(*packages):
|
||||
'''
|
||||
List the files that belong to a package. Not specifying any packages will
|
||||
|
@ -3,7 +3,6 @@ Resources needed by pkg providers
|
||||
'''
|
||||
|
||||
# Import python libs
|
||||
import distutils.version # pylint: disable=E0611
|
||||
import fnmatch
|
||||
import logging
|
||||
import os
|
||||
@ -97,7 +96,8 @@ def _parse_pkg_meta(path):
|
||||
except AttributeError:
|
||||
continue
|
||||
if arch:
|
||||
name += ':{0}'.format(arch)
|
||||
if cpuarch == 'x86_64' and arch != 'amd64':
|
||||
name += ':{0}'.format(arch)
|
||||
return name, version
|
||||
|
||||
if __grains__['os_family'] in ('Suse', 'RedHat', 'Mandriva'):
|
||||
@ -418,62 +418,10 @@ def find_changes(old=None, new=None):
|
||||
return pkgs
|
||||
|
||||
|
||||
def perform_cmp(pkg1='', pkg2=''):
|
||||
'''
|
||||
Compares two version strings using distutils.version.LooseVersion. This is
|
||||
a fallback for providers which don't have a version comparison utility
|
||||
built into them. Return -1 if version1 < version2, 0 if version1 ==
|
||||
version2, and 1 if version1 > version2. Return None if there was a problem
|
||||
making the comparison.
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' pkg_resource.perform_cmp
|
||||
'''
|
||||
try:
|
||||
if distutils.version.LooseVersion(pkg1) < \
|
||||
distutils.version.LooseVersion(pkg2):
|
||||
return -1
|
||||
elif distutils.version.LooseVersion(pkg1) == \
|
||||
distutils.version.LooseVersion(pkg2):
|
||||
return 0
|
||||
elif distutils.version.LooseVersion(pkg1) > \
|
||||
distutils.version.LooseVersion(pkg2):
|
||||
return 1
|
||||
except Exception as e:
|
||||
log.exception(e)
|
||||
return None
|
||||
|
||||
|
||||
def compare(pkg1='', oper='==', pkg2=''):
|
||||
'''
|
||||
Package version comparison function.
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' pkg_resource.compare
|
||||
'''
|
||||
cmp_map = {'<': (-1,), '<=': (-1, 0), '==': (0,),
|
||||
'>=': (0, 1), '>': (1,)}
|
||||
if oper not in ['!='] + cmp_map.keys():
|
||||
log.error('Invalid operator "{0}" for package '
|
||||
'comparison'.format(oper))
|
||||
return False
|
||||
|
||||
cmp_result = __salt__['pkg.perform_cmp'](pkg1, pkg2)
|
||||
if cmp_result is None:
|
||||
return False
|
||||
|
||||
if oper == '!=':
|
||||
return cmp_result not in cmp_map['==']
|
||||
else:
|
||||
return cmp_result in cmp_map[oper]
|
||||
|
||||
|
||||
def version_clean(version):
|
||||
'''
|
||||
Clean the version string removing extra data.
|
||||
This function will simply try to call "pkg.version_clean".
|
||||
This function will simply try to call ``pkg.version_clean``.
|
||||
|
||||
CLI Example::
|
||||
|
||||
|
@ -423,32 +423,6 @@ def rehash():
|
||||
__salt__['cmd.run']('rehash')
|
||||
|
||||
|
||||
def perform_cmp(pkg1='', pkg2=''):
|
||||
'''
|
||||
Do a cmp-style comparison on two packages. Return -1 if pkg1 < pkg2, 0 if
|
||||
pkg1 == pkg2, and 1 if pkg1 > pkg2. Return None if there was a problem
|
||||
making the comparison.
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' pkg.perform_cmp '0.2.4-0' '0.2.4.1-0'
|
||||
salt '*' pkg.perform_cmp pkg1='0.2.4-0' pkg2='0.2.4.1-0'
|
||||
'''
|
||||
return __salt__['pkg_resource.perform_cmp'](pkg1=pkg1, pkg2=pkg2)
|
||||
|
||||
|
||||
def compare(pkg1='', oper='==', pkg2=''):
|
||||
'''
|
||||
Compare two version strings.
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' pkg.compare '0.2.4-0' '<' '0.2.4.1-0'
|
||||
salt '*' pkg.compare pkg1='0.2.4-0' oper='<' pkg2='0.2.4.1-0'
|
||||
'''
|
||||
return __salt__['pkg_resource.compare'](pkg1=pkg1, oper=oper, pkg2=pkg2)
|
||||
|
||||
|
||||
def file_list(package):
|
||||
'''
|
||||
List the files that belong to a package.
|
||||
|
@ -857,29 +857,3 @@ def updating(pkg_name, filedate=None, filename=None):
|
||||
|
||||
cmd = 'pkg updating {0} {1}'.format(opts, pkg_name)
|
||||
return __salt__['cmd.run'](cmd)
|
||||
|
||||
|
||||
def perform_cmp(pkg1='', pkg2=''):
|
||||
'''
|
||||
Do a cmp-style comparison on two packages. Return -1 if pkg1 < pkg2, 0 if
|
||||
pkg1 == pkg2, and 1 if pkg1 > pkg2. Return None if there was a problem
|
||||
making the comparison.
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' pkg.perform_cmp '0.2.4-0' '0.2.4.1-0'
|
||||
salt '*' pkg.perform_cmp pkg1='0.2.4-0' pkg2='0.2.4.1-0'
|
||||
'''
|
||||
return __salt__['pkg_resource.perform_cmp'](pkg1=pkg1, pkg2=pkg2)
|
||||
|
||||
|
||||
def compare(pkg1='', oper='==', pkg2=''):
|
||||
'''
|
||||
Compare two version strings.
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' pkg.compare '0.2.4-0' '<' '0.2.4.1-0'
|
||||
salt '*' pkg.compare pkg1='0.2.4-0' oper='<' pkg2='0.2.4.1-0'
|
||||
'''
|
||||
return __salt__['pkg_resource.compare'](pkg1=pkg1, oper=oper, pkg2=pkg2)
|
||||
|
@ -194,7 +194,9 @@ def latest_version(*names, **kwargs):
|
||||
if name in names:
|
||||
cver = pkgs.get(name, '')
|
||||
nver = version_rev.split(',')[0]
|
||||
if not cver or compare(pkg1=cver, oper='<', pkg2=nver):
|
||||
if not cver or salt.utils.compare_versions(ver1=cver,
|
||||
oper='<',
|
||||
ver2=nver):
|
||||
# Remove revision for version comparison
|
||||
ret[name] = version_rev
|
||||
|
||||
@ -326,29 +328,3 @@ def purge(name=None, pkgs=None, **kwargs):
|
||||
salt '*' pkg.purge pkgs='["foo", "bar"]'
|
||||
'''
|
||||
return remove(name=name, pkgs=pkgs)
|
||||
|
||||
|
||||
def perform_cmp(pkg1='', pkg2=''):
|
||||
'''
|
||||
Do a cmp-style comparison on two packages. Return -1 if pkg1 < pkg2, 0 if
|
||||
pkg1 == pkg2, and 1 if pkg1 > pkg2. Return None if there was a problem
|
||||
making the comparison.
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' pkg.perform_cmp '0.2.4-0' '0.2.4.1-0'
|
||||
salt '*' pkg.perform_cmp pkg1='0.2.4-0' pkg2='0.2.4.1-0'
|
||||
'''
|
||||
return __salt__['pkg_resource.perform_cmp'](pkg1=pkg1, pkg2=pkg2)
|
||||
|
||||
|
||||
def compare(pkg1='', oper='==', pkg2=''):
|
||||
'''
|
||||
Compare two version strings.
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' pkg.compare '0.2.4-0' '<' '0.2.4.1-0'
|
||||
salt '*' pkg.compare pkg1='0.2.4-0' oper='<' pkg2='0.2.4.1-0'
|
||||
'''
|
||||
return __salt__['pkg_resource.compare'](pkg1=pkg1, oper=oper, pkg2=pkg2)
|
||||
|
@ -436,29 +436,3 @@ def purge(name=None, pkgs=None, **kwargs):
|
||||
salt '*' pkg.purge pkgs='["foo", "bar"]'
|
||||
'''
|
||||
return remove(name=name, pkgs=pkgs, **kwargs)
|
||||
|
||||
|
||||
def perform_cmp(pkg1='', pkg2=''):
|
||||
'''
|
||||
Do a cmp-style comparison on two packages. Return -1 if pkg1 < pkg2, 0 if
|
||||
pkg1 == pkg2, and 1 if pkg1 > pkg2. Return None if there was a problem
|
||||
making the comparison.
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' pkg.perform_cmp '0.2.4-0' '0.2.4.1-0'
|
||||
salt '*' pkg.perform_cmp pkg1='0.2.4-0' pkg2='0.2.4.1-0'
|
||||
'''
|
||||
return __salt__['pkg_resource.perform_cmp'](pkg1=pkg1, pkg2=pkg2)
|
||||
|
||||
|
||||
def compare(pkg1='', oper='==', pkg2=''):
|
||||
'''
|
||||
Compare two version strings.
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' pkg.compare '0.2.4-0' '<' '0.2.4.1-0'
|
||||
salt '*' pkg.compare pkg1='0.2.4-0' oper='<' pkg2='0.2.4.1-0'
|
||||
'''
|
||||
return __salt__['pkg_resource.compare'](pkg1=pkg1, oper=oper, pkg2=pkg2)
|
||||
|
@ -706,29 +706,3 @@ def _get_latest_pkg_version(pkginfo):
|
||||
return pkginfo.keys().pop()
|
||||
pkgkeys = pkginfo.keys()
|
||||
return sorted(pkgkeys, cmp=_reverse_cmp_pkg_versions).pop()
|
||||
|
||||
|
||||
def perform_cmp(pkg1='', pkg2=''):
|
||||
'''
|
||||
Do a cmp-style comparison on two packages. Return -1 if pkg1 < pkg2, 0 if
|
||||
pkg1 == pkg2, and 1 if pkg1 > pkg2. Return None if there was a problem
|
||||
making the comparison.
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' pkg.perform_cmp '0.2.4-0' '0.2.4.1-0'
|
||||
salt '*' pkg.perform_cmp pkg1='0.2.4-0' pkg2='0.2.4.1-0'
|
||||
'''
|
||||
return __salt__['pkg_resource.perform_cmp'](pkg1=pkg1, pkg2=pkg2)
|
||||
|
||||
|
||||
def compare(pkg1='', oper='==', pkg2=''):
|
||||
'''
|
||||
Compare two version strings.
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' pkg.compare '0.2.4-0' '<' '0.2.4.1-0'
|
||||
salt '*' pkg.compare pkg1='0.2.4-0' oper='<' pkg2='0.2.4.1-0'
|
||||
'''
|
||||
return __salt__['pkg_resource.compare'](pkg1=pkg1, oper=oper, pkg2=pkg2)
|
||||
|
@ -1039,32 +1039,6 @@ def _parse_repo_file(filename):
|
||||
return (header, repos)
|
||||
|
||||
|
||||
def perform_cmp(pkg1='', pkg2=''):
|
||||
'''
|
||||
Do a cmp-style comparison on two packages. Return -1 if pkg1 < pkg2, 0 if
|
||||
pkg1 == pkg2, and 1 if pkg1 > pkg2. Return None if there was a problem
|
||||
making the comparison.
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' pkg.perform_cmp '0.2.4-0' '0.2.4.1-0'
|
||||
salt '*' pkg.perform_cmp pkg1='0.2.4-0' pkg2='0.2.4.1-0'
|
||||
'''
|
||||
return __salt__['pkg_resource.perform_cmp'](pkg1=pkg1, pkg2=pkg2)
|
||||
|
||||
|
||||
def compare(pkg1='', oper='==', pkg2=''):
|
||||
'''
|
||||
Compare two version strings.
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' pkg.compare '0.2.4-0' '<' '0.2.4.1-0'
|
||||
salt '*' pkg.compare pkg1='0.2.4-0' oper='<' pkg2='0.2.4.1-0'
|
||||
'''
|
||||
return __salt__['pkg_resource.compare'](pkg1=pkg1, oper=oper, pkg2=pkg2)
|
||||
|
||||
|
||||
def file_list(*packages):
|
||||
'''
|
||||
List the files that belong to a package. Not specifying any packages will
|
||||
|
@ -505,29 +505,3 @@ def purge(name=None, pkgs=None, **kwargs):
|
||||
salt '*' pkg.purge pkgs='["foo", "bar"]'
|
||||
'''
|
||||
return remove(name=name, pkgs=pkgs)
|
||||
|
||||
|
||||
def perform_cmp(pkg1='', pkg2=''):
|
||||
'''
|
||||
Do a cmp-style comparison on two packages. Return -1 if pkg1 < pkg2, 0 if
|
||||
pkg1 == pkg2, and 1 if pkg1 > pkg2. Return None if there was a problem
|
||||
making the comparison.
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' pkg.perform_cmp '0.2.4-0' '0.2.4.1-0'
|
||||
salt '*' pkg.perform_cmp pkg1='0.2.4-0' pkg2='0.2.4.1-0'
|
||||
'''
|
||||
return __salt__['pkg_resource.perform_cmp'](pkg1=pkg1, pkg2=pkg2)
|
||||
|
||||
|
||||
def compare(pkg1='', oper='==', pkg2=''):
|
||||
'''
|
||||
Compare two version strings.
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' pkg.compare '0.2.4-0' '<' '0.2.4.1-0'
|
||||
salt '*' pkg.compare pkg1='0.2.4-0' oper='<' pkg2='0.2.4.1-0'
|
||||
'''
|
||||
return __salt__['pkg_resource.compare'](pkg1=pkg1, oper=oper, pkg2=pkg2)
|
||||
|
@ -419,29 +419,3 @@ def purge(name=None, pkgs=None, **kwargs):
|
||||
salt '*' pkg.purge pkgs='["foo", "bar"]'
|
||||
'''
|
||||
return _uninstall(action='purge', name=name, pkgs=pkgs)
|
||||
|
||||
|
||||
def perform_cmp(pkg1='', pkg2=''):
|
||||
'''
|
||||
Do a cmp-style comparison on two packages. Return -1 if pkg1 < pkg2, 0 if
|
||||
pkg1 == pkg2, and 1 if pkg1 > pkg2. Return None if there was a problem
|
||||
making the comparison.
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' pkg.perform_cmp '0.2.4-0' '0.2.4.1-0'
|
||||
salt '*' pkg.perform_cmp pkg1='0.2.4-0' pkg2='0.2.4.1-0'
|
||||
'''
|
||||
return __salt__['pkg_resource.perform_cmp'](pkg1=pkg1, pkg2=pkg2)
|
||||
|
||||
|
||||
def compare(pkg1='', oper='==', pkg2=''):
|
||||
'''
|
||||
Compare two version strings.
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' pkg.compare '0.2.4-0' '<' '0.2.4.1-0'
|
||||
salt '*' pkg.compare pkg1='0.2.4-0' oper='<' pkg2='0.2.4.1-0'
|
||||
'''
|
||||
return __salt__['pkg_resource.compare'](pkg1=pkg1, oper=oper, pkg2=pkg2)
|
||||
|
@ -58,49 +58,6 @@ def _get_ref(repo, short):
|
||||
return ref
|
||||
return False
|
||||
|
||||
|
||||
def _wait_lock(lk_fn, dest):
|
||||
'''
|
||||
If the write lock is there, check to see if the file is actually being
|
||||
written. If there is no change in the file size after a short sleep,
|
||||
remove the lock and move forward.
|
||||
'''
|
||||
if not os.path.isfile(lk_fn):
|
||||
return False
|
||||
if not os.path.isfile(dest):
|
||||
# The dest is not here, sleep for a bit, if the dest is not here yet
|
||||
# kill the lockfile and start the write
|
||||
time.sleep(1)
|
||||
if not os.path.isfile(dest):
|
||||
try:
|
||||
os.remove(lk_fn)
|
||||
except (OSError, IOError):
|
||||
pass
|
||||
return False
|
||||
# There is a lock file, the dest is there, stat the dest, sleep and check
|
||||
# that the dest is being written, if it is not being written kill the lock
|
||||
# file and continue. Also check if the lock file is gone.
|
||||
s_count = 0
|
||||
s_size = os.stat(dest).st_size
|
||||
while True:
|
||||
time.sleep(1)
|
||||
if not os.path.isfile(lk_fn):
|
||||
return False
|
||||
size = os.stat(dest).st_size
|
||||
if size == s_size:
|
||||
s_count += 1
|
||||
if s_count >= 3:
|
||||
# The file is not being written to, kill the lock and proceed
|
||||
try:
|
||||
os.remove(lk_fn)
|
||||
except (OSError, IOError):
|
||||
pass
|
||||
return False
|
||||
else:
|
||||
s_size = size
|
||||
return False
|
||||
|
||||
|
||||
def init(branch, repo_location):
|
||||
'''
|
||||
Return the git repo object for this session
|
||||
@ -125,6 +82,7 @@ def init(branch, repo_location):
|
||||
repo.create_remote('origin', repo_location)
|
||||
except Exception:
|
||||
pass
|
||||
repo.git.fetch()
|
||||
return repo
|
||||
|
||||
|
||||
@ -141,14 +99,7 @@ def update(branch, repo_location):
|
||||
except git.exc.GitCommandError as e:
|
||||
logging.error('Unable to checkout branch {0}: {1}'.format(branch, e))
|
||||
return False
|
||||
lk_fn = os.path.join(repo.working_dir, 'update.lk')
|
||||
with salt.utils.fopen(lk_fn, 'w+') as fp_:
|
||||
fp_.write(str(pid))
|
||||
repo.git.pull()
|
||||
try:
|
||||
os.remove(lk_fn)
|
||||
except (OSError, IOError):
|
||||
pass
|
||||
return True
|
||||
|
||||
|
||||
|
@ -2,11 +2,16 @@
|
||||
Execute salt convenience routines
|
||||
'''
|
||||
|
||||
# Import python libs
|
||||
import multiprocessing
|
||||
import datetime
|
||||
|
||||
# Import salt libs
|
||||
import salt.loader
|
||||
import salt.exceptions
|
||||
import salt.utils
|
||||
import salt.minion
|
||||
import salt.utils.event
|
||||
|
||||
|
||||
class RunnerClient(object):
|
||||
@ -17,6 +22,23 @@ class RunnerClient(object):
|
||||
self.opts = opts
|
||||
self.functions = salt.loader.runner(opts)
|
||||
|
||||
def _proc_runner(self, tag, fun, arg, kwarg):
|
||||
'''
|
||||
Run this method in a multiprocess target to execute the runner in a
|
||||
multiprocess and fire the return data on the event bus
|
||||
'''
|
||||
salt.utils.daemonize()
|
||||
data = {}
|
||||
try:
|
||||
data['ret'] = self.cmd(fun, arg, kwarg)
|
||||
except Exception as exc:
|
||||
data['ret'] = 'Exception occured in runner {0}: {1}'.format(
|
||||
fun,
|
||||
exc,
|
||||
)
|
||||
event = salt.utils.event.MasterEvent(self.opts['sock_dir'])
|
||||
event.fire_event(data, tag)
|
||||
|
||||
def _verify_fun(self, fun):
|
||||
'''
|
||||
Check that the function passed really exists
|
||||
@ -57,6 +79,19 @@ class RunnerClient(object):
|
||||
ret = l_fun(*f_call.get('args', ()), **f_call.get('kwargs', {}))
|
||||
return ret
|
||||
|
||||
def async(self, fun, arg, kwarg=None):
|
||||
'''
|
||||
Execute the runner in a multiprocess and return the event tag to use
|
||||
to watch for the return
|
||||
'''
|
||||
tag = '{0:%Y%m%d%H%M%S%f}'.format(datetime.datetime.now())
|
||||
tag[20] = 'r'
|
||||
proc = multiprocessing.Process(
|
||||
target=self._proc_runner,
|
||||
args=(tag, fun, arg, kwarg))
|
||||
proc.start()
|
||||
return tag
|
||||
|
||||
|
||||
class Runner(RunnerClient):
|
||||
'''
|
||||
|
@ -21,7 +21,7 @@ import salt.minion
|
||||
|
||||
def decode_list(data):
|
||||
'''
|
||||
JSON decodes as unicode, Jinja needs raw strings...
|
||||
JSON decodes as unicode, Jinja needs bytes...
|
||||
'''
|
||||
rv = []
|
||||
for item in data:
|
||||
@ -37,25 +37,25 @@ def decode_list(data):
|
||||
|
||||
def decode_dict(data):
|
||||
'''
|
||||
JSON decodes as unicode, Jinja needs raw strings...
|
||||
JSON decodes as unicode, Jinja needs bytes...
|
||||
'''
|
||||
rv = {}
|
||||
for key, value in data.iteritems():
|
||||
if isinstance(key, unicode):
|
||||
key = key.encode('utf-8')
|
||||
key = key.encode('utf-8')
|
||||
if isinstance(value, unicode):
|
||||
value = value.encode('utf-8')
|
||||
value = value.encode('utf-8')
|
||||
elif isinstance(value, list):
|
||||
value = decode_list(value)
|
||||
value = decode_list(value)
|
||||
elif isinstance(value, dict):
|
||||
value = decode_dict(value)
|
||||
value = decode_dict(value)
|
||||
rv[key] = value
|
||||
return rv
|
||||
|
||||
|
||||
class SSH(object):
|
||||
'''
|
||||
Create an ssh execution system
|
||||
Create an SSH execution system
|
||||
'''
|
||||
def __init__(self, opts):
|
||||
self.opts = opts
|
||||
@ -85,7 +85,7 @@ class SSH(object):
|
||||
|
||||
def get_pubkey(self):
|
||||
'''
|
||||
Return the keystring for the ssh public key
|
||||
Return the keystring for the SSH public key
|
||||
'''
|
||||
priv = self.opts.get(
|
||||
'ssh_priv',
|
||||
@ -101,7 +101,7 @@ class SSH(object):
|
||||
|
||||
def key_deploy(self, host, ret):
|
||||
'''
|
||||
Deploy the ssh key if the minions don't auth
|
||||
Deploy the SSH key if the minions don't auth
|
||||
'''
|
||||
if not isinstance(ret[host], basestring):
|
||||
return ret
|
||||
@ -405,7 +405,7 @@ class Single():
|
||||
class FunctionWrapper(dict):
|
||||
'''
|
||||
Create an object that acts like the salt function dict and makes function
|
||||
calls remotely via the ssh shell system
|
||||
calls remotely via the SSH shell system
|
||||
'''
|
||||
def __init__(
|
||||
self,
|
||||
@ -440,7 +440,7 @@ class FunctionWrapper(dict):
|
||||
|
||||
class SSHState(salt.state.State):
|
||||
'''
|
||||
Create a State object which wraps the ssh functions for state operations
|
||||
Create a State object which wraps the SSH functions for state operations
|
||||
'''
|
||||
def __init__(self, opts, pillar=None, wrapper=None):
|
||||
self.wrapper = wrapper
|
||||
|
@ -1241,7 +1241,7 @@ def recurse(name,
|
||||
|
||||
if not _src_path:
|
||||
pass
|
||||
elif _src_path.strip('/') not in __salt__['cp.list_master_dirs'](env):
|
||||
elif _src_path.strip('/') not in __salt__['cp.list_master_dirs'](env, _src_path):
|
||||
ret['result'] = False
|
||||
ret['comment'] = (
|
||||
'The source: {0} does not exist on the master'.format(source)
|
||||
@ -1353,11 +1353,9 @@ def recurse(name,
|
||||
#we're searching for things that start with this *directory*.
|
||||
# use '/' since #master only runs on POSIX
|
||||
srcpath = srcpath + '/'
|
||||
for fn_ in __salt__['cp.list_master'](env):
|
||||
for fn_ in __salt__['cp.list_master'](env, srcpath):
|
||||
if not fn_.strip():
|
||||
continue
|
||||
if not fn_.startswith(srcpath):
|
||||
continue
|
||||
|
||||
# fn_ here is the absolute (from file_roots) source path of
|
||||
# the file to copy from; it is either a normal file or an
|
||||
@ -1393,10 +1391,8 @@ def recurse(name,
|
||||
manage_file(dest, src)
|
||||
|
||||
if include_empty:
|
||||
mdirs = __salt__['cp.list_master_dirs'](env)
|
||||
mdirs = __salt__['cp.list_master_dirs'](env, srcpath)
|
||||
for mdir in mdirs:
|
||||
if not mdir.startswith(srcpath):
|
||||
continue
|
||||
if not _check_include_exclude(os.path.relpath(mdir, srcpath),
|
||||
include_pat,
|
||||
exclude_pat):
|
||||
|
@ -19,6 +19,7 @@ requisite to a pkg.installed state for the package which provides pip
|
||||
'''
|
||||
|
||||
# Import python libs
|
||||
import re
|
||||
import urlparse
|
||||
|
||||
# Import salt libs
|
||||
@ -33,6 +34,34 @@ def __virtual__():
|
||||
return 'pip' if 'pip.list' in __salt__ else False
|
||||
|
||||
|
||||
def _find_key(prefix, pip_list):
|
||||
'''
|
||||
Does a case-insensitive match in the pip_list for the desired package.
|
||||
'''
|
||||
try:
|
||||
match = next(
|
||||
iter(x for x in pip_list if x.lower() == prefix.lower())
|
||||
)
|
||||
except StopIteration:
|
||||
return None
|
||||
else:
|
||||
return match
|
||||
|
||||
|
||||
def _fulfills_version_spec(version, version_spec):
|
||||
'''
|
||||
Check version number against version specification info and return a
|
||||
boolean value based on whether or not the version number meets the
|
||||
specified version.
|
||||
'''
|
||||
for oper, spec in (version_spec[0:2], version_spec[2:4]):
|
||||
if oper is None:
|
||||
continue
|
||||
if not salt.utils.compare_versions(ver1=version, oper=oper, ver2=spec):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def installed(name,
|
||||
pip_bin=None,
|
||||
requirements=None,
|
||||
@ -87,17 +116,38 @@ def installed(name,
|
||||
elif env and not bin_env:
|
||||
bin_env = env
|
||||
|
||||
ret = {'name': name, 'result': None, 'comment': '', 'changes': {}}
|
||||
|
||||
scheme, netloc, path, query, fragment = urlparse.urlsplit(name)
|
||||
if scheme and netloc:
|
||||
# parse as VCS url
|
||||
prefix = path.lstrip('/').split('@', 1)[0]
|
||||
if scheme.startswith("git+"):
|
||||
prefix = prefix.rstrip(".git")
|
||||
if scheme.startswith('git+'):
|
||||
prefix = prefix.rstrip('.git')
|
||||
else:
|
||||
# Pull off any requirements specifiers
|
||||
prefix = name.split('=')[0].split('<')[0].split('>')[0].strip()
|
||||
# Split the passed string into the prefix and version
|
||||
try:
|
||||
version_spec = list(re.match(
|
||||
(r'([^=<>]+)(?:(?:([<>]=?|==?)([^<>=,]+))'
|
||||
r'(?:,([<>]=?|==?)([^<>=]+))?)?$'),
|
||||
name
|
||||
).groups())
|
||||
prefix = version_spec.pop(0)
|
||||
except AttributeError:
|
||||
ret['result'] = False
|
||||
ret['comment'] = 'Invalidly-formatted package {0}'.format(name)
|
||||
return ret
|
||||
else:
|
||||
# Check to see if '=' was used instead of '=='. version_spec will
|
||||
# contain two sets of comparison operators and version numbers, so
|
||||
# we are checking elements 0 and 2 of this list.
|
||||
if any((version_spec[x] == '=' for x in (0, 2))):
|
||||
ret['result'] = False
|
||||
ret['comment'] = ('Invalid version specification in '
|
||||
'package {0}. \'=\' is not supported, use '
|
||||
'\'==\' instead.'.format(name))
|
||||
return ret
|
||||
|
||||
ret = {'name': name, 'result': None, 'comment': '', 'changes': {}}
|
||||
if runas is not None:
|
||||
# The user is using a deprecated argument, warn!
|
||||
msg = (
|
||||
@ -107,41 +157,48 @@ def installed(name,
|
||||
salt.utils.warn_until((0, 18), msg)
|
||||
ret.setdefault('warnings', []).append(msg)
|
||||
|
||||
# "There can only be one"
|
||||
if runas is not None and user:
|
||||
raise CommandExecutionError(
|
||||
'The \'runas\' and \'user\' arguments are mutually exclusive. '
|
||||
'Please use \'user\' as \'runas\' is being deprecated.'
|
||||
)
|
||||
# Support deprecated 'runas' arg
|
||||
elif runas is not None and not user:
|
||||
user = runas
|
||||
# "There can only be one"
|
||||
if user:
|
||||
raise CommandExecutionError(
|
||||
'The \'runas\' and \'user\' arguments are mutually exclusive. '
|
||||
'Please use \'user\' as \'runas\' is being deprecated.'
|
||||
)
|
||||
# Support deprecated 'runas' arg
|
||||
else:
|
||||
user = runas
|
||||
|
||||
try:
|
||||
pip_list = __salt__['pip.list'](prefix, bin_env, user=user, cwd=cwd)
|
||||
pip_list = __salt__['pip.list'](prefix, bin_env=bin_env,
|
||||
user=user, cwd=cwd)
|
||||
prefix_realname = _find_key(prefix, pip_list)
|
||||
except (CommandNotFoundError, CommandExecutionError) as err:
|
||||
ret['result'] = False
|
||||
ret['comment'] = 'Error installing \'{0}\': {1}'.format(name, err)
|
||||
return ret
|
||||
|
||||
if ignore_installed is False and prefix.lower() in (p.lower()
|
||||
for p in pip_list):
|
||||
if force_reinstall is False and upgrade is False:
|
||||
ret['result'] = True
|
||||
ret['comment'] = 'Package already installed'
|
||||
return ret
|
||||
if ignore_installed is False and prefix_realname is not None:
|
||||
if force_reinstall is False and not upgrade:
|
||||
# Check desired version (if any) against currently-installed
|
||||
if (
|
||||
any(version_spec) and
|
||||
_fulfills_version_spec(pip_list[prefix_realname],
|
||||
version_spec)
|
||||
) or (not any(version_spec)):
|
||||
ret['result'] = True
|
||||
ret['comment'] = ('Python package {0} already '
|
||||
'installed'.format(name))
|
||||
return ret
|
||||
|
||||
if __opts__['test']:
|
||||
ret['result'] = None
|
||||
ret['comment'] = 'Python package {0} is set to be installed'.format(
|
||||
name)
|
||||
ret['comment'] = \
|
||||
'Python package {0} is set to be installed'.format(name)
|
||||
return ret
|
||||
|
||||
# Replace commas (used for version ranges) with semicolons (which are not
|
||||
# supported) in name so it does not treat them as multiple packages. Comma
|
||||
# will be re-added in pip.install call. Wrap in double quotes to allow for
|
||||
# version ranges
|
||||
name = '"' + name.replace(',', ';') + '"'
|
||||
# will be re-added in pip.install call.
|
||||
name = name.replace(',', ';')
|
||||
|
||||
if repo:
|
||||
name = repo
|
||||
@ -153,7 +210,7 @@ def installed(name,
|
||||
name = ''
|
||||
|
||||
pip_install_call = __salt__['pip.install'](
|
||||
pkgs=name,
|
||||
pkgs='"{0}"'.format(name),
|
||||
requirements=requirements,
|
||||
bin_env=bin_env,
|
||||
log=log,
|
||||
|
@ -48,8 +48,10 @@ if salt.utils.is_windows():
|
||||
from salt.modules.win_pkg import _reverse_cmp_pkg_versions
|
||||
_get_package_info = namespaced_function(_get_package_info, globals())
|
||||
get_repo_data = namespaced_function(get_repo_data, globals())
|
||||
_get_latest_pkg_version = namespaced_function(_get_latest_pkg_version, globals())
|
||||
_reverse_cmp_pkg_versions = namespaced_function(_reverse_cmp_pkg_versions, globals())
|
||||
_get_latest_pkg_version = \
|
||||
namespaced_function(_get_latest_pkg_version, globals())
|
||||
_reverse_cmp_pkg_versions = \
|
||||
namespaced_function(_reverse_cmp_pkg_versions, globals())
|
||||
# The following imports are used by the namespaced win_pkg funcs
|
||||
# and need to be included in their globals.
|
||||
import msgpack
|
||||
@ -65,13 +67,16 @@ def __gen_rtag():
|
||||
return os.path.join(__opts__['cachedir'], 'pkg_refresh')
|
||||
|
||||
|
||||
def _fulfills_version_spec(versions, oper, desired_version):
|
||||
def _fulfills_version_spec(version, oper, desired_version):
|
||||
'''
|
||||
Returns True if any of the installed versions match the specified version,
|
||||
otherwise returns False
|
||||
'''
|
||||
for ver in versions:
|
||||
if __salt__['pkg.compare'](pkg1=ver, oper=oper, pkg2=desired_version):
|
||||
for ver in version:
|
||||
if salt.utils.compare_versions(ver1=version,
|
||||
oper=oper,
|
||||
ver2=desired_version,
|
||||
cmp_func=__salt__.get('version_cmp')):
|
||||
return True
|
||||
return False
|
||||
|
||||
@ -153,7 +158,8 @@ def _find_install_targets(name=None, version=None, pkgs=None, sources=None):
|
||||
if not cver:
|
||||
targets[pkgname] = pkgver
|
||||
continue
|
||||
elif not __salt__['pkg_resource.check_extra_requirements'](pkgname, pkgver):
|
||||
elif not __salt__['pkg_resource.check_extra_requirements'](pkgname,
|
||||
pkgver):
|
||||
targets[pkgname] = pkgver
|
||||
continue
|
||||
# No version specified and pkg is installed, do not add to targets
|
||||
@ -170,7 +176,7 @@ def _find_install_targets(name=None, version=None, pkgs=None, sources=None):
|
||||
comparison = gt_lt or ''
|
||||
comparison += eq or ''
|
||||
# A comparison operator of "=" is redundant, but possible.
|
||||
# Change it to "==" so that it works in pkg.compare.
|
||||
# Change it to "==" so that the version comparison works
|
||||
if comparison in ['=', '']:
|
||||
comparison = '=='
|
||||
if not _fulfills_version_spec(cver, comparison, verstr):
|
||||
@ -215,7 +221,7 @@ def _verify_install(desired, new_pkgs):
|
||||
comparison = gt_lt or ''
|
||||
comparison += eq or ''
|
||||
# A comparison operator of "=" is redundant, but possible.
|
||||
# Change it to "==" so that it works in pkg.compare.
|
||||
# Change it to "==" so that the version comparison works.
|
||||
if comparison in ('=', ''):
|
||||
comparison = '=='
|
||||
if _fulfills_version_spec(cver, comparison, verstr):
|
||||
@ -557,10 +563,12 @@ def latest(
|
||||
msg = 'No information found for "{0}".'.format(pkg)
|
||||
log.error(msg)
|
||||
problems.append(msg)
|
||||
elif not cur[pkg] or \
|
||||
__salt__['pkg.compare'](pkg1=cur[pkg],
|
||||
oper='<',
|
||||
pkg2=avail[pkg]):
|
||||
elif not cur[pkg] \
|
||||
or salt.utils.compare_versions(
|
||||
ver1=cur[pkg],
|
||||
oper='<',
|
||||
ver2=avail[pkg],
|
||||
cmp_func=__salt__.get('version_cmp')):
|
||||
targets[pkg] = avail[pkg]
|
||||
|
||||
if problems:
|
||||
@ -608,7 +616,8 @@ def latest(
|
||||
|
||||
if changes:
|
||||
# Find failed and successful updates
|
||||
failed = [x for x in targets if changes[x]['new'] != targets[x]]
|
||||
failed = [x for x in targets
|
||||
if not changes.get(x) or changes[x]['new'] != targets[x]]
|
||||
successful = [x for x in targets if x not in failed]
|
||||
|
||||
comments = []
|
||||
|
@ -5,6 +5,7 @@ from __future__ import absolute_import
|
||||
|
||||
# Import python libs
|
||||
import datetime
|
||||
import distutils.version # pylint: disable=E0611
|
||||
import fnmatch
|
||||
import hashlib
|
||||
import imp
|
||||
@ -1389,3 +1390,51 @@ def warn_until(version_info,
|
||||
|
||||
if _dont_call_warnings is False:
|
||||
warnings.warn(message, category, stacklevel=stacklevel)
|
||||
|
||||
|
||||
def version_cmp(pkg1, pkg2):
|
||||
'''
|
||||
Compares two version strings using distutils.version.LooseVersion. This is
|
||||
a fallback for providers which don't have a version comparison utility
|
||||
built into them. Return -1 if version1 < version2, 0 if version1 ==
|
||||
version2, and 1 if version1 > version2. Return None if there was a problem
|
||||
making the comparison.
|
||||
'''
|
||||
try:
|
||||
if distutils.version.LooseVersion(pkg1) < \
|
||||
distutils.version.LooseVersion(pkg2):
|
||||
return -1
|
||||
elif distutils.version.LooseVersion(pkg1) == \
|
||||
distutils.version.LooseVersion(pkg2):
|
||||
return 0
|
||||
elif distutils.version.LooseVersion(pkg1) > \
|
||||
distutils.version.LooseVersion(pkg2):
|
||||
return 1
|
||||
except Exception as e:
|
||||
log.exception(e)
|
||||
return None
|
||||
|
||||
|
||||
def compare_versions(ver1='', oper='==', ver2='', cmp_func=None):
|
||||
'''
|
||||
Compares two version numbers. Accepts a custom function to perform the
|
||||
cmp-style version comparison, otherwise uses version_cmp().
|
||||
'''
|
||||
cmp_map = {'<': (-1,), '<=': (-1, 0), '==': (0,),
|
||||
'>=': (0, 1), '>': (1,)}
|
||||
if oper not in ['!='] + cmp_map.keys():
|
||||
log.error('Invalid operator "{0}" for version '
|
||||
'comparison'.format(oper))
|
||||
return False
|
||||
|
||||
if cmp_func is None:
|
||||
cmp_func = version_cmp
|
||||
|
||||
cmp_result = cmp_func(ver1, ver2)
|
||||
if cmp_result is None:
|
||||
return False
|
||||
|
||||
if oper == '!=':
|
||||
return cmp_result not in cmp_map['==']
|
||||
else:
|
||||
return cmp_result in cmp_map[oper]
|
||||
|
Loading…
Reference in New Issue
Block a user