Merge pull request #34525 from rallytime/merge-develop

[develop] Merge forward from 2016.3 to develop
This commit is contained in:
Nicole Thomas 2016-07-07 17:53:24 -04:00 committed by GitHub
commit 907f356770
25 changed files with 298 additions and 237 deletions

View File

@ -1207,8 +1207,73 @@ environments is to isolate via the top file.
.. code-block:: yaml
environment: None
environment: dev
.. conf_minion:: top_file_merging_strategy
``top_file_merging_strategy``
-----------------------------
Default: ``merge``
When no specific fileserver environment (a.k.a. ``saltenv``) has been specified
for a :ref:`highstate <running-highstate>`, all environments' top files are
inspected. This config option determines how the SLS targets in those top files
are handled.
When set to ``merge``, the targets for all SLS files in all environments are
merged together. A given environment's SLS targets for the highstate will
consist of the collective SLS targets specified for that environment in all top
files. The environments will be merged in no specific order, for greater
control over the order in which the environments are merged use
:conf_minion:`env_order`.
When set to ``same``, then for each environment, only that environment's top
file is processed, with the others being ignored. For example, only the ``dev``
environment's top file will be processed for the ``dev`` environment, and any
SLS targets defined for ``dev`` in the ``base`` environment's (or any other
environment's) top file will be ignored. If an environment does not have a top
file, then the top file from the :conf_minion:`default_top` config parameter
will be used as a fallback.
.. code-block:: yaml
top_file_merging_strategy: same
.. conf_minion:: env_order
``env_order``
-------------
Default: ``[]``
When :conf_minion:`top_file_merging_strategy` is set to ``merge``, and no
environment is specified for a :ref:`highstate <running-highstate>`, this
config option allows for the order in which top files are merged to be
explicitly defined.
.. code-block:: yaml
env_order:
- base
- dev
- qa
.. conf_minion:: default_top
``default_top``
---------------
Default: ``base``
When :conf_minion:`top_file_merging_strategy` is set to ``same``, and no
environment is specified for a :ref:`highstate <running-highstate>`, this
config option specifies a fallback environment in which to look for a top file
if an environment lacks one.
.. code-block:: yaml
default_top: dev
File Directory Settings
=======================

View File

