Merge branch '2015.2' into develop

This commit is contained in:
Pedro Algarvio 2015-02-27 10:02:47 +00:00
commit 62f868a076
22 changed files with 295 additions and 170 deletions

View File

@ -152,7 +152,8 @@ additional-builtins=__opts__,
__active_provider_name__,
__master_opts__,
__jid_event__,
__instance_id__
__instance_id__,
__salt_system_encoding__
# List of strings which can identify a callback function by name. A callback
# name must start or end with one of those strings.

View File

@ -209,7 +209,9 @@ additional-builtins=__opts__,
__active_provider_name__,
__master_opts__,
__jid_event__,
__instance_id__
__instance_id__,
__salt_system_encoding__
# List of strings which can identify a callback function by name. A callback
# name must start or end with one of those strings.

View File

@ -51,3 +51,10 @@ Deprecations
- Removed ``parameter`` argument from ``eselect.set_`` state. Please migrate to
``module_parameter`` or ``action_parameter``.
- The ``salt_events`` table schema has changed to include an additional field
called ``master_id`` to distinguish between events flowing into a database
from multiple masters. If ``event_return`` is enabled in the master config,
the database schema must first be updated to add the ``master_id`` field.
This alteration can be accomplished as follows:
``ALTER TABLE salt_events ADD master_id VARCHAR(255) NOT NULL;``

View File

@ -9,22 +9,65 @@ import warnings
# All salt related deprecation warnings should be shown once each!
warnings.filterwarnings(
'once', # Show once
'', # No deprecation message match
DeprecationWarning, # This filter is for DeprecationWarnings
r'^(salt|salt\.(.*))$' # Match module(s) 'salt' and 'salt.<whatever>'
'once', # Show once
'', # No deprecation message match
DeprecationWarning, # This filter is for DeprecationWarnings
r'^(salt|salt\.(.*))$' # Match module(s) 'salt' and 'salt.<whatever>'
)
# While we are supporting Python2.6, hide nested with-statements warnings
warnings.filterwarnings(
'ignore',
'With-statements now directly support multiple context managers',
DeprecationWarning
'ignore',
'With-statements now directly support multiple context managers',
DeprecationWarning
)
# Filter the backports package UserWarning about being re-imported
warnings.filterwarnings(
'ignore',
'^Module backports was already imported from (.*), but (.*) is being added to sys.path$',
UserWarning
'ignore',
'^Module backports was already imported from (.*), but (.*) is being added to sys.path$',
UserWarning
)
def __define_global_system_encoding_variable__():
import sys
# This is the most trustworthy source of the system encoding, though, if
# salt is being imported after being daemonized, this information is lost
# and reset to None
encoding = sys.stdin.encoding
if not encoding:
# If the system is properly codfigured this should return a valid
# encoding. MS Windows has problems with this and reports the wrong
# encoding
import locale
encoding = locale.getdefaultlocale()[-1]
# This is now garbage collectable
del locale
if not encoding:
# This is most likely asccii which is not the best but we were
# unable to find a better encoding
encoding = sys.getdefaultencoding()
# We can't use six.moves.builtins because these builtins get deleted sooner
# than expected. See:
# https://github.com/saltstack/salt/issues/21036
if sys.version_info[0] < 3:
import __builtin__ as builtins
else:
import builtins # pylint: disable=import-error
# Define the detected encoding as a built-in variable for ease of use
setattr(builtins, '__salt_system_encoding__', encoding)
# This is now garbage collectable
del sys
del builtins
del encoding
__define_global_system_encoding_variable__()
# This is now garbage collectable
del __define_global_system_encoding_variable__

View File

@ -442,7 +442,7 @@ class SSH(object):
# Save the invocation information
argv = self.opts['argv']
if self.opts['raw_shell']:
if self.opts.get('raw_shell', False):
fun = 'ssh._raw'
args = argv
else:

View File

