mirror of
https://github.com/valitydev/salt.git
synced 2024-11-07 17:09:03 +00:00
Merge pull request #21569 from basepi/merge-forward-2015.2
Merge forward from 2014.7 to 2015.2
This commit is contained in:
commit
cc9d294fcd
@ -151,7 +151,7 @@ copyright = '2015 SaltStack, Inc.'
|
||||
|
||||
version = salt.version.__version__
|
||||
#release = '.'.join(map(str, salt.version.__version_info__))
|
||||
release = '2015.2'
|
||||
release = '2014.7.2'
|
||||
|
||||
needs_sphinx = '1.3'
|
||||
|
||||
|
@ -1885,7 +1885,7 @@ strategy between different sources. It accepts 3 values:
|
||||
|
||||
* 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:
|
||||
|
||||
|
@ -6,8 +6,28 @@ Linode is a public cloud provider with a focus on Linux instances.
|
||||
|
||||
Dependencies
|
||||
============
|
||||
* linode-python >= 1.1
|
||||
|
||||
OR
|
||||
|
||||
* 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
|
||||
=============
|
||||
Linode requires a single API key, but the default root password for new
|
||||
@ -100,3 +120,34 @@ command:
|
||||
uuid:
|
||||
8457f92eaffc92b7666b6734a96ad7abe1a8a6dd
|
||||
...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
@ -386,6 +386,71 @@ def managedcloud(vm_):
|
||||
)
|
||||
|
||||
|
||||
def networks(vm_, kwargs=None):
|
||||
conn = get_conn()
|
||||
if kwargs is None:
|
||||
kwargs = {}
|
||||
networks = config.get_cloud_config_value(
|
||||
'networks', vm_, __opts__, search_global=False
|
||||
)
|
||||
|
||||
floating = []
|
||||
|
||||
if HAS014:
|
||||
if networks is not None:
|
||||
for net in networks:
|
||||
if 'fixed' in net:
|
||||
kwargs['networks'] = [
|
||||
OpenStackNetwork(n, None, None, None)
|
||||
for n in net['fixed']
|
||||
]
|
||||
elif 'floating' in net:
|
||||
pool = OpenStack_1_1_FloatingIpPool(
|
||||
net['floating'], conn.connection
|
||||
)
|
||||
for idx in pool.list_floating_ips():
|
||||
if idx.node_id is None:
|
||||
floating.append(idx)
|
||||
if not floating:
|
||||
# Note(pabelanger): We have no available floating IPs.
|
||||
# For now, we raise an exception and exit.
|
||||
# A future enhancement might be to allow salt-cloud
|
||||
# to dynamically allocate new address but that might
|
||||
raise SaltCloudSystemExit(
|
||||
'Floating pool {0!r} does not have any more '
|
||||
'please create some more or use a different '
|
||||
'pool.'.format(net['floating'])
|
||||
)
|
||||
# otherwise, attempt to obtain list without specifying pool
|
||||
# this is the same as 'nova floating-ip-list'
|
||||
elif ssh_interface(vm_) != 'private_ips':
|
||||
try:
|
||||
# This try/except is here because it appears some
|
||||
# *cough* Rackspace *cough*
|
||||
# OpenStack providers return a 404 Not Found for the
|
||||
# floating ip pool URL if there are no pools setup
|
||||
pool = OpenStack_1_1_FloatingIpPool(
|
||||
'', conn.connection
|
||||
)
|
||||
for idx in pool.list_floating_ips():
|
||||
if idx.node_id is None:
|
||||
floating.append(idx)
|
||||
if not floating:
|
||||
# Note(pabelanger): We have no available floating IPs.
|
||||
# For now, we raise an exception and exit.
|
||||
# A future enhancement might be to allow salt-cloud to
|
||||
# dynamically allocate new address but that might be
|
||||
# tricky to manage.
|
||||
raise SaltCloudSystemExit(
|
||||
'There are no more floating IP addresses '
|
||||
'available, please create some more'
|
||||
)
|
||||
except Exception as e:
|
||||
if not str(e).startswith('404'):
|
||||
raise
|
||||
vm_['floating'] = floating
|
||||
|
||||
|
||||
def request_instance(vm_=None, call=None):
|
||||
'''
|
||||
Put together all of the information necessary to request an instance on Openstack
|
||||
@ -620,9 +685,11 @@ def create(vm_):
|
||||
__opts__
|
||||
)
|
||||
)
|
||||
data = conn.ex_get_node_details(vm_['instance_id'])
|
||||
if vm_['key_filename'] is None and 'change_password' in __opts__ and __opts__['change_password'] is True:
|
||||
vm_['password'] = sup.secure_password()
|
||||
conn.root_password(vm_['instance_id'], vm_['password'])
|
||||
conn.ex_set_password(data, vm_['password'])
|
||||
networks(vm_)
|
||||
else:
|
||||
# Put together all of the information required to request the instance,
|
||||
# and then fire off the request for it
|
||||
|
@ -6,10 +6,11 @@ from __future__ import absolute_import
|
||||
|
||||
# Import python libs
|
||||
import logging
|
||||
import os.path
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils
|
||||
from salt.exceptions import CommandExecutionError
|
||||
from salt.exceptions import CommandExecutionError, CommandNotFoundError, SaltInvocationError
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@ -35,6 +36,162 @@ def _valid_composer(composer):
|
||||
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,
|
||||
composer=None,
|
||||
php=None,
|
||||
@ -102,60 +259,150 @@ def install(dir,
|
||||
salt '*' composer.install /var/www/application \
|
||||
no_dev=True optimize=True
|
||||
'''
|
||||
if composer is not None:
|
||||
if php is None:
|
||||
php = 'php'
|
||||
else:
|
||||
composer = 'composer'
|
||||
result = _run_composer('install',
|
||||
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
|
||||
|
||||
# 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:
|
||||
return '{0!r} is required for {1!r}'.format('dir', 'composer.install')
|
||||
def update(dir,
|
||||
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
|
||||
cmd = composer + ' install --no-interaction'
|
||||
If `composer install` has not yet been run, this runs `composer install`
|
||||
instead.
|
||||
|
||||
# If php is set, prepend it
|
||||
if php is not None:
|
||||
cmd = php + ' ' + cmd
|
||||
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.
|
||||
|
||||
# Add Working Dir
|
||||
cmd += ' --working-dir=' + dir
|
||||
dir
|
||||
Directory location of the composer.json file.
|
||||
|
||||
# Other Settings
|
||||
if quiet is True:
|
||||
cmd += ' --quiet'
|
||||
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)
|
||||
|
||||
if no_dev is True:
|
||||
cmd += ' --no-dev'
|
||||
php
|
||||
Location of the php executable to use with composer.
|
||||
(i.e. /usr/bin/php)
|
||||
|
||||
if prefer_source is True:
|
||||
cmd += ' --prefer-source'
|
||||
runas
|
||||
Which system user to run composer as.
|
||||
|
||||
if prefer_dist is True:
|
||||
cmd += ' --prefer-dist'
|
||||
prefer_source
|
||||
--prefer-source option of composer.
|
||||
|
||||
if no_scripts is True:
|
||||
cmd += ' --no-scripts'
|
||||
prefer_dist
|
||||
--prefer-dist option of composer.
|
||||
|
||||
if no_plugins is True:
|
||||
cmd += ' --no-plugins'
|
||||
no_scripts
|
||||
--no-scripts option of composer.
|
||||
|
||||
if optimize is True:
|
||||
cmd += ' --optimize-autoloader'
|
||||
no_plugins
|
||||
--no-plugins option of composer.
|
||||
|
||||
result = __salt__['cmd.run_all'](cmd,
|
||||
runas=runas,
|
||||
env={'COMPOSER_HOME': composer_home},
|
||||
python_shell=False)
|
||||
optimize
|
||||
--optimize-autoloader option of composer. Recommended for production.
|
||||
|
||||
if result['retcode'] != 0:
|
||||
raise CommandExecutionError(result['stderr'])
|
||||
no_dev
|
||||
--no-dev option for composer. Recommended for production.
|
||||
|
||||
if quiet is True:
|
||||
return True
|
||||
quiet
|
||||
--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
|
||||
|
@ -23,9 +23,9 @@ import jinja2
|
||||
import jinja2.exceptions
|
||||
import salt.ext.six as six
|
||||
from salt.ext.six.moves import StringIO as _StringIO # pylint: disable=import-error
|
||||
from xml.dom import minidom
|
||||
try:
|
||||
import libvirt # pylint: disable=import-error
|
||||
from xml.dom import minidom
|
||||
HAS_ALL_IMPORTS = True
|
||||
except ImportError:
|
||||
HAS_ALL_IMPORTS = False
|
||||
@ -799,8 +799,8 @@ def get_nics(vm_):
|
||||
# driver, source, and match can all have optional attributes
|
||||
if re.match('(driver|source|address)', v_node.tagName):
|
||||
temp = {}
|
||||
for key in v_node.attributes:
|
||||
temp[key] = v_node.getAttribute(key)
|
||||
for key, value in v_node.attributes.items():
|
||||
temp[key] = value
|
||||
nic[str(v_node.tagName)] = temp
|
||||
# virtualport needs to be handled separately, to pick up the
|
||||
# type attribute of the virtualport itself
|
||||
@ -857,8 +857,8 @@ def get_graphics(vm_):
|
||||
for node in doc.getElementsByTagName('domain'):
|
||||
g_nodes = node.getElementsByTagName('graphics')
|
||||
for g_node in g_nodes:
|
||||
for key in g_node.attributes:
|
||||
out[key] = g_node.getAttribute(key)
|
||||
for key, value in g_node.attributes.items():
|
||||
out[key] = value
|
||||
return out
|
||||
|
||||
|
||||
|
@ -303,7 +303,7 @@ def disable(name, **kwargs):
|
||||
|
||||
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)
|
||||
|
||||
|
||||
|
@ -122,7 +122,9 @@ def decrypt_object(o, gpg):
|
||||
o[k] = decrypt_object(v, gpg)
|
||||
return o
|
||||
elif isinstance(o, list):
|
||||
return [decrypt_object(e, gpg) for e in o]
|
||||
for number, value in enumerate(o):
|
||||
o[number] = decrypt_object(value, gpg)
|
||||
return o
|
||||
else:
|
||||
return o
|
||||
|
||||
|
@ -2804,7 +2804,7 @@ class BaseHighState(object):
|
||||
if state:
|
||||
self.merge_included_states(highstate, state, 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
|
||||
this_sls = 'SLS {0} in saltenv'.format(
|
||||
sls_match)
|
||||
|
@ -40,7 +40,7 @@ the location of composer in the state.
|
||||
from __future__ import absolute_import
|
||||
|
||||
# Import salt libs
|
||||
from salt.exceptions import CommandExecutionError, CommandNotFoundError
|
||||
from salt.exceptions import SaltException
|
||||
|
||||
|
||||
def __virtual__():
|
||||
@ -60,10 +60,138 @@ def installed(name,
|
||||
no_plugins=None,
|
||||
optimize=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
|
||||
``composer.json`` and ``composer.lock`` file in a directory.
|
||||
Verify that the correct versions of composer dependencies are present.
|
||||
|
||||
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
|
||||
Directory location of the composer.json file.
|
||||
@ -108,8 +236,26 @@ def installed(name,
|
||||
'''
|
||||
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:
|
||||
call = __salt__['composer.install'](
|
||||
call = __salt__['composer.update'](
|
||||
name,
|
||||
composer=composer,
|
||||
php=php,
|
||||
@ -120,22 +266,26 @@ def installed(name,
|
||||
no_plugins=no_plugins,
|
||||
optimize=optimize,
|
||||
no_dev=no_dev,
|
||||
quiet=False,
|
||||
quiet=quiet,
|
||||
composer_home=composer_home
|
||||
)
|
||||
except (CommandNotFoundError, CommandExecutionError) as err:
|
||||
except (SaltException) as err:
|
||||
ret['result'] = False
|
||||
ret['comment'] = 'Error executing composer in \'{0!r}\': {1!r}'.format(name, err)
|
||||
return ret
|
||||
|
||||
if call or isinstance(call, list) or isinstance(call, dict):
|
||||
ret['result'] = True
|
||||
if call.find('Nothing to install or update') < 0:
|
||||
ret['changes']['stdout'] = call
|
||||
# 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['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:
|
||||
ret['result'] = False
|
||||
ret['comment'] = 'Could not run composer'
|
||||
ret['comment'] = 'Composer update completed successfully'
|
||||
ret['changes'] = {
|
||||
'stderr': call['stderr'],
|
||||
'stdout': call['stdout']
|
||||
}
|
||||
|
||||
return ret
|
||||
|
@ -45,7 +45,7 @@ The following example installs all driver updates that don't require a reboot:
|
||||
.. code-block:: yaml
|
||||
|
||||
gryffindor:
|
||||
win_update.install:
|
||||
win_update.installed:
|
||||
- includes:
|
||||
- driver: True
|
||||
- software: False
|
||||
|
@ -221,7 +221,7 @@ def query(key, keyid, method='GET', params=None, headers=None,
|
||||
if return_url is True:
|
||||
return ret, requesturl
|
||||
else:
|
||||
if method == 'GET' or method == 'HEAD':
|
||||
if result.status_code != requests.codes.ok:
|
||||
return
|
||||
ret = {'headers': []}
|
||||
for header in result.headers:
|
||||
|
@ -11,6 +11,7 @@ import os
|
||||
import re
|
||||
import sys
|
||||
import stat
|
||||
import errno
|
||||
import socket
|
||||
import logging
|
||||
|
||||
@ -162,8 +163,11 @@ def verify_files(files, user):
|
||||
for fn_ in files:
|
||||
dirname = os.path.dirname(fn_)
|
||||
try:
|
||||
if not os.path.isdir(dirname):
|
||||
try:
|
||||
os.makedirs(dirname)
|
||||
except OSError as err:
|
||||
if err.errno != errno.EEXIST:
|
||||
raise
|
||||
if not os.path.isfile(fn_):
|
||||
with salt.utils.fopen(fn_, 'w+') as fp_:
|
||||
fp_.write('')
|
||||
|
4
setup.py
4
setup.py
@ -595,7 +595,7 @@ class SaltDistribution(distutils.dist.Distribution):
|
||||
|
||||
|
||||
self.name = 'salt-ssh' if PACKAGED_FOR_SALT_SSH else 'salt'
|
||||
self.version = __version__ # pylint: disable=undefined-variable
|
||||
self.salt_version = __version__ # pylint: disable=undefined-variable
|
||||
self.description = 'Portable, distributed, remote execution and configuration management system'
|
||||
self.author = 'Thomas S Hatch'
|
||||
self.author_email = 'thatch45@gmail.com'
|
||||
@ -627,6 +627,8 @@ class SaltDistribution(distutils.dist.Distribution):
|
||||
attrvalue = getattr(self, attrname, None)
|
||||
if attrvalue == 0:
|
||||
continue
|
||||
if attrname == 'salt_version':
|
||||
attrname = 'version'
|
||||
if hasattr(self.metadata, 'set_{0}'.format(attrname)):
|
||||
getattr(self.metadata, 'set_{0}'.format(attrname))(attrvalue)
|
||||
elif hasattr(self.metadata, attrname):
|
||||
|
@ -23,8 +23,8 @@ class VirtTest(integration.ModuleCase):
|
||||
'''
|
||||
profiles = self.run_function('virt.get_profiles', ['kvm'])
|
||||
nicp = profiles['nic']['default']
|
||||
self.assertTrue(nicp['eth0'].get('model', '') == 'virtio')
|
||||
self.assertTrue(nicp['eth0'].get('bridge', '') == 'br0')
|
||||
self.assertTrue(nicp[0].get('model', '') == 'virtio')
|
||||
self.assertTrue(nicp[0].get('source', '') == 'br0')
|
||||
diskp = profiles['disk']['default']
|
||||
self.assertTrue(diskp[0]['system'].get('model', '') == 'virtio')
|
||||
self.assertTrue(diskp[0]['system'].get('format', '') == 'qcow2')
|
||||
@ -36,8 +36,8 @@ class VirtTest(integration.ModuleCase):
|
||||
'''
|
||||
profiles = self.run_function('virt.get_profiles', ['esxi'])
|
||||
nicp = profiles['nic']['default']
|
||||
self.assertTrue(nicp['eth0'].get('model', '') == 'e1000')
|
||||
self.assertTrue(nicp['eth0'].get('bridge', '') == 'DEFAULT')
|
||||
self.assertTrue(nicp[0].get('model', '') == 'e1000')
|
||||
self.assertTrue(nicp[0].get('source', '') == 'DEFAULT')
|
||||
diskp = profiles['disk']['default']
|
||||
self.assertTrue(diskp[0]['system'].get('model', '') == 'scsi')
|
||||
self.assertTrue(diskp[0]['system'].get('format', '') == 'vmdk')
|
||||
|
172
tests/unit/modules/composer_test.py
Normal file
172
tests/unit/modules/composer_test.py
Normal 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)
|
@ -500,6 +500,43 @@ class VirtTestCase(TestCase):
|
||||
re.match('^([0-9A-F]{2}[:-]){5}([0-9A-F]{2})$',
|
||||
interface_attrs['mac'], re.I))
|
||||
|
||||
@skipIf(sys.version_info < (2, 7), 'ElementTree version 1.3 required'
|
||||
' which comes with Python 2.7')
|
||||
def test_get_graphics(self):
|
||||
virt.get_xml = MagicMock(return_value='''<domain type='kvm' id='7'>
|
||||
<name>test-vm</name>
|
||||
<devices>
|
||||
<graphics type='vnc' port='5900' autoport='yes' listen='0.0.0.0'>
|
||||
<listen type='address' address='0.0.0.0'/>
|
||||
</graphics>
|
||||
</devices>
|
||||
</domain>
|
||||
''')
|
||||
graphics = virt.get_graphics('test-vm')
|
||||
self.assertEqual('vnc', graphics['type'])
|
||||
self.assertEqual('5900', graphics['port'])
|
||||
self.assertEqual('0.0.0.0', graphics['listen'])
|
||||
|
||||
@skipIf(sys.version_info < (2, 7), 'ElementTree version 1.3 required'
|
||||
' which comes with Python 2.7')
|
||||
def test_get_nics(self):
|
||||
virt.get_xml = MagicMock(return_value='''<domain type='kvm' id='7'>
|
||||
<name>test-vm</name>
|
||||
<devices>
|
||||
<interface type='bridge'>
|
||||
<mac address='ac:de:48:b6:8b:59'/>
|
||||
<source bridge='br0'/>
|
||||
<model type='virtio'/>
|
||||
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
|
||||
</interface>
|
||||
</devices>
|
||||
</domain>
|
||||
''')
|
||||
nics = virt.get_nics('test-vm')
|
||||
nic = nics[nics.keys()[0]]
|
||||
self.assertEqual('bridge', nic['type'])
|
||||
self.assertEqual('ac:de:48:b6:8b:59', nic['mac'])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from integration import run_tests
|
||||
|
Loading…
Reference in New Issue
Block a user