@ -30,22 +30,22 @@ A Basic Example
Top files have three components:
- Environment: A state tree directory containing a set of state files to
configure systems.
- **Environment:** A state tree directory containing a set of state files to
configure systems.
- Target: A grouping of machines which will have a set of states applied
to them.
- **Target:** A grouping of machines which will have a set of states applied to
them.
- State files: A list of state files to apply to a target. Each state
file describes one or more states to be configured and enforced
on the targeted machines.
- **State files:** A list of state files to apply to a target. Each state file
describes one or more states to be configured and enforced on the targeted
machines.
The relationship between these three components is nested as follows:
- Environments contain targets
- Environments contain targets
- Targets contain states
- Targets contain states
Putting these concepts together, we can describe a scenario in which all
@ -172,26 +172,28 @@ Choosing an Environment to Target
The top file is used to assign a minion to an environment unless overridden
using the methods described below. The environment in the top file must match
an environment in :conf_master:`file_roots` in order for any states to be
applied to that minion. The states that will be applied to a minion in a given
environment can be viewed using the :py:func:`state.show_top
<salt.modules.state.show_top>` execution function.
valid fileserver environment (a.k.a. ``saltenv``) in order for any states to be
applied to that minion. When using the default fileserver backend, environments
are defined in :conf_master:`file_roots`.
Minions may be pinned to a particular environment by setting the ``environment``
value in the minion configuration file. In doing so, a minion will only
request files from the environment to which it is assigned.
The states that will be applied to a minion in a given environment can be
viewed using the :py:func:`state.show_top <salt.modules.state.show_top>`
function.
The environment to use may also be dynamically selected at the time that
a ``salt``, ``salt-call`` or ``salt-ssh`` by passing passing a flag to the
execution module being called. This is most commonly done with
functions in the ``state`` module by using the ``saltenv=`` argument. For
example, to run a ``highstate`` on all minions, using the state files in
the ``prod`` state tree, run: ``salt '*' state.highstate saltenv=prod``.
Minions may be pinned to a particular environment by setting the
:conf_minion:`environment` value in the minion configuration file. In doing so,
a minion will only request files from the environment to which it is assigned.
The environment may also be dynamically selected at runtime by passing it to
the ``salt``, ``salt-call`` or ``salt-ssh`` command. This is most commonly done
with functions in the ``state`` module by using the ``saltenv`` argument. For
example, to run a ``highstate`` on all minions, using only the top file and SLS
files in the ``prod`` environment, run: ``salt '*' state.highstate
saltenv=prod``.
.. note::
Not all functions accept ``saltenv`` as an argument See individual
function documentation to verify.
Not all functions accept ``saltenv`` as an argument, see the documentation
for an individual function documentation to verify.
Shorthand
@ -305,66 +307,132 @@ of matches you can perform:
How Top Files Are Compiled
==========================
When a :ref:`highstate <running-highstate>` is executed and an environment is
specified (either using the :conf_minion:`environment` config option or by
passing the saltenv when executing the :ref:`highstate <running-highstate>`),
then that environment's top file is the only top file used to assign states to
minions, and only states from the specified environment will be run.
The remainder of this section applies to cases in which a :ref:`highstate
<running-highstate>` is executed without an environment specified.
With no environment specified, the minion will look for a top file in each
environment, and each top file will be processed to determine the SLS files to
run on the minions. By default, the top files from each environment will be
merged together. In configurations with many environments, such as with
:ref:`GitFS <tutorial-gitfs>` where each branch and tag is treated as a
distinct environment, this may cause unexpected results as SLS files from older
tags cause defunct SLS files to be included in the highstate. In cases like
this, it can be helpful to set :conf_minion:`top_file_merging_strategy` to
``same`` to force each environment to use its own top file.
.. code-block:: yaml
top_file_merging_strategy: same
With :ref:`GitFS <tutorial-gitfs>`, it can also be helpful to simply manage
each environment's top file separately, and/or manually specify the environment
when executing the highstate to avoid any complicated merging scenarios.
:conf_master:`gitfs_env_whitelist` and :conf_master:`gitfs_env_blacklist` can
also be used to hide unneeded branches and tags from GitFS to reduce the number
of top files in play.
When using multiple environments, it is not necessary to create a top file for
each environment. The most common approach, and the easiest to maintain, is
to use a single top file placed in only one environment.
each environment. The easiest-to-maintain approach is to use a single top file
placed in the ``base`` environment. This is often infeasible with :ref:`GitFS
<tutorial-gitfs>` though, since branching/tagging can easily result in extra
top files. However, when only the default (``roots``) fileserver backend is
used, a single top file in the ``base`` environment is the most common way of
configuring a :ref:`highstate <running-highstate>`.
However, some workflows do call for multiple top files. In this case, top
files may be merged together to create ``high data`` for the state compiler
to use as a source to compile states on a minion.
The following minion configuration options affect how top files are compiled
when no environment is specified:
For the following discussion of top file compilation, assume the following
configuration:
- :conf_minion:`top_file_merging_strategy`
- :conf_minion:`env_order`
- :conf_minion:`default_top`
Top File Compilation Examples
=============================
``/etc/salt/master``:
For the scenarios below, assume the following configuration:
**/etc/salt/master**:
.. code-block:: yaml
<snip>
file_roots:
first_env:
- /srv/salt/first
second_env:
- /srv/salt/second
base:
- /srv/salt/base
dev:
- /srv/salt/dev
qa:
- /srv/salt/qa
``/srv/salt/first/top.sls``:
**/srv/salt/base/top.sls**:
.. code-block:: yaml
first_env:
base:
'*':
- first
second_env:
- base1
dev:
'*':
- second
- dev1
qa:
'*':
- qa1
The astute reader will ask how the state compiler resolves which should be
an obvious conflict if a minion is not pinned to a particular environment
and if no environment argument is passed into a state function.
**/srv/salt/dev/top.sls**:
Given the above, it is initially unclear whether ``first.sls`` will be applied
or whether ``second.sls`` will be applied in a ``salt '*' state.highstate`` command.
.. code-block:: yaml
When conflicting keys arise, there are several configuration options which
control the behaviour of salt:
base:
'minion1':
- base2
dev:
'minion2':
- dev2
qa:
'*':
- qa2
- ``env_order``
Setting ``env_order`` will set the order in which environments are processed
by the state compiler.
.. note::
For the purposes of these examples, there is no top file in the ``qa``
environment.
- ``top_file_merging_strategy``
Can be set to ``same``, which will process only the top file from the environment
that the minion belongs to via the ``environment`` configuration setting or
the environment that is requested via the ``saltenv`` argument supported
by some functions in the ``state`` module.
Scenario 1 - ``dev`` Environment Specified
------------------------------------------
Can also be set to ``merge``. This is the default. When set to ``merge``,
top files will be merged together. The order in which top files are
merged together can be controlled with ``env_order``.
In this scenario, the :ref:`highstate <running-highstate>` was either invoked
with ``saltenv=dev`` or the minion has ``environment: dev`` set in the minion
config file. The result will be that only the ``dev2`` SLS from the dev
environment will be part of the :ref:`highstate <running-highstate>`, and it
will be applied to minion2, while minion1 will have no states applied to it.
- ``default_top``
If ``top_file_merging_strategy`` is set to ``same`` and an environment does
not contain a top file, the top file in the environment specified by
``default_top`` will be used instead.
If the ``base`` environment were specified, the result would be that only the
``base1`` SLS from the ``base`` environment would be part of the
:ref:`highstate <running-highstate>`, and it would be applied to all minions.
If the ``qa`` environment were specified, the :ref:`highstate
<running-highstate>` would exit with an error.
Scenario 2 - No Environment Specified, :conf_minion:`top_file_merging_strategy` is "merge"
------------------------------------------------------------------------------------------
In this scenario, ``base1`` from the ``base`` environment, ``dev1`` from the
``dev`` environment, and ``qa1`` from the ``qa`` environment are applied to all
minions. Additionally, ``base2`` from the ``base`` environment is applied to
minion1, and ``dev2`` from the ``dev`` environment is applied to minion2.
Scenario 3 - No Environment Specified, :conf_minion:`top_file_merging_strategy` is "same"
-----------------------------------------------------------------------------------------
In this scenario, ``base1`` from the ``base`` environment is applied to all
minions. Additionally, ``dev2`` from the ``dev`` environment is applied to
minion2.
If :conf_minion:`default_top` is unset (or set to ``base``, which happens to be
the default), then ``qa1`` from the ``qa`` environment will be applied to all
minions. If :conf_minion:`default_top` were set to ``dev``, then ``qa2`` from
the ``qa`` environment would be applied to all minions.