@ -17,7 +17,7 @@
# CREATED: 10/15/2012 09:49:37 PM WEST
#======================================================================================================================
set -o nounset # Treat unset variables as an error
__ScriptVersion="2015.01.12"
__ScriptVersion="2015.02.27"
__ScriptName="bootstrap-salt.sh"
#======================================================================================================================
@ -1957,8 +1957,6 @@ install_debian_deps() {
# Additionally install procps and pciutils which allows for Docker boostraps. See 366#issuecomment-39666813
__PACKAGES="${__PACKAGES} python-pip"
__PIP_PACKAGES="${__PIP_PACKAGES} requests"
else
__PACKAGES="${__PACKAGES} python-requests"
fi
# shellcheck disable=SC2086
@ -2109,49 +2107,18 @@ install_debian_7_deps() {
# shellcheck disable=SC2086
wget $_WGET_ARGS -q http://debian.saltstack.com/debian-salt-team-joehealy.gpg.key -O - | apt-key add - || return 1
if [ "$_PIP_ALLOWED" -eq $BS_TRUE ]; then
echowarn "PyZMQ will be installed from PyPI in order to compile it against ZMQ3"
echowarn "This is required for long term stable minion connections to the master."
echowarn "YOU WILL END UP WITH QUITE A FEW PACKAGES FROM DEBIAN UNSTABLE"
echowarn "Sleeping for 5 seconds so you can cancel..."
sleep 5
if [ ! -f /etc/apt/sources.list.d/debian-unstable.list ]; then
cat <<_eof > /etc/apt/sources.list.d/debian-unstable.list
deb http://ftp.debian.org/debian unstable main
deb-src http://ftp.debian.org/debian unstable main
_eof
cat <<_eof > /etc/apt/preferences.d/libzmq3-debian-unstable.pref
Package: libzmq3
Pin: release a=unstable
Pin-Priority: 800
Package: libzmq3-dev
Pin: release a=unstable
Pin-Priority: 800
_eof
fi
apt-get update
__apt_get_install_noinput -t unstable libzmq3 libzmq3-dev || return 1
__PACKAGES="build-essential python-dev python-pip python-requests python-apt"
# Additionally install procps and pciutils which allows for Docker boostraps. See 366#issuecomment-39666813
__PACKAGES="${__PACKAGES} procps pciutils"
# shellcheck disable=SC2086
__apt_get_install_noinput ${__PACKAGES} || return 1
else
apt-get update || return 1
__PACKAGES="python-zmq python-requests python-apt"
# Additionally install procps and pciutils which allows for Docker boostraps. See 366#issuecomment-39666813
__PACKAGES="${__PACKAGES} procps pciutils"
# shellcheck disable=SC2086
__apt_get_install_noinput ${__PACKAGES} || return 1
fi
apt-get update || return 1
__apt_get_install_noinput -t wheezy-backports libzmq3 libzmq3-dev python-zmq python-requests python-apt || return 1
# Additionally install procps and pciutils which allows for Docker boostraps. See 366#issuecomment-39666813
__PACKAGES="procps pciutils"
# shellcheck disable=SC2086
__apt_get_install_noinput ${__PACKAGES} || return 1
if [ "$_INSTALL_CLOUD" -eq $BS_TRUE ]; then
check_pip_allowed "You need to allow pip based installations (-P) in order to install apache-libcloud"
__PACKAGES="build-essential python-dev python-pip"
# shellcheck disable=SC2086
__apt_get_install_noinput ${__PACKAGES} || return 1
pip install -U "apache-libcloud>=$_LIBCLOUD_MIN_VERSION"
fi
@ -2567,23 +2534,33 @@ __install_epel_repository() {
__install_saltstack_copr_zeromq_repository() {
echoinfo "Installing Zeromq >=4 and PyZMQ>=14 from SaltStack's COPR repository"
if [ ! -f /etc/yum.repos.d/saltstack-zeromq4.repo ]; then
if [ ! -s /etc/yum.repos.d/saltstack-zeromq4.repo ]; then
if [ "${DISTRO_NAME_L}" = "fedora" ]; then
__REPOTYPE="${DISTRO_NAME_L}"
else
__REPOTYPE="epel"
fi
wget -O /etc/yum.repos.d/saltstack-zeromq4.repo \
__fetch_url /etc/yum.repos.d/saltstack-zeromq4.repo \
"http://copr.fedoraproject.org/coprs/saltstack/zeromq4/repo/${__REPOTYPE}-${DISTRO_MAJOR_VERSION}/saltstack-zeromq4-${__REPOTYPE}-${DISTRO_MAJOR_VERSION}.repo" || return 1
fi
return 0
}
__install_saltstack_copr_salt_el5_repository() {
if [ ! -s /etc/yum.repos.d/saltstack-salt-el5-epel-5.repo ]; then
__fetch_url /etc/yum.repos.d/saltstack-salt-el5-epel-5.repo \
"http://copr.fedoraproject.org/coprs/saltstack/salt-el5/repo/epel-5/saltstack-salt-el5-epel-5.repo" || return 1
fi
return 0
}
install_centos_stable_deps() {
__install_epel_repository || return 1
if [ "$DISTRO_MAJOR_VERSION" -eq 5 ]; then
__install_saltstack_copr_salt_el5_repository || return 1
fi
if [ "$_ENABLE_EXTERNAL_ZMQ_REPOS" -eq $BS_TRUE ]; then
if [ "$_ENABLE_EXTERNAL_ZMQ_REPOS" -eq $BS_TRUE ] && [ "$DISTRO_MAJOR_VERSION" -gt 5 ]; then
yum -y install python-hashlib || return 1
__install_saltstack_copr_zeromq_repository || return 1
fi
@ -2625,7 +2602,7 @@ install_centos_stable_deps() {
if [ "$DISTRO_MAJOR_VERSION" -eq 5 ]; then
easy_install-2.6 "apache-libcloud>=$_LIBCLOUD_MIN_VERSION"
else
pip-python install "apache-libcloud>=$_LIBCLOUD_MIN_VERSION"
pip install "apache-libcloud>=$_LIBCLOUD_MIN_VERSION"
fi
fi
@ -2651,9 +2628,13 @@ install_centos_stable() {
if [ "$_INSTALL_MINION" -eq $BS_TRUE ]; then
__PACKAGES="${__PACKAGES} salt-minion"
fi
if [ "$_INSTALL_MASTER" -eq $BS_TRUE ] || [ "$_INSTALL_SYNDIC" -eq $BS_TRUE ]; then
if [ "$_INSTALL_MASTER" -eq $BS_TRUE ];then
__PACKAGES="${__PACKAGES} salt-master"
fi
if [ "$_INSTALL_SYNDIC" -eq $BS_TRUE ];then
__PACKAGES="${__PACKAGES} salt-syndic"
fi
if [ "$DISTRO_NAME_L" = "oracle_linux" ]; then
# We need to install one package at a time because --enablerepo=X disables ALL OTHER REPOS!!!!
for package in ${__PACKAGES}; do
@ -2868,6 +2849,10 @@ install_centos_check_services() {
__test_rhel_optionals_packages() {
__install_epel_repository || return 1
if [ "$DISTRO_MAJOR_VERSION" -ge 7 ]; then
yum-config-manager --enable \*server-optional || return 1
fi
if [ "$DISTRO_MAJOR_VERSION" -ge 6 ]; then
# Let's enable package installation testing, kind of, --dry-run
echoinfo "Testing if packages usually on the optionals repository are available:"

View File

@ -4,10 +4,8 @@ The crypt module manages all of the cryptography functions for minions and
masters, encrypting and decrypting payloads, preparing messages, and
authenticating peers
'''
from __future__ import absolute_import
from __future__ import print_function
# Import python libs
from __future__ import absolute_import, print_function
import os
import sys
import time
@ -16,7 +14,7 @@ import hashlib
import logging
import traceback
import binascii
from salt.ext.six.moves import zip
from salt.ext.six.moves import zip # pylint: disable=import-error,redefined-builtin
# Import third party libs
try:
@ -499,7 +497,8 @@ class SAuth(object):
'from master {0}'.format(self.opts['master']))
m_pub_fn = os.path.join(self.opts['pki_dir'], self.mpub)
uid = salt.utils.get_uid(self.opts.get('user', None))
salt.utils.fopen(m_pub_fn, 'w+', uid=uid).write(payload['pub_key'])
with salt.utils.fpopen(m_pub_fn, 'w+', uid=uid) as wfh:
wfh.write(payload['pub_key'])
return True
else:
log.error('Received signed public-key from master {0} '

View File

@ -1250,6 +1250,7 @@ def locale_info():
# might do, per #2205
grains['locale_info']['defaultlanguage'] = 'unknown'
grains['locale_info']['defaultencoding'] = 'unknown'
grains['locale_info']['detectedencoding'] = __salt_system_encoding__
return grains

View File

@ -1186,9 +1186,8 @@ class AESFuncs(object):
load['grains'],
load['id'],
load.get('saltenv', load.get('env')),
load.get('ext'),
self.mminion.functions,
load.get('pillar_override', {}))
ext=load.get('ext'),
pillar=load.get('pillar_override', {}))
data = pillar.compile_pillar(pillar_dirs=pillar_dirs)
if self.opts.get('minion_data_cache', False):
cdir = os.path.join(self.opts['cachedir'], 'minions', load['id'])
@ -1204,8 +1203,6 @@ class AESFuncs(object):
'pillar': data})
)
os.rename(tmpfname, datap)
for mod in mods:
sys.modules[mod].__grains__ = self.opts['grains']
return data
def _minion_event(self, load):

View File

@ -304,7 +304,7 @@ def _netstat_route_linux():
'''
ret = []
cmd = 'netstat -A inet -rn | tail -n+3'
out = __salt__['cmd.run'](cmd)
out = __salt__['cmd.run'](cmd, python_shell=True)
for line in out.splitlines():
comps = line.split()
ret.append({
@ -315,7 +315,7 @@ def _netstat_route_linux():
'flags': comps[3],
'interface': comps[7]})
cmd = 'netstat -A inet6 -rn | tail -n+3'
out = __salt__['cmd.run'](cmd)
out = __salt__['cmd.run'](cmd, python_shell=True)
for line in out.splitlines():
comps = line.split()
if len(comps) == 6:
@ -345,7 +345,7 @@ def _netstat_route_freebsd():
'''
ret = []
cmd = 'netstat -f inet -rn | tail -n+5'
out = __salt__['cmd.run'](cmd)
out = __salt__['cmd.run'](cmd, python_shell=True)
for line in out.splitlines():
comps = line.split()
ret.append({
@ -356,7 +356,7 @@ def _netstat_route_freebsd():
'flags': comps[3],
'interface': comps[5]})
cmd = 'netstat -f inet6 -rn | tail -n+5'
out = __salt__['cmd.run'](cmd)
out = __salt__['cmd.run'](cmd, python_shell=True)
for line in out.splitlines():
comps = line.split()
ret.append({
@ -375,7 +375,7 @@ def _netstat_route_netbsd():
'''
ret = []
cmd = 'netstat -f inet -rn | tail -n+5'
out = __salt__['cmd.run'](cmd)
out = __salt__['cmd.run'](cmd, python_shell=True)
for line in out.splitlines():
comps = line.split()
ret.append({
@ -386,7 +386,7 @@ def _netstat_route_netbsd():
'flags': comps[3],
'interface': comps[6]})
cmd = 'netstat -f inet6 -rn | tail -n+5'
out = __salt__['cmd.run'](cmd)
out = __salt__['cmd.run'](cmd, python_shell=True)
for line in out.splitlines():
comps = line.split()
ret.append({
@ -405,7 +405,7 @@ def _netstat_route_openbsd():
'''
ret = []
cmd = 'netstat -f inet -rn | tail -n+5'
out = __salt__['cmd.run'](cmd)
out = __salt__['cmd.run'](cmd, python_shell=True)
for line in out.splitlines():
comps = line.split()
ret.append({
@ -416,7 +416,7 @@ def _netstat_route_openbsd():
'flags': comps[2],
'interface': comps[7]})
cmd = 'netstat -f inet6 -rn | tail -n+5'
out = __salt__['cmd.run'](cmd)
out = __salt__['cmd.run'](cmd, python_shell=True)
for line in out.splitlines():
comps = line.split()
ret.append({

View File

@ -113,6 +113,8 @@ def _get_all_legacy_init_scripts():
otherwise.
'''
ret = {}
if not os.path.isdir(LEGACY_INIT_SCRIPT_PATH):
return ret
for fn in os.listdir(LEGACY_INIT_SCRIPT_PATH):
if not os.path.isfile(os.path.join(LEGACY_INIT_SCRIPT_PATH, fn)) or fn.startswith('rc'):
continue

View File

@ -5,18 +5,22 @@ from __future__ import print_function
from __future__ import absolute_import
import hashlib
import logging
import distutils.version
__virtualname__ = 'rest_tornado'
logger = logging.getLogger(__virtualname__)
# we require at least 4.0, as that includes all the Future's stuff we use
min_tornado_version = '4.0'
has_tornado = False
try:
import tornado.httpserver
import tornado.ioloop
import tornado.web
import tornado.gen
has_tornado = True
import tornado
if distutils.version.StrictVersion(tornado.version) >= \
distutils.version.StrictVersion(min_tornado_version):
has_tornado = True
else:
logger.error('rest_tornado requires at least tornado {0}'.format(min_tornado_version))
except ImportError as err:
has_tornado = False
logger.error('ImportError! {0}'.format(str(err)))

View File

@ -61,6 +61,7 @@ Example output:
# Import python libs
from __future__ import absolute_import
import pprint
import textwrap
# Import salt libs
import salt.utils
@ -255,9 +256,24 @@ def _format_host(host, data):
hstrs.append((u'{0}{1}{2[ENDC]}'
.format(tcolor, changes, colors)))
if 'warnings' in ret:
rcounts.setdefault('warnings', 0)
rcounts['warnings'] += 1
wrapper = textwrap.TextWrapper(
width=80,
initial_indent=u' ' * 14,
subsequent_indent=u' ' * 14
)
hstrs.append(
u' {colors[YELLOW]} Warnings: {0}{colors[ENDC]}'.format(
wrapper.fill('\n'.join(ret['warnings'])).lstrip(),
colors=colors
)
)
# Append result counts to end of output
colorfmt = u'{0}{1}{2[ENDC]}'
rlabel = {True: u'Succeeded', False: u'Failed', None: u'Not Run'}
rlabel = {True: u'Succeeded', False: u'Failed', None: u'Not Run', 'warnings': u'Warnings'}
count_max_len = max([len(str(x)) for x in six.itervalues(rcounts)] or [0])
label_max_len = max([len(x) for x in six.itervalues(rlabel)] or [0])
line_max_len = label_max_len + count_max_len + 2 # +2 for ': '
@ -320,8 +336,18 @@ def _format_host(host, data):
)
)
num_warnings = rcounts.get('warnings', 0)
if num_warnings:
hstrs.append(
colorfmt.format(
colors['YELLOW'],
_counts(rlabel['warnings'], num_warnings),
colors
)
)
totals = u'{0}\nTotal states run: {1:>{2}}'.format('-' * line_max_len,
sum(six.itervalues(rcounts)),
sum(six.itervalues(rcounts)) - rcounts.get('warnings', 0),
line_max_len - 7)
hstrs.append(colorfmt.format(colors['CYAN'], totals, colors))

View File

@ -74,6 +74,7 @@ Use the following mysql database schema::
`tag` varchar(255) NOT NULL,
`data` varchar(1024) NOT NULL,
`alter_time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`master_id` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
KEY `tag` (`tag`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
@ -220,9 +221,9 @@ def event_return(events):
for event in events:
tag = event.get('tag', '')
data = event.get('data', '')
sql = '''INSERT INTO `salt_events` (`tag`, `data` )
VALUES (%s, %s)'''
cur.execute(sql, (tag, json.dumps(data)))
sql = '''INSERT INTO `salt_events` (`tag`, `data`, `master_id` )
VALUES (%s, %s, %s)'''
cur.execute(sql, (tag, json.dumps(data), __opts__['id']))
def save_load(jid, load):

View File

@ -45,18 +45,28 @@ from salt.ext.six.moves import range
log = logging.getLogger(__name__)
STATE_INTERNAL_KEYWORDS = frozenset([
# These are keywords passed to state module functions which are to be used
# by salt in this state module and not on the actual state module function
# These are keywords passed to state module functions which are to be used
# by salt in this state module and not on the actual state module function
STATE_REQUISITE_KEYWORDS = frozenset([
'onchanges',
'onfail',
'prereq',
'prerequired',
'watch',
'require',
'listen',
])
STATE_REQUISITE_IN_KEYWORDS = frozenset([
'onchanges_in',
'onfail_in',
'prereq_in',
'watch_in',
'require_in',
'listen_in',
])
STATE_RUNTIME_KEYWORDS = frozenset([
'check_cmd',
'fail_hard',
'fun',
'listen',
'listen_in',
'onchanges',
'onchanges_in',
'onfail',
'onfail_in',
'onlyif',
'order',
'prereq',
@ -65,27 +75,24 @@ STATE_INTERNAL_KEYWORDS = frozenset([
'reload_modules',
'reload_grains',
'reload_pillar',
'require',
'require_in',
'saltenv',
'state',
'unless',
'use',
'use_in',
'watch',
'watch_in',
'__id__',
'__sls__',
'__env__',
'__sls__',
'__id__',
'__pub_user',
'__pub_arg',
'__pub_jid',
'__pub_fun',
'__pub_tgt',
'__pub_ret',
'__pub_pid',
'__pub_tgt_type',
'__prereq__',
])
])
STATE_INTERNAL_KEYWORDS = STATE_REQUISITE_KEYWORDS.union(STATE_REQUISITE_IN_KEYWORDS).union(STATE_RUNTIME_KEYWORDS)
def _odict_hashable(self):
@ -1953,7 +1960,7 @@ class State(object):
def call_listen(self, chunks, running):
'''
Find all of the listen routines and call the associated mod_match runs
Find all of the listen routines and call the associated mod_watch runs
'''
listeners = []
crefs = {}
@ -2001,6 +2008,9 @@ class State(object):
low['sfun'] = chunk['fun']
low['fun'] = 'mod_watch'
low['__id__'] = 'listener_{0}'.format(low['__id__'])
for req in STATE_REQUISITE_KEYWORDS:
if req in low:
low.pop(req)
mod_watchers.append(low)
ret = self.call_chunks(mod_watchers)
running.update(ret)

View File

@ -193,6 +193,7 @@ def mounted(name,
'defaults',
'delay_connect',
'intr',
'loop',
'nointr',
'nobootwait',
'nofail',

View File

@ -31,12 +31,12 @@ import types
import warnings
import string
import locale
from calendar import month_abbr as months
# Import 3rd-party libs
import salt.ext.six as six
# pylint: disable=import-error,redefined-builtin
# pylint: disable=import-error
from salt.ext.six.moves.urllib.parse import urlparse # pylint: disable=no-name-in-module
# pylint: disable=redefined-builtin
from salt.ext.six.moves import range
from salt.ext.six.moves import zip
from salt.ext.six.moves import map
@ -844,6 +844,17 @@ def format_call(fun,
continue
extra[key] = copy.deepcopy(value)
# We'll be showing errors to the users until Salt Carbon comes out, after
# which, errors will be raised instead.
warn_until(
'Carbon',
'It\'s time to start raising `SaltInvocationError` instead of '
'returning warnings',
# Let's not show the deprecation warning on the console, there's no
# need.
_dont_call_warnings=True
)
if extra:
# Found unexpected keyword arguments, raise an error to the user
if len(extra) == 1:
@ -857,7 +868,7 @@ def format_call(fun,
)
)
else:
msg = '{0} and {1!r} are invalid keyword arguments for {2}'.format(
msg = '{0} and {1!r} are invalid keyword arguments for {2!r}'.format(
', '.join(['{0!r}'.format(e) for e in extra][:-1]),
list(extra.keys())[-1],
ret.get(
@ -867,14 +878,20 @@ def format_call(fun,
'{0}.{1}'.format(fun.__module__, fun.__name__)
)
)
log.critical(
# Return a warning to the user explaining what's going on
ret.setdefault('warnings', []).append(
'{0}. If you were trying to pass additional data to be used '
'in a template context, please populate \'context\' with '
'\'key: value\' pairs.{1}'.format(
'\'key: value\' pairs. Your approach will work until Salt '
'Carbon is out.{1}'.format(
msg,
'' if 'full' not in ret else ' Please update your state files.'
)
)
# Lets pack the current extra kwargs as template context
ret.setdefault('context', {}).update(extra)
return ret
@ -1002,9 +1019,55 @@ def fopen(*args, **kwargs):
NB! We still have small race condition between open and fcntl.
Supported optional Keyword Arguments:
'''
# Remove lock, uid, gid and mode from kwargs if present
lock = kwargs.pop('lock', False)
lock: lock the file with fcntl
if lock is True:
warn_until(
'Beryllium',
'The \'lock\' keyword argument is deprecated and will be '
'removed in Salt Beryllium. Please use '
'\'salt.utils.flopen()\' for file locking while calling '
'\'salt.utils.fopen()\'.'
)
return flopen(*args, **kwargs)
fhandle = open(*args, **kwargs)
if is_fcntl_available():
# modify the file descriptor on systems with fcntl
# unix and unix-like systems only
try:
FD_CLOEXEC = fcntl.FD_CLOEXEC # pylint: disable=C0103
except AttributeError:
FD_CLOEXEC = 1 # pylint: disable=C0103
old_flags = fcntl.fcntl(fhandle.fileno(), fcntl.F_GETFD)
fcntl.fcntl(fhandle.fileno(), fcntl.F_SETFD, old_flags | FD_CLOEXEC)
return fhandle
@contextlib.contextmanager
def flopen(*args, **kwargs):
'''
Shortcut for fopen with lock and context manager
'''
with fopen(*args, **kwargs) as fhandle:
try:
if is_fcntl_available(check_sunos=True):
fcntl.flock(fhandle.fileno(), fcntl.LOCK_SH)
yield fhandle
finally:
if is_fcntl_available(check_sunos=True):
fcntl.flock(fhandle.fileno(), fcntl.LOCK_UN)
@contextlib.contextmanager
def fpopen(*args, **kwargs):
'''
Shortcut for fopen with extra uid, gid and mode options.
Supported optional Keyword Arguments:
mode: explicit mode to set. Mode is anything os.chmod
would accept as input for mode. Works only on unix/unix
@ -1019,53 +1082,26 @@ def fopen(*args, **kwargs):
gid. Must be int. Works only on unix/unix like systems.
'''
# Remove lock, uid, gid and mode from kwargs if present
lock = kwargs.pop('lock', False)
# Remove uid, gid and mode from kwargs if present
uid = kwargs.pop('uid', -1) # -1 means no change to current uid
gid = kwargs.pop('gid', -1) # -1 means no change to current gid
mode = kwargs.pop('mode', None)
with fopen(*args, **kwargs) as fhandle:
path = args[0]
d_stat = os.stat(path)
fhandle = open(*args, **kwargs)
if is_fcntl_available():
# modify the file descriptor on systems with fcntl
# unix and unix-like systems only
try:
FD_CLOEXEC = fcntl.FD_CLOEXEC # pylint: disable=C0103
except AttributeError:
FD_CLOEXEC = 1 # pylint: disable=C0103
old_flags = fcntl.fcntl(fhandle.fileno(), fcntl.F_GETFD)
if lock and is_fcntl_available(check_sunos=True):
fcntl.flock(fhandle.fileno(), fcntl.LOCK_SH)
fcntl.fcntl(fhandle.fileno(), fcntl.F_SETFD, old_flags | FD_CLOEXEC)
if hasattr(os, 'chown'):
# if uid and gid are both -1 then go ahead with
# no changes at all
if (d_stat.st_uid != uid or d_stat.st_gid != gid) and \
[i for i in (uid, gid) if i != -1]:
os.chown(path, uid, gid)
path = args[0]
d_stat = os.stat(path)
if mode is not None:
if d_stat.st_mode | mode != d_stat.st_mode:
os.chmod(path, d_stat.st_mode | mode)
if hasattr(os, 'chown'):
# if uid and gid are both -1 then go ahead with
# no changes at all
if (d_stat.st_uid != uid or d_stat.st_gid != gid) and \
[i for i in (uid, gid) if i != -1]:
os.chown(path, uid, gid)
if mode is not None:
if d_stat.st_mode | mode != d_stat.st_mode:
os.chmod(path, d_stat.st_mode | mode)
return fhandle
@contextlib.contextmanager
def flopen(*args, **kwargs):
'''
Shortcut for fopen with lock and context manager
'''
with fopen(*args, lock=True, **kwargs) as fp_:
try:
yield fp_
finally:
if is_fcntl_available(check_sunos=True):
fcntl.flock(fp_.fileno(), fcntl.LOCK_UN)
yield fhandle
def expr_match(line, expr):

View File

@ -52,7 +52,8 @@ class SaltCacheLoader(BaseLoader):
Templates are cached like regular salt states
and only loaded once per loader instance.
'''
def __init__(self, opts, saltenv='base', encoding='utf-8', env=None, pillar_rend=False):
def __init__(self, opts, saltenv='base', encoding='utf-8', env=None,
pillar_rend=False):
if env is not None:
salt.utils.warn_until(
'Boron',
@ -80,8 +81,7 @@ class SaltCacheLoader(BaseLoader):
'''
if not self._file_client:
self._file_client = salt.fileclient.get_file_client(
self.opts,
self.pillar_rend)
self.opts, self.pillar_rend)
return self._file_client
def cache_file(self, template):
@ -330,7 +330,7 @@ class SerializerExtension(Extension, object):
'''
tags = set(['load_yaml', 'load_json', 'import_yaml', 'import_json',
'load_text', 'import_text'])
'load_text', 'import_text'])
def __init__(self, environment):
super(SerializerExtension, self).__init__(environment)
@ -359,7 +359,9 @@ class SerializerExtension(Extension, object):
'''
def explore(data):
if isinstance(data, (dict, OrderedDict)):
return PrintableDict([(key, explore(value)) for key, value in six.iteritems(data)])
return PrintableDict(
[(key, explore(value)) for key, value in six.iteritems(data)]
)
elif isinstance(data, (list, tuple, set)):
return data.__class__([explore(value) for value in data])
return data
@ -382,7 +384,7 @@ class SerializerExtension(Extension, object):
return yaml.safe_load(value)
except AttributeError:
raise TemplateRuntimeError(
'Unable to load yaml from {0}'.format(value))
'Unable to load yaml from {0}'.format(value))
def load_json(self, value):
if isinstance(value, TemplateModule):
@ -391,7 +393,7 @@ class SerializerExtension(Extension, object):
return json.loads(value)
except (ValueError, TypeError, AttributeError):
raise TemplateRuntimeError(
'Unable to load json from {0}'.format(value))
'Unable to load json from {0}'.format(value))
def load_text(self, value):
if isinstance(value, TemplateModule):
@ -399,6 +401,8 @@ class SerializerExtension(Extension, object):
return value
_load_parsers = set(['load_yaml', 'load_json', 'load_text'])
def parse(self, parser):
if parser.stream.current.value == 'import_yaml':
return self.parse_yaml(parser)
@ -406,7 +410,7 @@ class SerializerExtension(Extension, object):
return self.parse_json(parser)
elif parser.stream.current.value == 'import_text':
return self.parse_text(parser)
elif parser.stream.current.value in ('load_yaml', 'load_json', 'load_text'):
elif parser.stream.current.value in self._load_parsers:
return self.parse_load(parser)
parser.fail('Unknown format ' + parser.stream.current.value,
@ -422,8 +426,8 @@ class SerializerExtension(Extension, object):
parser.stream.expect('name:as')
target = parser.parse_assign_target()
macro_name = '_' + parser.free_identifier().name
macro_body = parser.parse_statements(('name:endload',),
drop_needle=True)
macro_body = parser.parse_statements(
('name:endload',), drop_needle=True)
return [
nodes.Macro(

View File

@ -84,7 +84,7 @@ class SaltStackVersion(object):
'Lithium' : (2015, 2),
'Beryllium' : (MAX_SIZE - 105, 0),
'Boron' : (MAX_SIZE - 104, 0),
#'Carbon' : (MAX_SIZE - 103, 0),
'Carbon' : (MAX_SIZE - 103, 0),
#'Nitrogen' : (MAX_SIZE - 102, 0),
#'Oxygen' : (MAX_SIZE - 101, 0),
#'Fluorine' : (MAX_SIZE - 100, 0),

View File

@ -14,6 +14,7 @@ import integration
from salt.config import cloud_providers_config
# Import Salt Testing Libs
from salttesting import skipIf
from salttesting.helpers import ensure_in_syspath, expensiveTest
ensure_in_syspath('../../../')
@ -35,6 +36,7 @@ def __random_name(size=6):
INSTANCE_NAME = __random_name()
@skipIf(True, 'Skipping until we can figure out why the testrunner bails.')
class EC2Test(integration.ShellCase):
'''
Integration tests for the EC2 cloud provider in Salt-Cloud

View File

@ -14,8 +14,8 @@ from salttesting.helpers import ensure_in_syspath
ensure_in_syspath('../../')
# Import Salt libs
from salt.output import display_output
import integration
from salt.output import display_output
class OutputReturnTest(integration.ShellCase):

View File

@ -159,6 +159,10 @@ class UtilsTestCase(TestCase):
# Make sure we raise an error if we don't pass in the requisite number of arguments
self.assertRaises(SaltInvocationError, utils.format_call, dummy_func, {'1': 2})
# Make sure we warn on invalid kwargs
ret = utils.format_call(dummy_func, {'first': 2, 'second': 2, 'third': 3})
self.assertGreaterEqual(len(ret['warnings']), 1)
ret = utils.format_call(dummy_func, {'first': 2, 'second': 2, 'third': 3},
expected_extra_kws=('first', 'second', 'third'))
self.assertDictEqual(ret, {'args': [], 'kwargs': {}})