Merge remote-tracking branch 'upstream/2014.7' into merge-forward-2015.2

Conflicts:
	doc/conf.py
	doc/man/salt-api.1
	doc/man/salt-call.1
	doc/man/salt-cloud.1
	doc/man/salt-cp.1
	doc/man/salt-key.1
	doc/man/salt-master.1
	doc/man/salt-minion.1
	doc/man/salt-run.1
	doc/man/salt-ssh.1
	doc/man/salt-syndic.1
	doc/man/salt-unity.1
	doc/man/salt.1
	doc/man/salt.7
	salt/cloud/clouds/linode.py
	salt/states/composer.py
	salt/states/win_update.py
This commit is contained in:
Colton Myers 2015-03-11 15:14:56 -06:00
commit ebe7eeafd9
12 changed files with 1517 additions and 261 deletions

View File

@ -151,7 +151,7 @@ copyright = '2015 SaltStack, Inc.'
version = salt.version.__version__ version = salt.version.__version__
#release = '.'.join(map(str, salt.version.__version_info__)) #release = '.'.join(map(str, salt.version.__version_info__))
release = '2015.2' release = '2014.7.2'
needs_sphinx = '1.3' needs_sphinx = '1.3'

View File

@ -1885,7 +1885,7 @@ strategy between different sources. It accepts 3 values:
* aggregate: * aggregate:
instructs aggregation of elements between sources that use the #!yamlex rendered. instructs aggregation of elements between sources that use the #!yamlex renderer.
For example, these two documents: For example, these two documents:

View File

@ -6,8 +6,28 @@ Linode is a public cloud provider with a focus on Linux instances.
Dependencies Dependencies
============ ============
* linode-python >= 1.1
OR
* Libcloud >= 0.13.2 * Libcloud >= 0.13.2
This driver supports accessing Linode via linode-python or Apache Libcloud.
Linode-python is recommended, it is more full-featured than Libcloud. In
particular using linode-python enables stopping, starting, and cloning
machines.
Driver selection is automatic. If linode-python is present it will be used.
If it is absent, salt-cloud will fall back to Libcloud. If neither are present
salt-cloud will abort.
NOTE: linode-python 1.1 or later is recommended. As of this publication it is
not yet on PyPi. Earlier versions of linode-python should work but can leak
sensitive information into the debug logs.
Linode-python can be downloaded from
https://github.com/tjfontaine/linode-python.
Configuration Configuration
============= =============
Linode requires a single API key, but the default root password for new Linode requires a single API key, but the default root password for new
@ -100,3 +120,34 @@ command:
uuid: uuid:
8457f92eaffc92b7666b6734a96ad7abe1a8a6dd 8457f92eaffc92b7666b6734a96ad7abe1a8a6dd
...SNIP... ...SNIP...
Cloning
=======
When salt-cloud accesses Linode via linode-python it can clone machines.
It is safest to clone a stopped machine. To stop a machine run
.. code-block:: bash
salt-cloud -a stop machine_to_clone
To create a new machine based on another machine, add an entry to your linode
cloud profile that looks like this:
.. code-block:: yaml
li-clone:
provider: linode
clonefrom: machine_to_clone
script_args: -C
Then run salt-cloud as normal, specifying `-p li-clone`. The profile name can
be anything--it doesn't have to be `li-clone`.
`Clonefrom:` is the name of an existing machine in Linode from which to clone.
`Script_args: -C` is necessary to avoid re-deploying Salt via salt-bootstrap.
`-C` will just re-deploy keys so the new minion will not have a duplicate key
or minion_id on the master.

File diff suppressed because it is too large Load Diff

View File