View File

@ -45,6 +45,10 @@ minion configuration file:
The beacon system, like many others in Salt, can also be configured via the
minion pillar, grains, or local config file.
.. note::
The `inotify` beacon only works on OSes that have `inotify` kernel support.
Currently this excludes FreeBSD, Mac OS X, and Windows.
Beacon Monitoring Interval
--------------------------

View File

@ -15,6 +15,11 @@ configuring one or more repositories in :conf_master:`gitfs_remotes`.
Branches and tags become Salt fileserver environments.
.. note::
Branching and tagging can result in a lot of potentially-conflicting
:ref:`top files <states-top>`, for this reason it may be useful to set
:conf_minion:`top_file_merging_strategy` to ``same`` in the minions' config
files if the top files are being managed in a GitFS repo.
.. _gitfs-dependencies:

View File

@ -164,7 +164,7 @@ Downloading the script from develop branch:
.. code-block:: bash
wget https://bootstrap.saltstack.com/develop
wget -O bootstrap_salt.sh https://bootstrap.saltstack.com/develop
sudo sh bootstrap_salt.sh
Installing a specific version from git using ``wget``:

View File

@ -197,13 +197,13 @@ sudo -H $MAKE install
############################################################################
echo -n -e "\033]0;Build_Env: Python\007"
PKGURL="https://www.python.org/ftp/python/2.7.11/Python-2.7.11.tar.xz"
PKGDIR="Python-2.7.11"
PKGURL="https://www.python.org/ftp/python/2.7.12/Python-2.7.12.tar.xz"
PKGDIR="Python-2.7.12"
download $PKGURL
echo "################################################################################"
echo "Building Python 2.7.11"
echo "Building Python 2.7.12"
echo "################################################################################"
echo "Note there are some test failures"
cd $PKGDIR

