mirror of
https://github.com/valitydev/salt-common.git
synced 2024-11-06 10:25:23 +00:00
Update states/pkg, modules/ebuildpkg (#84)
This commit is contained in:
parent
78c84e3d19
commit
6cc508a9b4
@ -13,19 +13,27 @@ Support for Portage
|
||||
For now all package names *MUST* include the package category,
|
||||
i.e. ``'vim'`` will not work, ``'app-editors/vim'`` will.
|
||||
'''
|
||||
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
# Import python libs
|
||||
import os
|
||||
import copy
|
||||
import logging
|
||||
import re
|
||||
import importlib
|
||||
import datetime
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils
|
||||
import salt.utils.args
|
||||
import salt.utils.compat
|
||||
import salt.utils.data
|
||||
import salt.utils.functools
|
||||
import salt.utils.path
|
||||
import salt.utils.pkg
|
||||
import salt.utils.systemd
|
||||
import salt.utils.versions
|
||||
from salt.exceptions import CommandExecutionError, MinionError
|
||||
import salt.ext.six as six
|
||||
from salt.ext import six
|
||||
|
||||
|
||||
# Import third party libs
|
||||
HAS_PORTAGE = False
|
||||
@ -49,6 +57,21 @@ log = logging.getLogger(__name__)
|
||||
# Define the module's virtual name
|
||||
__virtualname__ = 'pkg'
|
||||
|
||||
r_gt_lt_eq_verstr = re.compile(r'^([<>])?(=)?([^<>=]*)$')
|
||||
r_split_ver = re.compile(r'^~?([^:\[]+)[\:\[]?.*$')
|
||||
r_split_repo = re.compile(r'^.+::([^\[]+).*$')
|
||||
r_strip_ver = re.compile(r'^~?[<>]?=?([^<>=:\[]+).*$')
|
||||
r_find_upgradeable = re.compile(r'(?m)^\[.+\] '
|
||||
r'([^ ]+/[^ ]+)' # Package string
|
||||
'-'
|
||||
r'([0-9]+[^ ]+)' # Version
|
||||
r'.*$')
|
||||
r_find_changes_in_section = re.compile(r'^[<>=][^ ]+/[^ ]+ [^\n]+', re.M)
|
||||
r_find_slot_conflicts = re.compile(r'^[^ \n]+/[^ ]+:[^ ]', re.M)
|
||||
r_find_blocked = re.compile(r'(?m)^\[blocks .+\] '
|
||||
r'([^ ]+/[^ ]+-[0-9]+[^ ]+)'
|
||||
r'.*$')
|
||||
r_find_unsatisfied = re.compile(r'Error: The above package list contains')
|
||||
|
||||
def __virtual__():
|
||||
'''
|
||||
@ -61,21 +84,38 @@ def __virtual__():
|
||||
|
||||
def _vartree():
|
||||
import portage # pylint: disable=3rd-party-module-not-gated
|
||||
portage = importlib.reload(portage)
|
||||
portage = salt.utils.compat.reload(portage)
|
||||
return portage.db[portage.root]['vartree']
|
||||
|
||||
|
||||
def _porttree():
|
||||
import portage # pylint: disable=3rd-party-module-not-gated
|
||||
portage = importlib.reload(portage)
|
||||
portage = salt.utils.compat.reload(portage)
|
||||
return portage.db[portage.root]['porttree']
|
||||
|
||||
|
||||
def _p_to_cp(p):
|
||||
ret = _porttree().dbapi.xmatch("match-all", p)
|
||||
if ret:
|
||||
return portage.cpv_getkey(ret[0])
|
||||
log.error('_p_to_cp: Package {0} not found by xmatch'.format(p))
|
||||
try:
|
||||
ret = portage.dep_getkey(p)
|
||||
if ret:
|
||||
return ret
|
||||
except portage.exception.InvalidAtom:
|
||||
pass
|
||||
|
||||
try:
|
||||
ret = _porttree().dbapi.xmatch('bestmatch-visible', p)
|
||||
if ret:
|
||||
return portage.dep_getkey(ret)
|
||||
except portage.exception.InvalidAtom:
|
||||
pass
|
||||
|
||||
try:
|
||||
ret = _porttree().dbapi.xmatch("match-all", p)
|
||||
if ret:
|
||||
return portage.cpv_getkey(ret[0])
|
||||
except portage.exception.InvalidAtom:
|
||||
pass
|
||||
|
||||
return None
|
||||
|
||||
|
||||
@ -89,11 +129,21 @@ def _allnodes():
|
||||
|
||||
|
||||
def _cpv_to_cp(cpv):
|
||||
ret = portage.cpv_getkey(cpv)
|
||||
if ret:
|
||||
return ret
|
||||
else:
|
||||
return cpv
|
||||
try:
|
||||
ret = portage.dep_getkey(cpv)
|
||||
if ret:
|
||||
return ret
|
||||
except portage.exception.InvalidAtom:
|
||||
pass
|
||||
|
||||
try:
|
||||
ret = portage.cpv_getkey(cpv)
|
||||
if ret:
|
||||
return ret
|
||||
except portage.exception.InvalidAtom:
|
||||
pass
|
||||
|
||||
return cpv
|
||||
|
||||
|
||||
def _cpv_to_version(cpv):
|
||||
@ -105,18 +155,14 @@ def _process_emerge_err(stdout, stderr):
|
||||
Used to parse emerge output to provide meaningful output when emerge fails
|
||||
'''
|
||||
ret = {}
|
||||
rexp = re.compile(r'^[<>=][^ ]+/[^ ]+ [^\n]+', re.M)
|
||||
|
||||
slot_conflicts = re.compile(r'^[^ \n]+/[^ ]+:[^ ]', re.M).findall(stderr)
|
||||
slot_conflicts = r_find_slot_conflicts.findall(stderr)
|
||||
if slot_conflicts:
|
||||
ret['slot conflicts'] = slot_conflicts
|
||||
|
||||
blocked = re.compile(r'(?m)^\[blocks .+\] '
|
||||
r'([^ ]+/[^ ]+-[0-9]+[^ ]+)'
|
||||
r'.*$').findall(stdout)
|
||||
blocked = r_find_blocked.findall(stdout)
|
||||
|
||||
unsatisfied = re.compile(
|
||||
r'Error: The above package list contains').findall(stderr)
|
||||
unsatisfied = r_find_unsatisfied.findall(stderr)
|
||||
|
||||
# If there were blocks and emerge could not resolve it.
|
||||
if blocked and unsatisfied:
|
||||
@ -125,13 +171,13 @@ def _process_emerge_err(stdout, stderr):
|
||||
sections = re.split('\n\n', stderr)
|
||||
for section in sections:
|
||||
if 'The following keyword changes' in section:
|
||||
ret['keywords'] = rexp.findall(section)
|
||||
ret['keywords'] = r_find_changes_in_section.findall(section)
|
||||
elif 'The following license changes' in section:
|
||||
ret['license'] = rexp.findall(section)
|
||||
ret['license'] = r_find_changes_in_section.findall(section)
|
||||
elif 'The following USE changes' in section:
|
||||
ret['use'] = rexp.findall(section)
|
||||
ret['use'] = r_find_changes_in_section.findall(section)
|
||||
elif 'The following mask changes' in section:
|
||||
ret['mask'] = rexp.findall(section)
|
||||
ret['mask'] = r_find_changes_in_section.findall(section)
|
||||
return ret
|
||||
|
||||
|
||||
@ -220,7 +266,7 @@ def latest_version(*names, **kwargs):
|
||||
salt '*' pkg.latest_version <package name>
|
||||
salt '*' pkg.latest_version <package1> <package2> <package3> ...
|
||||
'''
|
||||
refresh = salt.utils.is_true(kwargs.pop('refresh', True))
|
||||
refresh = salt.utils.data.is_true(kwargs.pop('refresh', True))
|
||||
|
||||
if len(names) == 0:
|
||||
return ''
|
||||
@ -235,7 +281,7 @@ def latest_version(*names, **kwargs):
|
||||
ret[name] = ''
|
||||
installed = _cpv_to_version(_vartree().dep_bestmatch(name))
|
||||
avail = _cpv_to_version(_porttree().dep_bestmatch(name))
|
||||
if avail and (not installed or salt.utils.compare_versions(ver1=installed, oper='<', ver2=avail, cmp_func=version_cmp)):
|
||||
if avail and (not installed or salt.utils.versions.compare(ver1=installed, oper='<', ver2=avail, cmp_func=version_cmp)):
|
||||
ret[name] = avail
|
||||
|
||||
# Return a string if only one package name passed
|
||||
@ -244,6 +290,10 @@ def latest_version(*names, **kwargs):
|
||||
return ret
|
||||
|
||||
|
||||
# available_version is being deprecated
|
||||
available_version = salt.utils.functools.alias_function(latest_version, 'available_version')
|
||||
|
||||
|
||||
def _get_upgradable(backtrack=3):
|
||||
'''
|
||||
Utility function to get upgradable packages
|
||||
@ -275,15 +325,10 @@ def _get_upgradable(backtrack=3):
|
||||
else:
|
||||
out = call['stdout']
|
||||
|
||||
rexp = re.compile(r'(?m)^\[.+\] '
|
||||
r'([^ ]+/[^ ]+)' # Package string
|
||||
'-'
|
||||
r'([0-9]+[^ ]+)' # Version
|
||||
r'.*$')
|
||||
keys = ['name', 'version']
|
||||
_get = lambda l, k: l[keys.index(k)]
|
||||
|
||||
upgrades = rexp.findall(out)
|
||||
upgrades = r_find_upgradeable.findall(out)
|
||||
|
||||
ret = {}
|
||||
for line in upgrades:
|
||||
@ -314,7 +359,7 @@ def list_upgrades(refresh=True, backtrack=3, **kwargs): # pylint: disable=W0613
|
||||
|
||||
salt '*' pkg.list_upgrades
|
||||
'''
|
||||
if salt.utils.is_true(refresh):
|
||||
if salt.utils.data.is_true(refresh):
|
||||
refresh_db()
|
||||
return _get_upgradable(backtrack)
|
||||
|
||||
@ -345,21 +390,8 @@ def version(*names, **kwargs):
|
||||
salt '*' pkg.version <package name>
|
||||
salt '*' pkg.version <package1> <package2> <package3> ...
|
||||
'''
|
||||
if len(names) == 0:
|
||||
return ''
|
||||
return __salt__['pkg_resource.version'](*names, **kwargs)
|
||||
|
||||
ret = {}
|
||||
# Initialize the dict with empty strings
|
||||
for name in names:
|
||||
ret[name] = ''
|
||||
installed = _cpv_to_version(_vartree().dep_bestmatch(name))
|
||||
if installed:
|
||||
ret[name] = installed
|
||||
|
||||
# Return a string if only one package name passed
|
||||
if len(names) == 1:
|
||||
return ret[names[0]]
|
||||
return ret
|
||||
|
||||
def porttree_matches(name):
|
||||
'''
|
||||
@ -387,9 +419,9 @@ def list_pkgs(versions_as_list=False, **kwargs):
|
||||
|
||||
salt '*' pkg.list_pkgs
|
||||
'''
|
||||
versions_as_list = salt.utils.is_true(versions_as_list)
|
||||
versions_as_list = salt.utils.data.is_true(versions_as_list)
|
||||
# not yet implemented or not applicable
|
||||
if any([salt.utils.is_true(kwargs.get(x))
|
||||
if any([salt.utils.data.is_true(kwargs.get(x))
|
||||
for x in ('removed', 'purge_desired')]):
|
||||
return {}
|
||||
|
||||
@ -416,7 +448,21 @@ def list_pkgs(versions_as_list=False, **kwargs):
|
||||
|
||||
def refresh_db():
|
||||
'''
|
||||
Updates the portage tree (emerge --sync). Uses eix-sync if available.
|
||||
Update the portage tree using the first available method from the following
|
||||
list:
|
||||
|
||||
- emaint sync
|
||||
- eix-sync
|
||||
- emerge-webrsync
|
||||
- emerge --sync
|
||||
|
||||
To prevent the portage tree from being synced within one day of the
|
||||
previous sync, add the following pillar data for this minion:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
portage:
|
||||
sync_wait_one_day: True
|
||||
|
||||
CLI Example:
|
||||
|
||||
@ -424,28 +470,37 @@ def refresh_db():
|
||||
|
||||
salt '*' pkg.refresh_db
|
||||
'''
|
||||
has_emaint = os.path.isdir('/etc/portage/repos.conf')
|
||||
has_eix = True if 'eix.sync' in __salt__ else False
|
||||
has_webrsync = True if __salt__['makeconf.features_contains']('webrsync-gpg') else False
|
||||
|
||||
# Remove rtag file to keep multiple refreshes from happening in pkg states
|
||||
salt.utils.pkg.clear_rtag(__opts__)
|
||||
if 'eix.sync' in __salt__:
|
||||
return __salt__['eix.sync']()
|
||||
# Option to prevent syncing package tree if done in the last 24 hours
|
||||
if __salt__['pillar.get']('portage:sync_wait_one_day', False):
|
||||
main_repo_root = __salt__['cmd.run']('portageq get_repo_path / gentoo')
|
||||
day = datetime.timedelta(days=1)
|
||||
now = datetime.datetime.now()
|
||||
timestamp = datetime.datetime.fromtimestamp(os.path.getmtime(main_repo_root))
|
||||
if now - timestamp < day:
|
||||
log.info('Did not sync package tree since last sync was done at'
|
||||
' {0}, less than 1 day ago'.format(timestamp))
|
||||
return False
|
||||
|
||||
if 'makeconf.features_contains'in __salt__ and __salt__['makeconf.features_contains']('webrsync-gpg'):
|
||||
# GPG sign verify is supported only for "webrsync"
|
||||
if has_emaint:
|
||||
return __salt__['cmd.retcode']('emaint sync -a') == 0
|
||||
elif has_eix:
|
||||
return __salt__['eix.sync']()
|
||||
elif has_webrsync:
|
||||
# GPG sign verify is supported only for 'webrsync'
|
||||
cmd = 'emerge-webrsync -q'
|
||||
# We prefer 'delta-webrsync' to 'webrsync'
|
||||
if salt.utils.which('emerge-delta-webrsync'):
|
||||
# Prefer 'delta-webrsync' to 'webrsync'
|
||||
if salt.utils.path.which('emerge-delta-webrsync'):
|
||||
cmd = 'emerge-delta-webrsync -q'
|
||||
return __salt__['cmd.retcode'](cmd, python_shell=False) == 0
|
||||
return __salt__['cmd.retcode'](cmd) == 0
|
||||
else:
|
||||
if __salt__['cmd.retcode']('emerge --ask n --quiet --sync',
|
||||
python_shell=False) == 0:
|
||||
return True
|
||||
# We fall back to "webrsync" if "rsync" fails for some reason
|
||||
cmd = 'emerge-webrsync -q'
|
||||
# We prefer 'delta-webrsync' to 'webrsync'
|
||||
if salt.utils.which('emerge-delta-webrsync'):
|
||||
cmd = 'emerge-delta-webrsync -q'
|
||||
return __salt__['cmd.retcode'](cmd, python_shell=False) == 0
|
||||
# Default to deprecated `emerge --sync` form
|
||||
return __salt__['cmd.retcode']('emerge --ask n --quiet --sync') == 0
|
||||
|
||||
|
||||
def _flags_changed(inst_flags, conf_flags):
|
||||
@ -466,72 +521,6 @@ def _flags_changed(inst_flags, conf_flags):
|
||||
return True
|
||||
return True if conf_flags else False
|
||||
|
||||
def process_target(param, version_num):
|
||||
installed = _cpv_to_version(_vartree().dep_bestmatch(param))
|
||||
if version_num is None:
|
||||
keyword, prefix = None, None
|
||||
target = param
|
||||
else:
|
||||
match = re.match('^(~|-|\*)?([<>]?=?)?([^<>=]*)$', version_num)
|
||||
if match:
|
||||
keyword, prefix, verstr = match.groups()
|
||||
# If no prefix characters were supplied and verstr contains a version, use '='
|
||||
if len(verstr) > 0 and verstr[0] != ':' and verstr[0] != '[':
|
||||
prefix = prefix or '='
|
||||
target = '{0}{1}-{2}'.format(prefix, param, verstr)
|
||||
else:
|
||||
target = '{0}{1}'.format(param, verstr)
|
||||
else:
|
||||
raise AttributeError(
|
||||
'Unable to parse version {0} of {1}'.\
|
||||
format(repr(version_num), param))
|
||||
|
||||
changes = {}
|
||||
|
||||
if '[' in target:
|
||||
# Clean target from use flags, since some of them may not exist.
|
||||
# This will raise an AttributeError, or some weird stack trace if portage_config is not patched.
|
||||
uses = portage.dep.dep_getusedeps(target)
|
||||
pv_target = target[:target.rfind('[')]
|
||||
if installed:
|
||||
old = __salt__['portage_config.get_flags_from_package_conf']('use', pv_target)
|
||||
else:
|
||||
old = []
|
||||
__salt__['portage_config.append_use_flags'](pv_target, uses)
|
||||
new = __salt__['portage_config.get_flags_from_package_conf']('use', pv_target)
|
||||
if old != new:
|
||||
changes[pv_target] = {'old': {'use': old},
|
||||
'new': {'use': new}}
|
||||
else:
|
||||
pv_target = target
|
||||
|
||||
if keyword is not None:
|
||||
if keyword == '~':
|
||||
kws = ['~*']
|
||||
elif keyword == '*':
|
||||
kws = ['**']
|
||||
elif keyword == '-':
|
||||
# Or [''] ?
|
||||
kws = ['~ARCH']
|
||||
else:
|
||||
kws = [keyword]
|
||||
if installed:
|
||||
old = __salt__['portage_config.get_flags_from_package_conf']('accept_keywords', pv_target)
|
||||
else:
|
||||
old = []
|
||||
__salt__['portage_config.append_to_package_conf']('accept_keywords', pv_target, kws)
|
||||
new = __salt__['portage_config.get_flags_from_package_conf']('accept_keywords', pv_target)
|
||||
if old != new:
|
||||
changes[pv_target] = {'old': {'accept_keywords': old},
|
||||
'new': {'accept_keywords': new}}
|
||||
|
||||
if installed and not changes:
|
||||
# Check if package has some changed use.
|
||||
all_uses = __salt__['portage_config.get_cleared_flags'](param)
|
||||
if _flags_changed(*all_uses):
|
||||
changes[pv_target] = {'old': {'use': all_uses[0]},
|
||||
'new': {'use': all_uses[1]}}
|
||||
return target, changes
|
||||
|
||||
def install(name=None,
|
||||
refresh=False,
|
||||
@ -543,6 +532,20 @@ def install(name=None,
|
||||
binhost=None,
|
||||
**kwargs):
|
||||
'''
|
||||
.. versionchanged:: 2015.8.12,2016.3.3,2016.11.0
|
||||
On minions running systemd>=205, `systemd-run(1)`_ is now used to
|
||||
isolate commands which modify installed packages from the
|
||||
``salt-minion`` daemon's control group. This is done to keep systemd
|
||||
from killing any emerge commands spawned by Salt when the
|
||||
``salt-minion`` service is restarted. (see ``KillMode`` in the
|
||||
`systemd.kill(5)`_ manpage for more information). If desired, usage of
|
||||
`systemd-run(1)`_ can be suppressed by setting a :mod:`config option
|
||||
<salt.modules.config.get>` called ``systemd.scope``, with a value of
|
||||
``False`` (no quotes).
|
||||
|
||||
.. _`systemd-run(1)`: https://www.freedesktop.org/software/systemd/man/systemd-run.html
|
||||
.. _`systemd.kill(5)`: https://www.freedesktop.org/software/systemd/man/systemd.kill.html
|
||||
|
||||
Install the passed package(s), add refresh=True to sync the portage tree
|
||||
before package is installed.
|
||||
|
||||
@ -642,7 +645,7 @@ def install(name=None,
|
||||
'binhost': binhost,
|
||||
}
|
||||
))
|
||||
if salt.utils.is_true(refresh):
|
||||
if salt.utils.data.is_true(refresh):
|
||||
refresh_db()
|
||||
|
||||
try:
|
||||
@ -655,9 +658,7 @@ def install(name=None,
|
||||
# Handle version kwarg for a single package target
|
||||
if pkgs is None and sources is None:
|
||||
version_num = kwargs.get('version')
|
||||
if version_num:
|
||||
pkg_params = {name: version_num}
|
||||
else:
|
||||
if not version_num:
|
||||
version_num = ''
|
||||
if slot is not None:
|
||||
version_num += ':{0}'.format(slot)
|
||||
@ -681,27 +682,60 @@ def install(name=None,
|
||||
else:
|
||||
bin_opts = []
|
||||
|
||||
if 'oneshot' in kwargs and kwargs.get('oneshot') == True:
|
||||
oneshot = ['--oneshot']
|
||||
else:
|
||||
oneshot = []
|
||||
|
||||
changes = {}
|
||||
|
||||
if not pkg_type == 'repository':
|
||||
targets = pkg_params
|
||||
else:
|
||||
if pkg_type == 'repository':
|
||||
targets = list()
|
||||
for param, version_num in six.iteritems(pkg_params):
|
||||
target, flag_changes = process_target(param, version_num)
|
||||
changes.update(flag_changes)
|
||||
targets.append(target)
|
||||
original_param = param
|
||||
param = _p_to_cp(param)
|
||||
if param is None:
|
||||
raise portage.dep.InvalidAtom(original_param)
|
||||
|
||||
if version_num is None:
|
||||
targets.append(param)
|
||||
else:
|
||||
keyword = None
|
||||
|
||||
match = re.match(r_gt_lt_eq_verstr, version_num)
|
||||
if match:
|
||||
gt_lt, eq, verstr = match.groups()
|
||||
prefix = gt_lt or ''
|
||||
prefix += eq or ''
|
||||
# If no prefix characters were supplied and verstr contains a version, use '='
|
||||
if len(verstr) > 0 and verstr[0] != ':' and verstr[0] != '[':
|
||||
prefix = prefix or '='
|
||||
target = '{0}{1}-{2}'.format(prefix, param, verstr)
|
||||
else:
|
||||
target = '{0}{1}'.format(param, verstr)
|
||||
else:
|
||||
target = '{0}'.format(param)
|
||||
|
||||
if '[' in target:
|
||||
target = target[:target.rfind('[')]
|
||||
|
||||
if not changes:
|
||||
inst_v = version(param)
|
||||
|
||||
# Prevent latest_version from calling refresh_db. Either we
|
||||
# just called it or we were asked not to.
|
||||
if latest_version(param, refresh=False) == inst_v:
|
||||
all_uses = __salt__['portage_config.get_cleared_flags'](param)
|
||||
if _flags_changed(*all_uses):
|
||||
changes[param] = {'version': inst_v,
|
||||
'old': {'use': all_uses[0]},
|
||||
'new': {'use': all_uses[1]}}
|
||||
targets.append(target)
|
||||
else:
|
||||
targets = pkg_params
|
||||
|
||||
cmd = []
|
||||
if salt.utils.systemd.has_scope(__context__) \
|
||||
and __salt__['config.get']('systemd.scope', True):
|
||||
cmd.extend(['systemd-run', '--scope'])
|
||||
cmd.extend(['emerge', '--ask', 'n', '--quiet'])
|
||||
cmd.extend(bin_opts)
|
||||
cmd.extend(emerge_opts)
|
||||
cmd.extend(oneshot)
|
||||
cmd.extend(targets)
|
||||
|
||||
old = list_pkgs()
|
||||
@ -715,22 +749,33 @@ def install(name=None,
|
||||
|
||||
__context__.pop('pkg.list_pkgs', None)
|
||||
new = list_pkgs()
|
||||
changes.update(salt.utils.compare_dicts(old, new))
|
||||
changes.update(salt.utils.data.compare_dicts(old, new))
|
||||
|
||||
if needed_changes:
|
||||
raise CommandExecutionError(
|
||||
'Error occurred installing package(s)',
|
||||
info={'needed changes': needed_changes, 'changes': changes}
|
||||
)
|
||||
if call['retcode'] != 0:
|
||||
raise CommandExecutionError(
|
||||
'unknown error stdout: {}, stderr: {}'.format(call['stdout'], call['stderr'])
|
||||
)
|
||||
|
||||
return changes
|
||||
|
||||
|
||||
def update(pkg, slot=None, fromrepo=None, refresh=False, binhost=None):
|
||||
'''
|
||||
.. versionchanged:: 2015.8.12,2016.3.3,2016.11.0
|
||||
On minions running systemd>=205, `systemd-run(1)`_ is now used to
|
||||
isolate commands which modify installed packages from the
|
||||
``salt-minion`` daemon's control group. This is done to keep systemd
|
||||
from killing any emerge commands spawned by Salt when the
|
||||
``salt-minion`` service is restarted. (see ``KillMode`` in the
|
||||
`systemd.kill(5)`_ manpage for more information). If desired, usage of
|
||||
`systemd-run(1)`_ can be suppressed by setting a :mod:`config option
|
||||
<salt.modules.config.get>` called ``systemd.scope``, with a value of
|
||||
``False`` (no quotes).
|
||||
|
||||
.. _`systemd-run(1)`: https://www.freedesktop.org/software/systemd/man/systemd-run.html
|
||||
.. _`systemd.kill(5)`: https://www.freedesktop.org/software/systemd/man/systemd.kill.html
|
||||
|
||||
Updates the passed package (emerge --update package)
|
||||
|
||||
slot
|
||||
@ -756,7 +801,7 @@ def update(pkg, slot=None, fromrepo=None, refresh=False, binhost=None):
|
||||
|
||||
salt '*' pkg.update <package name>
|
||||
'''
|
||||
if salt.utils.is_true(refresh):
|
||||
if salt.utils.data.is_true(refresh):
|
||||
refresh_db()
|
||||
|
||||
full_atom = pkg
|
||||
@ -768,14 +813,17 @@ def update(pkg, slot=None, fromrepo=None, refresh=False, binhost=None):
|
||||
full_atom = '{0}::{1}'.format(full_atom, fromrepo)
|
||||
|
||||
if binhost == 'try':
|
||||
bin_opts = ['--getbinpkg']
|
||||
bin_opts = ['-g']
|
||||
elif binhost == 'force':
|
||||
bin_opts = ['--getbinpkgonly']
|
||||
bin_opts = ['-G']
|
||||
else:
|
||||
bin_opts = []
|
||||
|
||||
old = list_pkgs()
|
||||
cmd = []
|
||||
if salt.utils.systemd.has_scope(__context__) \
|
||||
and __salt__['config.get']('systemd.scope', True):
|
||||
cmd.extend(['systemd-run', '--scope'])
|
||||
cmd.extend(['emerge',
|
||||
'--ask', 'n',
|
||||
'--quiet',
|
||||
@ -794,7 +842,7 @@ def update(pkg, slot=None, fromrepo=None, refresh=False, binhost=None):
|
||||
|
||||
__context__.pop('pkg.list_pkgs', None)
|
||||
new = list_pkgs()
|
||||
ret = salt.utils.compare_dicts(old, new)
|
||||
ret = salt.utils.data.compare_dicts(old, new)
|
||||
|
||||
if needed_changes:
|
||||
raise CommandExecutionError(
|
||||
@ -807,6 +855,20 @@ def update(pkg, slot=None, fromrepo=None, refresh=False, binhost=None):
|
||||
|
||||
def upgrade(refresh=True, binhost=None, backtrack=3):
|
||||
'''
|
||||
.. versionchanged:: 2015.8.12,2016.3.3,2016.11.0
|
||||
On minions running systemd>=205, `systemd-run(1)`_ is now used to
|
||||
isolate commands which modify installed packages from the
|
||||
``salt-minion`` daemon's control group. This is done to keep systemd
|
||||
from killing any emerge commands spawned by Salt when the
|
||||
``salt-minion`` service is restarted. (see ``KillMode`` in the
|
||||
`systemd.kill(5)`_ manpage for more information). If desired, usage of
|
||||
`systemd-run(1)`_ can be suppressed by setting a :mod:`config option
|
||||
<salt.modules.config.get>` called ``systemd.scope``, with a value of
|
||||
``False`` (no quotes).
|
||||
|
||||
.. _`systemd-run(1)`: https://www.freedesktop.org/software/systemd/man/systemd-run.html
|
||||
.. _`systemd.kill(5)`: https://www.freedesktop.org/software/systemd/man/systemd.kill.html
|
||||
|
||||
Run a full system upgrade (emerge -uDN @world)
|
||||
|
||||
binhost
|
||||
@ -839,7 +901,7 @@ def upgrade(refresh=True, binhost=None, backtrack=3):
|
||||
'result': True,
|
||||
'comment': ''}
|
||||
|
||||
if salt.utils.is_true(refresh):
|
||||
if salt.utils.data.is_true(refresh):
|
||||
refresh_db()
|
||||
|
||||
if binhost == 'try':
|
||||
@ -851,6 +913,9 @@ def upgrade(refresh=True, binhost=None, backtrack=3):
|
||||
|
||||
old = list_pkgs()
|
||||
cmd = []
|
||||
if salt.utils.systemd.has_scope(__context__) \
|
||||
and __salt__['config.get']('systemd.scope', True):
|
||||
cmd.extend(['systemd-run', '--scope'])
|
||||
cmd.extend(['emerge',
|
||||
'--ask', 'n',
|
||||
'--quiet',
|
||||
@ -867,7 +932,7 @@ def upgrade(refresh=True, binhost=None, backtrack=3):
|
||||
python_shell=False)
|
||||
__context__.pop('pkg.list_pkgs', None)
|
||||
new = list_pkgs()
|
||||
ret = salt.utils.compare_dicts(old, new)
|
||||
ret = salt.utils.data.compare_dicts(old, new)
|
||||
|
||||
if result['retcode'] != 0:
|
||||
raise CommandExecutionError(
|
||||
@ -880,6 +945,20 @@ def upgrade(refresh=True, binhost=None, backtrack=3):
|
||||
|
||||
def remove(name=None, slot=None, fromrepo=None, pkgs=None, **kwargs):
|
||||
'''
|
||||
.. versionchanged:: 2015.8.12,2016.3.3,2016.11.0
|
||||
On minions running systemd>=205, `systemd-run(1)`_ is now used to
|
||||
isolate commands which modify installed packages from the
|
||||
``salt-minion`` daemon's control group. This is done to keep systemd
|
||||
from killing any emerge commands spawned by Salt when the
|
||||
``salt-minion`` service is restarted. (see ``KillMode`` in the
|
||||
`systemd.kill(5)`_ manpage for more information). If desired, usage of
|
||||
`systemd-run(1)`_ can be suppressed by setting a :mod:`config option
|
||||
<salt.modules.config.get>` called ``systemd.scope``, with a value of
|
||||
``False`` (no quotes).
|
||||
|
||||
.. _`systemd-run(1)`: https://www.freedesktop.org/software/systemd/man/systemd-run.html
|
||||
.. _`systemd.kill(5)`: https://www.freedesktop.org/software/systemd/man/systemd.kill.html
|
||||
|
||||
Remove packages via emerge --unmerge.
|
||||
|
||||
name
|
||||
@ -930,6 +1009,9 @@ def remove(name=None, slot=None, fromrepo=None, pkgs=None, **kwargs):
|
||||
return {}
|
||||
|
||||
cmd = []
|
||||
if salt.utils.systemd.has_scope(__context__) \
|
||||
and __salt__['config.get']('systemd.scope', True):
|
||||
cmd.extend(['systemd-run', '--scope'])
|
||||
cmd.extend(['emerge',
|
||||
'--ask', 'n',
|
||||
'--quiet',
|
||||
@ -949,7 +1031,7 @@ def remove(name=None, slot=None, fromrepo=None, pkgs=None, **kwargs):
|
||||
|
||||
__context__.pop('pkg.list_pkgs', None)
|
||||
new = list_pkgs()
|
||||
ret = salt.utils.compare_dicts(old, new)
|
||||
ret = salt.utils.data.compare_dicts(old, new)
|
||||
|
||||
if errors:
|
||||
raise CommandExecutionError(
|
||||
@ -962,6 +1044,20 @@ def remove(name=None, slot=None, fromrepo=None, pkgs=None, **kwargs):
|
||||
|
||||
def purge(name=None, slot=None, fromrepo=None, pkgs=None, **kwargs):
|
||||
'''
|
||||
.. versionchanged:: 2015.8.12,2016.3.3,2016.11.0
|
||||
On minions running systemd>=205, `systemd-run(1)`_ is now used to
|
||||
isolate commands which modify installed packages from the
|
||||
``salt-minion`` daemon's control group. This is done to keep systemd
|
||||
from killing any emerge commands spawned by Salt when the
|
||||
``salt-minion`` service is restarted. (see ``KillMode`` in the
|
||||
`systemd.kill(5)`_ manpage for more information). If desired, usage of
|
||||
`systemd-run(1)`_ can be suppressed by setting a :mod:`config option
|
||||
<salt.modules.config.get>` called ``systemd.scope``, with a value of
|
||||
``False`` (no quotes).
|
||||
|
||||
.. _`systemd-run(1)`: https://www.freedesktop.org/software/systemd/man/systemd-run.html
|
||||
.. _`systemd.kill(5)`: https://www.freedesktop.org/software/systemd/man/systemd.kill.html
|
||||
|
||||
Portage does not have a purge, this function calls remove followed
|
||||
by depclean to emulate a purge process
|
||||
|
||||
@ -1048,7 +1144,7 @@ def depclean(name=None, slot=None, fromrepo=None, pkgs=None):
|
||||
python_shell=False)
|
||||
__context__.pop('pkg.list_pkgs', None)
|
||||
new = list_pkgs()
|
||||
return salt.utils.compare_dicts(old, new)
|
||||
return salt.utils.data.compare_dicts(old, new)
|
||||
|
||||
|
||||
def version_cmp(pkg1, pkg2, **kwargs):
|
||||
@ -1068,14 +1164,13 @@ def version_cmp(pkg1, pkg2, **kwargs):
|
||||
# definition (and thus have it show up in the docs), we just pop it out of
|
||||
# the kwargs dict and then raise an exception if any kwargs other than
|
||||
# ignore_epoch were passed.
|
||||
kwargs = salt.utils.clean_kwargs(**kwargs)
|
||||
kwargs = salt.utils.args.clean_kwargs(**kwargs)
|
||||
kwargs.pop('ignore_epoch', None)
|
||||
if kwargs:
|
||||
salt.utils.invalid_kwargs(kwargs)
|
||||
salt.utils.args.invalid_kwargs(kwargs)
|
||||
|
||||
regex = r'^(?:~|-|\*)?([^:\[\~\*]+):?[^\[]*\[?.*$'
|
||||
ver1 = re.match(regex, pkg1)
|
||||
ver2 = re.match(regex, pkg2)
|
||||
ver1 = r_split_ver.match(pkg1)
|
||||
ver2 = r_split_ver.match(pkg2)
|
||||
|
||||
if ver1 and ver2:
|
||||
return portage.versions.vercmp(ver1.group(1), ver2.group(1))
|
||||
@ -1092,7 +1187,7 @@ def version_clean(version):
|
||||
|
||||
salt '*' pkg.version_clean <version_string>
|
||||
'''
|
||||
return re.match(r'^(?:~|-|\*)?[<>]?=?([^<>=:\[\~\-\*]+).*$', version)
|
||||
return re.match(r_strip_ver, version)
|
||||
|
||||
|
||||
def check_extra_requirements(pkgname, pkgver):
|
||||
@ -1107,13 +1202,15 @@ def check_extra_requirements(pkgname, pkgver):
|
||||
'''
|
||||
keyword = None
|
||||
|
||||
match = re.match('^(~|-|\*)?([<>])?(=)?([^<>=]*)$', pkgver)
|
||||
match = re.match('^(~)?([<>])?(=)?([^<>=]*)$', pkgver)
|
||||
if match:
|
||||
keyword, gt_lt, eq, verstr = match.groups()
|
||||
prefix = gt_lt or ''
|
||||
prefix += eq or ''
|
||||
# We need to delete quotes around use flag list elements
|
||||
verstr = verstr.replace("'", "")
|
||||
# If no prefix characters were supplied and verstr contains a version, use '='
|
||||
if len(verstr) > 0 and verstr[0] != ':' and verstr[0] != '[':
|
||||
if verstr[0] != ':' and verstr[0] != '[':
|
||||
prefix = prefix or '='
|
||||
atom = '{0}{1}-{2}'.format(prefix, pkgname, verstr)
|
||||
else:
|
||||
@ -1135,26 +1232,16 @@ def check_extra_requirements(pkgname, pkgver):
|
||||
except KeyError:
|
||||
return False
|
||||
|
||||
des_repo = re.match(r'^.+::([^\[\~\-\*]+).*$', atom)
|
||||
des_repo = re.match(r_split_repo, atom)
|
||||
if des_repo and des_repo.group(1) != cur_repo:
|
||||
return False
|
||||
|
||||
des_uses = set(portage.dep.dep_getusedeps(atom))
|
||||
cur_use = cur_use.split()
|
||||
# TODO: clarify this filter
|
||||
# Filters out -flag that is not currently enabled thus not in cur_use
|
||||
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 is not None:
|
||||
if keyword == '~':
|
||||
v = '~*'
|
||||
elif keyword == '*':
|
||||
v = '**'
|
||||
elif keyword == '-':
|
||||
v = '~ARCH'
|
||||
else:
|
||||
v = keyword
|
||||
if not __salt__['portage_config.has_flag']('accept_keywords', atom, v):
|
||||
return False
|
||||
|
||||
return True
|
@ -1,735 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Configure ``portage(5)``
|
||||
'''
|
||||
|
||||
# Import python libs
|
||||
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
import importlib
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils
|
||||
from salt.utils.files import fopen
|
||||
|
||||
# Import third party libs
|
||||
import salt.ext.six as six
|
||||
# pylint: disable=import-error
|
||||
try:
|
||||
import portage
|
||||
HAS_PORTAGE = True
|
||||
except ImportError:
|
||||
HAS_PORTAGE = False
|
||||
import sys
|
||||
if os.path.isdir('/usr/lib/portage/pym'):
|
||||
try:
|
||||
# In a virtualenv, the portage python path needs to be manually
|
||||
# added
|
||||
sys.path.insert(0, '/usr/lib/portage/pym')
|
||||
import portage
|
||||
HAS_PORTAGE = True
|
||||
except ImportError:
|
||||
pass
|
||||
# pylint: enable=import-error
|
||||
|
||||
|
||||
BASE_PATH = '/etc/portage/package.{0}'
|
||||
SUPPORTED_CONFS = ('accept_keywords', 'env', 'license', 'mask', 'properties',
|
||||
'unmask', 'use')
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def __virtual__():
|
||||
'''
|
||||
Confirm this module is on a Gentoo based system.
|
||||
'''
|
||||
if HAS_PORTAGE and __grains__['os'] == 'Gentoo':
|
||||
return 'portage_config'
|
||||
return (False, 'portage_config execution module cannot be loaded: only available on Gentoo with portage installed.')
|
||||
|
||||
|
||||
def _get_portage():
|
||||
'''
|
||||
portage module must be reloaded or it can't catch the changes
|
||||
in portage.* which had been added after when the module was loaded
|
||||
'''
|
||||
return importlib.reload(portage)
|
||||
|
||||
|
||||
def _porttree():
|
||||
return portage.db[portage.root]['porttree']
|
||||
|
||||
|
||||
def _get_config_file(conf, atom):
|
||||
'''
|
||||
Parse the given atom, allowing access to its parts
|
||||
Success does not mean that the atom exists, just that it
|
||||
is in the correct format.
|
||||
Returns none if the atom is invalid.
|
||||
'''
|
||||
if '*' in atom:
|
||||
parts = portage.dep.Atom(atom, allow_wildcard=True)
|
||||
if not parts:
|
||||
raise AttributeError('Matching c/p form not found for atom {0}'.format(atom))
|
||||
if parts.cp == '*/*':
|
||||
# parts.repo will be empty if there is no repo part
|
||||
relative_path = parts.repo or "gentoo"
|
||||
else:
|
||||
relative_path = os.path.join(*[x for x in os.path.split(parts.cp) if x != '*'])
|
||||
else:
|
||||
relative_path = _p_to_cp(atom)
|
||||
if not relative_path:
|
||||
raise AttributeError('Matching c/p form not found for atom {0}'.format(atom))
|
||||
|
||||
complete_file_path = BASE_PATH.format(conf) + '/' + relative_path
|
||||
|
||||
return complete_file_path
|
||||
|
||||
|
||||
def _p_to_cp(p):
|
||||
'''
|
||||
Convert a package name or a DEPEND atom to category/package format.
|
||||
Raises an exception if program name is ambiguous.
|
||||
'''
|
||||
ret = _porttree().dbapi.xmatch("match-all", p)
|
||||
if ret:
|
||||
return portage.cpv_getkey(ret[0])
|
||||
log.error('_p_to_cp: Package {0} not found by xmatch'.format(p))
|
||||
return None
|
||||
|
||||
|
||||
def _get_cpv(cp, installed=True):
|
||||
'''
|
||||
add version to category/package
|
||||
@cp - name of package in format category/name
|
||||
@installed - boolean value, if False, function returns cpv
|
||||
for latest available package
|
||||
'''
|
||||
if installed:
|
||||
return _get_portage().db[portage.root]['vartree'].dep_bestmatch(cp)
|
||||
else:
|
||||
return _porttree().dep_bestmatch(cp)
|
||||
|
||||
|
||||
def enforce_nice_config():
|
||||
'''
|
||||
Enforce a nice tree structure for /etc/portage/package.* configuration
|
||||
files.
|
||||
|
||||
.. seealso::
|
||||
:py:func:`salt.modules.ebuild.ex_mod_init`
|
||||
for information on automatically running this when pkg is used.
|
||||
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' portage_config.enforce_nice_config
|
||||
'''
|
||||
_convert_all_package_confs_to_dir()
|
||||
_order_all_package_confs()
|
||||
|
||||
|
||||
def _convert_all_package_confs_to_dir():
|
||||
'''
|
||||
Convert all /etc/portage/package.* configuration files to directories.
|
||||
'''
|
||||
for conf_file in SUPPORTED_CONFS:
|
||||
_package_conf_file_to_dir(conf_file)
|
||||
|
||||
|
||||
def _order_all_package_confs():
|
||||
'''
|
||||
Place all entries in /etc/portage/package.* config dirs in the correct
|
||||
file.
|
||||
'''
|
||||
for conf_file in SUPPORTED_CONFS:
|
||||
_package_conf_ordering(conf_file)
|
||||
_unify_keywords()
|
||||
|
||||
|
||||
def _unify_keywords():
|
||||
'''
|
||||
Merge /etc/portage/package.keywords and
|
||||
/etc/portage/package.accept_keywords.
|
||||
'''
|
||||
old_path = BASE_PATH.format('keywords')
|
||||
if os.path.exists(old_path):
|
||||
if os.path.isdir(old_path):
|
||||
for triplet in os.walk(old_path):
|
||||
for file_name in triplet[2]:
|
||||
file_path = '{0}/{1}'.format(triplet[0], file_name)
|
||||
with fopen(file_path) as fh_:
|
||||
for line in fh_:
|
||||
line = line.strip()
|
||||
if line and not line.startswith('#'):
|
||||
append_to_package_conf(
|
||||
'accept_keywords', string=line)
|
||||
shutil.rmtree(old_path)
|
||||
else:
|
||||
with fopen(old_path) as fh_:
|
||||
for line in fh_:
|
||||
line = line.strip()
|
||||
if line and not line.startswith('#'):
|
||||
append_to_package_conf('accept_keywords', string=line)
|
||||
os.remove(old_path)
|
||||
|
||||
|
||||
def _package_conf_file_to_dir(file_name):
|
||||
'''
|
||||
Convert a config file to a config directory.
|
||||
'''
|
||||
if file_name in SUPPORTED_CONFS:
|
||||
path = BASE_PATH.format(file_name)
|
||||
if os.path.exists(path):
|
||||
if os.path.isdir(path):
|
||||
return False
|
||||
else:
|
||||
os.rename(path, path + '.tmpbak')
|
||||
os.mkdir(path, 0o755)
|
||||
with fopen(path + '.tmpbak') as fh_:
|
||||
for line in fh_:
|
||||
line = line.strip()
|
||||
if line and not line.startswith('#'):
|
||||
append_to_package_conf(file_name, string=line)
|
||||
os.remove(path + '.tmpbak')
|
||||
return True
|
||||
else:
|
||||
os.mkdir(path, 0o755)
|
||||
return True
|
||||
|
||||
|
||||
def _package_conf_ordering(conf, clean=True, keep_backup=False):
|
||||
'''
|
||||
Move entries in the correct file.
|
||||
'''
|
||||
if conf in SUPPORTED_CONFS:
|
||||
rearrange = []
|
||||
path = BASE_PATH.format(conf)
|
||||
|
||||
backup_files = []
|
||||
|
||||
for triplet in os.walk(path):
|
||||
for file_name in triplet[2]:
|
||||
file_path = '{0}/{1}'.format(triplet[0], file_name)
|
||||
cp = triplet[0][len(path) + 1:] + '/' + file_name
|
||||
|
||||
shutil.copy(file_path, file_path + '.bak')
|
||||
backup_files.append(file_path + '.bak')
|
||||
|
||||
if cp[0] == '/' or cp.split('/') > 2:
|
||||
with fopen(file_path) as fp_:
|
||||
rearrange.extend(fp_.readlines())
|
||||
os.remove(file_path)
|
||||
else:
|
||||
new_contents = ''
|
||||
with fopen(file_path, 'r+') as file_handler:
|
||||
for line in file_handler:
|
||||
try:
|
||||
atom = line.strip().split()[0]
|
||||
except IndexError:
|
||||
new_contents += line
|
||||
else:
|
||||
if atom[0] == '#' or \
|
||||
portage.dep_getkey(atom) == cp:
|
||||
new_contents += line
|
||||
else:
|
||||
rearrange.append(line.strip())
|
||||
if len(new_contents) != 0:
|
||||
file_handler.seek(0)
|
||||
file_handler.truncate(len(new_contents))
|
||||
file_handler.write(new_contents)
|
||||
|
||||
if len(new_contents) == 0:
|
||||
os.remove(file_path)
|
||||
|
||||
for line in rearrange:
|
||||
append_to_package_conf(conf, string=line)
|
||||
|
||||
if not keep_backup:
|
||||
for bfile in backup_files:
|
||||
try:
|
||||
os.remove(bfile)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
if clean:
|
||||
for triplet in os.walk(path):
|
||||
if len(triplet[1]) == 0 and len(triplet[2]) == 0 and \
|
||||
triplet[0] != path:
|
||||
shutil.rmtree(triplet[0])
|
||||
|
||||
|
||||
def _check_accept_keywords(approved, flag):
|
||||
'''check compatibility of accept_keywords'''
|
||||
if flag in approved:
|
||||
return False
|
||||
elif (flag.startswith('~') and flag[1:] in approved) \
|
||||
or ('~'+flag in approved):
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
def _merge_flags(new_flags, old_flags=None, conf='any'):
|
||||
'''
|
||||
Merges multiple lists of flags removing duplicates and resolving conflicts
|
||||
giving priority to lasts lists.
|
||||
'''
|
||||
if not old_flags:
|
||||
old_flags = []
|
||||
args = [old_flags, new_flags]
|
||||
if conf == 'accept_keywords':
|
||||
tmp = new_flags + \
|
||||
[i for i in old_flags if _check_accept_keywords(new_flags, i)]
|
||||
else:
|
||||
tmp = portage.flatten(args)
|
||||
flags = {}
|
||||
for flag in tmp:
|
||||
if flag[0] == '-':
|
||||
flags[flag[1:]] = False
|
||||
else:
|
||||
flags[flag] = True
|
||||
tmp = []
|
||||
for key, val in six.iteritems(flags):
|
||||
if val:
|
||||
tmp.append(key)
|
||||
else:
|
||||
tmp.append('-' + key)
|
||||
|
||||
# Next sort is just aesthetic, can be commented for a small performance
|
||||
# boost
|
||||
tmp.sort(key=lambda x: x.lstrip('-'))
|
||||
return tmp
|
||||
|
||||
|
||||
def append_to_package_conf(conf, atom='', flags=None, string='', overwrite=False):
|
||||
'''
|
||||
Append a string or a list of flags for a given package or DEPEND atom to a
|
||||
given configuration file.
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' portage_config.append_to_package_conf use string="app-admin/salt ldap -libvirt"
|
||||
salt '*' portage_config.append_to_package_conf use atom="> = app-admin/salt-0.14.1" flags="['ldap', '-libvirt']"
|
||||
'''
|
||||
if flags is None:
|
||||
flags = []
|
||||
if conf in SUPPORTED_CONFS:
|
||||
if not string:
|
||||
if '/' not in atom:
|
||||
atom = _p_to_cp(atom)
|
||||
if not atom:
|
||||
return
|
||||
string = '{0} {1}'.format(atom, ' '.join(flags))
|
||||
new_flags = list(flags)
|
||||
else:
|
||||
atom = string.strip().split()[0]
|
||||
new_flags = [flag for flag in string.strip().split(' ') if flag][1:]
|
||||
if '/' not in atom:
|
||||
atom = _p_to_cp(atom)
|
||||
string = '{0} {1}'.format(atom, ' '.join(new_flags))
|
||||
if not atom:
|
||||
return
|
||||
|
||||
to_delete_if_empty = []
|
||||
if conf == 'accept_keywords':
|
||||
if '-~ARCH' in new_flags:
|
||||
new_flags.remove('-~ARCH')
|
||||
to_delete_if_empty.append(atom)
|
||||
|
||||
if '~ARCH' in new_flags:
|
||||
new_flags.remove('~ARCH')
|
||||
append_to_package_conf(conf, string=atom, overwrite=overwrite)
|
||||
if not new_flags:
|
||||
return
|
||||
|
||||
# Next sort is just aesthetic, can be commented for a small performance
|
||||
# boost
|
||||
new_flags.sort(key=lambda x: x.lstrip('-'))
|
||||
|
||||
complete_file_path = _get_config_file(conf, atom)
|
||||
pdir = os.path.dirname(complete_file_path)
|
||||
if not os.path.exists(pdir):
|
||||
os.makedirs(pdir, 0o755)
|
||||
|
||||
try:
|
||||
shutil.copy(complete_file_path, complete_file_path + '.bak')
|
||||
except IOError:
|
||||
pass
|
||||
|
||||
try:
|
||||
file_handler = fopen(complete_file_path, 'r+') # pylint: disable=resource-leakage
|
||||
except IOError:
|
||||
file_handler = fopen(complete_file_path, 'w+') # pylint: disable=resource-leakage
|
||||
|
||||
new_contents = ''
|
||||
added = False
|
||||
|
||||
try:
|
||||
for l in file_handler:
|
||||
l_strip = l.strip()
|
||||
if l_strip == '':
|
||||
new_contents += '\n'
|
||||
elif l_strip[0] == '#':
|
||||
new_contents += l
|
||||
elif l_strip.split()[0] == atom:
|
||||
if l_strip in to_delete_if_empty:
|
||||
continue
|
||||
if overwrite:
|
||||
new_contents += string.strip() + '\n'
|
||||
added = True
|
||||
else:
|
||||
old_flags = [flag for flag in l_strip.split(' ') if flag][1:]
|
||||
if conf == 'accept_keywords':
|
||||
if not old_flags:
|
||||
new_contents += l
|
||||
if not new_flags:
|
||||
added = True
|
||||
continue
|
||||
elif not new_flags:
|
||||
continue
|
||||
merged_flags = _merge_flags(new_flags, old_flags, conf)
|
||||
if merged_flags:
|
||||
new_contents += '{0} {1}\n'.format(
|
||||
atom, ' '.join(merged_flags))
|
||||
else:
|
||||
new_contents += '{0}\n'.format(atom)
|
||||
added = True
|
||||
else:
|
||||
new_contents += l
|
||||
if not added:
|
||||
new_contents += string.strip() + '\n'
|
||||
except Exception as exc:
|
||||
log.error('Failed to write to %s: %s', complete_file_path, exc)
|
||||
else:
|
||||
file_handler.seek(0)
|
||||
file_handler.truncate(len(new_contents))
|
||||
file_handler.write(new_contents)
|
||||
finally:
|
||||
file_handler.close()
|
||||
|
||||
try:
|
||||
os.remove(complete_file_path + '.bak')
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
def append_use_flags(atom, uses=None, overwrite=False):
|
||||
'''
|
||||
Append a list of use flags for a given package or DEPEND atom
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' portage_config.append_use_flags "app-admin/salt[ldap, -libvirt]"
|
||||
salt '*' portage_config.append_use_flags ">=app-admin/salt-0.14.1" "['ldap', '-libvirt']"
|
||||
'''
|
||||
if not uses:
|
||||
uses = portage.dep.dep_getusedeps(atom)
|
||||
atom = atom[:atom.rfind('[')]
|
||||
if len(uses) == 0:
|
||||
return
|
||||
append_to_package_conf('use', atom=atom, flags=uses, overwrite=overwrite)
|
||||
|
||||
|
||||
def get_flags_from_package_conf(conf, atom):
|
||||
'''
|
||||
Get flags for a given package or DEPEND atom.
|
||||
Warning: This only works if the configuration files tree is in the correct
|
||||
format (the one enforced by enforce_nice_config)
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' portage_config.get_flags_from_package_conf license salt
|
||||
'''
|
||||
if conf in SUPPORTED_CONFS:
|
||||
if '/' not in atom:
|
||||
atom = _p_to_cp(atom)
|
||||
if not atom:
|
||||
raise AttributeError('Matching c/p form not found for atom {0}'.format(atom))
|
||||
package_file = _get_config_file(conf, atom)
|
||||
|
||||
has_wildcard = '*' in atom
|
||||
if has_wildcard:
|
||||
match_list = set(atom)
|
||||
else:
|
||||
try:
|
||||
match_list = set(_porttree().dbapi.xmatch("match-all", atom))
|
||||
except AttributeError:
|
||||
return []
|
||||
|
||||
flags = []
|
||||
try:
|
||||
with fopen(package_file) as fp_:
|
||||
for line in fp_:
|
||||
line = line.strip()
|
||||
line_package = line.split()[0]
|
||||
|
||||
if has_wildcard:
|
||||
found_match = line_package == atom
|
||||
else:
|
||||
line_list = _porttree().dbapi.xmatch("match-all", line_package)
|
||||
found_match = match_list.issubset(line_list)
|
||||
|
||||
if found_match:
|
||||
f_tmp = [flag for flag in line.strip().split(' ') if flag][1:]
|
||||
if f_tmp:
|
||||
flags.extend(f_tmp)
|
||||
else:
|
||||
flags.append('~ARCH')
|
||||
|
||||
return _merge_flags(flags)
|
||||
except IOError:
|
||||
return []
|
||||
|
||||
|
||||
def has_flag(conf, atom, flag):
|
||||
'''
|
||||
Verify if the given package or DEPEND atom has the given flag.
|
||||
Warning: This only works if the configuration files tree is in the correct
|
||||
format (the one enforced by enforce_nice_config)
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' portage_config.has_flag license salt Apache-2.0
|
||||
'''
|
||||
if flag in get_flags_from_package_conf(conf, atom):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def get_missing_flags(conf, atom, flags):
|
||||
'''
|
||||
Find out which of the given flags are currently not set.
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' portage_config.get_missing_flags use salt "['ldap', '-libvirt', 'openssl']"
|
||||
'''
|
||||
new_flags = []
|
||||
for flag in flags:
|
||||
if not has_flag(conf, atom, flag):
|
||||
new_flags.append(flag)
|
||||
return new_flags
|
||||
|
||||
|
||||
def has_use(atom, use):
|
||||
'''
|
||||
Verify if the given package or DEPEND atom has the given use flag.
|
||||
Warning: This only works if the configuration files tree is in the correct
|
||||
format (the one enforced by enforce_nice_config)
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' portage_config.has_use salt libvirt
|
||||
'''
|
||||
return has_flag('use', atom, use)
|
||||
|
||||
|
||||
def is_present(conf, atom):
|
||||
'''
|
||||
Tell if a given package or DEPEND atom is present in the configuration
|
||||
files tree.
|
||||
Warning: This only works if the configuration files tree is in the correct
|
||||
format (the one enforced by enforce_nice_config)
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' portage_config.is_present unmask salt
|
||||
'''
|
||||
if conf in SUPPORTED_CONFS:
|
||||
if not isinstance(atom, portage.dep.Atom):
|
||||
atom = portage.dep.Atom(atom, allow_wildcard=True)
|
||||
has_wildcard = '*' in atom
|
||||
|
||||
package_file = _get_config_file(conf, str(atom))
|
||||
|
||||
# wildcards are valid in confs
|
||||
if has_wildcard:
|
||||
match_list = set(atom)
|
||||
else:
|
||||
match_list = set(_porttree().dbapi.xmatch("match-all", atom))
|
||||
|
||||
try:
|
||||
with fopen(package_file) as fp_:
|
||||
for line in fp_:
|
||||
line = line.strip()
|
||||
line_package = line.split()[0]
|
||||
|
||||
if has_wildcard:
|
||||
if line_package == str(atom):
|
||||
return True
|
||||
else:
|
||||
line_list = _porttree().dbapi.xmatch("match-all", line_package)
|
||||
if match_list.issubset(line_list):
|
||||
return True
|
||||
except IOError:
|
||||
pass
|
||||
return False
|
||||
|
||||
|
||||
def get_iuse(cp):
|
||||
'''
|
||||
.. versionadded:: 2015.8.0
|
||||
|
||||
Gets the current IUSE flags from the tree.
|
||||
|
||||
@type: cpv: string
|
||||
@param cpv: cat/pkg
|
||||
@rtype list
|
||||
@returns [] or the list of IUSE flags
|
||||
'''
|
||||
cpv = _get_cpv(cp)
|
||||
try:
|
||||
# aux_get might return dupes, so run them through set() to remove them
|
||||
dirty_flags = _porttree().dbapi.aux_get(cpv, ["IUSE"])[0].split()
|
||||
return list(set(dirty_flags))
|
||||
except Exception as e:
|
||||
return []
|
||||
|
||||
|
||||
def get_installed_use(cp, use="USE"):
|
||||
'''
|
||||
.. versionadded:: 2015.8.0
|
||||
|
||||
Gets the installed USE flags from the VARDB.
|
||||
|
||||
@type: cp: string
|
||||
@param cp: cat/pkg
|
||||
@type use: string
|
||||
@param use: 1 of ["USE", "PKGUSE"]
|
||||
@rtype list
|
||||
@returns [] or the list of IUSE flags
|
||||
'''
|
||||
portage = _get_portage()
|
||||
cpv = _get_cpv(cp)
|
||||
return portage.db[portage.root]["vartree"].dbapi.aux_get(cpv, [use])[0].split()
|
||||
|
||||
|
||||
def filter_flags(use, use_expand_hidden, usemasked, useforced):
|
||||
'''
|
||||
.. versionadded:: 2015.8.0
|
||||
|
||||
Filter function to remove hidden or otherwise not normally
|
||||
visible USE flags from a list.
|
||||
|
||||
@type use: list
|
||||
@param use: the USE flag list to be filtered.
|
||||
@type use_expand_hidden: list
|
||||
@param use_expand_hidden: list of flags hidden.
|
||||
@type usemasked: list
|
||||
@param usemasked: list of masked USE flags.
|
||||
@type useforced: list
|
||||
@param useforced: the forced USE flags.
|
||||
@rtype: list
|
||||
@return the filtered USE flags.
|
||||
'''
|
||||
portage = _get_portage()
|
||||
# clean out some environment flags, since they will most probably
|
||||
# be confusing for the user
|
||||
for f in use_expand_hidden:
|
||||
f = f.lower()+ "_"
|
||||
for x in use:
|
||||
if f in x:
|
||||
use.remove(x)
|
||||
# clean out any arch's
|
||||
archlist = portage.settings["PORTAGE_ARCHLIST"].split()
|
||||
for a in use[:]:
|
||||
if a in archlist:
|
||||
use.remove(a)
|
||||
# dbl check if any from usemasked or useforced are still there
|
||||
masked = usemasked + useforced
|
||||
for a in use[:]:
|
||||
if a in masked:
|
||||
use.remove(a)
|
||||
return use
|
||||
|
||||
|
||||
def get_all_cpv_use(cp):
|
||||
'''
|
||||
.. versionadded:: 2015.8.0
|
||||
|
||||
Uses portage to determine final USE flags and settings for an emerge.
|
||||
|
||||
@type cp: string
|
||||
@param cp: eg cat/pkg
|
||||
@rtype: lists
|
||||
@return use, use_expand_hidden, usemask, useforce
|
||||
'''
|
||||
cpv = _get_cpv(cp)
|
||||
portage = _get_portage()
|
||||
use = None
|
||||
_porttree().dbapi.settings.unlock()
|
||||
try:
|
||||
_porttree().dbapi.settings.setcpv(cpv, mydb=portage.portdb)
|
||||
use = portage.settings['PORTAGE_USE'].split()
|
||||
use_expand_hidden = portage.settings["USE_EXPAND_HIDDEN"].split()
|
||||
usemask = list(_porttree().dbapi.settings.usemask)
|
||||
useforce = list(_porttree().dbapi.settings.useforce)
|
||||
except KeyError:
|
||||
_porttree().dbapi.settings.reset()
|
||||
_porttree().dbapi.settings.lock()
|
||||
return [], [], [], []
|
||||
# reset cpv filter
|
||||
_porttree().dbapi.settings.reset()
|
||||
_porttree().dbapi.settings.lock()
|
||||
return use, use_expand_hidden, usemask, useforce
|
||||
|
||||
|
||||
def get_cleared_flags(cp):
|
||||
'''
|
||||
.. versionadded:: 2015.8.0
|
||||
|
||||
Uses portage for compare use flags which is used for installing package
|
||||
and use flags which now exist int /etc/portage/package.use/
|
||||
|
||||
@type cp: string
|
||||
@param cp: eg cat/pkg
|
||||
@rtype: tuple
|
||||
@rparam: tuple with two lists - list of used flags and
|
||||
list of flags which will be used
|
||||
'''
|
||||
cpv = _get_cpv(cp)
|
||||
final_use, use_expand_hidden, usemasked, useforced = get_all_cpv_use(cpv)
|
||||
inst_flags = filter_flags(get_installed_use(cpv), use_expand_hidden,
|
||||
usemasked, useforced)
|
||||
final_flags = filter_flags(final_use, use_expand_hidden,
|
||||
usemasked, useforced)
|
||||
return inst_flags, final_flags
|
||||
|
||||
|
||||
def is_changed_uses(cp):
|
||||
'''
|
||||
.. versionadded:: 2015.8.0
|
||||
|
||||
Uses portage for determine if the use flags of installed package
|
||||
is compatible with use flags in portage configs.
|
||||
|
||||
@type cp: string
|
||||
@param cp: eg cat/pkg
|
||||
'''
|
||||
cpv = _get_cpv(cp)
|
||||
i_flags, conf_flags = get_cleared_flags(cpv)
|
||||
for i in i_flags:
|
||||
try:
|
||||
conf_flags.remove(i)
|
||||
except ValueError:
|
||||
return True
|
||||
return True if conf_flags else False
|
@ -1,284 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Manage ini files
|
||||
================
|
||||
|
||||
:maintainer: <akilesh1597@gmail.com>
|
||||
:maturity: new
|
||||
:depends: re
|
||||
:platform: all
|
||||
|
||||
'''
|
||||
|
||||
# Import Python libs
|
||||
|
||||
|
||||
# Import Salt libs
|
||||
import salt.ext.six as six
|
||||
|
||||
__virtualname__ = 'ini'
|
||||
|
||||
|
||||
def __virtual__():
|
||||
'''
|
||||
Only load if the ini module is available
|
||||
'''
|
||||
return __virtualname__ if 'ini.set_option' in __salt__ else False
|
||||
|
||||
|
||||
def options_present(name, sections=None, separator='=', strict=False):
|
||||
'''
|
||||
.. code-block:: yaml
|
||||
|
||||
/home/saltminion/api-paste.ini:
|
||||
ini.options_present:
|
||||
- separator: '='
|
||||
- strict: True
|
||||
- sections:
|
||||
test:
|
||||
testkey: 'testval'
|
||||
secondoption: 'secondvalue'
|
||||
test1:
|
||||
testkey1: 'testval121'
|
||||
|
||||
options present in file and not specified in sections
|
||||
dict will be untouched, unless `strict: True` flag is
|
||||
used
|
||||
|
||||
changes dict will contain the list of changes made
|
||||
'''
|
||||
ret = {'name': name,
|
||||
'changes': {},
|
||||
'result': True,
|
||||
'comment': 'No anomaly detected'
|
||||
}
|
||||
if __opts__['test']:
|
||||
ret['result'] = True
|
||||
ret['comment'] = ''
|
||||
for section in sections or {}:
|
||||
section_name = ' in section ' + section if section != 'DEFAULT_IMPLICIT' else ''
|
||||
try:
|
||||
cur_section = __salt__['ini.get_section'](name, section, separator)
|
||||
except IOError as err:
|
||||
ret['comment'] = "{0}".format(err)
|
||||
ret['result'] = False
|
||||
return ret
|
||||
for key in sections[section]:
|
||||
cur_value = cur_section.get(key)
|
||||
if cur_value == str(sections[section][key]):
|
||||
ret['comment'] += 'Key {0}{1} unchanged.\n'.format(key, section_name)
|
||||
continue
|
||||
ret['comment'] += 'Changed key {0}{1}.\n'.format(key, section_name)
|
||||
ret['result'] = None
|
||||
if ret['comment'] == '':
|
||||
ret['comment'] = 'No changes detected.'
|
||||
return ret
|
||||
try:
|
||||
changes = {}
|
||||
if sections:
|
||||
for section_name, section_body in sections.items():
|
||||
changes[section_name] = {}
|
||||
if strict:
|
||||
original = __salt__['ini.get_section'](name, section_name, separator)
|
||||
for key_to_remove in set(original.keys()).difference(section_body.keys()):
|
||||
orig_value = __salt__['ini.get_option'](name, section_name, key_to_remove, separator)
|
||||
__salt__['ini.remove_option'](name, section_name, key_to_remove, separator)
|
||||
changes[section_name].update({key_to_remove: ''})
|
||||
changes[section_name].update({key_to_remove: {'before': orig_value,
|
||||
'after': None}})
|
||||
options_updated = __salt__['ini.set_option'](name, {section_name: section_body}, separator)
|
||||
if options_updated:
|
||||
changes[section_name].update(options_updated[section_name])
|
||||
else:
|
||||
changes = __salt__['ini.set_option'](name, sections, separator)
|
||||
except IOError as err:
|
||||
ret['comment'] = "{0}".format(err)
|
||||
ret['result'] = False
|
||||
return ret
|
||||
if 'error' in changes:
|
||||
ret['result'] = False
|
||||
ret['comment'] = 'Errors encountered. {0}'.format(changes['error'])
|
||||
ret['changes'] = {}
|
||||
else:
|
||||
if all(value == {} for value in changes.values()):
|
||||
ret['changes'] = {}
|
||||
ret['comment'] = 'No changes take effect'
|
||||
else:
|
||||
ret['changes'] = changes
|
||||
ret['comment'] = 'Changes take effect'
|
||||
return ret
|
||||
|
||||
|
||||
def options_absent(name, sections=None, separator='='):
|
||||
'''
|
||||
.. code-block:: yaml
|
||||
|
||||
/home/saltminion/api-paste.ini:
|
||||
ini.options_absent:
|
||||
- separator: '='
|
||||
- sections:
|
||||
test:
|
||||
- testkey
|
||||
- secondoption
|
||||
test1:
|
||||
- testkey1
|
||||
|
||||
options present in file and not specified in sections
|
||||
dict will be untouched
|
||||
|
||||
changes dict will contain the list of changes made
|
||||
'''
|
||||
ret = {'name': name,
|
||||
'changes': {},
|
||||
'result': True,
|
||||
'comment': 'No anomaly detected'
|
||||
}
|
||||
if __opts__['test']:
|
||||
ret['result'] = True
|
||||
ret['comment'] = ''
|
||||
for section in sections or {}:
|
||||
section_name = ' in section ' + section if section != 'DEFAULT_IMPLICIT' else ''
|
||||
try:
|
||||
cur_section = __salt__['ini.get_section'](name, section, separator)
|
||||
except IOError as err:
|
||||
ret['comment'] = "{0}".format(err)
|
||||
ret['result'] = False
|
||||
return ret
|
||||
for key in sections[section]:
|
||||
cur_value = cur_section.get(key)
|
||||
if not cur_value:
|
||||
ret['comment'] += 'Key {0}{1} does not exist.\n'.format(key, section_name)
|
||||
continue
|
||||
ret['comment'] += 'Deleted key {0}{1}.\n'.format(key, section_name)
|
||||
ret['result'] = None
|
||||
if ret['comment'] == '':
|
||||
ret['comment'] = 'No changes detected.'
|
||||
return ret
|
||||
sections = sections or {}
|
||||
for section, keys in six.iteritems(sections):
|
||||
for key in keys:
|
||||
try:
|
||||
current_value = __salt__['ini.remove_option'](name, section, key, separator)
|
||||
except IOError as err:
|
||||
ret['comment'] = "{0}".format(err)
|
||||
ret['result'] = False
|
||||
return ret
|
||||
if not current_value:
|
||||
continue
|
||||
if section not in ret['changes']:
|
||||
ret['changes'].update({section: {}})
|
||||
ret['changes'][section].update({key: current_value})
|
||||
ret['comment'] = 'Changes take effect'
|
||||
return ret
|
||||
|
||||
|
||||
def sections_present(name, sections=None, separator='='):
|
||||
'''
|
||||
.. code-block:: yaml
|
||||
|
||||
/home/saltminion/api-paste.ini:
|
||||
ini.sections_present:
|
||||
- separator: '='
|
||||
- sections:
|
||||
- section_one
|
||||
- section_two
|
||||
|
||||
This will only create empty sections. To also create options, use
|
||||
options_present state
|
||||
|
||||
options present in file and not specified in sections will be deleted
|
||||
changes dict will contain the sections that changed
|
||||
'''
|
||||
ret = {'name': name,
|
||||
'changes': {},
|
||||
'result': True,
|
||||
'comment': 'No anomaly detected'
|
||||
}
|
||||
if __opts__['test']:
|
||||
ret['result'] = True
|
||||
ret['comment'] = ''
|
||||
for section in sections or {}:
|
||||
try:
|
||||
cur_section = __salt__['ini.get_section'](name, section, separator)
|
||||
except IOError as err:
|
||||
ret['result'] = False
|
||||
ret['comment'] = "{0}".format(err)
|
||||
return ret
|
||||
if cmp(dict(sections[section]), cur_section) == 0:
|
||||
ret['comment'] += 'Section unchanged {0}.\n'.format(section)
|
||||
continue
|
||||
elif cur_section:
|
||||
ret['comment'] += 'Changed existing section {0}.\n'.format(section)
|
||||
else:
|
||||
ret['comment'] += 'Created new section {0}.\n'.format(section)
|
||||
ret['result'] = None
|
||||
if ret['comment'] == '':
|
||||
ret['comment'] = 'No changes detected.'
|
||||
return ret
|
||||
section_to_update = {}
|
||||
for section_name in sections or []:
|
||||
section_to_update.update({section_name: {}})
|
||||
try:
|
||||
changes = __salt__['ini.set_option'](name, section_to_update, separator)
|
||||
except IOError as err:
|
||||
ret['result'] = False
|
||||
ret['comment'] = "{0}".format(err)
|
||||
return ret
|
||||
if 'error' in changes:
|
||||
ret['result'] = False
|
||||
ret['changes'] = 'Errors encountered {0}'.format(changes['error'])
|
||||
return ret
|
||||
ret['changes'] = changes
|
||||
ret['comment'] = 'Changes take effect'
|
||||
return ret
|
||||
|
||||
|
||||
def sections_absent(name, sections=None, separator='='):
|
||||
'''
|
||||
.. code-block:: yaml
|
||||
|
||||
/home/saltminion/api-paste.ini:
|
||||
ini.sections_absent:
|
||||
- separator: '='
|
||||
- sections:
|
||||
- test
|
||||
- test1
|
||||
|
||||
options present in file and not specified in sections will be deleted
|
||||
changes dict will contain the sections that changed
|
||||
'''
|
||||
ret = {'name': name,
|
||||
'changes': {},
|
||||
'result': True,
|
||||
'comment': 'No anomaly detected'
|
||||
}
|
||||
if __opts__['test']:
|
||||
ret['result'] = True
|
||||
ret['comment'] = ''
|
||||
for section in sections or []:
|
||||
try:
|
||||
cur_section = __salt__['ini.get_section'](name, section, separator)
|
||||
except IOError as err:
|
||||
ret['result'] = False
|
||||
ret['comment'] = "{0}".format(err)
|
||||
return ret
|
||||
if not cur_section:
|
||||
ret['comment'] += 'Section {0} does not exist.\n'.format(section)
|
||||
continue
|
||||
ret['comment'] += 'Deleted section {0}.\n'.format(section)
|
||||
ret['result'] = None
|
||||
if ret['comment'] == '':
|
||||
ret['comment'] = 'No changes detected.'
|
||||
return ret
|
||||
for section in sections or []:
|
||||
try:
|
||||
cur_section = __salt__['ini.remove_section'](name, section, separator)
|
||||
except IOError as err:
|
||||
ret['result'] = False
|
||||
ret['comment'] = "{0}".format(err)
|
||||
return ret
|
||||
if not cur_section:
|
||||
continue
|
||||
ret['changes'][section] = cur_section
|
||||
ret['comment'] = 'Changes take effect'
|
||||
return ret
|
File diff suppressed because it is too large
Load Diff
@ -28,9 +28,6 @@ include:
|
||||
|
||||
{% set main_reponame = salt['pillar.get']('salt:repos:main:name', 'local') %}
|
||||
{% set main_remote_uri = salt['pillar.get']('salt:repos:main:remote') %}
|
||||
{% set common_reponame = salt['pillar.get']('salt:repos:common:name', 'common') %}
|
||||
{% set common_remote_uri = salt['pillar.get']('salt:repos:common:remote',
|
||||
"git+ssh://git@git.bakka.su/salt-common.git") %}
|
||||
{% set extra_repos = salt['pillar.get']('salt:repos:extra', {} ) %}
|
||||
{% set extra_reponames = extra_repos|list %}
|
||||
|
||||
@ -122,26 +119,6 @@ salt-repo-{{ reponame }}-{{ branch }}:
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
/var/salt/{{ common_reponame }}:
|
||||
file.directory:
|
||||
- user: root
|
||||
- group: root
|
||||
- file_mode: 644
|
||||
- dir_mode: 755
|
||||
git.latest:
|
||||
- name: {{ common_remote_uri }}
|
||||
- target: /var/salt/{{ common_reponame }}
|
||||
- rev: master
|
||||
- force_clone: True
|
||||
- force_checkout: True
|
||||
- force_fetch: True
|
||||
- force_reset: True
|
||||
- identity: /var/salt/ssh/salt
|
||||
- require:
|
||||
- file: /var/salt/ssh/salt
|
||||
- require_in:
|
||||
- file: /etc/salt/master.d/roots.conf
|
||||
|
||||
salt-roots-restart:
|
||||
service.running:
|
||||
- name: {{ 'salt-minion' if salt['grains.get']('salt:masterless', False) else 'salt-master' }}
|
||||
|
@ -6,7 +6,6 @@ from glob import glob
|
||||
|
||||
d_salt = '/var/salt'
|
||||
main_reponame = __salt__['pillar.get']('salt:repos:main:name', 'local')
|
||||
common_reponame = __salt__['pillar.get']('salt:repos:common:name', 'common')
|
||||
extra_repos = __salt__['pillar.get']('salt:repos:extra', {})
|
||||
branches = filter(lambda x: x not in (main_reponame, '.git', '_mirror'),
|
||||
map(path.basename,
|
||||
@ -19,20 +18,23 @@ for branch in branches:
|
||||
env_name = 'base'
|
||||
else:
|
||||
env_name = branch
|
||||
content['file_roots'][env_name] = (
|
||||
[path.join(d_salt, main_reponame, branch, 'sls'),
|
||||
path.join(d_salt, 'private', 'files'),
|
||||
path.join(d_salt, common_reponame, 'sls')] +
|
||||
filter(path.isdir, [path.join(d_salt, repo_name, extra_repos[repo_name].get('branch', branch), 'sls')
|
||||
for repo_name in extra_repos.keys()]))
|
||||
content['pillar_roots'][env_name] = (
|
||||
[path.join(d_salt, main_reponame, branch, 'pillar'),
|
||||
path.join(d_salt, 'private', 'pillar'),
|
||||
path.join(d_salt, common_reponame, 'pillar')] +
|
||||
filter(path.isdir, [path.join(d_salt, repo_name, extra_repos[repo_name].get('branch', branch), 'pillar')
|
||||
for repo_name in extra_repos.keys()]))
|
||||
content['file_roots'][env_name] = [path.join(d_salt, main_reponame, branch, 'sls')]
|
||||
content['pillar_roots'][env_name] = [path.join(d_salt, main_reponame, branch, 'pillar')]
|
||||
for repo_name, data in extra_repos.items():
|
||||
if 'branch' in data:
|
||||
content['file_roots'][env_name].append(path.join(d_salt, repo_name, data['branch'], 'sls'))
|
||||
content['pillar_roots'][env_name].append(path.join(d_salt, repo_name, data['branch'], 'pillar'))
|
||||
else:
|
||||
if (path.isdir(path.join(d_salt, repo_name, branch, 'sls'))
|
||||
and path.isdir(path.join(d_salt, repo_name, branch, 'pillar'))):
|
||||
content['file_roots'][env_name].append(path.join(d_salt, repo_name, branch, 'sls'))
|
||||
content['pillar_roots'][env_name].append(path.join(d_salt, repo_name, branch, 'pillar'))
|
||||
elif 'default-branch' in data:
|
||||
content['file_roots'][env_name].append(path.join(d_salt, repo_name, data['default-branch'], 'sls'))
|
||||
content['pillar_roots'][env_name].append(path.join(d_salt, repo_name, data['default-branch'], 'pillar'))
|
||||
|
||||
content['pillar_roots']['base'].append(path.join(d_salt, 'private', 'pillar'))
|
||||
content['file_roots'][env_name].append(path.join(d_salt, 'private', 'files'))
|
||||
content['pillar_roots'][env_name].append(path.join(d_salt, 'private', 'pillar'))
|
||||
|
||||
state('/etc/salt/master.d/roots.conf').file.managed(
|
||||
mode='644', user='root',
|
||||
|
Loading…
Reference in New Issue
Block a user