mirror of
https://github.com/valitydev/salt.git
synced 2024-11-07 00:55:19 +00:00
Merge pull request #25903 from basepi/merge-forward-develop
Merge forward from 2015.8 to develop
This commit is contained in:
commit
abf389743a
@ -65,7 +65,9 @@
|
|||||||
# the coloring of the messages, these color formatters also include padding as
|
# the coloring of the messages, these color formatters also include padding as
|
||||||
# well. Color LogRecord attributes are only available for console logging.
|
# well. Color LogRecord attributes are only available for console logging.
|
||||||
#
|
#
|
||||||
|
#log_fmt_console: '%(colorlevel)s %(colormsg)s'
|
||||||
#log_fmt_console: '[%(levelname)-8s] %(message)s'
|
#log_fmt_console: '[%(levelname)-8s] %(message)s'
|
||||||
|
#
|
||||||
#log_fmt_logfile: '%(asctime)s,%(msecs)03.0f [%(name)-17s][%(levelname)-8s] %(message)s'
|
#log_fmt_logfile: '%(asctime)s,%(msecs)03.0f [%(name)-17s][%(levelname)-8s] %(message)s'
|
||||||
|
|
||||||
|
|
||||||
|
@ -696,7 +696,9 @@
|
|||||||
# the coloring of the messages, these color formatters also include padding as
|
# the coloring of the messages, these color formatters also include padding as
|
||||||
# well. Color LogRecord attributes are only available for console logging.
|
# well. Color LogRecord attributes are only available for console logging.
|
||||||
#
|
#
|
||||||
|
#log_fmt_console: '%(colorlevel)s %(colormsg)s'
|
||||||
#log_fmt_console: '[%(levelname)-8s] %(message)s'
|
#log_fmt_console: '[%(levelname)-8s] %(message)s'
|
||||||
|
#
|
||||||
#log_fmt_logfile: '%(asctime)s,%(msecs)03.0f [%(name)-17s][%(levelname)-8s] %(message)s'
|
#log_fmt_logfile: '%(asctime)s,%(msecs)03.0f [%(name)-17s][%(levelname)-8s] %(message)s'
|
||||||
|
|
||||||
# This can be used to control logging levels more specificically. This
|
# This can be used to control logging levels more specificically. This
|
||||||
|
@ -539,7 +539,9 @@
|
|||||||
# the coloring of the messages, these color formatters also include padding as
|
# the coloring of the messages, these color formatters also include padding as
|
||||||
# well. Color LogRecord attributes are only available for console logging.
|
# well. Color LogRecord attributes are only available for console logging.
|
||||||
#
|
#
|
||||||
|
#log_fmt_console: '%(colorlevel)s %(colormsg)s'
|
||||||
#log_fmt_console: '[%(levelname)-8s] %(message)s'
|
#log_fmt_console: '[%(levelname)-8s] %(message)s'
|
||||||
|
#
|
||||||
#log_fmt_logfile: '%(asctime)s,%(msecs)03.0f [%(name)-17s][%(levelname)-8s] %(message)s'
|
#log_fmt_logfile: '%(asctime)s,%(msecs)03.0f [%(name)-17s][%(levelname)-8s] %(message)s'
|
||||||
|
|
||||||
# This can be used to control logging levels more specificically. This
|
# This can be used to control logging levels more specificically. This
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "SALT-API" "1" "May 06, 2015" "2015.5.0" "Salt"
|
.TH "SALT-API" "1" "July 29, 2015" "2015.8.0rc2-13-g733b842" "Salt"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
salt-api \- salt-api Command
|
salt-api \- salt-api Command
|
||||||
.
|
.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "SALT-CALL" "1" "June 26, 2015" "2015.5.0-1639-g9f8cef2" "Salt"
|
.TH "SALT-CALL" "1" "July 29, 2015" "2015.8.0rc2-13-g733b842" "Salt"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
salt-call \- salt-call Documentation
|
salt-call \- salt-call Documentation
|
||||||
.
|
.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "SALT-CLOUD" "1" "June 26, 2015" "2015.5.0-1639-g9f8cef2" "Salt"
|
.TH "SALT-CLOUD" "1" "July 29, 2015" "2015.8.0rc2-13-g733b842" "Salt"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
salt-cloud \- Salt Cloud Command
|
salt-cloud \- Salt Cloud Command
|
||||||
.
|
.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "SALT-CP" "1" "June 26, 2015" "2015.5.0-1639-g9f8cef2" "Salt"
|
.TH "SALT-CP" "1" "July 29, 2015" "2015.8.0rc2-13-g733b842" "Salt"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
salt-cp \- salt-cp Documentation
|
salt-cp \- salt-cp Documentation
|
||||||
.
|
.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "SALT-KEY" "1" "May 06, 2015" "2015.5.0" "Salt"
|
.TH "SALT-KEY" "1" "July 29, 2015" "2015.8.0rc2-13-g733b842" "Salt"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
salt-key \- salt-key Documentation
|
salt-key \- salt-key Documentation
|
||||||
.
|
.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "SALT-MASTER" "1" "May 06, 2015" "2015.5.0" "Salt"
|
.TH "SALT-MASTER" "1" "July 29, 2015" "2015.8.0rc2-13-g733b842" "Salt"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
salt-master \- salt-master Documentation
|
salt-master \- salt-master Documentation
|
||||||
.
|
.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "SALT-MINION" "1" "May 06, 2015" "2015.5.0" "Salt"
|
.TH "SALT-MINION" "1" "July 29, 2015" "2015.8.0rc2-13-g733b842" "Salt"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
salt-minion \- salt-minion Documentation
|
salt-minion \- salt-minion Documentation
|
||||||
.
|
.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "SALT-RUN" "1" "May 06, 2015" "2015.5.0" "Salt"
|
.TH "SALT-RUN" "1" "July 29, 2015" "2015.8.0rc2-13-g733b842" "Salt"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
salt-run \- salt-run Documentation
|
salt-run \- salt-run Documentation
|
||||||
.
|
.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "SALT-SSH" "1" "May 06, 2015" "2015.5.0" "Salt"
|
.TH "SALT-SSH" "1" "July 29, 2015" "2015.8.0rc2-13-g733b842" "Salt"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
salt-ssh \- salt-ssh Documentation
|
salt-ssh \- salt-ssh Documentation
|
||||||
.
|
.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "SALT-SYNDIC" "1" "May 06, 2015" "2015.5.0" "Salt"
|
.TH "SALT-SYNDIC" "1" "July 29, 2015" "2015.8.0rc2-13-g733b842" "Salt"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
salt-syndic \- salt-syndic Documentation
|
salt-syndic \- salt-syndic Documentation
|
||||||
.
|
.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "SALT-UNITY" "1" "May 06, 2015" "2015.5.0" "Salt"
|
.TH "SALT-UNITY" "1" "July 29, 2015" "2015.8.0rc2-13-g733b842" "Salt"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
salt-unity \- salt-unity Command
|
salt-unity \- salt-unity Command
|
||||||
.
|
.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "SALT" "1" "May 06, 2015" "2015.5.0" "Salt"
|
.TH "SALT" "1" "July 29, 2015" "2015.8.0rc2-13-g733b842" "Salt"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
salt \- salt
|
salt \- salt
|
||||||
.
|
.
|
||||||
|
6625
doc/man/salt.7
6625
doc/man/salt.7
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "SPM" "1" "July 07, 2015" "2015.5.0-1703-gf8dc4fc" "Salt"
|
.TH "SPM" "1" "July 29, 2015" "2015.8.0rc2-13-g733b842" "Salt"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
spm \- Salt Package Manager Command
|
spm \- Salt Package Manager Command
|
||||||
.
|
.
|
||||||
|
@ -2452,7 +2452,6 @@ Examples:
|
|||||||
log_file: udp://loghost:10514
|
log_file: udp://loghost:10514
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. conf_master:: log_level
|
.. conf_master:: log_level
|
||||||
|
|
||||||
``log_level``
|
``log_level``
|
||||||
@ -2467,8 +2466,6 @@ The level of messages to send to the console. See also :conf_log:`log_level`.
|
|||||||
log_level: warning
|
log_level: warning
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. conf_master:: log_level_logfile
|
.. conf_master:: log_level_logfile
|
||||||
|
|
||||||
``log_level_logfile``
|
``log_level_logfile``
|
||||||
@ -2485,7 +2482,6 @@ it will inherit the level set by :conf_log:`log_level` option.
|
|||||||
log_level_logfile: warning
|
log_level_logfile: warning
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. conf_master:: log_datefmt
|
.. conf_master:: log_datefmt
|
||||||
|
|
||||||
``log_datefmt``
|
``log_datefmt``
|
||||||
@ -2501,8 +2497,6 @@ The date and time format used in console log messages. See also
|
|||||||
log_datefmt: '%H:%M:%S'
|
log_datefmt: '%H:%M:%S'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. conf_master:: log_datefmt_logfile
|
.. conf_master:: log_datefmt_logfile
|
||||||
|
|
||||||
``log_datefmt_logfile``
|
``log_datefmt_logfile``
|
||||||
@ -2518,7 +2512,6 @@ The date and time format used in log file messages. See also
|
|||||||
log_datefmt_logfile: '%Y-%m-%d %H:%M:%S'
|
log_datefmt_logfile: '%Y-%m-%d %H:%M:%S'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. conf_master:: log_fmt_console
|
.. conf_master:: log_fmt_console
|
||||||
|
|
||||||
``log_fmt_console``
|
``log_fmt_console``
|
||||||
@ -2529,12 +2522,29 @@ Default: ``[%(levelname)-8s] %(message)s``
|
|||||||
The format of the console logging messages. See also
|
The format of the console logging messages. See also
|
||||||
:conf_log:`log_fmt_console`.
|
:conf_log:`log_fmt_console`.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
Log colors are enabled in ``log_fmt_console`` rather than the
|
||||||
|
:conf_master:`color` config since the logging system is loaded before the
|
||||||
|
master config.
|
||||||
|
|
||||||
|
Console log colors are specified by these additional formatters:
|
||||||
|
|
||||||
|
%(colorlevel)s
|
||||||
|
%(colorname)s
|
||||||
|
%(colorprocess)s
|
||||||
|
%(colormsg)s
|
||||||
|
|
||||||
|
Since it is desirable to include the surrounding brackets, '[' and ']', in
|
||||||
|
the coloring of the messages, these color formatters also include padding
|
||||||
|
as well. Color LogRecord attributes are only available for console
|
||||||
|
logging.
|
||||||
|
|
||||||
.. code-block:: yaml
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
log_fmt_console: '%(colorlevel)s %(colormsg)s'
|
||||||
log_fmt_console: '[%(levelname)-8s] %(message)s'
|
log_fmt_console: '[%(levelname)-8s] %(message)s'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. conf_master:: log_fmt_logfile
|
.. conf_master:: log_fmt_logfile
|
||||||
|
|
||||||
``log_fmt_logfile``
|
``log_fmt_logfile``
|
||||||
@ -2550,7 +2560,6 @@ The format of the log file logging messages. See also
|
|||||||
log_fmt_logfile: '%(asctime)s,%(msecs)03.0f [%(name)-17s][%(levelname)-8s] %(message)s'
|
log_fmt_logfile: '%(asctime)s,%(msecs)03.0f [%(name)-17s][%(levelname)-8s] %(message)s'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. conf_master:: log_granular_levels
|
.. conf_master:: log_granular_levels
|
||||||
|
|
||||||
``log_granular_levels``
|
``log_granular_levels``
|
||||||
|
@ -145,7 +145,7 @@ the master hostname if name resolution fails. Defaults to 30 seconds.
|
|||||||
Set to zero if the minion should shutdown and not retry.
|
Set to zero if the minion should shutdown and not retry.
|
||||||
|
|
||||||
.. code-block:: yaml
|
.. code-block:: yaml
|
||||||
|
|
||||||
retry_dns: 30
|
retry_dns: 30
|
||||||
|
|
||||||
.. conf_minion:: master_port
|
.. conf_minion:: master_port
|
||||||
@ -994,7 +994,6 @@ Examples:
|
|||||||
log_file: udp://loghost:10514
|
log_file: udp://loghost:10514
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. conf_minion:: log_level
|
.. conf_minion:: log_level
|
||||||
|
|
||||||
``log_level``
|
``log_level``
|
||||||
@ -1009,8 +1008,6 @@ The level of messages to send to the console. See also :conf_log:`log_level`.
|
|||||||
log_level: warning
|
log_level: warning
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. conf_minion:: log_level_logfile
|
.. conf_minion:: log_level_logfile
|
||||||
|
|
||||||
``log_level_logfile``
|
``log_level_logfile``
|
||||||
@ -1027,7 +1024,6 @@ it will inherit the level set by :conf_log:`log_level` option.
|
|||||||
log_level_logfile: warning
|
log_level_logfile: warning
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. conf_minion:: log_datefmt
|
.. conf_minion:: log_datefmt
|
||||||
|
|
||||||
``log_datefmt``
|
``log_datefmt``
|
||||||
@ -1043,8 +1039,6 @@ The date and time format used in console log messages. See also
|
|||||||
log_datefmt: '%H:%M:%S'
|
log_datefmt: '%H:%M:%S'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. conf_minion:: log_datefmt_logfile
|
.. conf_minion:: log_datefmt_logfile
|
||||||
|
|
||||||
``log_datefmt_logfile``
|
``log_datefmt_logfile``
|
||||||
@ -1060,7 +1054,6 @@ The date and time format used in log file messages. See also
|
|||||||
log_datefmt_logfile: '%Y-%m-%d %H:%M:%S'
|
log_datefmt_logfile: '%Y-%m-%d %H:%M:%S'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. conf_minion:: log_fmt_console
|
.. conf_minion:: log_fmt_console
|
||||||
|
|
||||||
``log_fmt_console``
|
``log_fmt_console``
|
||||||
@ -1071,12 +1064,29 @@ Default: ``[%(levelname)-8s] %(message)s``
|
|||||||
The format of the console logging messages. See also
|
The format of the console logging messages. See also
|
||||||
:conf_log:`log_fmt_console`.
|
:conf_log:`log_fmt_console`.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
Log colors are enabled in ``log_fmt_console`` rather than the
|
||||||
|
:conf_minion:`color` config since the logging system is loaded before the
|
||||||
|
minion config.
|
||||||
|
|
||||||
|
Console log colors are specified by these additional formatters:
|
||||||
|
|
||||||
|
%(colorlevel)s
|
||||||
|
%(colorname)s
|
||||||
|
%(colorprocess)s
|
||||||
|
%(colormsg)s
|
||||||
|
|
||||||
|
Since it is desirable to include the surrounding brackets, '[' and ']', in
|
||||||
|
the coloring of the messages, these color formatters also include padding
|
||||||
|
as well. Color LogRecord attributes are only available for console
|
||||||
|
logging.
|
||||||
|
|
||||||
.. code-block:: yaml
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
log_fmt_console: '%(colorlevel)s %(colormsg)s'
|
||||||
log_fmt_console: '[%(levelname)-8s] %(message)s'
|
log_fmt_console: '[%(levelname)-8s] %(message)s'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. conf_minion:: log_fmt_logfile
|
.. conf_minion:: log_fmt_logfile
|
||||||
|
|
||||||
``log_fmt_logfile``
|
``log_fmt_logfile``
|
||||||
@ -1092,7 +1102,6 @@ The format of the log file logging messages. See also
|
|||||||
log_fmt_logfile: '%(asctime)s,%(msecs)03.0f [%(name)-17s][%(levelname)-8s] %(message)s'
|
log_fmt_logfile: '%(asctime)s,%(msecs)03.0f [%(name)-17s][%(levelname)-8s] %(message)s'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. conf_minion:: log_granular_levels
|
.. conf_minion:: log_granular_levels
|
||||||
|
|
||||||
``log_granular_levels``
|
``log_granular_levels``
|
||||||
@ -1104,7 +1113,6 @@ This can be used to control logging levels more specifically. See also
|
|||||||
:conf_log:`log_granular_levels`.
|
:conf_log:`log_granular_levels`.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. conf_minion:: failhard
|
.. conf_minion:: failhard
|
||||||
|
|
||||||
``failhard``
|
``failhard``
|
||||||
@ -1116,7 +1124,6 @@ Set the global failhard flag, this informs all states to stop running states
|
|||||||
at the moment a single state fails
|
at the moment a single state fails
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. code-block:: yaml
|
.. code-block:: yaml
|
||||||
|
|
||||||
failhard: False
|
failhard: False
|
||||||
|
@ -120,7 +120,8 @@ ssh_key_name
|
|||||||
ssh_interface
|
ssh_interface
|
||||||
This option allows you to create a VM without a public IP. If this option
|
This option allows you to create a VM without a public IP. If this option
|
||||||
is omitted and the VM does not have a public IP, then the salt-cloud waits
|
is omitted and the VM does not have a public IP, then the salt-cloud waits
|
||||||
for a certain period of time and then destroys the VM.
|
for a certain period of time and then destroys the VM. With the nova drive,
|
||||||
|
private cloud networks can be defined here.
|
||||||
|
|
||||||
For more information concerning cloud profiles, see :doc:`here
|
For more information concerning cloud profiles, see :doc:`here
|
||||||
</topics/cloud/profiles>`.
|
</topics/cloud/profiles>`.
|
||||||
@ -144,4 +145,4 @@ cloud-init if available.
|
|||||||
|
|
||||||
.. code-block:: yaml
|
.. code-block:: yaml
|
||||||
|
|
||||||
userdata_file: /etc/salt/cloud-init/packages.yml
|
userdata_file: /etc/salt/cloud-init/packages.yml
|
||||||
|
@ -86,7 +86,7 @@ Note: You must include the default net-ids when setting networks or the server
|
|||||||
will be created without the rest of the interfaces
|
will be created without the rest of the interfaces
|
||||||
|
|
||||||
Note: For rackconnect v3, rackconnectv3 needs to be specified with the
|
Note: For rackconnect v3, rackconnectv3 needs to be specified with the
|
||||||
rackconnect v3 cloud network as it's variable
|
rackconnect v3 cloud network as its variable.
|
||||||
'''
|
'''
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
# pylint: disable=E0102
|
# pylint: disable=E0102
|
||||||
@ -333,6 +333,17 @@ def rackconnect(vm_):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def cloudnetwork(vm_):
|
||||||
|
'''
|
||||||
|
Determine if we should use an extra network to bootstrap
|
||||||
|
Either 'False' (default) or 'True'.
|
||||||
|
'''
|
||||||
|
return config.get_cloud_config_value(
|
||||||
|
'cloudnetwork', vm_, __opts__, default='False',
|
||||||
|
search_global=False
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def managedcloud(vm_):
|
def managedcloud(vm_):
|
||||||
'''
|
'''
|
||||||
Determine if we should wait for the managed cloud automation before
|
Determine if we should wait for the managed cloud automation before
|
||||||
@ -628,10 +639,18 @@ def create(vm_):
|
|||||||
networkname = rackconnectv3
|
networkname = rackconnectv3
|
||||||
for network in node['addresses'].get(networkname, []):
|
for network in node['addresses'].get(networkname, []):
|
||||||
if network['version'] is 4:
|
if network['version'] is 4:
|
||||||
node['extra']['access_ip'] = network['addr']
|
access_ip = network['addr']
|
||||||
break
|
break
|
||||||
vm_['rackconnect'] = True
|
vm_['rackconnect'] = True
|
||||||
|
|
||||||
|
if ssh_interface(vm_) in node['addresses']:
|
||||||
|
networkname = ssh_interface(vm_)
|
||||||
|
for network in node['addresses'].get(networkname, []):
|
||||||
|
if network['version'] is 4:
|
||||||
|
node['extra']['access_ip'] = network['addr']
|
||||||
|
break
|
||||||
|
vm_['cloudnetwork'] = True
|
||||||
|
|
||||||
if rackconnect(vm_) is True:
|
if rackconnect(vm_) is True:
|
||||||
extra = node.get('extra', {})
|
extra = node.get('extra', {})
|
||||||
rc_status = extra.get('metadata', {}).get(
|
rc_status = extra.get('metadata', {}).get(
|
||||||
@ -689,6 +708,10 @@ def create(vm_):
|
|||||||
data.public_ips = access_ip
|
data.public_ips = access_ip
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
if cloudnetwork(vm_) is True:
|
||||||
|
data.public_ips = access_ip
|
||||||
|
return data
|
||||||
|
|
||||||
if result:
|
if result:
|
||||||
log.debug('result = {0}'.format(result))
|
log.debug('result = {0}'.format(result))
|
||||||
data.private_ips = result
|
data.private_ips = result
|
||||||
|
@ -307,6 +307,9 @@ VALID_OPTS = {
|
|||||||
# Specify the format for state outputs. See highstate outputter for additional details.
|
# Specify the format for state outputs. See highstate outputter for additional details.
|
||||||
'state_output': str,
|
'state_output': str,
|
||||||
|
|
||||||
|
# Tells the highstate outputter to only report diffs of states that changed
|
||||||
|
'state_output_diff': bool,
|
||||||
|
|
||||||
# When true, states run in the order defined in an SLS file, unless requisites re-order them
|
# When true, states run in the order defined in an SLS file, unless requisites re-order them
|
||||||
'state_auto_order': bool,
|
'state_auto_order': bool,
|
||||||
|
|
||||||
@ -700,6 +703,7 @@ VALID_OPTS = {
|
|||||||
# Used by salt-api for master requests timeout
|
# Used by salt-api for master requests timeout
|
||||||
'rest_timeout': int,
|
'rest_timeout': int,
|
||||||
|
|
||||||
|
# If set, all minion exec module actions will be rerouted through sudo as this user
|
||||||
'sudo_user': str,
|
'sudo_user': str,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -815,6 +819,7 @@ DEFAULT_MINION_OPTS = {
|
|||||||
'cython_enable': False,
|
'cython_enable': False,
|
||||||
'state_verbose': True,
|
'state_verbose': True,
|
||||||
'state_output': 'full',
|
'state_output': 'full',
|
||||||
|
'state_output_diff': False,
|
||||||
'state_auto_order': True,
|
'state_auto_order': True,
|
||||||
'state_events': False,
|
'state_events': False,
|
||||||
'state_aggregate': False,
|
'state_aggregate': False,
|
||||||
@ -1018,6 +1023,7 @@ DEFAULT_MASTER_OPTS = {
|
|||||||
'serial': 'msgpack',
|
'serial': 'msgpack',
|
||||||
'state_verbose': True,
|
'state_verbose': True,
|
||||||
'state_output': 'full',
|
'state_output': 'full',
|
||||||
|
'state_output_diff': False,
|
||||||
'state_auto_order': True,
|
'state_auto_order': True,
|
||||||
'state_events': False,
|
'state_events': False,
|
||||||
'state_aggregate': False,
|
'state_aggregate': False,
|
||||||
|
@ -40,10 +40,23 @@ from __future__ import absolute_import
|
|||||||
|
|
||||||
# Import third party libs
|
# Import third party libs
|
||||||
#import salt.ext.six as six
|
#import salt.ext.six as six
|
||||||
|
|
||||||
|
# Import salt libs
|
||||||
from salt.exceptions import (
|
from salt.exceptions import (
|
||||||
#CommandExecutionError,
|
#CommandExecutionError,
|
||||||
SaltInvocationError
|
SaltInvocationError
|
||||||
)
|
)
|
||||||
|
from salt.utils import warn_until
|
||||||
|
|
||||||
|
from salt.version import (
|
||||||
|
__version__,
|
||||||
|
SaltStackVersion
|
||||||
|
)
|
||||||
|
# is there not SaltStackVersion.current() to get
|
||||||
|
# the version of the salt running this code??
|
||||||
|
CUR_VER = SaltStackVersion(__version__[0], __version__[1])
|
||||||
|
BORON = SaltStackVersion.from_name('Boron')
|
||||||
|
|
||||||
# pylint: disable=import-error
|
# pylint: disable=import-error
|
||||||
HAS_GLANCE = False
|
HAS_GLANCE = False
|
||||||
try:
|
try:
|
||||||
@ -77,6 +90,7 @@ def __virtual__():
|
|||||||
return 'glance'
|
return 'glance'
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
__opts__ = {}
|
__opts__ = {}
|
||||||
|
|
||||||
|
|
||||||
@ -143,12 +157,14 @@ def _auth(profile=None, api_version=2, **connection_args):
|
|||||||
'get a new one using username and password.')
|
'get a new one using username and password.')
|
||||||
|
|
||||||
if HAS_KEYSTONE:
|
if HAS_KEYSTONE:
|
||||||
# TODO: redact kwargs['password']
|
|
||||||
log.debug('Calling keystoneclient.v2_0.client.Client(' +
|
log.debug('Calling keystoneclient.v2_0.client.Client(' +
|
||||||
'{0}, **{1})'.format(endpoint, kwargs))
|
'{0}, **{1})'.format(endpoint, kwargs))
|
||||||
keystone = kstone.Client(**kwargs)
|
keystone = kstone.Client(**kwargs)
|
||||||
log.debug(help(keystone.get_token))
|
log.debug(help(keystone.get_token))
|
||||||
kwargs['token'] = keystone.get_token(keystone.session)
|
kwargs['token'] = keystone.get_token(keystone.session)
|
||||||
|
# This doesn't realy prevent the password to show up
|
||||||
|
# in the minion log as keystoneclient.session is
|
||||||
|
# logging it anyway when in debug-mode
|
||||||
kwargs.pop('password')
|
kwargs.pop('password')
|
||||||
log.debug('Calling glanceclient.client.Client(' +
|
log.debug('Calling glanceclient.client.Client(' +
|
||||||
'{0}, {1}, **{2})'.format(api_version, endpoint, kwargs))
|
'{0}, {1}, **{2})'.format(api_version, endpoint, kwargs))
|
||||||
@ -158,22 +174,65 @@ def _auth(profile=None, api_version=2, **connection_args):
|
|||||||
"Can't retrieve a auth_token without keystone")
|
"Can't retrieve a auth_token without keystone")
|
||||||
|
|
||||||
|
|
||||||
def image_create(name, location, profile=None, visibility='public',
|
def _add_image(collection, image):
|
||||||
container_format='bare', disk_format='raw'):
|
'''
|
||||||
|
Add image to given dictionary
|
||||||
|
'''
|
||||||
|
image_prep = {
|
||||||
|
'id': image.id,
|
||||||
|
'name': image.name,
|
||||||
|
'created_at': image.created_at,
|
||||||
|
'file': image.file,
|
||||||
|
'min_disk': image.min_disk,
|
||||||
|
'min_ram': image.min_ram,
|
||||||
|
'owner': image.owner,
|
||||||
|
'protected': image.protected,
|
||||||
|
'status': image.status,
|
||||||
|
'tags': image.tags,
|
||||||
|
'updated_at': image.updated_at,
|
||||||
|
'visibility': image.visibility,
|
||||||
|
}
|
||||||
|
# Those cause AttributeErrors in Icehouse' glanceclient
|
||||||
|
for attr in ['container_format', 'disk_format', 'size']:
|
||||||
|
if attr in image:
|
||||||
|
image_prep[attr] = image[attr]
|
||||||
|
if type(collection) is dict:
|
||||||
|
collection[image.name] = image_prep
|
||||||
|
elif type(collection) is list:
|
||||||
|
collection.append(image_prep)
|
||||||
|
else:
|
||||||
|
msg = '"collection" is {0}'.format(type(collection)) +\
|
||||||
|
'instead of dict or list.'
|
||||||
|
log.error(msg)
|
||||||
|
raise TypeError(msg)
|
||||||
|
return collection
|
||||||
|
|
||||||
|
|
||||||
|
def image_create(name, location=None, profile=None, visibility=None,
|
||||||
|
container_format='bare', disk_format='raw', protected=None,
|
||||||
|
copy_from=None, is_public=None):
|
||||||
'''
|
'''
|
||||||
Create an image (glance image-create)
|
Create an image (glance image-create)
|
||||||
|
|
||||||
CLI Example:
|
CLI Example, old format:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
salt '*' glance.image_create name=f16-jeos is_public=true \\
|
||||||
|
disk_format=qcow2 container_format=ovf \\
|
||||||
|
copy_from=http://berrange.fedorapeople.org/\
|
||||||
|
images/2012-02-29/f16-x86_64-openstack-sda.qcow2
|
||||||
|
|
||||||
|
CLI Example, new format resembling Glance API v2:
|
||||||
|
|
||||||
salt '*' glance.image_create name=f16-jeos visibility=public \\
|
salt '*' glance.image_create name=f16-jeos visibility=public \\
|
||||||
disk_format=qcow2 container_format=ovf \\
|
disk_format=qcow2 container_format=ovf \\
|
||||||
copy_from=http://berrange.fedorapeople.org/\
|
copy_from=http://berrange.fedorapeople.org/\
|
||||||
images/2012-02-29/f16-x86_64-openstack-sda.qcow2
|
images/2012-02-29/f16-x86_64-openstack-sda.qcow2
|
||||||
|
|
||||||
For all possible values, run ``glance help image-create`` on the minion.
|
The parameter 'visibility' defaults to 'public' if neither
|
||||||
|
'visibility' nor 'is_public' is specified.
|
||||||
'''
|
'''
|
||||||
|
kwargs = {}
|
||||||
# valid options for "visibility":
|
# valid options for "visibility":
|
||||||
v_list = ['public', 'private']
|
v_list = ['public', 'private']
|
||||||
# valid options for "container_format":
|
# valid options for "container_format":
|
||||||
@ -181,20 +240,52 @@ def image_create(name, location, profile=None, visibility='public',
|
|||||||
# valid options for "disk_format":
|
# valid options for "disk_format":
|
||||||
df_list = ['ami', 'ari', 'aki', 'vhd', 'vmdk',
|
df_list = ['ami', 'ari', 'aki', 'vhd', 'vmdk',
|
||||||
'raw', 'qcow2', 'vdi', 'iso']
|
'raw', 'qcow2', 'vdi', 'iso']
|
||||||
if visibility not in v_list:
|
# 'location' and 'visibility' are the parameters used in
|
||||||
raise SaltInvocationError('"visibility" needs to be one ' +
|
# Glance API v2. For now we have to use v1 for now (see below)
|
||||||
'of the following: {0}'.format(', '.join(v_list)))
|
# but this modules interface will change in Carbon.
|
||||||
|
if copy_from is not None or is_public is not None:
|
||||||
|
warn_until('Carbon', 'The parameters \'copy_from\' and '
|
||||||
|
'\'is_public\' are deprecated and will be removed. '
|
||||||
|
'Use \'location\' and \'visibility\' instead.')
|
||||||
|
if is_public is not None and visibility is not None:
|
||||||
|
raise SaltInvocationError('Must only specify one of '
|
||||||
|
'\'is_public\' and \'visibility\'')
|
||||||
|
if copy_from is not None and location is not None:
|
||||||
|
raise SaltInvocationError('Must only specify one of '
|
||||||
|
'\'copy_from\' and \'location\'')
|
||||||
|
if copy_from is not None:
|
||||||
|
kwargs['copy_from'] = copy_from
|
||||||
|
else:
|
||||||
|
kwargs['copy_from'] = location
|
||||||
|
if is_public is not None:
|
||||||
|
kwargs['is_public'] = is_public
|
||||||
|
elif visibility is not None:
|
||||||
|
if visibility not in v_list:
|
||||||
|
raise SaltInvocationError('"visibility" needs to be one ' +
|
||||||
|
'of the following: {0}'.format(', '.join(v_list)))
|
||||||
|
elif visibility == 'public':
|
||||||
|
kwargs['is_public'] = True
|
||||||
|
else:
|
||||||
|
kwargs['is_public'] = False
|
||||||
|
else:
|
||||||
|
kwargs['is_public'] = True
|
||||||
if container_format not in cf_list:
|
if container_format not in cf_list:
|
||||||
raise SaltInvocationError('"container_format" needs to be ' +
|
raise SaltInvocationError('"container_format" needs to be ' +
|
||||||
'one of the following: {0}'.format(', '.join(cf_list)))
|
'one of the following: {0}'.format(', '.join(cf_list)))
|
||||||
|
else:
|
||||||
|
kwargs['container_format'] = container_format
|
||||||
if disk_format not in df_list:
|
if disk_format not in df_list:
|
||||||
raise SaltInvocationError('"disk_format" needs to be one ' +
|
raise SaltInvocationError('"disk_format" needs to be one ' +
|
||||||
'of the following: {0}'.format(', '.join(df_list)))
|
'of the following: {0}'.format(', '.join(df_list)))
|
||||||
|
else:
|
||||||
|
kwargs['disk_format'] = disk_format
|
||||||
|
if protected is not None:
|
||||||
|
kwargs['protected'] = protected
|
||||||
# Icehouse's glanceclient doesn't have add_location() and
|
# Icehouse's glanceclient doesn't have add_location() and
|
||||||
# glanceclient.v2 doesn't implement Client.images.create()
|
# glanceclient.v2 doesn't implement Client.images.create()
|
||||||
# in a usable fashion. Thus we have to use v1 for now.
|
# in a usable fashion. Thus we have to use v1 for now.
|
||||||
g_client = _auth(profile, api_version=1)
|
g_client = _auth(profile, api_version=1)
|
||||||
image = g_client.images.create(name=name, copy_from=location)
|
image = g_client.images.create(name=name, **kwargs)
|
||||||
return image_show(image.id)
|
return image_show(image.id)
|
||||||
|
|
||||||
|
|
||||||
@ -217,8 +308,15 @@ def image_delete(id=None, name=None, profile=None): # pylint: disable=C0103
|
|||||||
id = image.id # pylint: disable=C0103
|
id = image.id # pylint: disable=C0103
|
||||||
continue
|
continue
|
||||||
if not id:
|
if not id:
|
||||||
return {'Error': 'Unable to resolve image id'}
|
return {'Error': 'Unable to resolve '
|
||||||
g_client.images.delete(id)
|
'image id for name {0}'.format(name)}
|
||||||
|
try:
|
||||||
|
g_client.images.delete(id)
|
||||||
|
except exc.HTTPNotFound:
|
||||||
|
return {'Error': 'No image with ID {0}'.format(id)}
|
||||||
|
except exc.HTTPForbidden as forbidden:
|
||||||
|
log.error(str(forbidden))
|
||||||
|
return {'Error': str(forbidden)}
|
||||||
ret = 'Deleted image with ID {0}'.format(id)
|
ret = 'Deleted image with ID {0}'.format(id)
|
||||||
if name:
|
if name:
|
||||||
ret += ' ({0})'.format(name)
|
ret += ' ({0})'.format(name)
|
||||||
@ -248,18 +346,27 @@ def image_show(id=None, name=None, profile=None): # pylint: disable=C0103
|
|||||||
pformat = pprint.PrettyPrinter(indent=4).pformat
|
pformat = pprint.PrettyPrinter(indent=4).pformat
|
||||||
log.debug('Properties of image {0}:\n{1}'.format(
|
log.debug('Properties of image {0}:\n{1}'.format(
|
||||||
image.name, pformat(image)))
|
image.name, pformat(image)))
|
||||||
# TODO: Get rid of the wrapping dict, see #24568
|
ret_details = {}
|
||||||
ret[image.name] = {}
|
# I may want to use this code on Beryllium
|
||||||
|
# until we got Boron packages for Ubuntu
|
||||||
|
# so please keep this code until Carbon!
|
||||||
|
warn_until('Carbon', 'Starting with \'Boron\' image_show() '
|
||||||
|
'will stop wrapping the returned image in another '
|
||||||
|
'dictionary.')
|
||||||
|
if CUR_VER < BORON:
|
||||||
|
ret[image.name] = ret_details
|
||||||
|
else:
|
||||||
|
ret = ret_details
|
||||||
schema = image_schema(profile=profile)
|
schema = image_schema(profile=profile)
|
||||||
if len(schema.keys()) == 1:
|
if len(schema.keys()) == 1:
|
||||||
schema = schema['image']
|
schema = schema['image']
|
||||||
for key in schema.keys():
|
for key in schema.keys():
|
||||||
if key in image:
|
if key in image:
|
||||||
ret[image.name][key] = image[key]
|
ret_details[key] = image[key]
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def image_list(id=None, profile=None): # pylint: disable=C0103
|
def image_list(id=None, profile=None, name=None): # pylint: disable=C0103
|
||||||
'''
|
'''
|
||||||
Return a list of available images (glance image-list)
|
Return a list of available images (glance image-list)
|
||||||
|
|
||||||
@ -270,29 +377,30 @@ def image_list(id=None, profile=None): # pylint: disable=C0103
|
|||||||
salt '*' glance.image_list
|
salt '*' glance.image_list
|
||||||
'''
|
'''
|
||||||
g_client = _auth(profile)
|
g_client = _auth(profile)
|
||||||
ret = {}
|
# I may want to use this code on Beryllium
|
||||||
# TODO: Get rid of the wrapping dict, see #24568
|
# until we got Boron packages for Ubuntu
|
||||||
|
# so please keep this code until Carbon!
|
||||||
|
warn_until('Carbon', 'Starting in \'Boron\' image_list() '
|
||||||
|
'will return a list of images instead of a dictionary '
|
||||||
|
'keyed with the images\' names.')
|
||||||
|
if CUR_VER < BORON:
|
||||||
|
ret = {}
|
||||||
|
else:
|
||||||
|
ret = []
|
||||||
for image in g_client.images.list():
|
for image in g_client.images.list():
|
||||||
ret[image.name] = {
|
if id is None and name is None:
|
||||||
'id': image.id,
|
_add_image(ret, image)
|
||||||
'name': image.name,
|
else:
|
||||||
'created_at': image.created_at,
|
if id is not None and id == image.id:
|
||||||
'file': image.file,
|
_add_image(ret, image)
|
||||||
'min_disk': image.min_disk,
|
return ret
|
||||||
'min_ram': image.min_ram,
|
if name == image.name:
|
||||||
'owner': image.owner,
|
if name in ret and CUR_VER < BORON:
|
||||||
'protected': image.protected,
|
# Not really worth an exception
|
||||||
'status': image.status,
|
return {'Error': 'More than one image '
|
||||||
'tags': image.tags,
|
'with name "{0}"'.format(name)}
|
||||||
'updated_at': image.updated_at,
|
_add_image(ret, image)
|
||||||
'visibility': image.visibility,
|
log.debug('Returning images: {0}'.format(ret))
|
||||||
}
|
|
||||||
# Those cause AttributeErrors in Icehouse' glanceclient
|
|
||||||
for attr in ['container_format', 'disk_format', 'size']:
|
|
||||||
if attr in image:
|
|
||||||
ret[image.name][attr] = image[attr]
|
|
||||||
if id == image.id:
|
|
||||||
return ret[image.name]
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
@ -304,6 +412,52 @@ def image_schema(profile=None):
|
|||||||
return schema_get('image', profile)
|
return schema_get('image', profile)
|
||||||
|
|
||||||
|
|
||||||
|
def image_update(id=None, name=None, profile=None, **kwargs): # pylint: disable=C0103
|
||||||
|
'''
|
||||||
|
Update properties of given image.
|
||||||
|
Known to work for:
|
||||||
|
- min_ram (in MB)
|
||||||
|
- protected (bool)
|
||||||
|
- visibility ('public' or 'private')
|
||||||
|
'''
|
||||||
|
if id:
|
||||||
|
image = image_show(id=id)
|
||||||
|
# TODO: This unwrapping should get a warn_until
|
||||||
|
if len(image) == 1:
|
||||||
|
image = image.values()[0]
|
||||||
|
elif name:
|
||||||
|
img_list = image_list(name=name)
|
||||||
|
if img_list is not list and 'Error' in img_list:
|
||||||
|
return img_list
|
||||||
|
elif len(img_list) == 0:
|
||||||
|
return {'result': False,
|
||||||
|
'comment': 'No image with name \'{0}\' '
|
||||||
|
'found.'.format(name)}
|
||||||
|
elif len(img_list) == 1:
|
||||||
|
image = img_list[0]
|
||||||
|
else:
|
||||||
|
raise SaltInvocationError
|
||||||
|
log.debug('Found image:\n{0}'.format(image))
|
||||||
|
to_update = {}
|
||||||
|
for key, value in kwargs.items():
|
||||||
|
if key.startswith('_'):
|
||||||
|
continue
|
||||||
|
if key not in image or image[key] != value:
|
||||||
|
log.debug('add <{0}={1}> to to_update'.format(key, value))
|
||||||
|
to_update[key] = value
|
||||||
|
g_client = _auth(profile)
|
||||||
|
updated = g_client.images.update(image['id'], **to_update)
|
||||||
|
# I may want to use this code on Beryllium
|
||||||
|
# until we got Boron packages for Ubuntu
|
||||||
|
# so please keep this code until Carbon!
|
||||||
|
warn_until('Carbon', 'Starting with \'Boron\' image_update() '
|
||||||
|
'will stop wrapping the returned, updated image in '
|
||||||
|
'another dictionary.')
|
||||||
|
if CUR_VER < BORON:
|
||||||
|
updated = {updated.name: updated}
|
||||||
|
return updated
|
||||||
|
|
||||||
|
|
||||||
def schema_get(name, profile=None):
|
def schema_get(name, profile=None):
|
||||||
'''
|
'''
|
||||||
Known valid names of schemas are:
|
Known valid names of schemas are:
|
||||||
@ -343,11 +497,10 @@ def _item_list(profile=None):
|
|||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
#The following is a list of functions that need to be incorporated in the
|
# The following is a list of functions that need to be incorporated in the
|
||||||
#glance module. This list should be updated as functions are added.
|
# glance module. This list should be updated as functions are added.
|
||||||
|
|
||||||
# image-download Download a specific image.
|
# image-download Download a specific image.
|
||||||
# image-update Update a specific image.
|
|
||||||
# member-create Share a specific image with a tenant.
|
# member-create Share a specific image with a tenant.
|
||||||
# member-delete Remove a shared image from a tenant.
|
# member-delete Remove a shared image from a tenant.
|
||||||
# member-list Describe sharing permissions by image or tenant.
|
# member-list Describe sharing permissions by image or tenant.
|
||||||
|
@ -218,7 +218,7 @@ def build_rule(table='filter', chain=None, command=None, position='', full=None,
|
|||||||
|
|
||||||
if 'connstate' in kwargs:
|
if 'connstate' in kwargs:
|
||||||
if '-m state' not in rule:
|
if '-m state' not in rule:
|
||||||
rule += '-m state '
|
rule.append('-m state')
|
||||||
|
|
||||||
rule.append('{0}--state {1}'.format(maybe_add_negation('connstate'), kwargs['connstate']))
|
rule.append('{0}--state {1}'.format(maybe_add_negation('connstate'), kwargs['connstate']))
|
||||||
|
|
||||||
|
@ -376,7 +376,7 @@ def _format_host(host, data):
|
|||||||
sum_duration /= 1000
|
sum_duration /= 1000
|
||||||
duration_unit = 's'
|
duration_unit = 's'
|
||||||
total_duration = u'Total run time: {0} {1}'.format(
|
total_duration = u'Total run time: {0} {1}'.format(
|
||||||
'{:.3f}'.format(sum_duration).rjust(line_max_len - 5),
|
'{0:.3f}'.format(sum_duration).rjust(line_max_len - 5),
|
||||||
duration_unit)
|
duration_unit)
|
||||||
hstrs.append(colorfmt.format(colors['CYAN'], total_duration, colors))
|
hstrs.append(colorfmt.format(colors['CYAN'], total_duration, colors))
|
||||||
|
|
||||||
|
@ -144,6 +144,8 @@ def up(): # pylint: disable=C0103
|
|||||||
|
|
||||||
def list_state(subset=None, show_ipv4=False, state=None):
|
def list_state(subset=None, show_ipv4=False, state=None):
|
||||||
'''
|
'''
|
||||||
|
.. versionadded:: 2015.8.0
|
||||||
|
|
||||||
Print a list of all minions that are up according to Salt's presence
|
Print a list of all minions that are up according to Salt's presence
|
||||||
detection (no commands will be sent to minions)
|
detection (no commands will be sent to minions)
|
||||||
|
|
||||||
@ -157,8 +159,6 @@ def list_state(subset=None, show_ipv4=False, state=None):
|
|||||||
Show minions being in specific state that is one of 'available', 'joined',
|
Show minions being in specific state that is one of 'available', 'joined',
|
||||||
'allowed', 'alived' or 'reaped'.
|
'allowed', 'alived' or 'reaped'.
|
||||||
|
|
||||||
.. versionadded:: 2015.8.0
|
|
||||||
|
|
||||||
CLI Example:
|
CLI Example:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
@ -190,6 +190,8 @@ def list_state(subset=None, show_ipv4=False, state=None):
|
|||||||
|
|
||||||
def list_not_state(subset=None, show_ipv4=False, state=None):
|
def list_not_state(subset=None, show_ipv4=False, state=None):
|
||||||
'''
|
'''
|
||||||
|
.. versionadded:: 2015.8.0
|
||||||
|
|
||||||
Print a list of all minions that are NOT up according to Salt's presence
|
Print a list of all minions that are NOT up according to Salt's presence
|
||||||
detection (no commands will be sent to minions)
|
detection (no commands will be sent to minions)
|
||||||
|
|
||||||
@ -203,8 +205,6 @@ def list_not_state(subset=None, show_ipv4=False, state=None):
|
|||||||
Show minions being in specific state that is one of 'available', 'joined',
|
Show minions being in specific state that is one of 'available', 'joined',
|
||||||
'allowed', 'alived' or 'reaped'.
|
'allowed', 'alived' or 'reaped'.
|
||||||
|
|
||||||
.. versionadded:: 2015.8.0
|
|
||||||
|
|
||||||
CLI Example:
|
CLI Example:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
@ -236,16 +236,12 @@ def present(subset=None, show_ipv4=False):
|
|||||||
Print a list of all minions that are up according to Salt's presence
|
Print a list of all minions that are up according to Salt's presence
|
||||||
detection (no commands will be sent to minions)
|
detection (no commands will be sent to minions)
|
||||||
|
|
||||||
.. versionadded:: 2015.8.0
|
|
||||||
|
|
||||||
subset : None
|
subset : None
|
||||||
Pass in a CIDR range to filter minions by IP address.
|
Pass in a CIDR range to filter minions by IP address.
|
||||||
|
|
||||||
show_ipv4 : False
|
show_ipv4 : False
|
||||||
Also show the IP address each minion is connecting from.
|
Also show the IP address each minion is connecting from.
|
||||||
|
|
||||||
.. versionadded:: 2015.8.0
|
|
||||||
|
|
||||||
CLI Example:
|
CLI Example:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
@ -257,6 +253,8 @@ def present(subset=None, show_ipv4=False):
|
|||||||
|
|
||||||
def not_present(subset=None, show_ipv4=False):
|
def not_present(subset=None, show_ipv4=False):
|
||||||
'''
|
'''
|
||||||
|
.. versionadded:: 2015.5.0
|
||||||
|
|
||||||
Print a list of all minions that are NOT up according to Salt's presence
|
Print a list of all minions that are NOT up according to Salt's presence
|
||||||
detection (no commands will be sent)
|
detection (no commands will be sent)
|
||||||
|
|
||||||
@ -266,8 +264,6 @@ def not_present(subset=None, show_ipv4=False):
|
|||||||
show_ipv4 : False
|
show_ipv4 : False
|
||||||
Also show the IP address each minion is connecting from.
|
Also show the IP address each minion is connecting from.
|
||||||
|
|
||||||
.. versionadded:: 2015.8.0
|
|
||||||
|
|
||||||
CLI Example:
|
CLI Example:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
@ -279,6 +275,8 @@ def not_present(subset=None, show_ipv4=False):
|
|||||||
|
|
||||||
def joined(subset=None, show_ipv4=False):
|
def joined(subset=None, show_ipv4=False):
|
||||||
'''
|
'''
|
||||||
|
.. versionadded:: 2015.8.0
|
||||||
|
|
||||||
Print a list of all minions that are up according to Salt's presence
|
Print a list of all minions that are up according to Salt's presence
|
||||||
detection (no commands will be sent to minions)
|
detection (no commands will be sent to minions)
|
||||||
|
|
||||||
@ -288,8 +286,6 @@ def joined(subset=None, show_ipv4=False):
|
|||||||
show_ipv4 : False
|
show_ipv4 : False
|
||||||
Also show the IP address each minion is connecting from.
|
Also show the IP address each minion is connecting from.
|
||||||
|
|
||||||
.. versionadded:: 2015.8.0
|
|
||||||
|
|
||||||
CLI Example:
|
CLI Example:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
@ -301,6 +297,8 @@ def joined(subset=None, show_ipv4=False):
|
|||||||
|
|
||||||
def not_joined(subset=None, show_ipv4=False):
|
def not_joined(subset=None, show_ipv4=False):
|
||||||
'''
|
'''
|
||||||
|
.. versionadded:: 2015.8.0
|
||||||
|
|
||||||
Print a list of all minions that are NOT up according to Salt's presence
|
Print a list of all minions that are NOT up according to Salt's presence
|
||||||
detection (no commands will be sent)
|
detection (no commands will be sent)
|
||||||
|
|
||||||
@ -310,8 +308,6 @@ def not_joined(subset=None, show_ipv4=False):
|
|||||||
show_ipv4 : False
|
show_ipv4 : False
|
||||||
Also show the IP address each minion is connecting from.
|
Also show the IP address each minion is connecting from.
|
||||||
|
|
||||||
.. versionadded:: 2015.8.0
|
|
||||||
|
|
||||||
CLI Example:
|
CLI Example:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
@ -323,6 +319,8 @@ def not_joined(subset=None, show_ipv4=False):
|
|||||||
|
|
||||||
def allowed(subset=None, show_ipv4=False):
|
def allowed(subset=None, show_ipv4=False):
|
||||||
'''
|
'''
|
||||||
|
.. versionadded:: 2015.8.0
|
||||||
|
|
||||||
Print a list of all minions that are up according to Salt's presence
|
Print a list of all minions that are up according to Salt's presence
|
||||||
detection (no commands will be sent to minions)
|
detection (no commands will be sent to minions)
|
||||||
|
|
||||||
@ -332,8 +330,6 @@ def allowed(subset=None, show_ipv4=False):
|
|||||||
show_ipv4 : False
|
show_ipv4 : False
|
||||||
Also show the IP address each minion is connecting from.
|
Also show the IP address each minion is connecting from.
|
||||||
|
|
||||||
.. versionadded:: 2015.8.0
|
|
||||||
|
|
||||||
CLI Example:
|
CLI Example:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
@ -345,6 +341,8 @@ def allowed(subset=None, show_ipv4=False):
|
|||||||
|
|
||||||
def not_allowed(subset=None, show_ipv4=False):
|
def not_allowed(subset=None, show_ipv4=False):
|
||||||
'''
|
'''
|
||||||
|
.. versionadded:: 2015.8.0
|
||||||
|
|
||||||
Print a list of all minions that are NOT up according to Salt's presence
|
Print a list of all minions that are NOT up according to Salt's presence
|
||||||
detection (no commands will be sent)
|
detection (no commands will be sent)
|
||||||
|
|
||||||
@ -354,8 +352,6 @@ def not_allowed(subset=None, show_ipv4=False):
|
|||||||
show_ipv4 : False
|
show_ipv4 : False
|
||||||
Also show the IP address each minion is connecting from.
|
Also show the IP address each minion is connecting from.
|
||||||
|
|
||||||
.. versionadded:: 2015.8.0
|
|
||||||
|
|
||||||
CLI Example:
|
CLI Example:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
@ -367,6 +363,8 @@ def not_allowed(subset=None, show_ipv4=False):
|
|||||||
|
|
||||||
def alived(subset=None, show_ipv4=False):
|
def alived(subset=None, show_ipv4=False):
|
||||||
'''
|
'''
|
||||||
|
.. versionadded:: 2015.8.0
|
||||||
|
|
||||||
Print a list of all minions that are up according to Salt's presence
|
Print a list of all minions that are up according to Salt's presence
|
||||||
detection (no commands will be sent to minions)
|
detection (no commands will be sent to minions)
|
||||||
|
|
||||||
@ -376,8 +374,6 @@ def alived(subset=None, show_ipv4=False):
|
|||||||
show_ipv4 : False
|
show_ipv4 : False
|
||||||
Also show the IP address each minion is connecting from.
|
Also show the IP address each minion is connecting from.
|
||||||
|
|
||||||
.. versionadded:: 2015.8.0
|
|
||||||
|
|
||||||
CLI Example:
|
CLI Example:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
@ -389,6 +385,8 @@ def alived(subset=None, show_ipv4=False):
|
|||||||
|
|
||||||
def not_alived(subset=None, show_ipv4=False):
|
def not_alived(subset=None, show_ipv4=False):
|
||||||
'''
|
'''
|
||||||
|
.. versionadded:: 2015.8.0
|
||||||
|
|
||||||
Print a list of all minions that are NOT up according to Salt's presence
|
Print a list of all minions that are NOT up according to Salt's presence
|
||||||
detection (no commands will be sent)
|
detection (no commands will be sent)
|
||||||
|
|
||||||
@ -398,8 +396,6 @@ def not_alived(subset=None, show_ipv4=False):
|
|||||||
show_ipv4 : False
|
show_ipv4 : False
|
||||||
Also show the IP address each minion is connecting from.
|
Also show the IP address each minion is connecting from.
|
||||||
|
|
||||||
.. versionadded:: 2015.8.0
|
|
||||||
|
|
||||||
CLI Example:
|
CLI Example:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
@ -411,6 +407,8 @@ def not_alived(subset=None, show_ipv4=False):
|
|||||||
|
|
||||||
def reaped(subset=None, show_ipv4=False):
|
def reaped(subset=None, show_ipv4=False):
|
||||||
'''
|
'''
|
||||||
|
.. versionadded:: 2015.8.0
|
||||||
|
|
||||||
Print a list of all minions that are up according to Salt's presence
|
Print a list of all minions that are up according to Salt's presence
|
||||||
detection (no commands will be sent to minions)
|
detection (no commands will be sent to minions)
|
||||||
|
|
||||||
@ -420,8 +418,6 @@ def reaped(subset=None, show_ipv4=False):
|
|||||||
show_ipv4 : False
|
show_ipv4 : False
|
||||||
Also show the IP address each minion is connecting from.
|
Also show the IP address each minion is connecting from.
|
||||||
|
|
||||||
.. versionadded:: 2015.8.0
|
|
||||||
|
|
||||||
CLI Example:
|
CLI Example:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
@ -433,6 +429,8 @@ def reaped(subset=None, show_ipv4=False):
|
|||||||
|
|
||||||
def not_reaped(subset=None, show_ipv4=False):
|
def not_reaped(subset=None, show_ipv4=False):
|
||||||
'''
|
'''
|
||||||
|
.. versionadded:: 2015.8.0
|
||||||
|
|
||||||
Print a list of all minions that are NOT up according to Salt's presence
|
Print a list of all minions that are NOT up according to Salt's presence
|
||||||
detection (no commands will be sent)
|
detection (no commands will be sent)
|
||||||
|
|
||||||
@ -442,8 +440,6 @@ def not_reaped(subset=None, show_ipv4=False):
|
|||||||
show_ipv4 : False
|
show_ipv4 : False
|
||||||
Also show the IP address each minion is connecting from.
|
Also show the IP address each minion is connecting from.
|
||||||
|
|
||||||
.. versionadded:: 2015.8.0
|
|
||||||
|
|
||||||
CLI Example:
|
CLI Example:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
250
salt/states/glance.py
Normal file
250
salt/states/glance.py
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
'''
|
||||||
|
Managing Images in OpenStack Glance
|
||||||
|
===================================
|
||||||
|
'''
|
||||||
|
# Import python libs
|
||||||
|
from __future__ import absolute_import
|
||||||
|
import logging
|
||||||
|
import time
|
||||||
|
|
||||||
|
# Import salt libs
|
||||||
|
from salt.utils import warn_until
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def _find_image(name):
|
||||||
|
'''
|
||||||
|
Tries to find image with given name, returns
|
||||||
|
- image, 'Found image <name>'
|
||||||
|
- None, 'No such image found'
|
||||||
|
- False, 'Found more than one image with given name'
|
||||||
|
'''
|
||||||
|
images_dict = __salt__['glance.image_list'](name=name)
|
||||||
|
log.debug('Got images_dict: {0}'.format(images_dict))
|
||||||
|
|
||||||
|
warn_until('Boron', 'Starting with Boron '
|
||||||
|
'\'glance.image_list\' is not supposed to return '
|
||||||
|
'the images wrapped in a separate dict anymore.')
|
||||||
|
if len(images_dict) == 1 and 'images' in images_dict:
|
||||||
|
images_dict = images_dict['images']
|
||||||
|
|
||||||
|
# I /think/ this will still work when glance.image_list
|
||||||
|
# starts returning a list instead of a dictionary...
|
||||||
|
if len(images_dict) == 0:
|
||||||
|
return None, 'No image with name "{0}"'.format(name)
|
||||||
|
elif len(images_dict) == 1:
|
||||||
|
return images_dict.values()[0], 'Found image {0}'.format(name)
|
||||||
|
elif len(images_dict) > 1:
|
||||||
|
return False, 'Found more than one image with given name'
|
||||||
|
else:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
|
def image_present(name, visibility='public', protected=None,
|
||||||
|
checksum=None, location=None, wait_for=None, timeout=30):
|
||||||
|
'''
|
||||||
|
Checks if given image is present with properties
|
||||||
|
set as specified.
|
||||||
|
|
||||||
|
An image should got through the stages 'queued', 'saving'
|
||||||
|
before becoming 'active'. The attribute 'checksum' can
|
||||||
|
only be checked once the image is active.
|
||||||
|
If you don't specify 'wait_for' but 'checksum' the function
|
||||||
|
will wait for the image to become active before comparing
|
||||||
|
checksums. If you don't specify checksum either the function
|
||||||
|
will return when the image reached 'saving'.
|
||||||
|
The default timeout for both is 30 seconds.
|
||||||
|
|
||||||
|
Supported properties:
|
||||||
|
- visibility ('public' or 'private')
|
||||||
|
- protected (bool)
|
||||||
|
- checksum (string, md5sum)
|
||||||
|
- location (URL, to copy from)
|
||||||
|
'''
|
||||||
|
ret = {'name': name,
|
||||||
|
'changes': {},
|
||||||
|
'result': True,
|
||||||
|
'comment': '',
|
||||||
|
}
|
||||||
|
acceptable = ['queued', 'saving', 'active']
|
||||||
|
if wait_for is None and checksum is None:
|
||||||
|
wait_for = 'saving'
|
||||||
|
elif wait_for is None and checksum is not None:
|
||||||
|
wait_for = 'active'
|
||||||
|
|
||||||
|
# Just pop states until we reach the
|
||||||
|
# first acceptable one:
|
||||||
|
while len(acceptable) > 1:
|
||||||
|
if acceptable[0] == wait_for:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
acceptable.pop(0)
|
||||||
|
|
||||||
|
image, msg = _find_image(name)
|
||||||
|
if image is False:
|
||||||
|
if __opts__['test']:
|
||||||
|
ret['result'] = None
|
||||||
|
else:
|
||||||
|
ret['result'] = False
|
||||||
|
ret['comment'] = msg
|
||||||
|
return ret
|
||||||
|
log.debug(msg)
|
||||||
|
# No image yet and we know where to get one
|
||||||
|
if image is None and location is not None:
|
||||||
|
if __opts__['test']:
|
||||||
|
ret['result'] = None
|
||||||
|
ret['comment'] = 'glance.image_present would ' \
|
||||||
|
'create an image from {0}'.format(location)
|
||||||
|
return ret
|
||||||
|
image = __salt__['glance.image_create'](name=name,
|
||||||
|
protected=protected, visibility=visibility,
|
||||||
|
location=location)
|
||||||
|
# See Salt issue #24568
|
||||||
|
warn_until('Boron', 'Starting with Boron '
|
||||||
|
'\'glance.image_create\' is not supposed to return '
|
||||||
|
'the image wrapped in a dict anymore.')
|
||||||
|
if len(image.keys()) == 1:
|
||||||
|
image = image.values()[0]
|
||||||
|
log.debug('Created new image:\n{0}'.format(image))
|
||||||
|
ret['changes'] = {
|
||||||
|
name:
|
||||||
|
{
|
||||||
|
'new':
|
||||||
|
{
|
||||||
|
'id': image['id']
|
||||||
|
},
|
||||||
|
'old': None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
timer = timeout
|
||||||
|
# Kinda busy-loopy but I don't think the Glance
|
||||||
|
# API has events we can listen for
|
||||||
|
while timer > 0:
|
||||||
|
if 'status' in image and \
|
||||||
|
image['status'] in acceptable:
|
||||||
|
log.debug('Image {0} has reached status {1}'.format(
|
||||||
|
image['name'], image['status']))
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
timer -= 5
|
||||||
|
time.sleep(5)
|
||||||
|
image, msg = _find_image(name)
|
||||||
|
if not image:
|
||||||
|
ret['result'] = False
|
||||||
|
ret['comment'] += 'Created image {0} '.format(
|
||||||
|
name) + ' vanished:\n' + msg
|
||||||
|
return ret
|
||||||
|
elif len(image.keys()) == 1:
|
||||||
|
# See Salt issue #24568
|
||||||
|
warn_until('Boron', 'Starting with Boron '
|
||||||
|
'\'_find_image()\' is not supposed to return '
|
||||||
|
'the image wrapped in a dict anymore.')
|
||||||
|
image = image.values()[0]
|
||||||
|
if timer <= 0 and image['status'] not in acceptable:
|
||||||
|
ret['result'] = False
|
||||||
|
ret['comment'] += 'Image didn\'t reach an acceptable '+\
|
||||||
|
'state ({0}) before timeout:\n'.format(acceptable)+\
|
||||||
|
'\tLast status was "{0}".\n'.format(image['status'])
|
||||||
|
|
||||||
|
# See Salt issue #24568
|
||||||
|
warn_until('Boron', 'Starting with Boron '
|
||||||
|
'\'_find_image()\' is not supposed to return '
|
||||||
|
'the image wrapped in a dict anymore.')
|
||||||
|
if len(image.keys()) == 1:
|
||||||
|
image = image.values()[0]
|
||||||
|
# ret[comment] +=
|
||||||
|
|
||||||
|
# There's no image but where would I get one??
|
||||||
|
elif location is None:
|
||||||
|
if __opts__['test']:
|
||||||
|
ret['result'] = None
|
||||||
|
ret['comment'] = 'No location to copy image from specified,\n' +\
|
||||||
|
'glance.image_present would not create one'
|
||||||
|
else:
|
||||||
|
ret['result'] = False
|
||||||
|
ret['comment'] = 'No location to copy image from specified,\n' +\
|
||||||
|
'not creating a new image.'
|
||||||
|
return ret
|
||||||
|
|
||||||
|
# If we've created a new image also return its last status:
|
||||||
|
if name in ret['changes']:
|
||||||
|
ret['changes'][name]['new']['status'] = image['status']
|
||||||
|
|
||||||
|
if visibility:
|
||||||
|
if image['visibility'] != visibility:
|
||||||
|
old_value = image['visibility']
|
||||||
|
if not __opts__['test']:
|
||||||
|
image = __salt__['glance.image_update'](
|
||||||
|
id=image['id'], visibility=visibility)
|
||||||
|
# See Salt issue #24568
|
||||||
|
warn_until('Boron', 'Starting with Boron '
|
||||||
|
'\'glance.image_update\' is not supposed to return '
|
||||||
|
'the image wrapped in a dict anymore.')
|
||||||
|
if len(image.keys()) == 1:
|
||||||
|
image = image.values()[0]
|
||||||
|
# Check if image_update() worked:
|
||||||
|
if image['visibility'] != visibility:
|
||||||
|
if not __opts__['test']:
|
||||||
|
ret['result'] = False
|
||||||
|
elif __opts__['test']:
|
||||||
|
ret['result'] = None
|
||||||
|
ret['comment'] += '"visibility" is {0}, '\
|
||||||
|
'should be {1}.\n'.format(image['visibility'],
|
||||||
|
visibility)
|
||||||
|
else:
|
||||||
|
if 'new' in ret['changes']:
|
||||||
|
ret['changes']['new']['visibility'] = visibility
|
||||||
|
else:
|
||||||
|
ret['changes']['new'] = {'visibility': visibility}
|
||||||
|
if 'old' in ret['changes']:
|
||||||
|
ret['changes']['old']['visibility'] = old_value
|
||||||
|
else:
|
||||||
|
ret['changes']['old'] = {'visibility': old_value}
|
||||||
|
else:
|
||||||
|
ret['comment'] += '"visibility" is correct ({0}).\n'.format(
|
||||||
|
visibility)
|
||||||
|
if protected is not None:
|
||||||
|
if not isinstance(protected, bool) or image['protected'] ^ protected:
|
||||||
|
if not __opts__['test']:
|
||||||
|
ret['result'] = False
|
||||||
|
else:
|
||||||
|
ret['result'] = None
|
||||||
|
ret['comment'] += '"protected" is {0}, should be {1}.\n'.format(
|
||||||
|
image['protected'], protected)
|
||||||
|
else:
|
||||||
|
ret['comment'] += '"protected" is correct ({0}).\n'.format(
|
||||||
|
protected)
|
||||||
|
if 'status' in image and checksum:
|
||||||
|
if image['status'] == 'active':
|
||||||
|
if 'checksum' not in image:
|
||||||
|
# Refresh our info about the image
|
||||||
|
image = __salt__['glance.image_show'](image['id'])
|
||||||
|
warn_until('Boron', 'Starting with Boron '
|
||||||
|
'\'glance.image_show\' is not supposed to return '
|
||||||
|
'the image wrapped in a dict anymore.')
|
||||||
|
if len(image.keys()) == 1:
|
||||||
|
image = image.values()[0]
|
||||||
|
if 'checksum' not in image:
|
||||||
|
if not __opts__['test']:
|
||||||
|
ret['result'] = False
|
||||||
|
else:
|
||||||
|
ret['result'] = None
|
||||||
|
ret['comment'] += 'No checksum available for this image:\n' +\
|
||||||
|
'\tImage has status "{0}".'.format(image['status'])
|
||||||
|
elif image['checksum'] != checksum:
|
||||||
|
if not __opts__['test']:
|
||||||
|
ret['result'] = False
|
||||||
|
else:
|
||||||
|
ret['result'] = None
|
||||||
|
ret['comment'] += '"checksum" is {0}, should be {1}.\n'.format(
|
||||||
|
image['checksum'], checksum)
|
||||||
|
else:
|
||||||
|
ret['comment'] += '"checksum" is correct ({0}).\n'.format(
|
||||||
|
checksum)
|
||||||
|
elif image['status'] in ['saving', 'queued']:
|
||||||
|
ret['comment'] += 'Checksum won\'t be verified as image ' +\
|
||||||
|
'hasn\'t reached\n\t "status=active" yet.\n'
|
||||||
|
log.debug('glance.image_present will return: {0}'.format(ret))
|
||||||
|
return ret
|
@ -1586,6 +1586,40 @@ def is_sunos():
|
|||||||
return sys.platform.startswith('sunos')
|
return sys.platform.startswith('sunos')
|
||||||
|
|
||||||
|
|
||||||
|
@real_memoize
|
||||||
|
def is_smartos():
|
||||||
|
'''
|
||||||
|
Simple function to return if host is SmartOS (Illumos) or not
|
||||||
|
'''
|
||||||
|
if not is_sunos():
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return os.uname()[3].startswith('joyent_')
|
||||||
|
|
||||||
|
|
||||||
|
@real_memoize
|
||||||
|
def is_smartos_globalzone():
|
||||||
|
'''
|
||||||
|
Function to return if host is SmartOS (Illumos) global zone or not
|
||||||
|
'''
|
||||||
|
if not is_smartos():
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
cmd = ['zonename']
|
||||||
|
try:
|
||||||
|
zonename = subprocess.Popen(
|
||||||
|
cmd, shell=False,
|
||||||
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
except OSError:
|
||||||
|
return False
|
||||||
|
if zonename.returncode:
|
||||||
|
return False
|
||||||
|
if zonename.stdout.read().strip() == 'global':
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
@real_memoize
|
@real_memoize
|
||||||
def is_freebsd():
|
def is_freebsd():
|
||||||
'''
|
'''
|
||||||
|
@ -7,11 +7,14 @@ from __future__ import absolute_import
|
|||||||
|
|
||||||
import tornado.ioloop
|
import tornado.ioloop
|
||||||
import tornado.concurrent
|
import tornado.concurrent
|
||||||
|
LOOP_CLASS = tornado.ioloop.IOLoop
|
||||||
|
# attempt to use zmq-- if we have it otherwise fallback to tornado loop
|
||||||
try:
|
try:
|
||||||
import zmq.eventloop.ioloop
|
import zmq.eventloop.ioloop
|
||||||
# support pyzmq 13.0.x, TODO: remove once we force people to 14.0.x
|
# support pyzmq 13.0.x, TODO: remove once we force people to 14.0.x
|
||||||
if not hasattr(zmq.eventloop.ioloop, 'ZMQIOLoop'):
|
if not hasattr(zmq.eventloop.ioloop, 'ZMQIOLoop'):
|
||||||
zmq.eventloop.ioloop.ZMQIOLoop = zmq.eventloop.ioloop.IOLoop
|
zmq.eventloop.ioloop.ZMQIOLoop = zmq.eventloop.ioloop.IOLoop
|
||||||
|
LOOP_CLASS = zmq.eventloop.ioloop.ZMQIOLoop
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass # salt-ssh doesn't dep zmq
|
pass # salt-ssh doesn't dep zmq
|
||||||
|
|
||||||
@ -47,6 +50,8 @@ class SyncWrapper(object):
|
|||||||
ret = sync.async_method()
|
ret = sync.async_method()
|
||||||
'''
|
'''
|
||||||
loop_map = weakref.WeakKeyDictionary() # keep a mapping of parent io_loop -> sync_loop
|
loop_map = weakref.WeakKeyDictionary() # keep a mapping of parent io_loop -> sync_loop
|
||||||
|
# Can't use WeakSet since we have to support python 2.6 :(
|
||||||
|
loops_in_use = weakref.WeakKeyDictionary() # set of sync_loops in use
|
||||||
|
|
||||||
def __init__(self, method, args=tuple(), kwargs=None):
|
def __init__(self, method, args=tuple(), kwargs=None):
|
||||||
if kwargs is None:
|
if kwargs is None:
|
||||||
@ -54,14 +59,25 @@ class SyncWrapper(object):
|
|||||||
|
|
||||||
parent_io_loop = tornado.ioloop.IOLoop.current()
|
parent_io_loop = tornado.ioloop.IOLoop.current()
|
||||||
if parent_io_loop not in SyncWrapper.loop_map:
|
if parent_io_loop not in SyncWrapper.loop_map:
|
||||||
SyncWrapper.loop_map[parent_io_loop] = zmq.eventloop.ioloop.ZMQIOLoop()
|
SyncWrapper.loop_map[parent_io_loop] = LOOP_CLASS()
|
||||||
|
|
||||||
self.io_loop = SyncWrapper.loop_map[parent_io_loop]
|
io_loop = SyncWrapper.loop_map[parent_io_loop]
|
||||||
|
if io_loop in self.loops_in_use:
|
||||||
|
io_loop = LOOP_CLASS()
|
||||||
|
self.io_loop = io_loop
|
||||||
|
self.loops_in_use[self.io_loop] = True
|
||||||
kwargs['io_loop'] = self.io_loop
|
kwargs['io_loop'] = self.io_loop
|
||||||
|
|
||||||
with current_ioloop(self.io_loop):
|
with current_ioloop(self.io_loop):
|
||||||
self.async = method(*args, **kwargs)
|
self.async = method(*args, **kwargs)
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
'''
|
||||||
|
Once the async wrapper is complete, remove our loop from the in use set
|
||||||
|
so someone else can use it without making another one
|
||||||
|
'''
|
||||||
|
del self.loops_in_use[self.io_loop]
|
||||||
|
|
||||||
def __getattribute__(self, key):
|
def __getattribute__(self, key):
|
||||||
try:
|
try:
|
||||||
return object.__getattribute__(self, key)
|
return object.__getattribute__(self, key)
|
||||||
|
@ -2710,8 +2710,9 @@ class SPMParser(six.with_metaclass(OptionParserMeta,
|
|||||||
def _mixin_after_parsed(self):
|
def _mixin_after_parsed(self):
|
||||||
# spm needs arguments
|
# spm needs arguments
|
||||||
if len(self.args) <= 1:
|
if len(self.args) <= 1:
|
||||||
self.print_help()
|
if self.args[0] not in ('update_repo',):
|
||||||
self.exit(salt.defaults.exitcodes.EX_USAGE)
|
self.print_help()
|
||||||
|
self.exit(salt.defaults.exitcodes.EX_USAGE)
|
||||||
|
|
||||||
def setup_config(self):
|
def setup_config(self):
|
||||||
return salt.config.spm_config(self.get_config_file_path())
|
return salt.config.spm_config(self.get_config_file_path())
|
||||||
|
@ -5,6 +5,9 @@ Create and verify ANSI X9.31 RSA signatures using OpenSSL libcrypto
|
|||||||
|
|
||||||
# python libs
|
# python libs
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
import glob
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
# salt libs
|
# salt libs
|
||||||
import salt.utils
|
import salt.utils
|
||||||
@ -12,7 +15,6 @@ import salt.utils
|
|||||||
# 3rd-party libs
|
# 3rd-party libs
|
||||||
from ctypes import cdll, c_char_p, c_int, c_void_p, pointer, create_string_buffer
|
from ctypes import cdll, c_char_p, c_int, c_void_p, pointer, create_string_buffer
|
||||||
from ctypes.util import find_library
|
from ctypes.util import find_library
|
||||||
import sys
|
|
||||||
|
|
||||||
|
|
||||||
def _load_libcrypto():
|
def _load_libcrypto():
|
||||||
@ -21,6 +23,10 @@ def _load_libcrypto():
|
|||||||
'''
|
'''
|
||||||
if sys.platform.startswith('win'):
|
if sys.platform.startswith('win'):
|
||||||
return cdll.LoadLibrary('libeay32')
|
return cdll.LoadLibrary('libeay32')
|
||||||
|
elif getattr(sys, 'frozen', False) and salt.utils.is_smartos():
|
||||||
|
return cdll.LoadLibrary(glob.glob(os.path.join(
|
||||||
|
os.path.dirname(sys.executable),
|
||||||
|
'libcrypto.so*'))[0])
|
||||||
else:
|
else:
|
||||||
lib = find_library('crypto')
|
lib = find_library('crypto')
|
||||||
if lib:
|
if lib:
|
||||||
|
78
tests/unit/utils/async_test.py
Normal file
78
tests/unit/utils/async_test.py
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
# Import Python Libs
|
||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
# Import 3rd-party libs
|
||||||
|
import tornado.testing
|
||||||
|
import tornado.gen
|
||||||
|
from tornado.testing import AsyncTestCase
|
||||||
|
|
||||||
|
from salt.utils import async
|
||||||
|
|
||||||
|
|
||||||
|
class HelperA(object):
|
||||||
|
def __init__(self, io_loop=None):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@tornado.gen.coroutine
|
||||||
|
def sleep(self):
|
||||||
|
yield tornado.gen.sleep(0.5)
|
||||||
|
raise tornado.gen.Return(True)
|
||||||
|
|
||||||
|
|
||||||
|
class HelperB(object):
|
||||||
|
def __init__(self, a=None, io_loop=None):
|
||||||
|
if a is None:
|
||||||
|
a = async.SyncWrapper(HelperA)
|
||||||
|
self.a = a
|
||||||
|
|
||||||
|
@tornado.gen.coroutine
|
||||||
|
def sleep(self):
|
||||||
|
yield tornado.gen.sleep(0.5)
|
||||||
|
self.a.sleep()
|
||||||
|
raise tornado.gen.Return(False)
|
||||||
|
|
||||||
|
|
||||||
|
class TestSyncWrapper(AsyncTestCase):
|
||||||
|
@tornado.testing.gen_test
|
||||||
|
def test_helpers(self):
|
||||||
|
'''
|
||||||
|
Test that the helper classes do what we expect within a regular async env
|
||||||
|
'''
|
||||||
|
ha = HelperA()
|
||||||
|
ret = yield ha.sleep()
|
||||||
|
self.assertTrue(ret)
|
||||||
|
|
||||||
|
hb = HelperB()
|
||||||
|
ret = yield hb.sleep()
|
||||||
|
self.assertFalse(ret)
|
||||||
|
|
||||||
|
def test_basic_wrap(self):
|
||||||
|
'''
|
||||||
|
Test that we can wrap an async caller.
|
||||||
|
'''
|
||||||
|
sync = async.SyncWrapper(HelperA)
|
||||||
|
ret = sync.sleep()
|
||||||
|
self.assertTrue(ret)
|
||||||
|
|
||||||
|
def test_double(self):
|
||||||
|
'''
|
||||||
|
Test when the async wrapper object itself creates a wrap of another thing
|
||||||
|
|
||||||
|
This works fine since the second wrap is based on the first's IOLoop so we
|
||||||
|
don't have to worry about complex start/stop mechanics
|
||||||
|
'''
|
||||||
|
sync = async.SyncWrapper(HelperB)
|
||||||
|
ret = sync.sleep()
|
||||||
|
self.assertFalse(ret)
|
||||||
|
|
||||||
|
def test_double_sameloop(self):
|
||||||
|
'''
|
||||||
|
Test async wrappers initiated from the same IOLoop, to ensure that
|
||||||
|
we don't wire up both to the same IOLoop (since it causes MANY problems).
|
||||||
|
'''
|
||||||
|
a = async.SyncWrapper(HelperA)
|
||||||
|
sync = async.SyncWrapper(HelperB, (a,))
|
||||||
|
ret = sync.sleep()
|
||||||
|
self.assertFalse(ret)
|
Loading…
Reference in New Issue
Block a user