View File

@ -1 +0,0 @@
72166763a2fe6aab45ecf378f55a1efc7322d1742c4638bae84f4ed4b9fb4c01f2a0293733c64426ae2c70df24d95ff2b1e2a4f3c2715de00d8f320d4d939ea0 Python-2.7.11.tar.xz

View File

@ -0,0 +1 @@
6ddbbce47cc49597433d98ca05c2f62f07ed1070807b645602a8e9e9b996adc6fa66fa20a33cd7d23d4e7e925e25071d7301d288149fbe4e8c5f06d5438dda1f ./Python-2.7.12.tar.xz

View File

@ -45,7 +45,7 @@ Function Get-Settings {
# Filenames for 64 bit Windows
$64bitPrograms = @{
"PyCrypto" = "pycrypto-2.6.1-cp27-none-win_amd64.whl"
"Python" = "python-2.7.11.amd64.msi"
"Python" = "python-2.7.12.amd64.msi"
"PyYAML" = "PyYAML-3.11.win-amd64-py2.7.exe"
}
$ini.Add("64bitPrograms", $64bitPrograms)
@ -53,7 +53,7 @@ Function Get-Settings {
# Filenames for 32 bit Windows
$32bitPrograms = @{
"PyCrypto" = "pycrypto-2.6.1-cp27-none-win32.whl"
"Python" = "python-2.7.11.msi"
"Python" = "python-2.7.12.msi"
"PyYAML" = "PyYAML-3.11.win32-py2.7.exe"
}
$ini.Add("32bitPrograms", $32bitPrograms)

View File

@ -846,14 +846,6 @@ def create(vm_):
'access_ip' in node.get('extra', {}):
result = [node['extra']['access_ip']]
if not result:
temp_dd = node.get('addresses', {})
for k, addr_ll in temp_dd.iteritems():
for addr_dd in addr_ll:
addr = addr_dd.get('addr', None)
if addr is not None:
result.append(addr.strip())
private = node.get('private_ips', [])
public = node.get('public_ips', [])
fixed = node.get('fixed_ips', [])

View File

@ -1382,7 +1382,7 @@ class LazyLoader(salt.utils.lazy.LazyDict):
module_name,
)
if virtual_err is not None:
log.debug('Error loading {0}.{1}: {2}'.format(self.tag,
log.trace('Error loading {0}.{1}: {2}'.format(self.tag,
module_name,
virtual_err,
))

View File

@ -118,12 +118,16 @@ def get_config(config_file='/etc/dnsmasq.conf'):
'''
Dumps all options from the config file.
config_file
The location of the config file from which to obtain contents.
Defaults to ``/etc/dnsmasq.conf``.
CLI Examples:
.. code-block:: bash
salt '*' dnsmasq.get_config
salt '*' dnsmasq.get_config file=/etc/dnsmasq.conf
salt '*' dnsmasq.get_config config_file=/etc/dnsmasq.conf
'''
dnsopts = _parse_dnamasq(config_file)
if 'conf-dir' in dnsopts:

View File

@ -2521,11 +2521,11 @@ def append(path, *args, **kwargs):
if ofile.read(len(linesep)) != linesep:
ofile.seek(0, os.SEEK_END)
ofile.write(linesep)
# Append lines in text mode
with salt.utils.fopen(path, 'r+') as ofile:
ofile.seek(0, os.SEEK_END)
for line in args:
ofile.write('{0}\n'.format(line))
with salt.utils.fopen(path, 'a') as ofile:
for new_line in args:
ofile.write('{0}{1}'.format(new_line, os.linesep))
return 'Wrote {0} lines to "{1}"'.format(len(args), path)

View File

@ -1372,7 +1372,10 @@ def describe(cwd, rev='HEAD', user=None, ignore_retcode=False):
cwd = _expand_path(cwd, user)
if not isinstance(rev, six.string_types):
rev = str(rev)
command = ['git', 'describe', rev]
command = ['git', 'describe']
if _LooseVersion(version(versioninfo=False)) >= _LooseVersion('1.5.6'):
command.append('--always')
command.append(rev)
return _git_run(command,
cwd=cwd,
runas=user,

View File

@ -12,7 +12,7 @@ import xml.etree.ElementTree as ET
# Import salt libs
import salt.utils
import salt.utils.cloud as suc
from salt.exceptions import SaltInvocationError
from salt.exceptions import SaltInvocationError, CommandExecutionError
log = logging.getLogger(__name__)
@ -75,7 +75,12 @@ def _gluster_xml(cmd):
result = __salt__['cmd.run'](
'gluster --xml --mode=script', stdin="{0}\n".format(cmd)
)
root = ET.fromstring(_gluster_output_cleanup(result))
try:
root = ET.fromstring(_gluster_output_cleanup(result))
except ET.ParseError:
raise CommandExecutionError('\n'.join(result.splitlines()[:-1]))
if _gluster_ok(root):
output = root.find('output')
if output:
@ -84,6 +89,7 @@ def _gluster_xml(cmd):
log.info('Gluster call "{0}" succeeded'.format(cmd))
else:
log.error('Failed gluster call: {0}: {1}'.format(cmd, root.find('opErrstr').text))
return root

View File

@ -139,7 +139,15 @@ def output(data):
data = data.pop('data')
for host, hostdata in six.iteritems(data):
if not isinstance(hostdata, dict):
# Highstate return data must be a dict, if this is not the case
# then this value is likely a retcode.
continue
return _format_host(host, hostdata)[0]
log.error(
'Data passed to highstate outputter is not a valid highstate return: %s',
data
)
def _format_host(host, data):

View File

@ -2576,9 +2576,14 @@ class BaseHighState(object):
tops[saltenv].append({})
log.debug('No contents loaded for env: {0}'.format(saltenv))
if found > 1:
log.warning('Top file merge strategy set to \'merge\' and multiple top files found. '
'Top file merging order is undefined; '
'for better results use \'same\' option')
log.warning(
'top_file_merging_strategy is set to \'merge\' and '
'multiple top files were found. Merging order is not '
'deterministic, it may be desirable to either set '
'top_file_merging_strategy to \'same\' or use the '
'\'env_order\' configuration parameter to specify the '
'merging order.'
)
if found == 0:
log.error('No contents found in top file')

View File

@ -3829,17 +3829,17 @@ def append(name,
.. versionadded:: 0.9.5
'''
name = os.path.expanduser(name)
ret = {
'name': name,
ret = {'name': name,
'changes': {},
'pchanges': {},
'result': False,
'comment': ''}
if not name:
return _error(ret, 'Must provide name to file.append')
name = os.path.expanduser(name)
if sources is None:
sources = []
@ -3888,17 +3888,16 @@ def append(name,
with salt.utils.fopen(name, 'rb') as fp_:
slines = fp_.readlines()
slines = [item.rstrip() for item in slines]
count = 0
test_lines = []
append_lines = []
try:
for chunk in text:
if ignore_whitespace:
if __salt__['file.search'](
name,
salt.utils.build_whitespace_split_regex(chunk),
multiline=True):
name,
salt.utils.build_whitespace_split_regex(chunk),
multiline=True):
continue
elif __salt__['file.search'](
name,
@ -3906,37 +3905,39 @@ def append(name,
multiline=True):
continue
lines = chunk.splitlines()
for line_item in chunk.splitlines():
append_lines.append('{0}'.format(line_item))
for line in lines:
if __opts__['test']:
ret['comment'] = 'File {0} is set to be updated'.format(name)
ret['result'] = None
test_lines.append('{0}\n'.format(line))
else:
__salt__['file.append'](name, line)
count += 1
except TypeError:
return _error(ret, 'No text found to append. Nothing appended')
if __opts__['test']:
nlines = slines + test_lines
ret['comment'] = 'File {0} is set to be updated'.format(name)
ret['result'] = None
nlines = list(slines)
nlines.extend(append_lines)
if slines != nlines:
if not salt.utils.istextfile(name):
ret['changes']['diff'] = 'Replace binary file'
else:
# Changes happened, add them
ret['changes']['diff'] = (
''.join(difflib.unified_diff(slines, nlines))
'\n'.join(difflib.unified_diff(slines, nlines))
)
else:
ret['comment'] = 'File {0} is in correct state'.format(name)
ret['result'] = True
return ret
if append_lines:
__salt__['file.append'](name, args=append_lines)
ret['comment'] = 'Appended {0} lines'.format(len(append_lines))
else:
ret['comment'] = 'File {0} is in correct state'.format(name)
with salt.utils.fopen(name, 'rb') as fp_:
nlines = fp_.readlines()
nlines = [item.rstrip(os.linesep) for item in nlines]
if slines != nlines:
if not salt.utils.istextfile(name):
@ -3944,14 +3945,10 @@ def append(name,
else:
# Changes happened, add them
ret['changes']['diff'] = (
''.join(difflib.unified_diff(slines, nlines))
)
'\n'.join(difflib.unified_diff(slines, nlines)))
if count:
ret['comment'] = 'Appended {0} lines'.format(count)
else:
ret['comment'] = 'File {0} is in correct state'.format(name)
ret['result'] = True
return ret

View File

@ -1946,7 +1946,7 @@ def detached(name,
local_commit_id = _get_local_rev_and_branch(target, user)[0]
if remote_ref_type is 'hash' and __salt__['git.describe'](ref):
if remote_ref_type is 'hash' and __salt__['git.describe'](target, ref):
# The ref is a hash and it exists locally so skip to checkout
hash_exists_locally = True
else:
@ -2110,7 +2110,7 @@ def detached(name,
#get refs and checkout
checkout_commit_id = ''
if remote_ref_type is 'hash':
if __salt__['git.describe'](ref):
if __salt__['git.describe'](target, ref):
checkout_commit_id = ref
else:
return _fail(

View File

@ -1765,31 +1765,18 @@ def latest(
targets = {}
problems = []
cmp_func = __salt__.get('pkg.version_cmp')
minion_os = __salt__['grains.item']('os')['os']
if minion_os == 'Gentoo' and watch_flags:
for pkg in desired_pkgs:
if not avail[pkg] and not cur[pkg]:
for pkg in desired_pkgs:
if not avail[pkg]:
if not cur[pkg]:
msg = 'No information found for \'{0}\'.'.format(pkg)
log.error(msg)
problems.append(msg)
else:
if salt.utils.compare_versions(ver1=cur[pkg], oper='!=', ver2=avail[pkg], cmp_func=cmp_func):
targets[pkg] = avail[pkg]
else:
if not cur[pkg] or __salt__['portage_config.is_changed_uses'](pkg):
targets[pkg] = avail[pkg]
else:
for pkg in desired_pkgs:
if pkg not in avail:
if not cur.get(pkg):
msg = 'No information found for \'{0}\'.'.format(pkg)
log.error(msg)
problems.append(msg)
elif not cur.get(pkg) \
or salt.utils.compare_versions(ver1=cur[pkg], oper='<', ver2=avail[pkg], cmp_func=cmp_func):
elif watch_flags \
and __grains__.get('os') == 'Gentoo' \
and __salt__['portage_config.is_changed_uses'](pkg):
targets[pkg] = avail[pkg]
else:
targets[pkg] = avail[pkg]
if problems:
return {

View File

@ -111,9 +111,14 @@ class TestModulesGrains(integration.ModuleCase):
test to ensure some core grains are returned
'''
grains = ['os', 'os_family', 'osmajorrelease', 'osrelease', 'osfullname', 'id']
os = self.run_function('grains.get', ['os'])
for grain in grains:
get_grain = self.run_function('grains.get', [grain])
self.assertTrue(get_grain, grain + "is not available")
if os == 'Arch' and grain in ['osmajorrelease', 'osrelease']:
self.assertEqual(get_grain, '')
continue
self.assertTrue(get_grain)
class GrainsAppendTestCase(integration.ModuleCase):

View File

@ -10,29 +10,23 @@ from __future__ import absolute_import
# Salt libs
import integration
import salt.utils
# Salttesting libs
from salttesting import skipIf
from salttesting.helpers import destructiveTest, ensure_in_syspath
ensure_in_syspath('../../')
def _check_arch_linux():
with salt.utils.fopen('/etc/os-release', 'r') as f:
release = f.readline()
r = release.split('=')[1].strip().strip('"')
return r
@destructiveTest
@skipIf(_check_arch_linux() == 'Arch Linux', 'Network state not supported on Arch')
class NetworkTest(integration.ModuleCase, integration.SaltReturnAssertsMixIn):
'''
Validate network state module
'''
def setUp(self):
os_family = self.run_function('grains.get', ['os_family'])
if os_family not in ('RedHat', 'Debian'):
self.skipTest('Network state only supported on RedHat and Debian based systems')
self.run_function('cmd.run', ['ip link add name dummy0 type dummy'])
def tearDown(self):

View File

@ -1088,88 +1088,6 @@ class FileTestCase(TestCase):
ret.update({'comment': comt, 'result': True})
self.assertDictEqual(filestate.uncomment(name, regex), ret)
# 'append' function tests: 1
def test_append(self):
'''
Test to ensure that some text appears at the end of a file.
'''
name = '/etc/motd'
source = ['salt://motd/hr-messages.tmpl']
sources = ['salt://motd/devops-messages.tmpl']
text = ['Trust no one unless you have eaten much salt with him.']
ret = {'name': name,
'result': False,
'comment': '',
'pchanges': {},
'changes': {}}
comt = ('Must provide name to file.append')
ret.update({'comment': comt, 'name': ''})
self.assertDictEqual(filestate.append(''), ret)
comt = ('source and sources are mutually exclusive')
ret.update({'comment': comt, 'name': name})
self.assertDictEqual(filestate.append(name, source=source,
sources=sources), ret)
mock_t = MagicMock(return_value=True)
mock_f = MagicMock(return_value=False)
mock_err = MagicMock(side_effect=[TypeError, True, True])
with patch.dict(filestate.__salt__,
{'file.directory_exists': mock_f,
'file.makedirs': mock_t,
'file.stats': mock_f,
'cp.get_template': mock_f,
'file.contains_regex_multiline': mock_err,
'file.search': mock_err}):
with patch.object(os.path, 'isdir', mock_t):
comt = ('The following files will be changed:\n/etc:'
' directory - new\n')
ret.update({'comment': comt, 'name': name, 'pchanges': {'/etc': {'directory': 'new'}}})
self.assertDictEqual(filestate.append(name, makedirs=True), ret)
with patch.object(os.path, 'isabs', mock_f):
comt = ('Specified file {0} is not an absolute path'
.format(name))
ret.update({'comment': comt, 'pchanges': {}})
self.assertDictEqual(filestate.append(name), ret)
with patch.object(os.path, 'isabs', mock_t):
with patch.object(os.path, 'exists', mock_t):
comt = ("Failed to load template file {0}".format(source))
ret.pop('pchanges')
ret.update({'comment': comt, 'name': source, 'data': [], })
self.assertDictEqual(filestate.append(name, source=source),
ret)
ret.pop('data', None)
ret.update({'name': name})
with patch.object(salt.utils, 'fopen',
MagicMock(mock_open(read_data=''))):
comt = ('No text found to append. Nothing appended')
ret.update({'comment': comt, 'pchanges': {}})
self.assertDictEqual(filestate.append(name, text=text),
ret)
with patch.object(salt.utils, 'istextfile', mock_f):
with patch.dict(filestate.__opts__, {'test': True}):
change = {'diff': 'Replace binary file'}
ret.update({'comment': '', 'result': None,
'changes': change})
self.assertDictEqual(filestate.append
(name, text=text), ret)
with patch.dict(filestate.__opts__,
{'test': False}):
comt = ('File {0} is in correct state'
.format(name))
ret.update({'comment': comt, 'result': True,
'changes': {}})
self.assertDictEqual(filestate.append
(name, text=text), ret)
# 'prepend' function tests: 1
def test_prepend(self):