@ -6,10 +6,11 @@ from __future__ import absolute_import
# Import python libs # Import python libs
import logging import logging
import os.path
# Import salt libs # Import salt libs
import salt.utils import salt.utils
from salt.exceptions import CommandExecutionError from salt.exceptions import CommandExecutionError, CommandNotFoundError, SaltInvocationError
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -35,6 +36,162 @@ def _valid_composer(composer):
return False return False
def did_composer_install(dir):
'''
Test to see if the vendor directory exists in this directory
dir
Directory location of the composer.json file
CLI Example:
.. code-block:: bash
salt '*' composer.did_composer_install /var/www/application
'''
lockFile = "{0}/vendor".format(dir)
if os.path.exists(lockFile):
return True
return False
def _run_composer(action,
dir=None,
composer=None,
php=None,
runas=None,
prefer_source=None,
prefer_dist=None,
no_scripts=None,
no_plugins=None,
optimize=None,
no_dev=None,
quiet=False,
composer_home='/root',
extra_flags=None):
'''
Run PHP's composer with a specific action.
If composer has not been installed globally making it available in the
system PATH & making it executable, the ``composer`` and ``php`` parameters
will need to be set to the location of the executables.
action
The action to pass to composer ('install', 'update', 'selfupdate', etc).
dir
Directory location of the composer.json file. Required except when
action='selfupdate'
composer
Location of the composer.phar file. If not set composer will
just execute "composer" as if it is installed globally.
(i.e. /path/to/composer.phar)
php
Location of the php executable to use with composer.
(i.e. /usr/bin/php)
runas
Which system user to run composer as.
prefer_source
--prefer-source option of composer.
prefer_dist
--prefer-dist option of composer.
no_scripts
--no-scripts option of composer.
no_plugins
--no-plugins option of composer.
optimize
--optimize-autoloader option of composer. Recommended for production.
no_dev
--no-dev option for composer. Recommended for production.
quiet
--quiet option for composer. Whether or not to return output from composer.
composer_home
$COMPOSER_HOME environment variable
extra_flags
None, or a string containing extra flags to pass to composer.
'''
if composer is not None:
if php is None:
php = 'php'
else:
composer = 'composer'
# Validate Composer is there
if not _valid_composer(composer):
raise CommandNotFoundError('\'composer.{0}\' is not available. Couldn\'t find {1!r}.'
.format(action, composer))
# Don't need a dir for the 'selfupdate' action; all other actions do need a dir
if dir is None and action != 'selfupdate':
raise SaltInvocationError('{0!r} is required for \'composer.{1}\''
.format('dir', action))
if action is None:
raise SaltInvocationError('{0!r} is required for {1!r}'
.format('action', 'composer._run_composer'))
# Base Settings
cmd = '{0} {1} {2}'.format(composer, action, '--no-interaction --no-ansi')
if extra_flags is not None:
cmd = '{0} {1}'.format(cmd, extra_flags)
# If php is set, prepend it
if php is not None:
cmd = php + ' ' + cmd
# Add Working Dir
if dir is not None:
cmd += ' --working-dir=' + dir
# Other Settings
if quiet is True:
cmd += ' --quiet'
if no_dev is True:
cmd += ' --no-dev'
if prefer_source is True:
cmd += ' --prefer-source'
if prefer_dist is True:
cmd += ' --prefer-dist'
if no_scripts is True:
cmd += ' --no-scripts'
if no_plugins is True:
cmd += ' --no-plugins'
if optimize is True:
cmd += ' --optimize-autoloader'
result = __salt__['cmd.run_all'](cmd,
runas=runas,
env={'COMPOSER_HOME': composer_home},
python_shell=False)
if result['retcode'] != 0:
raise CommandExecutionError(result['stderr'])
if quiet is True:
return True
return result
def install(dir, def install(dir,
composer=None, composer=None,
php=None, php=None,
@ -102,60 +259,150 @@ def install(dir,
salt '*' composer.install /var/www/application \ salt '*' composer.install /var/www/application \
no_dev=True optimize=True no_dev=True optimize=True
''' '''
if composer is not None: result = _run_composer('install',
if php is None: dir=dir,
php = 'php' composer=composer,
else: php=php,
composer = 'composer' runas=runas,
prefer_source=prefer_source,
prefer_dist=prefer_dist,
no_scripts=no_scripts,
no_plugins=no_plugins,
optimize=optimize,
no_dev=no_dev,
quiet=quiet,
composer_home=composer_home)
return result
# Validate Composer is there
if not _valid_composer(composer):
return '{0!r} is not available. Couldn\'t find {1!r}.'.format('composer.install', composer)
if dir is None: def update(dir,
return '{0!r} is required for {1!r}'.format('dir', 'composer.install') composer=None,
php=None,
runas=None,
prefer_source=None,
prefer_dist=None,
no_scripts=None,
no_plugins=None,
optimize=None,
no_dev=None,
quiet=False,
composer_home='/root'):
'''
Update composer dependencies for a directory.
# Base Settings If `composer install` has not yet been run, this runs `composer install`
cmd = composer + ' install --no-interaction' instead.
# If php is set, prepend it If composer has not been installed globally making it available in the
if php is not None: system PATH & making it executable, the ``composer`` and ``php`` parameters
cmd = php + ' ' + cmd will need to be set to the location of the executables.
# Add Working Dir dir
cmd += ' --working-dir=' + dir Directory location of the composer.json file.
# Other Settings composer
if quiet is True: Location of the composer.phar file. If not set composer will
cmd += ' --quiet' just execute "composer" as if it is installed globally.
(i.e. /path/to/composer.phar)
if no_dev is True: php
cmd += ' --no-dev' Location of the php executable to use with composer.
(i.e. /usr/bin/php)
if prefer_source is True: runas
cmd += ' --prefer-source' Which system user to run composer as.
if prefer_dist is True: prefer_source
cmd += ' --prefer-dist' --prefer-source option of composer.
if no_scripts is True: prefer_dist
cmd += ' --no-scripts' --prefer-dist option of composer.
if no_plugins is True: no_scripts
cmd += ' --no-plugins' --no-scripts option of composer.
if optimize is True: no_plugins
cmd += ' --optimize-autoloader' --no-plugins option of composer.
result = __salt__['cmd.run_all'](cmd, optimize
runas=runas, --optimize-autoloader option of composer. Recommended for production.
env={'COMPOSER_HOME': composer_home},
python_shell=False)
if result['retcode'] != 0: no_dev
raise CommandExecutionError(result['stderr']) --no-dev option for composer. Recommended for production.
if quiet is True: quiet
return True --quiet option for composer. Whether or not to return output from composer.
return result['stdout'] composer_home
$COMPOSER_HOME environment variable
CLI Example:
.. code-block:: bash
salt '*' composer.update /var/www/application
salt '*' composer.update /var/www/application \
no_dev=True optimize=True
'''
result = _run_composer('update',
extra_flags='--no-progress',
dir=dir,
composer=composer,
php=php,
runas=runas,
prefer_source=prefer_source,
prefer_dist=prefer_dist,
no_scripts=no_scripts,
no_plugins=no_plugins,
optimize=optimize,
no_dev=no_dev,
quiet=quiet,
composer_home=composer_home)
return result
def selfupdate(composer=None,
php=None,
runas=None,
quiet=False,
composer_home='/root'):
'''
Update composer itself.
If composer has not been installed globally making it available in the
system PATH & making it executable, the ``composer`` and ``php`` parameters
will need to be set to the location of the executables.
composer
Location of the composer.phar file. If not set composer will
just execute "composer" as if it is installed globally.
(i.e. /path/to/composer.phar)
php
Location of the php executable to use with composer.
(i.e. /usr/bin/php)
runas
Which system user to run composer as.
quiet
--quiet option for composer. Whether or not to return output from composer.
composer_home
$COMPOSER_HOME environment variable
CLI Example:
.. code-block:: bash
salt '*' composer.selfupdate
'''
result = _run_composer('selfupdate',
extra_flags='--no-progress',
composer=composer,
php=php,
runas=runas,
quiet=quiet,
composer_home=composer_home)
return result

View File

@ -303,7 +303,7 @@ def disable(name, **kwargs):
salt '*' service.disable <service name> salt '*' service.disable <service name>
''' '''
cmd = ['sc', 'config', name, 'start=', 'demand'] cmd = ['sc', 'config', name, 'start=', 'disabled']
return not __salt__['cmd.retcode'](cmd, python_shell=False) return not __salt__['cmd.retcode'](cmd, python_shell=False)

View File

@ -2804,7 +2804,7 @@ class BaseHighState(object):
if state: if state:
self.merge_included_states(highstate, state, errors) self.merge_included_states(highstate, state, errors)
for i, error in enumerate(errors[:]): for i, error in enumerate(errors[:]):
if 'is not available on the salt master' in error: if 'is not available' in error:
# match SLS foobar in environment # match SLS foobar in environment
this_sls = 'SLS {0} in saltenv'.format( this_sls = 'SLS {0} in saltenv'.format(
sls_match) sls_match)

View File

@ -40,7 +40,7 @@ the location of composer in the state.
from __future__ import absolute_import from __future__ import absolute_import
# Import salt libs # Import salt libs
from salt.exceptions import CommandExecutionError, CommandNotFoundError from salt.exceptions import SaltException
def __virtual__(): def __virtual__():
@ -60,10 +60,138 @@ def installed(name,
no_plugins=None, no_plugins=None,
optimize=None, optimize=None,
no_dev=None, no_dev=None,
composer_home='/root'): quiet=False,
composer_home='/root',
always_check=True):
''' '''
Verify that composer has installed the latest packages give a Verify that the correct versions of composer dependencies are present.
``composer.json`` and ``composer.lock`` file in a directory.
dir
Directory location of the composer.json file.
composer
Location of the composer.phar file. If not set composer will
just execute "composer" as if it is installed globally.
(i.e. /path/to/composer.phar)
php
Location of the php executable to use with composer.
(i.e. /usr/bin/php)
user
Which system user to run composer as.
.. versionadded:: 2014.1.4
prefer_source
--prefer-source option of composer.
prefer_dist
--prefer-dist option of composer.
no_scripts
--no-scripts option of composer.
no_plugins
--no-plugins option of composer.
optimize
--optimize-autoloader option of composer. Recommended for production.
no_dev
--no-dev option for composer. Recommended for production.
quiet
--quiet option for composer. Whether or not to return output from composer.
composer_home
$COMPOSER_HOME environment variable
always_check
If True, _always_ run `composer install` in the directory. This is the
default behavior. If False, only run `composer install` if there is no
vendor directory present.
'''
ret = {'name': name, 'result': None, 'comment': '', 'changes': {}}
did_install = __salt__['composer.did_composer_install'](name)
# Check if composer.lock exists, if so we already ran `composer install`
# and we don't need to do it again
if always_check is False and did_install:
ret['result'] = True
ret['comment'] = 'Composer already installed this directory'
return ret
# The state of the system does need to be changed. Check if we're running
# in ``test=true`` mode.
if __opts__['test'] is True:
if did_install is True:
install_status = ""
else:
install_status = "not "
ret['comment'] = 'The state of "{0}" will be changed.'.format(name)
ret['changes'] = {
'old': 'composer install has {0}been run in {1}'.format(install_status, name),
'new': 'composer install will be run in {0}'.format(name)
}
ret['result'] = None
return ret
try:
call = __salt__['composer.install'](
name,
composer=composer,
php=php,
runas=user,
prefer_source=prefer_source,
prefer_dist=prefer_dist,
no_scripts=no_scripts,
no_plugins=no_plugins,
optimize=optimize,
no_dev=no_dev,
quiet=quiet,
composer_home=composer_home
)
except (SaltException) as err:
ret['result'] = False
ret['comment'] = 'Error executing composer in \'{0!r}\': {1!r}'.format(name, err)
return ret
# If composer retcode != 0 then an exception was thrown and we dealt with it.
# Any other case is success, regardless of what composer decides to output.
ret['result'] = True
if quiet is True:
ret['comment'] = 'Composer install completed successfully, output silenced by quiet flag'
else:
ret['comment'] = 'Composer install completed successfully'
ret['changes'] = {
'stderr': call['stderr'],
'stdout': call['stdout']
}
return ret
def update(name,
composer=None,
php=None,
user=None,
prefer_source=None,
prefer_dist=None,
no_scripts=None,
no_plugins=None,
optimize=None,
no_dev=None,
quiet=False,
composer_home='/root'):
'''
Composer update the directory to ensure we have the latest versions
of all project dependencies.
dir dir
Directory location of the composer.json file. Directory location of the composer.json file.
@ -108,8 +236,26 @@ def installed(name,
''' '''
ret = {'name': name, 'result': None, 'comment': '', 'changes': {}} ret = {'name': name, 'result': None, 'comment': '', 'changes': {}}
# Check if composer.lock exists, if so we already ran `composer install`
is_installed = __salt__['composer.did_composer_install'](name)
if is_installed:
old_status = "composer install has not yet been run in {0}".format(name)
else:
old_status = "composer install has been run in {0}".format(name)
# The state of the system does need to be changed. Check if we're running
# in ``test=true`` mode.
if __opts__['test'] is True:
ret['comment'] = 'The state of "{0}" will be changed.'.format(name)
ret['changes'] = {
'old': old_status,
'new': 'composer install/update will be run in {0}'.format(name)
}
ret['result'] = None
return ret
try: try:
call = __salt__['composer.install']( call = __salt__['composer.update'](
name, name,
composer=composer, composer=composer,
php=php, php=php,
@ -120,22 +266,26 @@ def installed(name,
no_plugins=no_plugins, no_plugins=no_plugins,
optimize=optimize, optimize=optimize,
no_dev=no_dev, no_dev=no_dev,
quiet=False, quiet=quiet,
composer_home=composer_home composer_home=composer_home
) )
except (CommandNotFoundError, CommandExecutionError) as err: except (SaltException) as err:
ret['result'] = False ret['result'] = False
ret['comment'] = 'Error executing composer in \'{0!r}\': {1!r}'.format(name, err) ret['comment'] = 'Error executing composer in \'{0!r}\': {1!r}'.format(name, err)
return ret return ret
if call or isinstance(call, list) or isinstance(call, dict): # If composer retcode != 0 then an exception was thrown and we dealt with it.
ret['result'] = True # Any other case is success, regardless of what composer decides to output.
if call.find('Nothing to install or update') < 0:
ret['changes']['stdout'] = call
ret['comment'] = 'Composer ran, nothing changed in {0!r}'.format(name) ret['result'] = True
if quiet is True:
ret['comment'] = 'Composer update completed successfully, output silenced by quiet flag'
else: else:
ret['result'] = False ret['comment'] = 'Composer update completed successfully'
ret['comment'] = 'Could not run composer' ret['changes'] = {
'stderr': call['stderr'],
'stdout': call['stdout']
}
return ret return ret

View File

@ -45,7 +45,7 @@ The following example installs all driver updates that don't require a reboot:
.. code-block:: yaml .. code-block:: yaml
gryffindor: gryffindor:
win_update.install: win_update.installed:
- includes: - includes:
- driver: True - driver: True
- software: False - software: False

View File

@ -221,7 +221,7 @@ def query(key, keyid, method='GET', params=None, headers=None,
if return_url is True: if return_url is True:
return ret, requesturl return ret, requesturl
else: else:
if method == 'GET' or method == 'HEAD': if result.status_code != requests.codes.ok:
return return
ret = {'headers': []} ret = {'headers': []}
for header in result.headers: for header in result.headers:

View File

@ -11,6 +11,7 @@ import os
import re import re
import sys import sys
import stat import stat
import errno
import socket import socket
import logging import logging
@ -162,8 +163,11 @@ def verify_files(files, user):
for fn_ in files: for fn_ in files:
dirname = os.path.dirname(fn_) dirname = os.path.dirname(fn_)
try: try:
if not os.path.isdir(dirname): try:
os.makedirs(dirname) os.makedirs(dirname)
except OSError as err:
if err.errno != errno.EEXIST:
raise
if not os.path.isfile(fn_): if not os.path.isfile(fn_):
with salt.utils.fopen(fn_, 'w+') as fp_: with salt.utils.fopen(fn_, 'w+') as fp_:
fp_.write('') fp_.write('')

View File

@ -0,0 +1,172 @@
# -*- coding: utf-8 -*-
'''
:codeauthor: :email:`Rupesh Tare <rupesht@saltstack.com>`
'''
# Import Python libs
from __future__ import absolute_import
# Import Salt Testing Libs
from salttesting import TestCase, skipIf
from salttesting.mock import (
MagicMock,
patch,
NO_MOCK,
NO_MOCK_REASON
)
# Import Salt Libs
from salt.modules import composer
from salt.exceptions import CommandExecutionError, CommandNotFoundError, SaltInvocationError
# Globals
composer.__grains__ = {}
composer.__salt__ = {}
composer.__context__ = {}
composer.__opts__ = {}
@skipIf(NO_MOCK, NO_MOCK_REASON)
class ComposerTestCase(TestCase):
'''
Test cases for salt.modules.composer
'''
def test_install(self):
'''
Test for Install composer dependencies for a directory.
'''
# Test _valid_composer=False throws exception
mock = MagicMock(return_value=False)
with patch.object(composer, '_valid_composer', mock):
self.assertRaises(CommandNotFoundError, composer.install, 'd')
# Test no directory specified throws exception
mock = MagicMock(return_value=True)
with patch.object(composer, '_valid_composer', mock):
self.assertRaises(SaltInvocationError, composer.install, None)
# Test `composer install` exit status != 0 throws exception
mock = MagicMock(return_value=True)
with patch.object(composer, '_valid_composer', mock):
mock = MagicMock(return_value={'retcode': 1, 'stderr': 'A'})
with patch.dict(composer.__salt__, {'cmd.run_all': mock}):
self.assertRaises(CommandExecutionError, composer.install, 'd')
# Test success with quiet=True returns True
mock = MagicMock(return_value=True)
with patch.object(composer, '_valid_composer', mock):
mock = MagicMock(return_value={'retcode': 0, 'stderr': 'A'})
with patch.dict(composer.__salt__, {'cmd.run_all': mock}):
self.assertTrue(composer.install('dir', None, None, None, None,
None, None, None, None, None,
True))
# Test success with quiet=False returns object
mock = MagicMock(return_value=True)
with patch.object(composer, '_valid_composer', mock):
rval = {'retcode': 0, 'stderr': 'A', 'stdout': 'B'}
mock = MagicMock(return_value=rval)
with patch.dict(composer.__salt__, {'cmd.run_all': mock}):
self.assertEqual(composer.install('dir'), rval)
def test_update(self):
'''
Test for Update composer dependencies for a directory.
'''
# Test _valid_composer=False throws exception
mock = MagicMock(return_value=False)
with patch.object(composer, '_valid_composer', mock):
self.assertRaises(CommandNotFoundError, composer.update, 'd')
# Test no directory specified throws exception
mock = MagicMock(return_value=True)
with patch.object(composer, '_valid_composer', mock):
mock = MagicMock(return_value=True)
with patch.object(composer, 'did_composer_install', mock):
self.assertRaises(SaltInvocationError, composer.update, None)
# Test update with error exit status throws exception
mock = MagicMock(return_value=True)
with patch.object(composer, '_valid_composer', mock):
mock = MagicMock(return_value=True)
with patch.object(composer, 'did_composer_install', mock):
mock = MagicMock(return_value={'retcode': 1, 'stderr': 'A'})
with patch.dict(composer.__salt__, {'cmd.run_all': mock}):
self.assertRaises(CommandExecutionError, composer.update, 'd')
# Test update with existing vendor directory and quiet=True
mock = MagicMock(return_value=True)
with patch.object(composer, '_valid_composer', mock):
mock = MagicMock(return_value=True)
with patch.object(composer, 'did_composer_install', mock):
mock = MagicMock(return_value={'retcode': 0, 'stderr': 'A'})
with patch.dict(composer.__salt__, {'cmd.run_all': mock}):
self.assertTrue(composer.update('dir', None, None, None, None,
None, None, None, None, None,
True))
# Test update with no vendor directory and quiet=True
mock = MagicMock(return_value=True)
with patch.object(composer, '_valid_composer', mock):
mock = MagicMock(return_value=False)
with patch.object(composer, 'did_composer_install', mock):
mock = MagicMock(return_value={'retcode': 0, 'stderr': 'A'})
with patch.dict(composer.__salt__, {'cmd.run_all': mock}):
self.assertTrue(composer.update('dir', None, None, None, None,
None, None, None, None, None,
True))
# Test update with existing vendor directory
mock = MagicMock(return_value=True)
with patch.object(composer, '_valid_composer', mock):
mock = MagicMock(return_value=True)
with patch.object(composer, 'did_composer_install', mock):
rval = {'retcode': 0, 'stderr': 'A', 'stdout': 'B'}
mock = MagicMock(return_value=rval)
with patch.dict(composer.__salt__, {'cmd.run_all': mock}):
self.assertEqual(composer.update('dir'), rval)
# Test update with no vendor directory
mock = MagicMock(return_value=True)
with patch.object(composer, '_valid_composer', mock):
mock = MagicMock(return_value=False)
with patch.object(composer, 'did_composer_install', mock):
rval = {'retcode': 0, 'stderr': 'A', 'stdout': 'B'}
mock = MagicMock(return_value=rval)
with patch.dict(composer.__salt__, {'cmd.run_all': mock}):
self.assertEqual(composer.update('dir'), rval)
def test_selfupdate(self):
'''
Test for Composer selfupdate
'''
mock = MagicMock(return_value=False)
with patch.object(composer, '_valid_composer', mock):
self.assertRaises(CommandNotFoundError, composer.selfupdate)
mock = MagicMock(return_value=True)
with patch.object(composer, '_valid_composer', mock):
mock = MagicMock(return_value={'retcode': 1, 'stderr': 'A'})
with patch.dict(composer.__salt__, {'cmd.run_all': mock}):
self.assertRaises(CommandExecutionError, composer.selfupdate)
mock = MagicMock(return_value=True)
with patch.object(composer, '_valid_composer', mock):
mock = MagicMock(return_value={'retcode': 0, 'stderr': 'A'})
with patch.dict(composer.__salt__, {'cmd.run_all': mock}):
self.assertTrue(composer.selfupdate(quiet=True))
mock = MagicMock(return_value=True)
with patch.object(composer, '_valid_composer', mock):
rval = {'retcode': 0, 'stderr': 'A', 'stdout': 'B'}
mock = MagicMock(return_value=rval)
with patch.dict(composer.__salt__, {'cmd.run_all': mock}):
self.assertEqual(composer.selfupdate(), rval)
if __name__ == '__main__':
from integration import run_tests
run_tests(ComposerTestCase, needs_daemon=False)