Compare commits
168 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
16113e255b | ||
|
|
30d6f07ceb | ||
|
|
343a65952a | ||
|
|
9af6886b0e | ||
|
|
b0ef77f5d1 | ||
|
|
f5157f2894 | ||
|
|
13331935df | ||
|
|
8d61c1a2b4 | ||
|
|
6b4b5c2fe5 | ||
|
|
62623a7f77 | ||
|
|
9d2f8d11ec | ||
|
|
f1d064c759 | ||
|
|
6cb02c18a7 | ||
|
|
37fc37e138 | ||
|
|
b68685741e | ||
|
|
6721977f74 | ||
|
|
c303ad4cdc | ||
|
|
51c9db2936 | ||
|
|
1e003d4153 | ||
|
|
bab89fd769 | ||
|
|
e1e17ab0b9 | ||
|
|
3d542472f6 | ||
|
|
eaa09a4cfc | ||
|
|
e78f2d073f | ||
|
|
47004b7c67 | ||
|
|
9ecd22f4c8 | ||
|
|
daee2336a4 | ||
|
|
893b730a44 | ||
|
|
d5b6e0a54f | ||
|
|
13b89c8dd2 | ||
|
|
7a300832b2 | ||
|
|
d218e6f107 | ||
|
|
d2f70f9d6f | ||
|
|
4951854f76 | ||
|
|
ffbd263888 | ||
|
|
985c6c49f9 | ||
|
|
adac2c0c16 | ||
|
|
f700ca4e0f | ||
|
|
5b741b2a4d | ||
|
|
382f641b22 | ||
|
|
5da5db8b56 | ||
|
|
c4888fee63 | ||
|
|
76f85591ea | ||
|
|
b006cadd22 | ||
|
|
1fd2053001 | ||
|
|
6a920fd307 | ||
|
|
514eeb75ef | ||
|
|
b43633fa6d | ||
|
|
d5a7d7674c | ||
|
|
bce87b3d05 | ||
|
|
783627626c | ||
|
|
3043e57066 | ||
|
|
be8b163a62 | ||
|
|
4f38595e4e | ||
|
|
30def6f35b | ||
|
|
0b31828a01 | ||
|
|
b5ac97bc2d | ||
|
|
398974a7b0 | ||
|
|
3a29b4e710 | ||
|
|
8024dbf913 | ||
|
|
529b0d34ee | ||
|
|
dac0924194 | ||
|
|
3bb66b645c | ||
|
|
63cebc0bfa | ||
|
|
5a28ac772a | ||
|
|
fe7ad9e42b | ||
|
|
711de94855 | ||
|
|
5817f6833c | ||
|
|
a24b7f0b61 | ||
|
|
c03668cb02 | ||
|
|
aab18245eb | ||
|
|
c12178920b | ||
|
|
f733fbeecd | ||
|
|
67754102c8 | ||
|
|
6545f9c2ad | ||
|
|
583c23b9d9 | ||
|
|
ea9ab8d6e5 | ||
|
|
8fd57276be | ||
|
|
1d197e5e8f | ||
|
|
b33337b7bd | ||
|
|
d0b9b6ce38 | ||
|
|
3cd847e2ab | ||
|
|
ba907f4905 | ||
|
|
8e787d0a87 | ||
|
|
b45c7b678e | ||
|
|
ec64e04cc5 | ||
|
|
f206c2d425 | ||
|
|
bff76de6f1 | ||
|
|
1500bee1c6 | ||
|
|
9f813fb90d | ||
|
|
8167eec625 | ||
|
|
6731851383 | ||
|
|
0ddfa278ef | ||
|
|
aae7699bc5 | ||
|
|
8521608e19 | ||
|
|
2266e2baa3 | ||
|
|
e08a0e9af2 | ||
|
|
844577e9cc | ||
|
|
0b44492da7 | ||
|
|
b146e29c39 | ||
|
|
0cabd5bd3a | ||
|
|
728acc091b | ||
|
|
7340decf73 | ||
|
|
84e8eb4cb0 | ||
|
|
5283871af5 | ||
|
|
916fd73186 | ||
|
|
22ee0aa8f7 | ||
|
|
63c1aabdd2 | ||
|
|
03569db6c3 | ||
|
|
19cf05fd75 | ||
|
|
251ca83ddc | ||
|
|
5b349b4e89 | ||
|
|
b0d03ae6b8 | ||
|
|
78de029a57 | ||
|
|
489356da3a | ||
|
|
db4339c371 | ||
|
|
c7ec186576 | ||
|
|
12bdfca0d9 | ||
|
|
5f179609d0 | ||
|
|
a842bc1c91 | ||
|
|
5eb1d91335 | ||
|
|
264b0fe9a1 | ||
|
|
a487a4efc8 | ||
|
|
034f0bf68a | ||
|
|
87b95bb639 | ||
|
|
e081ac91b4 | ||
|
|
3574dba9da | ||
|
|
8fc9c6c1d8 | ||
|
|
51f17f1d7d | ||
|
|
313f156394 | ||
|
|
129de26419 | ||
|
|
d38bc4e716 | ||
|
|
6ffa5feaaf | ||
|
|
bdd3a6ab89 | ||
|
|
8c5f363844 | ||
|
|
e61140edfb | ||
|
|
abc019829f | ||
|
|
0dd5826dd3 | ||
|
|
227a9e9b63 | ||
|
|
5b6768140f | ||
|
|
1ac7fbec34 | ||
|
|
ebb8885ece | ||
|
|
3fb4cadd76 | ||
|
|
c1d3f8094b | ||
|
|
59649f6a81 | ||
|
|
045404095d | ||
|
|
606a340b5b | ||
|
|
35fdbbe16e | ||
|
|
2db279e019 | ||
|
|
986ba9872f | ||
|
|
44a5a1573c | ||
|
|
fe34b420a5 | ||
|
|
43da4a6d21 | ||
|
|
7ba1bf2237 | ||
|
|
206bb413e2 | ||
|
|
1188d4263d | ||
|
|
1451d9c134 | ||
|
|
6d739ae1d0 | ||
|
|
f2751b4818 | ||
|
|
e2bf82607e | ||
|
|
d76b5d2f7e | ||
|
|
69730d80b2 | ||
|
|
17aa1122da | ||
|
|
d0f5a9fdf5 | ||
|
|
32dacdca8b | ||
|
|
fbfb7159e3 | ||
|
|
65c63a9351 | ||
|
|
27c56a19e4 |
12
.gitignore
vendored
12
.gitignore
vendored
@@ -4,8 +4,7 @@
|
|||||||
*.so
|
*.so
|
||||||
|
|
||||||
# Packages
|
# Packages
|
||||||
*.egg
|
*.egg*
|
||||||
*.egg-info
|
|
||||||
dist
|
dist
|
||||||
build
|
build
|
||||||
eggs
|
eggs
|
||||||
@@ -43,9 +42,11 @@ output/*/index.html
|
|||||||
|
|
||||||
# Sphinx
|
# Sphinx
|
||||||
doc/build
|
doc/build
|
||||||
doc/source/api
|
doc/source/api/*
|
||||||
doc/source/samples
|
doc/source/samples
|
||||||
doc/source/watcher.conf.sample
|
doc/source/_static/*.sample
|
||||||
|
!doc/source/api/index.rst
|
||||||
|
!doc/source/api/v1.rst
|
||||||
|
|
||||||
# pbr generates these
|
# pbr generates these
|
||||||
AUTHORS
|
AUTHORS
|
||||||
@@ -71,3 +72,6 @@ releasenotes/build
|
|||||||
|
|
||||||
# Desktop Service Store
|
# Desktop Service Store
|
||||||
*.DS_Store
|
*.DS_Store
|
||||||
|
|
||||||
|
# Autogenerated sample config file
|
||||||
|
etc/watcher/watcher.conf.sample
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
[gerrit]
|
[gerrit]
|
||||||
host=review.openstack.org
|
host=review.opendev.org
|
||||||
port=29418
|
port=29418
|
||||||
project=openstack/watcher.git
|
project=openstack/watcher.git
|
||||||
|
defaultbranch=stable/pike
|
||||||
|
|||||||
9
.zuul.yaml
Normal file
9
.zuul.yaml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
- project:
|
||||||
|
templates:
|
||||||
|
- openstack-python-jobs
|
||||||
|
- openstack-python35-jobs
|
||||||
|
- publish-openstack-sphinx-docs
|
||||||
|
- check-requirements
|
||||||
|
- release-notes-jobs
|
||||||
|
gate:
|
||||||
|
queue: watcher
|
||||||
@@ -28,4 +28,4 @@ migration, increased energy efficiency-and more!
|
|||||||
* Wiki: https://wiki.openstack.org/wiki/Watcher
|
* Wiki: https://wiki.openstack.org/wiki/Watcher
|
||||||
* Source: https://github.com/openstack/watcher
|
* Source: https://github.com/openstack/watcher
|
||||||
* Bugs: https://bugs.launchpad.net/watcher
|
* Bugs: https://bugs.launchpad.net/watcher
|
||||||
* Documentation: https://docs.openstack.org/developer/watcher/
|
* Documentation: https://docs.openstack.org/watcher/latest/
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ function init_watcher {
|
|||||||
recreate_database watcher
|
recreate_database watcher
|
||||||
|
|
||||||
# Create watcher schema
|
# Create watcher schema
|
||||||
$WATCHER_BIN_DIR/watcher-db-manage --config-file $WATCHER_CONF upgrade head
|
$WATCHER_BIN_DIR/watcher-db-manage --config-file $WATCHER_CONF upgrade
|
||||||
fi
|
fi
|
||||||
create_watcher_cache_dir
|
create_watcher_cache_dir
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ VNCSERVER_PROXYCLIENT_ADDRESS=$HOST_IP
|
|||||||
NOVA_INSTANCES_PATH=/opt/stack/data/instances
|
NOVA_INSTANCES_PATH=/opt/stack/data/instances
|
||||||
|
|
||||||
# Enable the Ceilometer plugin for the compute agent
|
# Enable the Ceilometer plugin for the compute agent
|
||||||
enable_plugin ceilometer git://git.openstack.org/openstack/ceilometer
|
enable_plugin ceilometer https://git.openstack.org/openstack/ceilometer
|
||||||
disable_service ceilometer-acentral,ceilometer-collector,ceilometer-api
|
disable_service ceilometer-acentral,ceilometer-collector,ceilometer-api
|
||||||
|
|
||||||
LOGFILE=$DEST/logs/stack.sh.log
|
LOGFILE=$DEST/logs/stack.sh.log
|
||||||
|
|||||||
@@ -32,13 +32,13 @@ ENABLED_SERVICES+=,q-svc,q-dhcp,q-meta,q-agt,q-l3,neutron
|
|||||||
enable_service n-cauth
|
enable_service n-cauth
|
||||||
|
|
||||||
# Enable the Watcher Dashboard plugin
|
# Enable the Watcher Dashboard plugin
|
||||||
enable_plugin watcher-dashboard git://git.openstack.org/openstack/watcher-dashboard
|
enable_plugin watcher-dashboard https://git.openstack.org/openstack/watcher-dashboard
|
||||||
|
|
||||||
# Enable the Watcher plugin
|
# Enable the Watcher plugin
|
||||||
enable_plugin watcher git://git.openstack.org/openstack/watcher
|
enable_plugin watcher https://git.openstack.org/openstack/watcher
|
||||||
|
|
||||||
# Enable the Ceilometer plugin
|
# Enable the Ceilometer plugin
|
||||||
enable_plugin ceilometer git://git.openstack.org/openstack/ceilometer
|
enable_plugin ceilometer https://git.openstack.org/openstack/ceilometer
|
||||||
|
|
||||||
# This is the controller node, so disable the ceilometer compute agent
|
# This is the controller node, so disable the ceilometer compute agent
|
||||||
disable_service ceilometer-acompute
|
disable_service ceilometer-acompute
|
||||||
@@ -46,7 +46,7 @@ disable_service ceilometer-acompute
|
|||||||
enable_service ceilometer-api
|
enable_service ceilometer-api
|
||||||
|
|
||||||
# Enable the Gnocchi plugin
|
# Enable the Gnocchi plugin
|
||||||
enable_plugin gnocchi https://git.openstack.org/openstack/gnocchi
|
enable_plugin gnocchi https://github.com/gnocchixyz/gnocchi
|
||||||
|
|
||||||
LOGFILE=$DEST/logs/stack.sh.log
|
LOGFILE=$DEST/logs/stack.sh.log
|
||||||
LOGDAYS=2
|
LOGDAYS=2
|
||||||
|
|||||||
0
doc/source/_static/.placeholder
Normal file
0
doc/source/_static/.placeholder
Normal file
12
doc/source/admin/index.rst
Normal file
12
doc/source/admin/index.rst
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
===================
|
||||||
|
Administrator Guide
|
||||||
|
===================
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
apache-mod-wsgi
|
||||||
|
gmr
|
||||||
|
policy
|
||||||
|
ways-to-install
|
||||||
|
../strategies/index
|
||||||
@@ -4,12 +4,13 @@
|
|||||||
|
|
||||||
https://creativecommons.org/licenses/by/3.0/
|
https://creativecommons.org/licenses/by/3.0/
|
||||||
|
|
||||||
==================
|
=======================
|
||||||
Installing Watcher
|
Ways to install Watcher
|
||||||
==================
|
=======================
|
||||||
|
|
||||||
This document describes how to install Watcher in order to use it. If you are
|
This document describes some ways to install Watcher in order to use it.
|
||||||
intending to develop on or with Watcher, please read :doc:`../dev/environment`.
|
If you are intending to develop on or with Watcher,
|
||||||
|
please read :doc:`../contributor/environment`.
|
||||||
|
|
||||||
Prerequisites
|
Prerequisites
|
||||||
-------------
|
-------------
|
||||||
@@ -77,9 +78,10 @@ Install the Watcher modules dependencies:
|
|||||||
|
|
||||||
# pip install -r requirements.txt
|
# pip install -r requirements.txt
|
||||||
|
|
||||||
From here, refer to :doc:`configuration` to declare Watcher as a new service
|
From here, refer to :doc:`../configuration/configuring` to declare Watcher
|
||||||
into Keystone and to configure its different modules. Once configured, you
|
as a new service into Keystone and to configure its different modules.
|
||||||
should be able to run the Watcher services by issuing these commands:
|
Once configured, you should be able to run the Watcher services by issuing
|
||||||
|
these commands:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
@@ -107,7 +109,7 @@ installed on your system.
|
|||||||
|
|
||||||
Once installed, you still need to declare Watcher as a new service into
|
Once installed, you still need to declare Watcher as a new service into
|
||||||
Keystone and to configure its different modules, which you can find described
|
Keystone and to configure its different modules, which you can find described
|
||||||
in :doc:`configuration`.
|
in :doc:`../configuration/configuring`.
|
||||||
|
|
||||||
|
|
||||||
Installing from packages: Debian (experimental)
|
Installing from packages: Debian (experimental)
|
||||||
4
doc/source/api/index.rst
Normal file
4
doc/source/api/index.rst
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
v1
|
||||||
@@ -20,6 +20,17 @@ Goals
|
|||||||
.. autotype:: watcher.api.controllers.v1.goal.Goal
|
.. autotype:: watcher.api.controllers.v1.goal.Goal
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
Strategies
|
||||||
|
==========
|
||||||
|
|
||||||
|
.. rest-controller:: watcher.api.controllers.v1.strategy:StrategiesController
|
||||||
|
:webprefix: /v1/strategies
|
||||||
|
|
||||||
|
.. autotype:: watcher.api.controllers.v1.strategy.StrategyCollection
|
||||||
|
:members:
|
||||||
|
|
||||||
|
.. autotype:: watcher.api.controllers.v1.strategy.Strategy
|
||||||
|
:members:
|
||||||
|
|
||||||
Audit Templates
|
Audit Templates
|
||||||
===============
|
===============
|
||||||
@@ -31,8 +31,7 @@ sys.path.insert(0, os.path.abspath('./'))
|
|||||||
# Add any Sphinx extension module names here, as strings. They can be
|
# Add any Sphinx extension module names here, as strings. They can be
|
||||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||||
extensions = [
|
extensions = [
|
||||||
'oslo_config.sphinxconfiggen',
|
'oslo_config.sphinxext',
|
||||||
'oslosphinx',
|
|
||||||
'sphinx.ext.autodoc',
|
'sphinx.ext.autodoc',
|
||||||
'sphinx.ext.viewcode',
|
'sphinx.ext.viewcode',
|
||||||
'sphinxcontrib.httpdomain',
|
'sphinxcontrib.httpdomain',
|
||||||
@@ -41,10 +40,14 @@ extensions = [
|
|||||||
'wsmeext.sphinxext',
|
'wsmeext.sphinxext',
|
||||||
'ext.term',
|
'ext.term',
|
||||||
'ext.versioned_notifications',
|
'ext.versioned_notifications',
|
||||||
|
'oslo_config.sphinxconfiggen',
|
||||||
|
'openstackdocstheme',
|
||||||
]
|
]
|
||||||
|
|
||||||
wsme_protocols = ['restjson']
|
wsme_protocols = ['restjson']
|
||||||
config_generator_config_file = '../../etc/watcher/watcher-config-generator.conf'
|
config_generator_config_file = [(
|
||||||
|
'../../etc/watcher/oslo-config-generator/watcher.conf',
|
||||||
|
'_static/watcher')]
|
||||||
sample_config_basename = 'watcher'
|
sample_config_basename = 'watcher'
|
||||||
|
|
||||||
# autodoc generation is a bit aggressive and a nuisance when doing heavy
|
# autodoc generation is a bit aggressive and a nuisance when doing heavy
|
||||||
@@ -92,6 +95,8 @@ add_function_parentheses = True
|
|||||||
# unit titles (such as .. function::).
|
# unit titles (such as .. function::).
|
||||||
add_module_names = True
|
add_module_names = True
|
||||||
|
|
||||||
|
suppress_warnings = ['app.add_directive']
|
||||||
|
|
||||||
# The name of the Pygments (syntax highlighting) style to use.
|
# The name of the Pygments (syntax highlighting) style to use.
|
||||||
pygments_style = 'sphinx'
|
pygments_style = 'sphinx'
|
||||||
|
|
||||||
@@ -117,12 +122,20 @@ man_pages = [
|
|||||||
# Sphinx are currently 'default' and 'sphinxdoc'.
|
# Sphinx are currently 'default' and 'sphinxdoc'.
|
||||||
# html_theme_path = ["."]
|
# html_theme_path = ["."]
|
||||||
# html_theme = '_theme'
|
# html_theme = '_theme'
|
||||||
|
html_theme = 'openstackdocs'
|
||||||
# html_static_path = ['static']
|
# html_static_path = ['static']
|
||||||
html_theme_options = {'incubating': True}
|
# html_theme_options = {}
|
||||||
|
|
||||||
# Output file base name for HTML help builder.
|
# Output file base name for HTML help builder.
|
||||||
htmlhelp_basename = '%sdoc' % project
|
htmlhelp_basename = '%sdoc' % project
|
||||||
|
|
||||||
|
html_last_updated_fmt = '%Y-%m-%d %H:%M'
|
||||||
|
|
||||||
|
#openstackdocstheme options
|
||||||
|
repository_name = 'openstack/watcher'
|
||||||
|
bug_project = 'watcher'
|
||||||
|
bug_tag = ''
|
||||||
|
|
||||||
# Grouping the document tree into LaTeX files. List of tuples
|
# Grouping the document tree into LaTeX files. List of tuples
|
||||||
# (source start file, target name, title, author, documentclass
|
# (source start file, target name, title, author, documentclass
|
||||||
# [howto/manual]).
|
# [howto/manual]).
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
../../etc/watcher/watcher-config-generator.conf
|
|
||||||
@@ -165,7 +165,7 @@ You can easily generate and update a sample configuration file
|
|||||||
named :ref:`watcher.conf.sample <watcher_sample_configuration_files>` by using
|
named :ref:`watcher.conf.sample <watcher_sample_configuration_files>` by using
|
||||||
these following commands::
|
these following commands::
|
||||||
|
|
||||||
$ git clone git://git.openstack.org/openstack/watcher
|
$ git clone https://git.openstack.org/openstack/watcher
|
||||||
$ cd watcher/
|
$ cd watcher/
|
||||||
$ tox -e genconfig
|
$ tox -e genconfig
|
||||||
$ vi etc/watcher/watcher.conf.sample
|
$ vi etc/watcher/watcher.conf.sample
|
||||||
@@ -430,6 +430,26 @@ to Watcher receives Nova notifications in ``watcher_notifications`` as well.
|
|||||||
* Restart the Nova services.
|
* Restart the Nova services.
|
||||||
|
|
||||||
|
|
||||||
|
Configure Cinder Notifications
|
||||||
|
==============================
|
||||||
|
|
||||||
|
Watcher can also consume notifications generated by the Cinder services, in
|
||||||
|
order to build or update, in real time, its cluster data model related to
|
||||||
|
storage resources. To do so, you have to update the Cinder configuration
|
||||||
|
file on controller and volume nodes, in order to let Watcher receive Cinder
|
||||||
|
notifications in a dedicated ``watcher_notifications`` channel.
|
||||||
|
|
||||||
|
* In the file ``/etc/cinder/cinder.conf``, update the section
|
||||||
|
``[oslo_messaging_notifications]``, by redefining the list of topics
|
||||||
|
into which Cinder services will publish events ::
|
||||||
|
|
||||||
|
[oslo_messaging_notifications]
|
||||||
|
driver = messagingv2
|
||||||
|
topics = notifications,watcher_notifications
|
||||||
|
|
||||||
|
* Restart the Cinder services.
|
||||||
|
|
||||||
|
|
||||||
Workers
|
Workers
|
||||||
=======
|
=======
|
||||||
|
|
||||||
5
doc/source/configuration/index.rst
Normal file
5
doc/source/configuration/index.rst
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
configuring
|
||||||
|
watcher
|
||||||
11
doc/source/configuration/watcher.rst
Normal file
11
doc/source/configuration/watcher.rst
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
.. _watcher_sample_configuration_files:
|
||||||
|
|
||||||
|
------------
|
||||||
|
watcher.conf
|
||||||
|
------------
|
||||||
|
|
||||||
|
The ``watcher.conf`` file contains most of the options to configure the
|
||||||
|
Watcher services.
|
||||||
|
|
||||||
|
.. show-options::
|
||||||
|
:config-file: etc/watcher/oslo-config-generator/watcher.conf
|
||||||
@@ -64,8 +64,9 @@ IRC Channel
|
|||||||
``#openstack-watcher`` (changelog_)
|
``#openstack-watcher`` (changelog_)
|
||||||
|
|
||||||
Weekly Meetings
|
Weekly Meetings
|
||||||
on Wednesdays at 14:00 UTC on even weeks, 9:00 UTC on odd weeks, in the
|
On Wednesdays at 14:00 UTC on even weeks in the ``#openstack-meeting-4``
|
||||||
``#openstack-meeting-4`` IRC channel (`meetings logs`_)
|
IRC channel, 13:00 UTC on odd weeks in the ``#openstack-meeting-alt``
|
||||||
|
IRC channel (`meetings logs`_)
|
||||||
|
|
||||||
.. _changelog: http://eavesdrop.openstack.org/irclogs/%23openstack-watcher/
|
.. _changelog: http://eavesdrop.openstack.org/irclogs/%23openstack-watcher/
|
||||||
.. _meetings logs: http://eavesdrop.openstack.org/meetings/watcher/
|
.. _meetings logs: http://eavesdrop.openstack.org/meetings/watcher/
|
||||||
@@ -19,7 +19,7 @@ model. To enable the Watcher plugin with DevStack, add the following to the
|
|||||||
`[[local|localrc]]` section of your controller's `local.conf` to enable the
|
`[[local|localrc]]` section of your controller's `local.conf` to enable the
|
||||||
Watcher plugin::
|
Watcher plugin::
|
||||||
|
|
||||||
enable_plugin watcher git://git.openstack.org/openstack/watcher
|
enable_plugin watcher https://git.openstack.org/openstack/watcher
|
||||||
|
|
||||||
For more detailed instructions, see `Detailed DevStack Instructions`_. Check
|
For more detailed instructions, see `Detailed DevStack Instructions`_. Check
|
||||||
out the `DevStack documentation`_ for more information regarding DevStack.
|
out the `DevStack documentation`_ for more information regarding DevStack.
|
||||||
@@ -17,7 +17,7 @@ To install Watcher from packaging, refer instead to Watcher `User
|
|||||||
Documentation`_.
|
Documentation`_.
|
||||||
|
|
||||||
.. _`Git Repository`: https://git.openstack.org/cgit/openstack/watcher
|
.. _`Git Repository`: https://git.openstack.org/cgit/openstack/watcher
|
||||||
.. _`User Documentation`: https://docs.openstack.org/developer/watcher/
|
.. _`User Documentation`: https://docs.openstack.org/watcher/latest/
|
||||||
|
|
||||||
Prerequisites
|
Prerequisites
|
||||||
=============
|
=============
|
||||||
@@ -25,7 +25,7 @@ Prerequisites
|
|||||||
This document assumes you are using Ubuntu or Fedora, and that you have the
|
This document assumes you are using Ubuntu or Fedora, and that you have the
|
||||||
following tools available on your system:
|
following tools available on your system:
|
||||||
|
|
||||||
- Python_ 2.7 and 3.4
|
- Python_ 2.7 and 3.5
|
||||||
- git_
|
- git_
|
||||||
- setuptools_
|
- setuptools_
|
||||||
- pip_
|
- pip_
|
||||||
@@ -77,13 +77,13 @@ extension, PyPi) cannot satisfy. These dependencies should be installed
|
|||||||
prior to using `pip`, and the installation method may vary depending on
|
prior to using `pip`, and the installation method may vary depending on
|
||||||
your platform.
|
your platform.
|
||||||
|
|
||||||
* Ubuntu 14.04::
|
* Ubuntu 16.04::
|
||||||
|
|
||||||
$ sudo apt-get install python-dev libssl-dev libmysqlclient-dev libffi-dev
|
$ sudo apt-get install python-dev libssl-dev libmysqlclient-dev libffi-dev
|
||||||
|
|
||||||
* Fedora 19+::
|
* Fedora 24+::
|
||||||
|
|
||||||
$ sudo yum install openssl-devel libffi-devel mysql-devel
|
$ sudo dnf install redhat-rpm-config gcc python-devel libxml2-devel
|
||||||
|
|
||||||
* CentOS 7::
|
* CentOS 7::
|
||||||
|
|
||||||
@@ -194,7 +194,7 @@ still need to configure the following sections:
|
|||||||
message bus
|
message bus
|
||||||
|
|
||||||
So if you need some more details on how to configure one or more of these
|
So if you need some more details on how to configure one or more of these
|
||||||
sections, please do have a look at :doc:`../deploy/configuration` before
|
sections, please do have a look at :doc:`../configuration/configuring` before
|
||||||
continuing.
|
continuing.
|
||||||
|
|
||||||
|
|
||||||
@@ -240,7 +240,7 @@ To run the Watcher Applier service, use:
|
|||||||
(watcher) $ watcher-applier
|
(watcher) $ watcher-applier
|
||||||
|
|
||||||
Default configuration of these services are available into ``/etc/watcher``
|
Default configuration of these services are available into ``/etc/watcher``
|
||||||
directory. See :doc:`../deploy/configuration` for details on how Watcher is
|
directory. See :doc:`../configuration/configuring` for details on how Watcher is
|
||||||
configured. By default, Watcher is configured with SQL backends.
|
configured. By default, Watcher is configured with SQL backends.
|
||||||
|
|
||||||
|
|
||||||
8
doc/source/contributor/index.rst
Normal file
8
doc/source/contributor/index.rst
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
environment
|
||||||
|
devstack
|
||||||
|
notifications
|
||||||
|
testing
|
||||||
|
rally_link
|
||||||
@@ -178,7 +178,7 @@ Here below is how you would proceed to register ``DummyAction`` using pbr_:
|
|||||||
watcher_actions =
|
watcher_actions =
|
||||||
dummy = thirdparty.dummy:DummyAction
|
dummy = thirdparty.dummy:DummyAction
|
||||||
|
|
||||||
.. _pbr: http://docs.openstack.org/developer/pbr/
|
.. _pbr: https://docs.openstack.org/pbr/latest
|
||||||
|
|
||||||
|
|
||||||
Using action plugins
|
Using action plugins
|
||||||
@@ -217,3 +217,11 @@ which is only able to process the Watcher built-in actions. Therefore, you will
|
|||||||
either have to use an existing third-party planner or :ref:`implement another
|
either have to use an existing third-party planner or :ref:`implement another
|
||||||
planner <implement_planner_plugin>` that will be able to take into account your
|
planner <implement_planner_plugin>` that will be able to take into account your
|
||||||
new action plugin.
|
new action plugin.
|
||||||
|
|
||||||
|
|
||||||
|
Test your new action
|
||||||
|
====================
|
||||||
|
|
||||||
|
In order to test your new action via a manual test or a Tempest test, you can
|
||||||
|
use the :py:class:`~.Actuator` strategy and pass it one or more actions to
|
||||||
|
execute. This way, you can isolate your action to see if it works as expected.
|
||||||
@@ -198,7 +198,7 @@ Here below is how to register ``DummyClusterDataModelCollector`` using pbr_:
|
|||||||
watcher_cluster_data_model_collectors =
|
watcher_cluster_data_model_collectors =
|
||||||
dummy = thirdparty.dummy:DummyClusterDataModelCollector
|
dummy = thirdparty.dummy:DummyClusterDataModelCollector
|
||||||
|
|
||||||
.. _pbr: http://docs.openstack.org/developer/pbr/
|
.. _pbr: http://docs.openstack.org/pbr/latest
|
||||||
|
|
||||||
|
|
||||||
Add new notification endpoints
|
Add new notification endpoints
|
||||||
@@ -123,8 +123,9 @@ Here below is how you would proceed to register ``NewGoal`` using pbr_:
|
|||||||
new_goal = thirdparty.new:NewGoal
|
new_goal = thirdparty.new:NewGoal
|
||||||
|
|
||||||
|
|
||||||
To get a better understanding on how to implement a more advanced goal,
|
To get a better understanding on how to implement a more advanced goal, have
|
||||||
have a look at the :py:class:`~.ServerConsolidation` class.
|
a look at the
|
||||||
|
:py:class:`watcher.decision_engine.goal.goals.ServerConsolidation` class.
|
||||||
|
|
||||||
.. _pbr: http://docs.openstack.org/developer/pbr/
|
.. _pbr: http://docs.openstack.org/developer/pbr/
|
||||||
|
|
||||||
11
doc/source/contributor/plugin/index.rst
Normal file
11
doc/source/contributor/plugin/index.rst
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
base-setup
|
||||||
|
action-plugin
|
||||||
|
cdmc-plugin
|
||||||
|
goal-plugin
|
||||||
|
planner-plugin
|
||||||
|
scoring-engine-plugin
|
||||||
|
strategy-plugin
|
||||||
|
plugins
|
||||||
@@ -37,7 +37,8 @@ Create a new scoring engine plugin
|
|||||||
|
|
||||||
In order to create a new scoring engine you have to:
|
In order to create a new scoring engine you have to:
|
||||||
|
|
||||||
- Extend the :py:class:`~.ScoringEngine` class
|
- Extend the :py:class:`watcher.decision_engine.scoring.base.ScoringEngine`
|
||||||
|
class
|
||||||
- Implement its :py:meth:`~.ScoringEngine.get_name` method to return the
|
- Implement its :py:meth:`~.ScoringEngine.get_name` method to return the
|
||||||
**unique** ID of the new scoring engine you want to create. This unique ID
|
**unique** ID of the new scoring engine you want to create. This unique ID
|
||||||
should be the same as the name of :ref:`the entry point we will declare later
|
should be the same as the name of :ref:`the entry point we will declare later
|
||||||
@@ -124,7 +125,8 @@ scoring engine deployed as a web service on external servers:
|
|||||||
Abstract Plugin Class
|
Abstract Plugin Class
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
Here below is the abstract :py:class:`~.ScoringEngine` class:
|
Here below is the abstract
|
||||||
|
:py:class:`watcher.decision_engine.scoring.base.ScoringEngine` class:
|
||||||
|
|
||||||
.. autoclass:: watcher.decision_engine.scoring.base.ScoringEngine
|
.. autoclass:: watcher.decision_engine.scoring.base.ScoringEngine
|
||||||
:members:
|
:members:
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
.. _watcher_sample_configuration_files:
|
|
||||||
|
|
||||||
==================================
|
|
||||||
Watcher sample configuration files
|
|
||||||
==================================
|
|
||||||
|
|
||||||
watcher.conf
|
|
||||||
~~~~~~~~~~~~
|
|
||||||
|
|
||||||
The ``watcher.conf`` file contains most of the options to configure the
|
|
||||||
Watcher services.
|
|
||||||
|
|
||||||
.. literalinclude:: ../watcher.conf.sample
|
|
||||||
:language: ini
|
|
||||||
@@ -65,6 +65,14 @@ Audit
|
|||||||
|
|
||||||
.. _audit_template_definition:
|
.. _audit_template_definition:
|
||||||
|
|
||||||
|
Audit Scope
|
||||||
|
===========
|
||||||
|
|
||||||
|
An Audit Scope is a set of audited resources. Audit Scope should be defined
|
||||||
|
in each Audit Template (which contains the Audit settings).
|
||||||
|
|
||||||
|
.. _audit_scope_definition:
|
||||||
|
|
||||||
Audit Template
|
Audit Template
|
||||||
==============
|
==============
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ ONGOING --> FAILED: Something failed while executing\nthe Action Plan in the Wat
|
|||||||
ONGOING --> SUCCEEDED: The Watcher Applier executed\nthe Action Plan successfully
|
ONGOING --> SUCCEEDED: The Watcher Applier executed\nthe Action Plan successfully
|
||||||
FAILED --> DELETED : Administrator removes\nAction Plan
|
FAILED --> DELETED : Administrator removes\nAction Plan
|
||||||
SUCCEEDED --> DELETED : Administrator removes\nAction Plan
|
SUCCEEDED --> DELETED : Administrator removes\nAction Plan
|
||||||
ONGOING --> CANCELLED : Administrator cancels\nAction Plan
|
ONGOING --> CANCELLING : Administrator cancels\nAction Plan
|
||||||
|
CANCELLING --> CANCELLED : The Watcher Applier cancelled\nthe Action Plan successfully
|
||||||
|
CANCELLING --> FAILED : Something failed while cancelling\nthe Action Plan in the Watcher Applier
|
||||||
RECOMMENDED --> CANCELLED : Administrator cancels\nAction Plan
|
RECOMMENDED --> CANCELLED : Administrator cancels\nAction Plan
|
||||||
RECOMMENDED --> SUPERSEDED : The Watcher Decision Engine supersedes\nAction Plan
|
RECOMMENDED --> SUPERSEDED : The Watcher Decision Engine supersedes\nAction Plan
|
||||||
PENDING --> CANCELLED : Administrator cancels\nAction Plan
|
PENDING --> CANCELLED : Administrator cancels\nAction Plan
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 76 KiB |
@@ -13,7 +13,7 @@
|
|||||||
height="210mm"
|
height="210mm"
|
||||||
id="svg4946"
|
id="svg4946"
|
||||||
version="1.1"
|
version="1.1"
|
||||||
inkscape:version="0.48.4 r9939"
|
inkscape:version="0.91 r13725"
|
||||||
sodipodi:docname="architecture.svg">
|
sodipodi:docname="architecture.svg">
|
||||||
<defs
|
<defs
|
||||||
id="defs4948">
|
id="defs4948">
|
||||||
@@ -325,6 +325,48 @@
|
|||||||
style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
|
style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
|
||||||
transform="matrix(-0.8,0,0,-0.8,4.8,0)" />
|
transform="matrix(-0.8,0,0,-0.8,4.8,0)" />
|
||||||
</marker>
|
</marker>
|
||||||
|
<marker
|
||||||
|
inkscape:stockid="EmptyTriangleInL"
|
||||||
|
orient="auto"
|
||||||
|
refY="0"
|
||||||
|
refX="0"
|
||||||
|
id="EmptyTriangleInL-5"
|
||||||
|
style="overflow:visible">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path7091-3"
|
||||||
|
d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
|
||||||
|
style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
|
||||||
|
transform="matrix(-0.8,0,0,-0.8,4.8,0)" />
|
||||||
|
</marker>
|
||||||
|
<marker
|
||||||
|
inkscape:stockid="EmptyTriangleInL"
|
||||||
|
orient="auto"
|
||||||
|
refY="0"
|
||||||
|
refX="0"
|
||||||
|
id="EmptyTriangleInL-6"
|
||||||
|
style="overflow:visible">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path7091-2"
|
||||||
|
d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
|
||||||
|
style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
|
||||||
|
transform="matrix(-0.8,0,0,-0.8,4.8,0)" />
|
||||||
|
</marker>
|
||||||
|
<marker
|
||||||
|
inkscape:stockid="EmptyTriangleInL"
|
||||||
|
orient="auto"
|
||||||
|
refY="0"
|
||||||
|
refX="0"
|
||||||
|
id="EmptyTriangleInL-12"
|
||||||
|
style="overflow:visible">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path7091-70"
|
||||||
|
d="m 5.77,0 -8.65,5 0,-10 8.65,5 z"
|
||||||
|
style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
|
||||||
|
transform="matrix(-0.8,0,0,-0.8,4.8,0)" />
|
||||||
|
</marker>
|
||||||
</defs>
|
</defs>
|
||||||
<sodipodi:namedview
|
<sodipodi:namedview
|
||||||
inkscape:document-units="mm"
|
inkscape:document-units="mm"
|
||||||
@@ -333,17 +375,21 @@
|
|||||||
borderopacity="1.0"
|
borderopacity="1.0"
|
||||||
inkscape:pageopacity="0.0"
|
inkscape:pageopacity="0.0"
|
||||||
inkscape:pageshadow="2"
|
inkscape:pageshadow="2"
|
||||||
inkscape:zoom="4"
|
inkscape:zoom="1.4142136"
|
||||||
inkscape:cx="261.24633"
|
inkscape:cx="665.19215"
|
||||||
inkscape:cy="108.90512"
|
inkscape:cy="108.90512"
|
||||||
inkscape:current-layer="g5356"
|
inkscape:current-layer="g4866-2-3"
|
||||||
id="namedview4950"
|
id="namedview4950"
|
||||||
showgrid="false"
|
showgrid="true"
|
||||||
inkscape:window-width="1846"
|
inkscape:window-width="1211"
|
||||||
inkscape:window-height="1053"
|
inkscape:window-height="698"
|
||||||
inkscape:window-x="1911"
|
inkscape:window-x="65"
|
||||||
inkscape:window-y="37"
|
inkscape:window-y="24"
|
||||||
inkscape:window-maximized="1" />
|
inkscape:window-maximized="1">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid4203" />
|
||||||
|
</sodipodi:namedview>
|
||||||
<metadata
|
<metadata
|
||||||
id="metadata4952">
|
id="metadata4952">
|
||||||
<rdf:RDF>
|
<rdf:RDF>
|
||||||
@@ -363,6 +409,12 @@
|
|||||||
<g
|
<g
|
||||||
id="g5356"
|
id="g5356"
|
||||||
transform="translate(-15.096057,-107.16694)">
|
transform="translate(-15.096057,-107.16694)">
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="cc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path3284-4-2-3-77-5-9"
|
||||||
|
d="m 813.66791,753.1462 0,-92.21768"
|
||||||
|
style="display:inline;fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#EmptyTriangleInL-6)" />
|
||||||
<rect
|
<rect
|
||||||
y="377.8927"
|
y="377.8927"
|
||||||
x="96.920677"
|
x="96.920677"
|
||||||
@@ -410,7 +462,7 @@
|
|||||||
sodipodi:cy="358.94418"
|
sodipodi:cy="358.94418"
|
||||||
sodipodi:rx="70.677063"
|
sodipodi:rx="70.677063"
|
||||||
sodipodi:ry="70.677063"
|
sodipodi:ry="70.677063"
|
||||||
d="m 394.67978,358.94418 c 0,39.03387 -31.6432,70.67707 -70.67706,70.67707 -39.03387,0 -70.67707,-31.6432 -70.67707,-70.67707 0,-39.03386 31.6432,-70.67706 70.67707,-70.67706 39.03386,0 70.67706,31.6432 70.67706,70.67706 z"
|
d="m 394.67978,358.94418 a 70.677063,70.677063 0 0 1 -70.67706,70.67707 70.677063,70.677063 0 0 1 -70.67707,-70.67707 70.677063,70.677063 0 0 1 70.67707,-70.67706 70.677063,70.677063 0 0 1 70.67706,70.67706 z"
|
||||||
transform="matrix(0.36664048,0,0,0.36664048,0.86684619,-80.697844)" />
|
transform="matrix(0.36664048,0,0,0.36664048,0.86684619,-80.697844)" />
|
||||||
<g
|
<g
|
||||||
id="g5262">
|
id="g5262">
|
||||||
@@ -536,29 +588,29 @@
|
|||||||
</g>
|
</g>
|
||||||
<rect
|
<rect
|
||||||
y="754.5235"
|
y="754.5235"
|
||||||
x="225.29219"
|
x="231.29219"
|
||||||
height="42.939091"
|
height="42.939091"
|
||||||
width="118.56741"
|
width="118.56741"
|
||||||
id="rect4267-4-7-7-3-3"
|
id="rect4267-4-7-7-3-3"
|
||||||
style="fill:#ffffff;stroke:#000000;stroke-width:1;stroke-opacity:1;display:inline" />
|
style="display:inline;fill:#ffffff;stroke:#000000;stroke-width:1;stroke-opacity:1" />
|
||||||
<text
|
<text
|
||||||
sodipodi:linespacing="125%"
|
sodipodi:linespacing="125%"
|
||||||
id="text5037-4-6-9-1-4"
|
id="text5037-4-6-9-1-4"
|
||||||
y="783.03412"
|
y="783.03412"
|
||||||
x="284.34656"
|
x="290.34656"
|
||||||
style="font-size:20.86613655px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
|
style="font-style:normal;font-weight:normal;font-size:20.86613655px;line-height:125%;font-family:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;display:inline;fill:#000000;fill-opacity:1;stroke:none"
|
||||||
xml:space="preserve"><tspan
|
xml:space="preserve"><tspan
|
||||||
id="tspan5184-3-5-2-1"
|
id="tspan5184-3-5-2-1"
|
||||||
style="font-size:20px;text-align:center;text-anchor:middle"
|
style="font-size:20px;text-align:center;text-anchor:middle"
|
||||||
y="783.03412"
|
y="783.03412"
|
||||||
x="284.34656"
|
x="290.34656"
|
||||||
sodipodi:role="line">ceilometer</tspan></text>
|
sodipodi:role="line">ceilometer</tspan></text>
|
||||||
<g
|
<g
|
||||||
transform="matrix(1.7775787,0,0,1.7775787,593.58186,304.14299)"
|
transform="matrix(1.7775787,0,0,1.7775787,599.58186,304.14299)"
|
||||||
id="g4982"
|
id="g4982"
|
||||||
style="display:inline">
|
style="display:inline">
|
||||||
<rect
|
<rect
|
||||||
style="fill:#ffffff;stroke:#000000;stroke-width:0.562563;stroke-opacity:1;display:inline"
|
style="display:inline;fill:#ffffff;stroke:#000000;stroke-width:0.562563;stroke-opacity:1"
|
||||||
id="rect4267-4-7-7-3-3-1"
|
id="rect4267-4-7-7-3-3-1"
|
||||||
width="66.701637"
|
width="66.701637"
|
||||||
height="24.155943"
|
height="24.155943"
|
||||||
@@ -566,7 +618,7 @@
|
|||||||
y="253.36743" />
|
y="253.36743" />
|
||||||
<text
|
<text
|
||||||
xml:space="preserve"
|
xml:space="preserve"
|
||||||
style="font-size:11.73851585px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
|
style="font-style:normal;font-weight:normal;font-size:11.73851585px;line-height:125%;font-family:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;display:inline;fill:#000000;fill-opacity:1;stroke:none"
|
||||||
x="-100.86156"
|
x="-100.86156"
|
||||||
y="268.36258"
|
y="268.36258"
|
||||||
id="text5037-4-6-9-1-4-3"
|
id="text5037-4-6-9-1-4-3"
|
||||||
@@ -620,12 +672,6 @@
|
|||||||
style="font-size:11.2512598px;text-align:center;text-anchor:middle"
|
style="font-size:11.2512598px;text-align:center;text-anchor:middle"
|
||||||
id="tspan5022">drivers</tspan></text>
|
id="tspan5022">drivers</tspan></text>
|
||||||
</g>
|
</g>
|
||||||
<path
|
|
||||||
sodipodi:nodetypes="cc"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
id="path5110"
|
|
||||||
d="m 376.75141,726.9703 -57.95106,0"
|
|
||||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline" />
|
|
||||||
<g
|
<g
|
||||||
transform="matrix(1.7775787,0,0,1.7775787,704.59677,780.35846)"
|
transform="matrix(1.7775787,0,0,1.7775787,704.59677,780.35846)"
|
||||||
id="g5267"
|
id="g5267"
|
||||||
@@ -863,8 +909,8 @@
|
|||||||
sodipodi:nodetypes="cc"
|
sodipodi:nodetypes="cc"
|
||||||
inkscape:connector-curvature="0"
|
inkscape:connector-curvature="0"
|
||||||
id="path5110-9"
|
id="path5110-9"
|
||||||
d="m 472.18905,726.66568 221.85496,0"
|
d="m 472.18905,726.66568 331.45651,0"
|
||||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline" />
|
style="display:inline;fill:none;stroke:#000000;stroke-width:1.22230256px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||||
<path
|
<path
|
||||||
sodipodi:nodetypes="cc"
|
sodipodi:nodetypes="cc"
|
||||||
inkscape:connector-curvature="0"
|
inkscape:connector-curvature="0"
|
||||||
@@ -907,8 +953,8 @@
|
|||||||
sodipodi:nodetypes="cc"
|
sodipodi:nodetypes="cc"
|
||||||
inkscape:connector-curvature="0"
|
inkscape:connector-curvature="0"
|
||||||
id="path3284-4-2-3-4-6"
|
id="path3284-4-2-3-4-6"
|
||||||
d="m 540.57926,651.7922 179.16488,0"
|
d="m 543.75943,651.7922 280.63651,0"
|
||||||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1.99999999, 1.99999999;stroke-dashoffset:0;marker-start:url(#TriangleInL);display:inline" />
|
style="display:inline;fill:none;stroke:#000000;stroke-width:1.25154257;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:2.50308524, 2.50308524;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#TriangleInL)" />
|
||||||
<rect
|
<rect
|
||||||
y="262.01205"
|
y="262.01205"
|
||||||
x="451.89563"
|
x="451.89563"
|
||||||
@@ -1052,8 +1098,8 @@
|
|||||||
sodipodi:nodetypes="cc"
|
sodipodi:nodetypes="cc"
|
||||||
inkscape:connector-curvature="0"
|
inkscape:connector-curvature="0"
|
||||||
id="path5112-89"
|
id="path5112-89"
|
||||||
d="m 328.87061,655.34778 0,71.7093"
|
d="m 324.87061,655.34778 0,71.7093"
|
||||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline" />
|
style="display:inline;fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||||
<path
|
<path
|
||||||
sodipodi:nodetypes="cc"
|
sodipodi:nodetypes="cc"
|
||||||
inkscape:connector-curvature="0"
|
inkscape:connector-curvature="0"
|
||||||
@@ -1178,7 +1224,7 @@
|
|||||||
sodipodi:role="line">extensions</tspan></text>
|
sodipodi:role="line">extensions</tspan></text>
|
||||||
<path
|
<path
|
||||||
transform="translate(68.397849,130.15566)"
|
transform="translate(68.397849,130.15566)"
|
||||||
d="m 519.41589,367.58817 c 0,4.01434 -2.01125,7.2686 -4.49224,7.2686 -2.481,0 -4.49225,-3.25426 -4.49225,-7.2686 0,-4.01434 2.01125,-7.26861 4.49225,-7.26861 2.48099,0 4.49224,3.25427 4.49224,7.26861 z"
|
d="m 519.41589,367.58817 a 4.4922457,7.2686057 0 0 1 -4.49224,7.2686 4.4922457,7.2686057 0 0 1 -4.49225,-7.2686 4.4922457,7.2686057 0 0 1 4.49225,-7.26861 4.4922457,7.2686057 0 0 1 4.49224,7.26861 z"
|
||||||
sodipodi:ry="7.2686057"
|
sodipodi:ry="7.2686057"
|
||||||
sodipodi:rx="4.4922457"
|
sodipodi:rx="4.4922457"
|
||||||
sodipodi:cy="367.58817"
|
sodipodi:cy="367.58817"
|
||||||
@@ -1188,7 +1234,7 @@
|
|||||||
sodipodi:type="arc" />
|
sodipodi:type="arc" />
|
||||||
<path
|
<path
|
||||||
transform="matrix(0.36538461,0,0,0.36538461,397.30905,368.17877)"
|
transform="matrix(0.36538461,0,0,0.36538461,397.30905,368.17877)"
|
||||||
d="m 521.38126,368.43045 c 0,4.03162 -3.26828,7.2999 -7.2999,7.2999 -4.03162,0 -7.2999,-3.26828 -7.2999,-7.2999 0,-4.03162 3.26828,-7.2999 7.2999,-7.2999 4.03162,0 7.2999,3.26828 7.2999,7.2999 z"
|
d="m 521.38126,368.43045 a 7.2998991,7.2998991 0 0 1 -7.2999,7.2999 7.2998991,7.2998991 0 0 1 -7.2999,-7.2999 7.2998991,7.2998991 0 0 1 7.2999,-7.2999 7.2998991,7.2998991 0 0 1 7.2999,7.2999 z"
|
||||||
sodipodi:ry="7.2998991"
|
sodipodi:ry="7.2998991"
|
||||||
sodipodi:rx="7.2998991"
|
sodipodi:rx="7.2998991"
|
||||||
sodipodi:cy="368.43045"
|
sodipodi:cy="368.43045"
|
||||||
@@ -1198,7 +1244,7 @@
|
|||||||
sodipodi:type="arc" />
|
sodipodi:type="arc" />
|
||||||
<path
|
<path
|
||||||
transform="matrix(0.36538461,0,0,0.36538461,-27.122619,99.964199)"
|
transform="matrix(0.36538461,0,0,0.36538461,-27.122619,99.964199)"
|
||||||
d="m 521.38126,368.43045 c 0,4.03162 -3.26828,7.2999 -7.2999,7.2999 -4.03162,0 -7.2999,-3.26828 -7.2999,-7.2999 0,-4.03162 3.26828,-7.2999 7.2999,-7.2999 4.03162,0 7.2999,3.26828 7.2999,7.2999 z"
|
d="m 521.38126,368.43045 a 7.2998991,7.2998991 0 0 1 -7.2999,7.2999 7.2998991,7.2998991 0 0 1 -7.2999,-7.2999 7.2998991,7.2998991 0 0 1 7.2999,-7.2999 7.2998991,7.2998991 0 0 1 7.2999,7.2999 z"
|
||||||
sodipodi:ry="7.2998991"
|
sodipodi:ry="7.2998991"
|
||||||
sodipodi:rx="7.2998991"
|
sodipodi:rx="7.2998991"
|
||||||
sodipodi:cy="368.43045"
|
sodipodi:cy="368.43045"
|
||||||
@@ -1214,7 +1260,7 @@
|
|||||||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:3.99999997, 1.99999998, 0.99999999, 1.99999998;stroke-dashoffset:0;marker-start:none;display:inline" />
|
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:3.99999997, 1.99999998, 0.99999999, 1.99999998;stroke-dashoffset:0;marker-start:none;display:inline" />
|
||||||
<path
|
<path
|
||||||
transform="matrix(0.36538461,0,0,0.36538461,396.74123,268.71562)"
|
transform="matrix(0.36538461,0,0,0.36538461,396.74123,268.71562)"
|
||||||
d="m 521.38126,368.43045 c 0,4.03162 -3.26828,7.2999 -7.2999,7.2999 -4.03162,0 -7.2999,-3.26828 -7.2999,-7.2999 0,-4.03162 3.26828,-7.2999 7.2999,-7.2999 4.03162,0 7.2999,3.26828 7.2999,7.2999 z"
|
d="m 521.38126,368.43045 a 7.2998991,7.2998991 0 0 1 -7.2999,7.2999 7.2998991,7.2998991 0 0 1 -7.2999,-7.2999 7.2998991,7.2998991 0 0 1 7.2999,-7.2999 7.2998991,7.2998991 0 0 1 7.2999,7.2999 z"
|
||||||
sodipodi:ry="7.2998991"
|
sodipodi:ry="7.2998991"
|
||||||
sodipodi:rx="7.2998991"
|
sodipodi:rx="7.2998991"
|
||||||
sodipodi:cy="368.43045"
|
sodipodi:cy="368.43045"
|
||||||
@@ -1224,7 +1270,7 @@
|
|||||||
sodipodi:type="arc" />
|
sodipodi:type="arc" />
|
||||||
<path
|
<path
|
||||||
transform="matrix(0.36538461,0,0,0.36538461,428.69747,559.36511)"
|
transform="matrix(0.36538461,0,0,0.36538461,428.69747,559.36511)"
|
||||||
d="m 521.38126,368.43045 c 0,4.03162 -3.26828,7.2999 -7.2999,7.2999 -4.03162,0 -7.2999,-3.26828 -7.2999,-7.2999 0,-4.03162 3.26828,-7.2999 7.2999,-7.2999 4.03162,0 7.2999,3.26828 7.2999,7.2999 z"
|
d="m 521.38126,368.43045 a 7.2998991,7.2998991 0 0 1 -7.2999,7.2999 7.2998991,7.2998991 0 0 1 -7.2999,-7.2999 7.2998991,7.2998991 0 0 1 7.2999,-7.2999 7.2998991,7.2998991 0 0 1 7.2999,7.2999 z"
|
||||||
sodipodi:ry="7.2998991"
|
sodipodi:ry="7.2998991"
|
||||||
sodipodi:rx="7.2998991"
|
sodipodi:rx="7.2998991"
|
||||||
sodipodi:cy="368.43045"
|
sodipodi:cy="368.43045"
|
||||||
@@ -1234,7 +1280,7 @@
|
|||||||
sodipodi:type="arc" />
|
sodipodi:type="arc" />
|
||||||
<path
|
<path
|
||||||
transform="matrix(0.36538461,0,0,0.36538461,531.88959,559.36511)"
|
transform="matrix(0.36538461,0,0,0.36538461,531.88959,559.36511)"
|
||||||
d="m 521.38126,368.43045 c 0,4.03162 -3.26828,7.2999 -7.2999,7.2999 -4.03162,0 -7.2999,-3.26828 -7.2999,-7.2999 0,-4.03162 3.26828,-7.2999 7.2999,-7.2999 4.03162,0 7.2999,3.26828 7.2999,7.2999 z"
|
d="m 521.38126,368.43045 a 7.2998991,7.2998991 0 0 1 -7.2999,7.2999 7.2998991,7.2998991 0 0 1 -7.2999,-7.2999 7.2998991,7.2998991 0 0 1 7.2999,-7.2999 7.2998991,7.2998991 0 0 1 7.2999,7.2999 z"
|
||||||
sodipodi:ry="7.2998991"
|
sodipodi:ry="7.2998991"
|
||||||
sodipodi:rx="7.2998991"
|
sodipodi:rx="7.2998991"
|
||||||
sodipodi:cy="368.43045"
|
sodipodi:cy="368.43045"
|
||||||
@@ -1250,7 +1296,7 @@
|
|||||||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1.99999998, 1.99999998;stroke-dashoffset:0;marker-start:none;display:inline" />
|
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1.99999998, 1.99999998;stroke-dashoffset:0;marker-start:none;display:inline" />
|
||||||
<path
|
<path
|
||||||
transform="matrix(0.36538461,0,0,0.36538461,748.91653,525.25993)"
|
transform="matrix(0.36538461,0,0,0.36538461,748.91653,525.25993)"
|
||||||
d="m 521.38126,368.43045 c 0,4.03162 -3.26828,7.2999 -7.2999,7.2999 -4.03162,0 -7.2999,-3.26828 -7.2999,-7.2999 0,-4.03162 3.26828,-7.2999 7.2999,-7.2999 4.03162,0 7.2999,3.26828 7.2999,7.2999 z"
|
d="m 521.38126,368.43045 a 7.2998991,7.2998991 0 0 1 -7.2999,7.2999 7.2998991,7.2998991 0 0 1 -7.2999,-7.2999 7.2998991,7.2998991 0 0 1 7.2999,-7.2999 7.2998991,7.2998991 0 0 1 7.2999,7.2999 z"
|
||||||
sodipodi:ry="7.2998991"
|
sodipodi:ry="7.2998991"
|
||||||
sodipodi:rx="7.2998991"
|
sodipodi:rx="7.2998991"
|
||||||
sodipodi:cy="368.43045"
|
sodipodi:cy="368.43045"
|
||||||
@@ -1260,7 +1306,7 @@
|
|||||||
sodipodi:type="arc" />
|
sodipodi:type="arc" />
|
||||||
<path
|
<path
|
||||||
transform="matrix(0.36538461,0,0,0.36538461,748.91653,495.84628)"
|
transform="matrix(0.36538461,0,0,0.36538461,748.91653,495.84628)"
|
||||||
d="m 521.38126,368.43045 c 0,4.03162 -3.26828,7.2999 -7.2999,7.2999 -4.03162,0 -7.2999,-3.26828 -7.2999,-7.2999 0,-4.03162 3.26828,-7.2999 7.2999,-7.2999 4.03162,0 7.2999,3.26828 7.2999,7.2999 z"
|
d="m 521.38126,368.43045 a 7.2998991,7.2998991 0 0 1 -7.2999,7.2999 7.2998991,7.2998991 0 0 1 -7.2999,-7.2999 7.2998991,7.2998991 0 0 1 7.2999,-7.2999 7.2998991,7.2998991 0 0 1 7.2999,7.2999 z"
|
||||||
sodipodi:ry="7.2998991"
|
sodipodi:ry="7.2998991"
|
||||||
sodipodi:rx="7.2998991"
|
sodipodi:rx="7.2998991"
|
||||||
sodipodi:cy="368.43045"
|
sodipodi:cy="368.43045"
|
||||||
@@ -1313,7 +1359,7 @@
|
|||||||
</g>
|
</g>
|
||||||
<path
|
<path
|
||||||
transform="matrix(0.36538461,0,0,0.36538461,396.74122,268.71562)"
|
transform="matrix(0.36538461,0,0,0.36538461,396.74122,268.71562)"
|
||||||
d="m 521.38126,368.43045 c 0,4.03162 -3.26828,7.2999 -7.2999,7.2999 -4.03162,0 -7.2999,-3.26828 -7.2999,-7.2999 0,-4.03162 3.26828,-7.2999 7.2999,-7.2999 4.03162,0 7.2999,3.26828 7.2999,7.2999 z"
|
d="m 521.38126,368.43045 a 7.2998991,7.2998991 0 0 1 -7.2999,7.2999 7.2998991,7.2998991 0 0 1 -7.2999,-7.2999 7.2998991,7.2998991 0 0 1 7.2999,-7.2999 7.2998991,7.2998991 0 0 1 7.2999,7.2999 z"
|
||||||
sodipodi:ry="7.2998991"
|
sodipodi:ry="7.2998991"
|
||||||
sodipodi:rx="7.2998991"
|
sodipodi:rx="7.2998991"
|
||||||
sodipodi:cy="368.43045"
|
sodipodi:cy="368.43045"
|
||||||
@@ -1323,7 +1369,7 @@
|
|||||||
sodipodi:type="arc" />
|
sodipodi:type="arc" />
|
||||||
<path
|
<path
|
||||||
transform="matrix(0.36538461,0,0,0.36538461,-27.122619,74.87915)"
|
transform="matrix(0.36538461,0,0,0.36538461,-27.122619,74.87915)"
|
||||||
d="m 521.38126,368.43045 c 0,4.03162 -3.26828,7.2999 -7.2999,7.2999 -4.03162,0 -7.2999,-3.26828 -7.2999,-7.2999 0,-4.03162 3.26828,-7.2999 7.2999,-7.2999 4.03162,0 7.2999,3.26828 7.2999,7.2999 z"
|
d="m 521.38126,368.43045 a 7.2998991,7.2998991 0 0 1 -7.2999,7.2999 7.2998991,7.2998991 0 0 1 -7.2999,-7.2999 7.2998991,7.2998991 0 0 1 7.2999,-7.2999 7.2998991,7.2998991 0 0 1 7.2999,7.2999 z"
|
||||||
sodipodi:ry="7.2998991"
|
sodipodi:ry="7.2998991"
|
||||||
sodipodi:rx="7.2998991"
|
sodipodi:rx="7.2998991"
|
||||||
sodipodi:cy="368.43045"
|
sodipodi:cy="368.43045"
|
||||||
@@ -1339,7 +1385,7 @@
|
|||||||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:3.99999997, 1.99999998, 0.99999999, 1.99999998;stroke-dashoffset:0;marker-start:url(#TriangleInL);display:inline" />
|
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:3.99999997, 1.99999998, 0.99999999, 1.99999998;stroke-dashoffset:0;marker-start:url(#TriangleInL);display:inline" />
|
||||||
<path
|
<path
|
||||||
transform="matrix(0.36538461,0,0,0.36538461,422.9095,223.59883)"
|
transform="matrix(0.36538461,0,0,0.36538461,422.9095,223.59883)"
|
||||||
d="m 521.38126,368.43045 c 0,4.03162 -3.26828,7.2999 -7.2999,7.2999 -4.03162,0 -7.2999,-3.26828 -7.2999,-7.2999 0,-4.03162 3.26828,-7.2999 7.2999,-7.2999 4.03162,0 7.2999,3.26828 7.2999,7.2999 z"
|
d="m 521.38126,368.43045 a 7.2998991,7.2998991 0 0 1 -7.2999,7.2999 7.2998991,7.2998991 0 0 1 -7.2999,-7.2999 7.2998991,7.2998991 0 0 1 7.2999,-7.2999 7.2998991,7.2998991 0 0 1 7.2999,7.2999 z"
|
||||||
sodipodi:ry="7.2998991"
|
sodipodi:ry="7.2998991"
|
||||||
sodipodi:rx="7.2998991"
|
sodipodi:rx="7.2998991"
|
||||||
sodipodi:cy="368.43045"
|
sodipodi:cy="368.43045"
|
||||||
@@ -1351,15 +1397,87 @@
|
|||||||
sodipodi:nodetypes="cc"
|
sodipodi:nodetypes="cc"
|
||||||
inkscape:connector-curvature="0"
|
inkscape:connector-curvature="0"
|
||||||
id="path3284-4-2-3-40"
|
id="path3284-4-2-3-40"
|
||||||
d="m 319.30136,753.47677 0,-27.00021"
|
d="m 325.23661,753.47677 0,-27.00021"
|
||||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#EmptyTriangleInL);display:inline" />
|
style="display:inline;fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#EmptyTriangleInL)" />
|
||||||
<path
|
<path
|
||||||
sodipodi:nodetypes="cc"
|
sodipodi:nodetypes="cc"
|
||||||
inkscape:connector-curvature="0"
|
inkscape:connector-curvature="0"
|
||||||
id="path3284-4-2-3-8"
|
id="path3284-4-2-3-8"
|
||||||
d="m 376.2546,753.65849 0,-27.00021"
|
d="m 414.2546,753.65849 0,-27.00021"
|
||||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#EmptyTriangleInL);display:inline" />
|
style="display:inline;fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#EmptyTriangleInL)" />
|
||||||
|
<rect
|
||||||
|
y="754.5235"
|
||||||
|
x="102.92204"
|
||||||
|
height="42.939091"
|
||||||
|
width="118.56741"
|
||||||
|
id="rect4267-4-7-7-3-3-3"
|
||||||
|
style="display:inline;fill:#ffffff;stroke:#000000;stroke-width:1;stroke-opacity:1" />
|
||||||
|
<text
|
||||||
|
sodipodi:linespacing="125%"
|
||||||
|
id="text5037-4-6-9-1-4-6"
|
||||||
|
y="783.03412"
|
||||||
|
x="160.34656"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:20.86613655px;line-height:125%;font-family:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;display:inline;fill:#000000;fill-opacity:1;stroke:none"
|
||||||
|
xml:space="preserve"><tspan
|
||||||
|
id="tspan5184-3-5-2-1-7"
|
||||||
|
style="font-size:20px;text-align:center;text-anchor:middle"
|
||||||
|
y="783.03412"
|
||||||
|
x="160.34656"
|
||||||
|
sodipodi:role="line">gnocchi</tspan></text>
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="cc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path3284-4-2-3-40-5"
|
||||||
|
d="m 191.30136,753.47677 0,-27.00021"
|
||||||
|
style="display:inline;fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#EmptyTriangleInL-5)" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="cc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path5110-9-6"
|
||||||
|
d="m 192.18905,726.66568 221.85496,0"
|
||||||
|
style="display:inline;fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||||
|
<g
|
||||||
|
id="g4866-2-3"
|
||||||
|
style="display:inline"
|
||||||
|
transform="matrix(1.7775787,0,0,1.7775787,991.15946,596.08131)">
|
||||||
|
<rect
|
||||||
|
style="display:inline;fill:#ffffff;stroke:#000000;stroke-width:0.562563;stroke-opacity:1"
|
||||||
|
id="rect4267-4-7-7-6"
|
||||||
|
width="49.81258"
|
||||||
|
height="24.243191"
|
||||||
|
x="-116.67716"
|
||||||
|
y="88.977051" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:11.73851585px;line-height:125%;font-family:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;display:inline;fill:#000000;fill-opacity:1;stroke:none"
|
||||||
|
x="-91.899979"
|
||||||
|
y="104.01585"
|
||||||
|
id="text5037-4-6-9-7"
|
||||||
|
sodipodi:linespacing="125%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
x="-91.899979"
|
||||||
|
y="104.01585"
|
||||||
|
style="font-size:11.2512598px;text-align:center;text-anchor:middle"
|
||||||
|
id="tspan5184-3-5-5">cinder</tspan></text>
|
||||||
|
</g>
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="cc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path3284-4-2-3-4-9-3"
|
||||||
|
d="m 824.37881,651.58554 0,102.98987"
|
||||||
|
style="display:inline;fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.99999999, 1.99999999;stroke-dashoffset:0;stroke-opacity:1;marker-start:none" />
|
||||||
|
<circle
|
||||||
|
r="2.6672709"
|
||||||
|
cy="693.98395"
|
||||||
|
cx="823.72699"
|
||||||
|
id="path13407-89-5"
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ececec;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="cc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path3284-4-2-3-7-9"
|
||||||
|
d="m 804.16781,752.35205 0,-26.2061"
|
||||||
|
style="display:inline;fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#EmptyTriangleInL-12)" />
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 64 KiB |
@@ -43,7 +43,7 @@ Introduction
|
|||||||
|
|
||||||
glossary
|
glossary
|
||||||
architecture
|
architecture
|
||||||
dev/contributing
|
contributor/contributing
|
||||||
|
|
||||||
|
|
||||||
Getting Started
|
Getting Started
|
||||||
@@ -52,14 +52,7 @@ Getting Started
|
|||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
|
||||||
dev/environment
|
contributor/index
|
||||||
dev/devstack
|
|
||||||
deploy/configuration
|
|
||||||
deploy/conf-files
|
|
||||||
deploy/apache-mod-wsgi
|
|
||||||
dev/notifications
|
|
||||||
dev/testing
|
|
||||||
dev/rally_link
|
|
||||||
|
|
||||||
API References
|
API References
|
||||||
--------------
|
--------------
|
||||||
@@ -67,7 +60,7 @@ API References
|
|||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
|
||||||
webapi/v1
|
api/index
|
||||||
|
|
||||||
Plugins
|
Plugins
|
||||||
-------
|
-------
|
||||||
@@ -75,30 +68,38 @@ Plugins
|
|||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
|
||||||
dev/plugin/base-setup
|
contributor/plugin/index
|
||||||
dev/plugin/goal-plugin
|
|
||||||
dev/plugin/scoring-engine-plugin
|
|
||||||
dev/plugin/strategy-plugin
|
|
||||||
dev/plugin/cdmc-plugin
|
|
||||||
dev/plugin/action-plugin
|
|
||||||
dev/plugin/planner-plugin
|
|
||||||
dev/plugins
|
|
||||||
|
|
||||||
|
Installation
|
||||||
|
============
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
install/index
|
||||||
|
|
||||||
|
Watcher Configuration Options
|
||||||
|
=============================
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
configuration/index
|
||||||
|
|
||||||
Admin Guide
|
Admin Guide
|
||||||
===========
|
===========
|
||||||
|
|
||||||
Introduction
|
.. toctree::
|
||||||
------------
|
:maxdepth: 2
|
||||||
|
|
||||||
|
admin/index
|
||||||
|
|
||||||
|
User Guide
|
||||||
|
==========
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 1
|
:maxdepth: 2
|
||||||
|
|
||||||
deploy/installation
|
user/index
|
||||||
deploy/user-guide
|
|
||||||
deploy/policy
|
|
||||||
deploy/gmr
|
|
||||||
strategies/strategies
|
|
||||||
|
|
||||||
Watcher Manual Pages
|
Watcher Manual Pages
|
||||||
====================
|
====================
|
||||||
@@ -107,7 +108,7 @@ Watcher Manual Pages
|
|||||||
:glob:
|
:glob:
|
||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
|
||||||
man/*
|
man/index
|
||||||
|
|
||||||
.. # NOTE(mriedem): This is the section where we hide things that we don't
|
.. # NOTE(mriedem): This is the section where we hide things that we don't
|
||||||
# actually want in the table of contents but sphinx build would fail if
|
# actually want in the table of contents but sphinx build would fail if
|
||||||
|
|||||||
@@ -68,4 +68,4 @@
|
|||||||
|
|
||||||
.. code-block:: ini
|
.. code-block:: ini
|
||||||
|
|
||||||
su -s /bin/sh -c "watcher-db-manage" watcher
|
su -s /bin/sh -c "watcher-db-manage --config-file /etc/watcher/watcher.conf create_schema"
|
||||||
@@ -15,13 +15,13 @@ you must create a database, service credentials, and API endpoints.
|
|||||||
|
|
||||||
* Create the ``watcher`` database:
|
* Create the ``watcher`` database:
|
||||||
|
|
||||||
.. code-block:: none
|
.. code-block:: console
|
||||||
|
|
||||||
CREATE DATABASE watcher CHARACTER SET utf8;
|
CREATE DATABASE watcher CHARACTER SET utf8;
|
||||||
|
|
||||||
* Grant proper access to the ``watcher`` database:
|
* Grant proper access to the ``watcher`` database:
|
||||||
|
|
||||||
.. code-block:: none
|
.. code-block:: console
|
||||||
|
|
||||||
GRANT ALL PRIVILEGES ON watcher.* TO 'watcher'@'localhost' \
|
GRANT ALL PRIVILEGES ON watcher.* TO 'watcher'@'localhost' \
|
||||||
IDENTIFIED BY 'WATCHER_DBPASS';
|
IDENTIFIED BY 'WATCHER_DBPASS';
|
||||||
@@ -32,7 +32,7 @@ you must create a database, service credentials, and API endpoints.
|
|||||||
|
|
||||||
* Exit the database access client.
|
* Exit the database access client.
|
||||||
|
|
||||||
.. code-block:: none
|
.. code-block:: console
|
||||||
|
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
@@ -23,15 +23,15 @@ of data center operating costs, increased system performance
|
|||||||
via intelligent virtual machine migration, increased energy
|
via intelligent virtual machine migration, increased energy
|
||||||
efficiency—and more!
|
efficiency—and more!
|
||||||
|
|
||||||
watcher also supports a pluggable architecture by which custom
|
Watcher also supports a pluggable architecture by which custom
|
||||||
optimization algorithms, data metrics and data profilers can be
|
optimization algorithms, data metrics and data profilers can be
|
||||||
developed and inserted into the Watcher framework.
|
developed and inserted into the Watcher framework.
|
||||||
|
|
||||||
check the documentation for watcher optimization strategies at
|
Check the documentation for watcher optimization strategies at
|
||||||
https://docs.openstack.org/developer/watcher/strategies
|
https://docs.openstack.org/watcher/latest/strategies/index.html
|
||||||
|
|
||||||
check watcher glossary at
|
Check watcher glossary at
|
||||||
https://docs.openstack.org/developer/watcher/glossary.html
|
https://docs.openstack.org/watcher/latest/glossary.html
|
||||||
|
|
||||||
|
|
||||||
This chapter assumes a working setup of OpenStack following the
|
This chapter assumes a working setup of OpenStack following the
|
||||||
@@ -4,8 +4,9 @@
|
|||||||
Install and configure for openSUSE and SUSE Linux Enterprise
|
Install and configure for openSUSE and SUSE Linux Enterprise
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
This section describes how to install and configure the Infrastructure Optimization service
|
This section describes how to install and configure the Infrastructure
|
||||||
for openSUSE Leap 42.1 and SUSE Linux Enterprise Server 12 SP1.
|
Optimization service for openSUSE Leap 42.1 and
|
||||||
|
SUSE Linux Enterprise Server 12 SP1.
|
||||||
|
|
||||||
.. include:: common_prerequisites.rst
|
.. include:: common_prerequisites.rst
|
||||||
|
|
||||||
@@ -4,8 +4,8 @@ Install and configure for Red Hat Enterprise Linux and CentOS
|
|||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
||||||
This section describes how to install and configure the Infrastructure Optimization service
|
This section describes how to install and configure the Infrastructure
|
||||||
for Red Hat Enterprise Linux 7 and CentOS 7.
|
Optimization service for Red Hat Enterprise Linux 7 and CentOS 7.
|
||||||
|
|
||||||
.. include:: common_prerequisites.rst
|
.. include:: common_prerequisites.rst
|
||||||
|
|
||||||
@@ -3,8 +3,8 @@
|
|||||||
Install and configure for Ubuntu
|
Install and configure for Ubuntu
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
This section describes how to install and configure the Infrastructure Optimization
|
This section describes how to install and configure the Infrastructure
|
||||||
service for Ubuntu 14.04 (LTS).
|
Optimization service for Ubuntu 14.04 (LTS).
|
||||||
|
|
||||||
.. include:: common_prerequisites.rst
|
.. include:: common_prerequisites.rst
|
||||||
|
|
||||||
@@ -3,8 +3,8 @@
|
|||||||
Install and configure
|
Install and configure
|
||||||
~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
This section describes how to install and configure the
|
This section describes how to install and configure the Infrastructure
|
||||||
Infrastructure Optimization service, code-named watcher, on the controller node.
|
Optimization service, code-named watcher, on the controller node.
|
||||||
|
|
||||||
This section assumes that you already have a working OpenStack
|
This section assumes that you already have a working OpenStack
|
||||||
environment with at least the following components installed:
|
environment with at least the following components installed:
|
||||||
8
doc/source/man/index.rst
Normal file
8
doc/source/man/index.rst
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
.. toctree::
|
||||||
|
:glob:
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
watcher-api
|
||||||
|
watcher-applier
|
||||||
|
watcher-db-manage
|
||||||
|
watcher-decision-engine
|
||||||
@@ -57,7 +57,7 @@ Planner
|
|||||||
|
|
||||||
Default Watcher's planner:
|
Default Watcher's planner:
|
||||||
|
|
||||||
.. watcher-term:: watcher.decision_engine.planner.default.DefaultPlanner
|
.. watcher-term:: watcher.decision_engine.planner.weight.WeightPlanner
|
||||||
|
|
||||||
Configuration
|
Configuration
|
||||||
-------------
|
-------------
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ Planner
|
|||||||
|
|
||||||
Default Watcher's planner:
|
Default Watcher's planner:
|
||||||
|
|
||||||
.. watcher-term:: watcher.decision_engine.planner.default.DefaultPlanner
|
.. watcher-term:: watcher.decision_engine.planner.weight.WeightPlanner
|
||||||
|
|
||||||
Configuration
|
Configuration
|
||||||
-------------
|
-------------
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ Planner
|
|||||||
|
|
||||||
Default Watcher's planner:
|
Default Watcher's planner:
|
||||||
|
|
||||||
.. watcher-term:: watcher.decision_engine.planner.default.DefaultPlanner
|
.. watcher-term:: watcher.decision_engine.planner.weight.WeightPlanner
|
||||||
|
|
||||||
Configuration
|
Configuration
|
||||||
-------------
|
-------------
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ The *vm_workload_consolidation* strategy requires the following metrics:
|
|||||||
============================ ============ ======= =======
|
============================ ============ ======= =======
|
||||||
metric service name plugins comment
|
metric service name plugins comment
|
||||||
============================ ============ ======= =======
|
============================ ============ ======= =======
|
||||||
``memory`` ceilometer_ none
|
``memory`` ceilometer_ none
|
||||||
``disk.root.size`` ceilometer_ none
|
``disk.root.size`` ceilometer_ none
|
||||||
============================ ============ ======= =======
|
============================ ============ ======= =======
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ the strategy if available:
|
|||||||
============================ ============ ======= =======
|
============================ ============ ======= =======
|
||||||
metric service name plugins comment
|
metric service name plugins comment
|
||||||
============================ ============ ======= =======
|
============================ ============ ======= =======
|
||||||
``memory.usage`` ceilometer_ none
|
``memory.resident`` ceilometer_ none
|
||||||
``cpu_util`` ceilometer_ none
|
``cpu_util`` ceilometer_ none
|
||||||
============================ ============ ======= =======
|
============================ ============ ======= =======
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ Planner
|
|||||||
|
|
||||||
Default Watcher's planner:
|
Default Watcher's planner:
|
||||||
|
|
||||||
.. watcher-term:: watcher.decision_engine.planner.default.DefaultPlanner
|
.. watcher-term:: watcher.decision_engine.planner.weight.WeightPlanner
|
||||||
|
|
||||||
|
|
||||||
Configuration
|
Configuration
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ Planner
|
|||||||
|
|
||||||
Default Watcher's planner:
|
Default Watcher's planner:
|
||||||
|
|
||||||
.. watcher-term:: watcher.decision_engine.planner.default.DefaultPlanner
|
.. watcher-term:: watcher.decision_engine.planner.weight.WeightPlanner
|
||||||
|
|
||||||
Configuration
|
Configuration
|
||||||
-------------
|
-------------
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ The *workload_balance* strategy requires the following metrics:
|
|||||||
metric service name plugins comment
|
metric service name plugins comment
|
||||||
======================= ============ ======= =======
|
======================= ============ ======= =======
|
||||||
``cpu_util`` ceilometer_ none
|
``cpu_util`` ceilometer_ none
|
||||||
|
``memory.resident`` ceilometer_ none
|
||||||
======================= ============ ======= =======
|
======================= ============ ======= =======
|
||||||
|
|
||||||
.. _ceilometer: http://docs.openstack.org/admin-guide/telemetry-measurements.html#openstack-compute
|
.. _ceilometer: http://docs.openstack.org/admin-guide/telemetry-measurements.html#openstack-compute
|
||||||
@@ -56,7 +57,7 @@ Planner
|
|||||||
|
|
||||||
Default Watcher's planner:
|
Default Watcher's planner:
|
||||||
|
|
||||||
.. watcher-term:: watcher.decision_engine.planner.default.DefaultPlanner
|
.. watcher-term:: watcher.decision_engine.planner.weight.WeightPlanner
|
||||||
|
|
||||||
Configuration
|
Configuration
|
||||||
-------------
|
-------------
|
||||||
@@ -66,6 +67,9 @@ Strategy parameters are:
|
|||||||
============== ====== ============= ====================================
|
============== ====== ============= ====================================
|
||||||
parameter type default Value description
|
parameter type default Value description
|
||||||
============== ====== ============= ====================================
|
============== ====== ============= ====================================
|
||||||
|
``metrics`` String 'cpu_util' Workload balance base on cpu or ram
|
||||||
|
utilization. choice: ['cpu_util',
|
||||||
|
'memory.resident']
|
||||||
``threshold`` Number 25.0 Workload threshold for migration
|
``threshold`` Number 25.0 Workload threshold for migration
|
||||||
``period`` Number 300 Aggregate time period of ceilometer
|
``period`` Number 300 Aggregate time period of ceilometer
|
||||||
============== ====== ============= ====================================
|
============== ====== ============= ====================================
|
||||||
@@ -90,7 +94,7 @@ How to use it ?
|
|||||||
at1 workload_balancing --strategy workload_balance
|
at1 workload_balancing --strategy workload_balance
|
||||||
|
|
||||||
$ openstack optimize audit create -a at1 -p threshold=26.0 \
|
$ openstack optimize audit create -a at1 -p threshold=26.0 \
|
||||||
-p period=310
|
-p period=310 -p metrics=cpu_util
|
||||||
|
|
||||||
External Links
|
External Links
|
||||||
--------------
|
--------------
|
||||||
|
|||||||
4
doc/source/user/index.rst
Normal file
4
doc/source/user/index.rst
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
user-guide
|
||||||
@@ -11,7 +11,7 @@ Watcher User Guide
|
|||||||
==================
|
==================
|
||||||
|
|
||||||
See the
|
See the
|
||||||
`architecture page <http://docs.openstack.org/developer/watcher/architecture.html>`_
|
`architecture page <https://docs.openstack.org/watcher/latest/architecture.html>`_
|
||||||
for an architectural overview of the different components of Watcher and how
|
for an architectural overview of the different components of Watcher and how
|
||||||
they fit together.
|
they fit together.
|
||||||
|
|
||||||
@@ -1,301 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
# implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
|
|
||||||
# This file is execfile()d with the current directory set to its
|
|
||||||
# containing dir.
|
|
||||||
#
|
|
||||||
# Note that not all possible configuration values are present in this
|
|
||||||
# autogenerated file.
|
|
||||||
#
|
|
||||||
# All configuration values have a default; values that are commented out
|
|
||||||
# serve to show the default.
|
|
||||||
|
|
||||||
import os
|
|
||||||
# import sys
|
|
||||||
|
|
||||||
|
|
||||||
import openstackdocstheme
|
|
||||||
|
|
||||||
# If extensions (or modules to document with autodoc) are in another directory,
|
|
||||||
# add these directories to sys.path here. If the directory is relative to the
|
|
||||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
|
||||||
# sys.path.insert(0, os.path.abspath('.'))
|
|
||||||
|
|
||||||
# -- General configuration ------------------------------------------------
|
|
||||||
|
|
||||||
# If your documentation needs a minimal Sphinx version, state it here.
|
|
||||||
# needs_sphinx = '1.0'
|
|
||||||
|
|
||||||
# Add any Sphinx extension module names here, as strings. They can be
|
|
||||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
|
||||||
# ones.
|
|
||||||
# TODO(ajaeger): enable PDF building, for example add 'rst2pdf.pdfbuilder'
|
|
||||||
# extensions =
|
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
|
||||||
# templates_path = ['_templates']
|
|
||||||
|
|
||||||
# The suffix of source filenames.
|
|
||||||
source_suffix = '.rst'
|
|
||||||
|
|
||||||
# The encoding of source files.
|
|
||||||
# source_encoding = 'utf-8-sig'
|
|
||||||
|
|
||||||
# The master toctree document.
|
|
||||||
master_doc = 'index'
|
|
||||||
|
|
||||||
# General information about the project.
|
|
||||||
project = u'Installation Guide for Infrastructure Optimization Service'
|
|
||||||
bug_tag = u'install-guide'
|
|
||||||
copyright = u'2016, OpenStack contributors'
|
|
||||||
|
|
||||||
# The version info for the project you're documenting, acts as replacement for
|
|
||||||
# |version| and |release|, also used in various other places throughout the
|
|
||||||
# built documents.
|
|
||||||
#
|
|
||||||
# The short X.Y version.
|
|
||||||
version = '0.1'
|
|
||||||
# The full version, including alpha/beta/rc tags.
|
|
||||||
release = '0.1'
|
|
||||||
|
|
||||||
# A few variables have to be set for the log-a-bug feature.
|
|
||||||
# giturl: The location of conf.py on Git. Must be set manually.
|
|
||||||
# gitsha: The SHA checksum of the bug description. Automatically extracted
|
|
||||||
# from git log.
|
|
||||||
# bug_tag: Tag for categorizing the bug. Must be set manually.
|
|
||||||
# These variables are passed to the logabug code via html_context.
|
|
||||||
giturl = u'http://git.openstack.org/cgit/openstack/watcher/tree/install-guide/source' # noqa
|
|
||||||
git_cmd = "/usr/bin/git log | head -n1 | cut -f2 -d' '"
|
|
||||||
gitsha = os.popen(git_cmd).read().strip('\n')
|
|
||||||
html_context = {"gitsha": gitsha, "bug_tag": bug_tag,
|
|
||||||
"giturl": giturl,
|
|
||||||
"bug_project": "watcher"}
|
|
||||||
|
|
||||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
|
||||||
# for a list of supported languages.
|
|
||||||
# language = None
|
|
||||||
|
|
||||||
# There are two options for replacing |today|: either, you set today to some
|
|
||||||
# non-false value, then it is used:
|
|
||||||
# today = ''
|
|
||||||
# Else, today_fmt is used as the format for a strftime call.
|
|
||||||
# today_fmt = '%B %d, %Y'
|
|
||||||
|
|
||||||
# List of patterns, relative to source directory, that match files and
|
|
||||||
# directories to ignore when looking for source files.
|
|
||||||
exclude_patterns = ["common_prerequisites.rst", "common_configure.rst"]
|
|
||||||
|
|
||||||
# The reST default role (used for this markup: `text`) to use for all
|
|
||||||
# documents.
|
|
||||||
# default_role = None
|
|
||||||
|
|
||||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
|
||||||
# add_function_parentheses = True
|
|
||||||
|
|
||||||
# If true, the current module name will be prepended to all description
|
|
||||||
# unit titles (such as .. function::).
|
|
||||||
# add_module_names = True
|
|
||||||
|
|
||||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
|
||||||
# output. They are ignored by default.
|
|
||||||
# show_authors = False
|
|
||||||
|
|
||||||
# The name of the Pygments (syntax highlighting) style to use.
|
|
||||||
pygments_style = 'sphinx'
|
|
||||||
|
|
||||||
# A list of ignored prefixes for module index sorting.
|
|
||||||
# modindex_common_prefix = []
|
|
||||||
|
|
||||||
# If true, keep warnings as "system message" paragraphs in the built documents.
|
|
||||||
# keep_warnings = False
|
|
||||||
|
|
||||||
|
|
||||||
# -- Options for HTML output ----------------------------------------------
|
|
||||||
|
|
||||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
|
||||||
# a list of builtin themes.
|
|
||||||
html_theme = 'openstackdocs'
|
|
||||||
|
|
||||||
# Theme options are theme-specific and customize the look and feel of a theme
|
|
||||||
# further. For a list of options available for each theme, see the
|
|
||||||
# documentation.
|
|
||||||
# html_theme_options = {}
|
|
||||||
|
|
||||||
# Add any paths that contain custom themes here, relative to this directory.
|
|
||||||
html_theme_path = [openstackdocstheme.get_html_theme_path()]
|
|
||||||
|
|
||||||
# The name for this set of Sphinx documents. If None, it defaults to
|
|
||||||
# "<project> v<release> documentation".
|
|
||||||
# html_title = None
|
|
||||||
|
|
||||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
|
||||||
# html_short_title = None
|
|
||||||
|
|
||||||
# The name of an image file (relative to this directory) to place at the top
|
|
||||||
# of the sidebar.
|
|
||||||
# html_logo = None
|
|
||||||
|
|
||||||
# The name of an image file (within the static path) to use as favicon of the
|
|
||||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
|
||||||
# pixels large.
|
|
||||||
# html_favicon = None
|
|
||||||
|
|
||||||
# Add any paths that contain custom static files (such as style sheets) here,
|
|
||||||
# relative to this directory. They are copied after the builtin static files,
|
|
||||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
|
||||||
# html_static_path = []
|
|
||||||
|
|
||||||
# Add any extra paths that contain custom files (such as robots.txt or
|
|
||||||
# .htaccess) here, relative to this directory. These files are copied
|
|
||||||
# directly to the root of the documentation.
|
|
||||||
# html_extra_path = []
|
|
||||||
|
|
||||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
|
||||||
# using the given strftime format.
|
|
||||||
# So that we can enable "log-a-bug" links from each output HTML page, this
|
|
||||||
# variable must be set to a format that includes year, month, day, hours and
|
|
||||||
# minutes.
|
|
||||||
html_last_updated_fmt = '%Y-%m-%d %H:%M'
|
|
||||||
|
|
||||||
|
|
||||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
|
||||||
# typographically correct entities.
|
|
||||||
# html_use_smartypants = True
|
|
||||||
|
|
||||||
# Custom sidebar templates, maps document names to template names.
|
|
||||||
# html_sidebars = {}
|
|
||||||
|
|
||||||
# Additional templates that should be rendered to pages, maps page names to
|
|
||||||
# template names.
|
|
||||||
# html_additional_pages = {}
|
|
||||||
|
|
||||||
# If false, no module index is generated.
|
|
||||||
# html_domain_indices = True
|
|
||||||
|
|
||||||
# If false, no index is generated.
|
|
||||||
html_use_index = False
|
|
||||||
|
|
||||||
# If true, the index is split into individual pages for each letter.
|
|
||||||
# html_split_index = False
|
|
||||||
|
|
||||||
# If true, links to the reST sources are added to the pages.
|
|
||||||
html_show_sourcelink = False
|
|
||||||
|
|
||||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
|
||||||
# html_show_sphinx = True
|
|
||||||
|
|
||||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
|
||||||
# html_show_copyright = True
|
|
||||||
|
|
||||||
# If true, an OpenSearch description file will be output, and all pages will
|
|
||||||
# contain a <link> tag referring to it. The value of this option must be the
|
|
||||||
# base URL from which the finished HTML is served.
|
|
||||||
# html_use_opensearch = ''
|
|
||||||
|
|
||||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
|
||||||
# html_file_suffix = None
|
|
||||||
|
|
||||||
# Output file base name for HTML help builder.
|
|
||||||
htmlhelp_basename = 'install-guide'
|
|
||||||
|
|
||||||
# If true, publish source files
|
|
||||||
html_copy_source = False
|
|
||||||
|
|
||||||
# -- Options for LaTeX output ---------------------------------------------
|
|
||||||
|
|
||||||
latex_elements = {
|
|
||||||
# The paper size ('letterpaper' or 'a4paper').
|
|
||||||
# 'papersize': 'letterpaper',
|
|
||||||
|
|
||||||
# The font size ('10pt', '11pt' or '12pt').
|
|
||||||
# 'pointsize': '10pt',
|
|
||||||
|
|
||||||
# Additional stuff for the LaTeX preamble.
|
|
||||||
# 'preamble': '',
|
|
||||||
}
|
|
||||||
|
|
||||||
# Grouping the document tree into LaTeX files. List of tuples
|
|
||||||
# (source start file, target name, title,
|
|
||||||
# author, documentclass [howto, manual, or own class]).
|
|
||||||
latex_documents = [
|
|
||||||
('index', 'InstallGuide.tex', u'Install Guide',
|
|
||||||
u'OpenStack contributors', 'manual'),
|
|
||||||
]
|
|
||||||
|
|
||||||
# The name of an image file (relative to this directory) to place at the top of
|
|
||||||
# the title page.
|
|
||||||
# latex_logo = None
|
|
||||||
|
|
||||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
|
||||||
# not chapters.
|
|
||||||
# latex_use_parts = False
|
|
||||||
|
|
||||||
# If true, show page references after internal links.
|
|
||||||
# latex_show_pagerefs = False
|
|
||||||
|
|
||||||
# If true, show URL addresses after external links.
|
|
||||||
# latex_show_urls = False
|
|
||||||
|
|
||||||
# Documents to append as an appendix to all manuals.
|
|
||||||
# latex_appendices = []
|
|
||||||
|
|
||||||
# If false, no module index is generated.
|
|
||||||
# latex_domain_indices = True
|
|
||||||
|
|
||||||
|
|
||||||
# -- Options for manual page output ---------------------------------------
|
|
||||||
|
|
||||||
# One entry per manual page. List of tuples
|
|
||||||
# (source start file, name, description, authors, manual section).
|
|
||||||
man_pages = [
|
|
||||||
('index', 'installguide', u'Install Guide',
|
|
||||||
[u'OpenStack contributors'], 1)
|
|
||||||
]
|
|
||||||
|
|
||||||
# If true, show URL addresses after external links.
|
|
||||||
# man_show_urls = False
|
|
||||||
|
|
||||||
|
|
||||||
# -- Options for Texinfo output -------------------------------------------
|
|
||||||
|
|
||||||
# Grouping the document tree into Texinfo files. List of tuples
|
|
||||||
# (source start file, target name, title, author,
|
|
||||||
# dir menu entry, description, category)
|
|
||||||
texinfo_documents = [
|
|
||||||
('index', 'InstallGuide', u'Install Guide',
|
|
||||||
u'OpenStack contributors', 'InstallGuide',
|
|
||||||
'This guide shows OpenStack end users how to install '
|
|
||||||
'an OpenStack cloud.', 'Miscellaneous'),
|
|
||||||
]
|
|
||||||
|
|
||||||
# Documents to append as an appendix to all manuals.
|
|
||||||
# texinfo_appendices = []
|
|
||||||
|
|
||||||
# If false, no module index is generated.
|
|
||||||
# texinfo_domain_indices = True
|
|
||||||
|
|
||||||
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
|
||||||
# texinfo_show_urls = 'footnote'
|
|
||||||
|
|
||||||
# If true, do not generate a @detailmenu in the "Top" node's menu.
|
|
||||||
# texinfo_no_detailmenu = False
|
|
||||||
|
|
||||||
# -- Options for Internationalization output ------------------------------
|
|
||||||
locale_dirs = ['locale/']
|
|
||||||
|
|
||||||
# -- Options for PDF output --------------------------------------------------
|
|
||||||
|
|
||||||
pdf_documents = [
|
|
||||||
('index', u'InstallGuide', u'Install Guide',
|
|
||||||
u'OpenStack contributors')
|
|
||||||
]
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Add notifications related to Action object.
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Add action for compute node power on/off
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Added the functionality to filter out instances which have metadata field
|
||||||
|
'optimize' set to False. For now, this is only available for the
|
||||||
|
basic_consolidation strategy (if "check_optimize_metadata" configuration
|
||||||
|
option is enabled).
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Added binding between apscheduler job and Watcher decision engine service.
|
||||||
|
It will allow to provide HA support in the future.
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Enhancement of vm_workload_consolidation strategy
|
||||||
|
by using 'memory.resident' metric in place of
|
||||||
|
'memory.usage', as memory.usage shows the memory
|
||||||
|
usage inside guest-os and memory.resident
|
||||||
|
represents volume of RAM used by instance
|
||||||
|
on host machine.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Added cinder cluster data model
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- There is new ability to create Watcher continuous audits with cron
|
||||||
|
interval. It means you may use, for example, optional argument
|
||||||
|
'--interval "\*/5 \* \* \* \*"' to launch audit every 5 minutes.
|
||||||
|
These jobs are executed on a best effort basis and therefore, we
|
||||||
|
recommend you to use a minimal cron interval of at least one minute.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Add description property for dynamic action. Admin can see detail information
|
||||||
|
of any specify action.
|
||||||
4
releasenotes/notes/gnocchi-watcher-43c25d391fbd3e9c.yaml
Normal file
4
releasenotes/notes/gnocchi-watcher-43c25d391fbd3e9c.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Added gnocchi support as data source for metrics. Administrator can change
|
||||||
|
data source for each strategy using config file.
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Added using of JSONSchema instead of voluptuous to validate Actions.
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Added strategy to identify and migrate a Noisy Neighbor - a low priority VM
|
||||||
|
that negatively affects peformance of a high priority VM by over utilizing
|
||||||
|
Last Level Cache.
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Add notifications related to Service object.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Added volume migrate action
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Existing workload_balance strategy based on
|
||||||
|
the VM workloads of CPU. This feature improves
|
||||||
|
the strategy. By the input parameter "metrics",
|
||||||
|
it makes decision to migrate a VM base on CPU
|
||||||
|
or memory utilization.
|
||||||
@@ -38,7 +38,7 @@ from watcher import version as watcher_version
|
|||||||
# Add any Sphinx extension module names here, as strings. They can be
|
# Add any Sphinx extension module names here, as strings. They can be
|
||||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||||
extensions = ['reno.sphinxext',
|
extensions = ['reno.sphinxext',
|
||||||
'oslosphinx']
|
'openstackdocstheme']
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
templates_path = ['_templates']
|
templates_path = ['_templates']
|
||||||
@@ -104,7 +104,7 @@ pygments_style = 'sphinx'
|
|||||||
|
|
||||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
# a list of builtin themes.
|
# a list of builtin themes.
|
||||||
html_theme = 'default'
|
html_theme = 'openstackdocs'
|
||||||
|
|
||||||
# Theme options are theme-specific and customize the look and feel of a theme
|
# Theme options are theme-specific and customize the look and feel of a theme
|
||||||
# further. For a list of options available for each theme, see the
|
# further. For a list of options available for each theme, see the
|
||||||
|
|||||||
@@ -5,20 +5,22 @@
|
|||||||
apscheduler # MIT License
|
apscheduler # MIT License
|
||||||
enum34;python_version=='2.7' or python_version=='2.6' or python_version=='3.3' # BSD
|
enum34;python_version=='2.7' or python_version=='2.6' or python_version=='3.3' # BSD
|
||||||
jsonpatch>=1.1 # BSD
|
jsonpatch>=1.1 # BSD
|
||||||
keystoneauth1>=2.20.0 # Apache-2.0
|
keystoneauth1>=3.1.0 # Apache-2.0
|
||||||
|
jsonschema!=2.5.0,<3.0.0,>=2.0.0 # MIT
|
||||||
keystonemiddleware>=4.12.0 # Apache-2.0
|
keystonemiddleware>=4.12.0 # Apache-2.0
|
||||||
lxml!=3.7.0,>=2.3 # BSD
|
lxml!=3.7.0,>=2.3 # BSD
|
||||||
|
croniter>=0.3.4 # MIT License
|
||||||
oslo.concurrency>=3.8.0 # Apache-2.0
|
oslo.concurrency>=3.8.0 # Apache-2.0
|
||||||
oslo.cache>=1.5.0 # Apache-2.0
|
oslo.cache>=1.5.0 # Apache-2.0
|
||||||
oslo.config>=4.0.0 # Apache-2.0
|
oslo.config!=4.3.0,!=4.4.0,>=4.0.0 # Apache-2.0
|
||||||
oslo.context>=2.14.0 # Apache-2.0
|
oslo.context>=2.14.0 # Apache-2.0
|
||||||
oslo.db>=4.21.1 # Apache-2.0
|
oslo.db>=4.24.0 # Apache-2.0
|
||||||
oslo.i18n!=3.15.2,>=2.1.0 # Apache-2.0
|
oslo.i18n!=3.15.2,>=2.1.0 # Apache-2.0
|
||||||
oslo.log>=3.22.0 # Apache-2.0
|
oslo.log>=3.22.0 # Apache-2.0
|
||||||
oslo.messaging!=5.25.0,>=5.24.2 # Apache-2.0
|
oslo.messaging!=5.25.0,>=5.24.2 # Apache-2.0
|
||||||
oslo.policy>=1.17.0 # Apache-2.0
|
oslo.policy>=1.23.0 # Apache-2.0
|
||||||
oslo.reports>=0.6.0 # Apache-2.0
|
oslo.reports>=0.6.0 # Apache-2.0
|
||||||
oslo.serialization>=1.10.0 # Apache-2.0
|
oslo.serialization!=2.19.1,>=1.10.0 # Apache-2.0
|
||||||
oslo.service>=1.10.0 # Apache-2.0
|
oslo.service>=1.10.0 # Apache-2.0
|
||||||
oslo.utils>=3.20.0 # Apache-2.0
|
oslo.utils>=3.20.0 # Apache-2.0
|
||||||
oslo.versionedobjects>=1.17.0 # Apache-2.0
|
oslo.versionedobjects>=1.17.0 # Apache-2.0
|
||||||
@@ -29,19 +31,19 @@ PrettyTable<0.8,>=0.7.1 # BSD
|
|||||||
voluptuous>=0.8.9 # BSD License
|
voluptuous>=0.8.9 # BSD License
|
||||||
gnocchiclient>=2.7.0 # Apache-2.0
|
gnocchiclient>=2.7.0 # Apache-2.0
|
||||||
python-ceilometerclient>=2.5.0 # Apache-2.0
|
python-ceilometerclient>=2.5.0 # Apache-2.0
|
||||||
python-cinderclient>=2.1.0 # Apache-2.0
|
python-cinderclient>=3.1.0 # Apache-2.0
|
||||||
python-glanceclient>=2.7.0 # Apache-2.0
|
python-glanceclient>=2.8.0 # Apache-2.0
|
||||||
python-keystoneclient>=3.8.0 # Apache-2.0
|
python-keystoneclient>=3.8.0 # Apache-2.0
|
||||||
python-monascaclient>=1.1.0 # Apache-2.0
|
python-monascaclient>=1.7.0 # Apache-2.0
|
||||||
python-neutronclient>=6.3.0 # Apache-2.0
|
python-neutronclient>=6.3.0 # Apache-2.0
|
||||||
python-novaclient>=7.1.0 # Apache-2.0
|
python-novaclient>=9.0.0 # Apache-2.0
|
||||||
python-openstackclient!=3.10.0,>=3.3.0 # Apache-2.0
|
python-openstackclient>=3.11.0 # Apache-2.0
|
||||||
python-ironicclient>=1.11.0 # Apache-2.0
|
python-ironicclient>=1.14.0 # Apache-2.0
|
||||||
six>=1.9.0 # MIT
|
six>=1.9.0 # MIT
|
||||||
SQLAlchemy!=1.1.5,!=1.1.6,!=1.1.7,!=1.1.8,>=1.0.10 # MIT
|
SQLAlchemy!=1.1.5,!=1.1.6,!=1.1.7,!=1.1.8,>=1.0.10 # MIT
|
||||||
stevedore>=1.20.0 # Apache-2.0
|
stevedore>=1.20.0 # Apache-2.0
|
||||||
taskflow>=2.7.0 # Apache-2.0
|
taskflow>=2.7.0 # Apache-2.0
|
||||||
WebOb>=1.7.1 # MIT
|
WebOb>=1.7.1 # MIT
|
||||||
WSME>=0.8 # MIT
|
WSME>=0.8 # MIT
|
||||||
networkx>=1.10 # BSD
|
networkx<2.0,>=1.10 # BSD
|
||||||
|
|
||||||
|
|||||||
13
setup.cfg
13
setup.cfg
@@ -5,7 +5,7 @@ description-file =
|
|||||||
README.rst
|
README.rst
|
||||||
author = OpenStack
|
author = OpenStack
|
||||||
author-email = openstack-dev@lists.openstack.org
|
author-email = openstack-dev@lists.openstack.org
|
||||||
home-page = http://docs.openstack.org/developer/watcher/
|
home-page = https://docs.openstack.org/watcher/latest/
|
||||||
classifier =
|
classifier =
|
||||||
Environment :: OpenStack
|
Environment :: OpenStack
|
||||||
Intended Audience :: Information Technology
|
Intended Audience :: Information Technology
|
||||||
@@ -53,6 +53,8 @@ watcher_goals =
|
|||||||
thermal_optimization = watcher.decision_engine.goal.goals:ThermalOptimization
|
thermal_optimization = watcher.decision_engine.goal.goals:ThermalOptimization
|
||||||
workload_balancing = watcher.decision_engine.goal.goals:WorkloadBalancing
|
workload_balancing = watcher.decision_engine.goal.goals:WorkloadBalancing
|
||||||
airflow_optimization = watcher.decision_engine.goal.goals:AirflowOptimization
|
airflow_optimization = watcher.decision_engine.goal.goals:AirflowOptimization
|
||||||
|
noisy_neighbor = watcher.decision_engine.goal.goals:NoisyNeighborOptimization
|
||||||
|
saving_energy = watcher.decision_engine.goal.goals:SavingEnergy
|
||||||
|
|
||||||
watcher_scoring_engines =
|
watcher_scoring_engines =
|
||||||
dummy_scorer = watcher.decision_engine.scoring.dummy_scorer:DummyScorer
|
dummy_scorer = watcher.decision_engine.scoring.dummy_scorer:DummyScorer
|
||||||
@@ -64,12 +66,15 @@ watcher_strategies =
|
|||||||
dummy = watcher.decision_engine.strategy.strategies.dummy_strategy:DummyStrategy
|
dummy = watcher.decision_engine.strategy.strategies.dummy_strategy:DummyStrategy
|
||||||
dummy_with_scorer = watcher.decision_engine.strategy.strategies.dummy_with_scorer:DummyWithScorer
|
dummy_with_scorer = watcher.decision_engine.strategy.strategies.dummy_with_scorer:DummyWithScorer
|
||||||
dummy_with_resize = watcher.decision_engine.strategy.strategies.dummy_with_resize:DummyWithResize
|
dummy_with_resize = watcher.decision_engine.strategy.strategies.dummy_with_resize:DummyWithResize
|
||||||
|
actuator = watcher.decision_engine.strategy.strategies.actuation:Actuator
|
||||||
basic = watcher.decision_engine.strategy.strategies.basic_consolidation:BasicConsolidation
|
basic = watcher.decision_engine.strategy.strategies.basic_consolidation:BasicConsolidation
|
||||||
outlet_temperature = watcher.decision_engine.strategy.strategies.outlet_temp_control:OutletTempControl
|
outlet_temperature = watcher.decision_engine.strategy.strategies.outlet_temp_control:OutletTempControl
|
||||||
|
saving_energy = watcher.decision_engine.strategy.strategies.saving_energy:SavingEnergy
|
||||||
vm_workload_consolidation = watcher.decision_engine.strategy.strategies.vm_workload_consolidation:VMWorkloadConsolidation
|
vm_workload_consolidation = watcher.decision_engine.strategy.strategies.vm_workload_consolidation:VMWorkloadConsolidation
|
||||||
workload_stabilization = watcher.decision_engine.strategy.strategies.workload_stabilization:WorkloadStabilization
|
workload_stabilization = watcher.decision_engine.strategy.strategies.workload_stabilization:WorkloadStabilization
|
||||||
workload_balance = watcher.decision_engine.strategy.strategies.workload_balance:WorkloadBalance
|
workload_balance = watcher.decision_engine.strategy.strategies.workload_balance:WorkloadBalance
|
||||||
uniform_airflow = watcher.decision_engine.strategy.strategies.uniform_airflow:UniformAirflow
|
uniform_airflow = watcher.decision_engine.strategy.strategies.uniform_airflow:UniformAirflow
|
||||||
|
noisy_neighbor = watcher.decision_engine.strategy.strategies.noisy_neighbor:NoisyNeighbor
|
||||||
|
|
||||||
watcher_actions =
|
watcher_actions =
|
||||||
migrate = watcher.applier.actions.migration:Migrate
|
migrate = watcher.applier.actions.migration:Migrate
|
||||||
@@ -77,6 +82,8 @@ watcher_actions =
|
|||||||
sleep = watcher.applier.actions.sleep:Sleep
|
sleep = watcher.applier.actions.sleep:Sleep
|
||||||
change_nova_service_state = watcher.applier.actions.change_nova_service_state:ChangeNovaServiceState
|
change_nova_service_state = watcher.applier.actions.change_nova_service_state:ChangeNovaServiceState
|
||||||
resize = watcher.applier.actions.resize:Resize
|
resize = watcher.applier.actions.resize:Resize
|
||||||
|
change_node_power_state = watcher.applier.actions.change_node_power_state:ChangeNodePowerState
|
||||||
|
volume_migrate = watcher.applier.actions.volume_migration:VolumeMigrate
|
||||||
|
|
||||||
watcher_workflow_engines =
|
watcher_workflow_engines =
|
||||||
taskflow = watcher.applier.workflow_engine.default:DefaultWorkFlowEngine
|
taskflow = watcher.applier.workflow_engine.default:DefaultWorkFlowEngine
|
||||||
@@ -87,9 +94,10 @@ watcher_planners =
|
|||||||
|
|
||||||
watcher_cluster_data_model_collectors =
|
watcher_cluster_data_model_collectors =
|
||||||
compute = watcher.decision_engine.model.collector.nova:NovaClusterDataModelCollector
|
compute = watcher.decision_engine.model.collector.nova:NovaClusterDataModelCollector
|
||||||
|
storage = watcher.decision_engine.model.collector.cinder:CinderClusterDataModelCollector
|
||||||
|
|
||||||
|
|
||||||
[pbr]
|
[pbr]
|
||||||
warnerrors = true
|
|
||||||
autodoc_index_modules = true
|
autodoc_index_modules = true
|
||||||
autodoc_exclude_modules =
|
autodoc_exclude_modules =
|
||||||
watcher.db.sqlalchemy.alembic.env
|
watcher.db.sqlalchemy.alembic.env
|
||||||
@@ -104,6 +112,7 @@ source-dir = doc/source
|
|||||||
build-dir = doc/build
|
build-dir = doc/build
|
||||||
fresh_env = 1
|
fresh_env = 1
|
||||||
all_files = 1
|
all_files = 1
|
||||||
|
warning-is-error = 1
|
||||||
|
|
||||||
[upload_sphinx]
|
[upload_sphinx]
|
||||||
upload-dir = doc/build/html
|
upload-dir = doc/build/html
|
||||||
|
|||||||
@@ -15,9 +15,8 @@ testscenarios>=0.4 # Apache-2.0/BSD
|
|||||||
testtools>=1.4.0 # MIT
|
testtools>=1.4.0 # MIT
|
||||||
|
|
||||||
# Doc requirements
|
# Doc requirements
|
||||||
openstackdocstheme>=1.5.0 # Apache-2.0
|
openstackdocstheme>=1.16.0 # Apache-2.0
|
||||||
oslosphinx>=4.7.0 # Apache-2.0
|
sphinx>=1.6.2 # BSD
|
||||||
sphinx!=1.6.1,>=1.5.1 # BSD
|
|
||||||
sphinxcontrib-pecanwsme>=0.8 # Apache-2.0
|
sphinxcontrib-pecanwsme>=0.8 # Apache-2.0
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
11
tox.ini
11
tox.ini
@@ -7,7 +7,7 @@ skipsdist = True
|
|||||||
usedevelop = True
|
usedevelop = True
|
||||||
whitelist_externals = find
|
whitelist_externals = find
|
||||||
rm
|
rm
|
||||||
install_command = pip install -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} {opts} {packages}
|
install_command = pip install -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt?h=stable/pike} {opts} {packages}
|
||||||
setenv =
|
setenv =
|
||||||
VIRTUAL_ENV={envdir}
|
VIRTUAL_ENV={envdir}
|
||||||
deps = -r{toxinidir}/test-requirements.txt
|
deps = -r{toxinidir}/test-requirements.txt
|
||||||
@@ -15,6 +15,7 @@ commands =
|
|||||||
rm -f .testrepository/times.dbm
|
rm -f .testrepository/times.dbm
|
||||||
find . -type f -name "*.py[c|o]" -delete
|
find . -type f -name "*.py[c|o]" -delete
|
||||||
ostestr --concurrency=6 {posargs}
|
ostestr --concurrency=6 {posargs}
|
||||||
|
passenv = http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY
|
||||||
|
|
||||||
[testenv:pep8]
|
[testenv:pep8]
|
||||||
commands =
|
commands =
|
||||||
@@ -43,12 +44,13 @@ commands = oslo_debug_helper -t watcher/tests {posargs}
|
|||||||
[testenv:genconfig]
|
[testenv:genconfig]
|
||||||
sitepackages = False
|
sitepackages = False
|
||||||
commands =
|
commands =
|
||||||
oslo-config-generator --config-file etc/watcher/watcher-config-generator.conf
|
oslo-config-generator --config-file etc/watcher/oslo-config-generator/watcher.conf
|
||||||
|
|
||||||
[flake8]
|
[flake8]
|
||||||
show-source=True
|
show-source=True
|
||||||
ignore= H105,E123,E226,N320
|
ignore= H105,E123,E226,N320,H202
|
||||||
builtins= _
|
builtins= _
|
||||||
|
enable-extensions = H106,H203
|
||||||
exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build,*sqlalchemy/alembic/versions/*,demo/,releasenotes
|
exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build,*sqlalchemy/alembic/versions/*,demo/,releasenotes
|
||||||
|
|
||||||
[testenv:wheel]
|
[testenv:wheel]
|
||||||
@@ -69,6 +71,3 @@ commands = sphinx-build -a -W -E -d releasenotes/build/doctrees -b html releasen
|
|||||||
[testenv:bandit]
|
[testenv:bandit]
|
||||||
deps = -r{toxinidir}/test-requirements.txt
|
deps = -r{toxinidir}/test-requirements.txt
|
||||||
commands = bandit -r watcher -x tests -n5 -ll -s B320
|
commands = bandit -r watcher -x tests -n5 -ll -s B320
|
||||||
|
|
||||||
[testenv:install-guide]
|
|
||||||
commands = sphinx-build -a -E -W -d install-guide/build/doctrees -b html install-guide/source install-guide/build/html
|
|
||||||
|
|||||||
@@ -32,16 +32,6 @@ _C = _translators.contextual_form
|
|||||||
# The plural translation function using the name "_P"
|
# The plural translation function using the name "_P"
|
||||||
_P = _translators.plural_form
|
_P = _translators.plural_form
|
||||||
|
|
||||||
# Translators for log levels.
|
|
||||||
#
|
|
||||||
# The abbreviated names are meant to reflect the usual use of a short
|
|
||||||
# name like '_'. The "L" is for "log" and the other letter comes from
|
|
||||||
# the level.
|
|
||||||
_LI = _translators.log_info
|
|
||||||
_LW = _translators.log_warning
|
|
||||||
_LE = _translators.log_error
|
|
||||||
_LC = _translators.log_critical
|
|
||||||
|
|
||||||
|
|
||||||
def lazy_translation_enabled():
|
def lazy_translation_enabled():
|
||||||
return _lazy.USE_LAZY
|
return _lazy.USE_LAZY
|
||||||
|
|||||||
@@ -118,6 +118,9 @@ class Action(base.APIBase):
|
|||||||
action_type = wtypes.text
|
action_type = wtypes.text
|
||||||
"""Action type"""
|
"""Action type"""
|
||||||
|
|
||||||
|
description = wtypes.text
|
||||||
|
"""Action description"""
|
||||||
|
|
||||||
input_parameters = types.jsontype
|
input_parameters = types.jsontype
|
||||||
"""One or more key/value pairs """
|
"""One or more key/value pairs """
|
||||||
|
|
||||||
@@ -141,6 +144,7 @@ class Action(base.APIBase):
|
|||||||
setattr(self, field, kwargs.get(field, wtypes.Unset))
|
setattr(self, field, kwargs.get(field, wtypes.Unset))
|
||||||
|
|
||||||
self.fields.append('action_plan_id')
|
self.fields.append('action_plan_id')
|
||||||
|
self.fields.append('description')
|
||||||
setattr(self, 'action_plan_uuid', kwargs.get('action_plan_id',
|
setattr(self, 'action_plan_uuid', kwargs.get('action_plan_id',
|
||||||
wtypes.Unset))
|
wtypes.Unset))
|
||||||
|
|
||||||
@@ -162,6 +166,14 @@ class Action(base.APIBase):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def convert_with_links(cls, action, expand=True):
|
def convert_with_links(cls, action, expand=True):
|
||||||
action = Action(**action.as_dict())
|
action = Action(**action.as_dict())
|
||||||
|
try:
|
||||||
|
obj_action_desc = objects.ActionDescription.get_by_type(
|
||||||
|
pecan.request.context, action.action_type)
|
||||||
|
description = obj_action_desc.description
|
||||||
|
except exception.ActionDescriptionNotFound:
|
||||||
|
description = ""
|
||||||
|
setattr(action, 'description', description)
|
||||||
|
|
||||||
return cls._convert_with_links(action, pecan.request.host_url, expand)
|
return cls._convert_with_links(action, pecan.request.host_url, expand)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ class AuditPostType(wtypes.Base):
|
|||||||
|
|
||||||
parameters = wtypes.wsattr({wtypes.text: types.jsontype}, mandatory=False,
|
parameters = wtypes.wsattr({wtypes.text: types.jsontype}, mandatory=False,
|
||||||
default={})
|
default={})
|
||||||
interval = wsme.wsattr(int, mandatory=False)
|
interval = wsme.wsattr(types.interval_or_cron, mandatory=False)
|
||||||
|
|
||||||
scope = wtypes.wsattr(types.jsontype, readonly=True)
|
scope = wtypes.wsattr(types.jsontype, readonly=True)
|
||||||
|
|
||||||
@@ -261,7 +261,7 @@ class Audit(base.APIBase):
|
|||||||
links = wsme.wsattr([link.Link], readonly=True)
|
links = wsme.wsattr([link.Link], readonly=True)
|
||||||
"""A list containing a self link and associated audit links"""
|
"""A list containing a self link and associated audit links"""
|
||||||
|
|
||||||
interval = wsme.wsattr(int, mandatory=False)
|
interval = wsme.wsattr(wtypes.text, mandatory=False)
|
||||||
"""Launch audit periodically (in seconds)"""
|
"""Launch audit periodically (in seconds)"""
|
||||||
|
|
||||||
scope = wsme.wsattr(types.jsontype, mandatory=False)
|
scope = wsme.wsattr(types.jsontype, mandatory=False)
|
||||||
@@ -270,6 +270,9 @@ class Audit(base.APIBase):
|
|||||||
auto_trigger = wsme.wsattr(bool, mandatory=False, default=False)
|
auto_trigger = wsme.wsattr(bool, mandatory=False, default=False)
|
||||||
"""Autoexecute action plan once audit is succeeded"""
|
"""Autoexecute action plan once audit is succeeded"""
|
||||||
|
|
||||||
|
next_run_time = wsme.wsattr(datetime.datetime, mandatory=False)
|
||||||
|
"""The next time audit launch"""
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
self.fields = []
|
self.fields = []
|
||||||
fields = list(objects.Audit.fields)
|
fields = list(objects.Audit.fields)
|
||||||
@@ -301,7 +304,8 @@ class Audit(base.APIBase):
|
|||||||
audit.unset_fields_except(['uuid', 'audit_type', 'state',
|
audit.unset_fields_except(['uuid', 'audit_type', 'state',
|
||||||
'goal_uuid', 'interval', 'scope',
|
'goal_uuid', 'interval', 'scope',
|
||||||
'strategy_uuid', 'goal_name',
|
'strategy_uuid', 'goal_name',
|
||||||
'strategy_name', 'auto_trigger'])
|
'strategy_name', 'auto_trigger',
|
||||||
|
'next_run_time'])
|
||||||
|
|
||||||
audit.links = [link.Link.make_link('self', url,
|
audit.links = [link.Link.make_link('self', url,
|
||||||
'audits', audit.uuid),
|
'audits', audit.uuid),
|
||||||
@@ -325,9 +329,10 @@ class Audit(base.APIBase):
|
|||||||
created_at=datetime.datetime.utcnow(),
|
created_at=datetime.datetime.utcnow(),
|
||||||
deleted_at=None,
|
deleted_at=None,
|
||||||
updated_at=datetime.datetime.utcnow(),
|
updated_at=datetime.datetime.utcnow(),
|
||||||
interval=7200,
|
interval='7200',
|
||||||
scope=[],
|
scope=[],
|
||||||
auto_trigger=False)
|
auto_trigger=False,
|
||||||
|
next_run_time=datetime.datetime.utcnow())
|
||||||
|
|
||||||
sample.goal_id = '7ae81bb3-dec3-4289-8d6c-da80bd8001ae'
|
sample.goal_id = '7ae81bb3-dec3-4289-8d6c-da80bd8001ae'
|
||||||
sample.strategy_id = '7ae81bb3-dec3-4289-8d6c-da80bd8001ff'
|
sample.strategy_id = '7ae81bb3-dec3-4289-8d6c-da80bd8001ff'
|
||||||
|
|||||||
@@ -550,7 +550,7 @@ class AuditTemplatesController(rest.RestController):
|
|||||||
def get_one(self, audit_template):
|
def get_one(self, audit_template):
|
||||||
"""Retrieve information about the given audit template.
|
"""Retrieve information about the given audit template.
|
||||||
|
|
||||||
:param audit audit_template: UUID or name of an audit template.
|
:param audit_template: UUID or name of an audit template.
|
||||||
"""
|
"""
|
||||||
if self.from_audit_templates:
|
if self.from_audit_templates:
|
||||||
raise exception.OperationNotPermitted
|
raise exception.OperationNotPermitted
|
||||||
@@ -597,7 +597,7 @@ class AuditTemplatesController(rest.RestController):
|
|||||||
def patch(self, audit_template, patch):
|
def patch(self, audit_template, patch):
|
||||||
"""Update an existing audit template.
|
"""Update an existing audit template.
|
||||||
|
|
||||||
:param audit template_uuid: UUID of a audit template.
|
:param template_uuid: UUID of a audit template.
|
||||||
:param patch: a json PATCH document to apply to this audit template.
|
:param patch: a json PATCH document to apply to this audit template.
|
||||||
"""
|
"""
|
||||||
if self.from_audit_templates:
|
if self.from_audit_templates:
|
||||||
@@ -645,7 +645,7 @@ class AuditTemplatesController(rest.RestController):
|
|||||||
def delete(self, audit_template):
|
def delete(self, audit_template):
|
||||||
"""Delete a audit template.
|
"""Delete a audit template.
|
||||||
|
|
||||||
:param audit template_uuid: UUID or name of an audit template.
|
:param template_uuid: UUID or name of an audit template.
|
||||||
"""
|
"""
|
||||||
context = pecan.request.context
|
context = pecan.request.context
|
||||||
audit_template_to_delete = api_utils.get_resource('AuditTemplate',
|
audit_template_to_delete = api_utils.get_resource('AuditTemplate',
|
||||||
|
|||||||
@@ -43,6 +43,28 @@ class UuidOrNameType(wtypes.UserType):
|
|||||||
return UuidOrNameType.validate(value)
|
return UuidOrNameType.validate(value)
|
||||||
|
|
||||||
|
|
||||||
|
class IntervalOrCron(wtypes.UserType):
|
||||||
|
"""A simple int value or cron syntax type"""
|
||||||
|
|
||||||
|
basetype = wtypes.text
|
||||||
|
name = 'interval_or_cron'
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def validate(value):
|
||||||
|
if not (utils.is_int_like(value) or utils.is_cron_like(value)):
|
||||||
|
raise exception.InvalidIntervalOrCron(name=value)
|
||||||
|
return value
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def frombasetype(value):
|
||||||
|
if value is None:
|
||||||
|
return None
|
||||||
|
return IntervalOrCron.validate(value)
|
||||||
|
|
||||||
|
|
||||||
|
interval_or_cron = IntervalOrCron()
|
||||||
|
|
||||||
|
|
||||||
class NameType(wtypes.UserType):
|
class NameType(wtypes.UserType):
|
||||||
"""A simple logical name type."""
|
"""A simple logical name type."""
|
||||||
|
|
||||||
|
|||||||
@@ -52,8 +52,8 @@ class AuthTokenMiddleware(auth_token.AuthProtocol):
|
|||||||
# The information whether the API call is being performed against the
|
# The information whether the API call is being performed against the
|
||||||
# public API is required for some other components. Saving it to the
|
# public API is required for some other components. Saving it to the
|
||||||
# WSGI environment is reasonable thereby.
|
# WSGI environment is reasonable thereby.
|
||||||
env['is_public_api'] = any(map(lambda pattern: re.match(pattern, path),
|
env['is_public_api'] = any(re.match(pattern, path)
|
||||||
self.public_api_routes))
|
for pattern in self.public_api_routes)
|
||||||
|
|
||||||
if env['is_public_api']:
|
if env['is_public_api']:
|
||||||
return self._app(env, start_response)
|
return self._app(env, start_response)
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ from oslo_log import log
|
|||||||
from oslo_utils import timeutils
|
from oslo_utils import timeutils
|
||||||
import six
|
import six
|
||||||
|
|
||||||
from watcher._i18n import _LW
|
|
||||||
from watcher.common import context as watcher_context
|
from watcher.common import context as watcher_context
|
||||||
from watcher.common import scheduling
|
from watcher.common import scheduling
|
||||||
from watcher import notifications
|
from watcher import notifications
|
||||||
@@ -67,9 +66,8 @@ class APISchedulingService(scheduling.BackgroundSchedulerService):
|
|||||||
elapsed = timeutils.delta_seconds(last_heartbeat, timeutils.utcnow())
|
elapsed = timeutils.delta_seconds(last_heartbeat, timeutils.utcnow())
|
||||||
is_up = abs(elapsed) <= CONF.service_down_time
|
is_up = abs(elapsed) <= CONF.service_down_time
|
||||||
if not is_up:
|
if not is_up:
|
||||||
LOG.warning(_LW('Seems service %(name)s on host %(host)s is down. '
|
LOG.warning('Seems service %(name)s on host %(host)s is down. '
|
||||||
'Last heartbeat was %(lhb)s.'
|
'Last heartbeat was %(lhb)s. Elapsed time is %(el)s',
|
||||||
'Elapsed time is %(el)s'),
|
|
||||||
{'name': service.name,
|
{'name': service.name,
|
||||||
'host': service.host,
|
'host': service.host,
|
||||||
'lhb': str(last_heartbeat), 'el': str(elapsed)})
|
'lhb': str(last_heartbeat), 'el': str(elapsed)})
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
import abc
|
import abc
|
||||||
|
|
||||||
|
import jsonschema
|
||||||
import six
|
import six
|
||||||
|
|
||||||
from watcher.common import clients
|
from watcher.common import clients
|
||||||
@@ -130,8 +131,11 @@ class BaseAction(loadable.Loadable):
|
|||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def validate_parameters(self):
|
def validate_parameters(self):
|
||||||
self.schema(self.input_parameters)
|
try:
|
||||||
return True
|
jsonschema.validate(self.input_parameters, self.schema)
|
||||||
|
return True
|
||||||
|
except jsonschema.ValidationError as e:
|
||||||
|
raise e
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def get_description(self):
|
def get_description(self):
|
||||||
@@ -139,4 +143,10 @@ class BaseAction(loadable.Loadable):
|
|||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def check_abort(self):
|
def check_abort(self):
|
||||||
return bool(self.__class__.__name__ in self.ABORT_TRUE)
|
if self.__class__.__name__ is 'Migrate':
|
||||||
|
if self.migration_type == self.LIVE_MIGRATION:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return bool(self.__class__.__name__ in self.ABORT_TRUE)
|
||||||
|
|||||||
118
watcher/applier/actions/change_node_power_state.py
Normal file
118
watcher/applier/actions/change_node_power_state.py
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
# -*- encoding: utf-8 -*-
|
||||||
|
# Copyright (c) 2017 ZTE
|
||||||
|
#
|
||||||
|
# Authors: Li Canwei
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
# implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
import enum
|
||||||
|
|
||||||
|
from watcher._i18n import _
|
||||||
|
from watcher.applier.actions import base
|
||||||
|
from watcher.common import exception
|
||||||
|
|
||||||
|
|
||||||
|
class NodeState(enum.Enum):
|
||||||
|
POWERON = 'on'
|
||||||
|
POWEROFF = 'off'
|
||||||
|
|
||||||
|
|
||||||
|
class ChangeNodePowerState(base.BaseAction):
|
||||||
|
"""Compute node power on/off
|
||||||
|
|
||||||
|
By using this action, you will be able to on/off the power of a
|
||||||
|
compute node.
|
||||||
|
|
||||||
|
The action schema is::
|
||||||
|
|
||||||
|
schema = Schema({
|
||||||
|
'resource_id': str,
|
||||||
|
'state': str,
|
||||||
|
})
|
||||||
|
|
||||||
|
The `resource_id` references a ironic node id (list of available
|
||||||
|
ironic node is returned by this command: ``ironic node-list``).
|
||||||
|
The `state` value should either be `on` or `off`.
|
||||||
|
"""
|
||||||
|
|
||||||
|
STATE = 'state'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def schema(self):
|
||||||
|
return {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'resource_id': {
|
||||||
|
'type': 'string',
|
||||||
|
"minlength": 1
|
||||||
|
},
|
||||||
|
'state': {
|
||||||
|
'type': 'string',
|
||||||
|
'enum': [NodeState.POWERON.value,
|
||||||
|
NodeState.POWEROFF.value]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'required': ['resource_id', 'state'],
|
||||||
|
'additionalProperties': False,
|
||||||
|
}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def node_uuid(self):
|
||||||
|
return self.resource_id
|
||||||
|
|
||||||
|
@property
|
||||||
|
def state(self):
|
||||||
|
return self.input_parameters.get(self.STATE)
|
||||||
|
|
||||||
|
def execute(self):
|
||||||
|
target_state = self.state
|
||||||
|
return self._node_manage_power(target_state)
|
||||||
|
|
||||||
|
def revert(self):
|
||||||
|
if self.state == NodeState.POWERON.value:
|
||||||
|
target_state = NodeState.POWEROFF.value
|
||||||
|
elif self.state == NodeState.POWEROFF.value:
|
||||||
|
target_state = NodeState.POWERON.value
|
||||||
|
return self._node_manage_power(target_state)
|
||||||
|
|
||||||
|
def _node_manage_power(self, state):
|
||||||
|
if state is None:
|
||||||
|
raise exception.IllegalArgumentException(
|
||||||
|
message=_("The target state is not defined"))
|
||||||
|
|
||||||
|
result = False
|
||||||
|
ironic_client = self.osc.ironic()
|
||||||
|
nova_client = self.osc.nova()
|
||||||
|
if state == NodeState.POWEROFF.value:
|
||||||
|
node_info = ironic_client.node.get(self.node_uuid).to_dict()
|
||||||
|
compute_node_id = node_info['extra']['compute_node_id']
|
||||||
|
compute_node = nova_client.hypervisors.get(compute_node_id)
|
||||||
|
compute_node = compute_node.to_dict()
|
||||||
|
if (compute_node['running_vms'] == 0):
|
||||||
|
result = ironic_client.node.set_power_state(
|
||||||
|
self.node_uuid, state)
|
||||||
|
else:
|
||||||
|
result = ironic_client.node.set_power_state(self.node_uuid, state)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def pre_condition(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def post_condition(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_description(self):
|
||||||
|
"""Description of the action"""
|
||||||
|
return ("Compute node power on/off through ironic.")
|
||||||
@@ -17,9 +17,6 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
|
|
||||||
import six
|
|
||||||
import voluptuous
|
|
||||||
|
|
||||||
from watcher._i18n import _
|
from watcher._i18n import _
|
||||||
from watcher.applier.actions import base
|
from watcher.applier.actions import base
|
||||||
from watcher.common import exception
|
from watcher.common import exception
|
||||||
@@ -51,15 +48,24 @@ class ChangeNovaServiceState(base.BaseAction):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def schema(self):
|
def schema(self):
|
||||||
return voluptuous.Schema({
|
return {
|
||||||
voluptuous.Required(self.RESOURCE_ID):
|
'type': 'object',
|
||||||
voluptuous.All(
|
'properties': {
|
||||||
voluptuous.Any(*six.string_types),
|
'resource_id': {
|
||||||
voluptuous.Length(min=1)),
|
'type': 'string',
|
||||||
voluptuous.Required(self.STATE):
|
"minlength": 1
|
||||||
voluptuous.Any(*[state.value
|
},
|
||||||
for state in list(element.ServiceState)]),
|
'state': {
|
||||||
})
|
'type': 'string',
|
||||||
|
'enum': [element.ServiceState.ONLINE.value,
|
||||||
|
element.ServiceState.OFFLINE.value,
|
||||||
|
element.ServiceState.ENABLED.value,
|
||||||
|
element.ServiceState.DISABLED.value]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'required': ['resource_id', 'state'],
|
||||||
|
'additionalProperties': False,
|
||||||
|
}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def host(self):
|
def host(self):
|
||||||
|
|||||||
@@ -17,15 +17,12 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
|
|
||||||
from oslo_log import log
|
|
||||||
import six
|
|
||||||
import voluptuous
|
|
||||||
|
|
||||||
|
from oslo_log import log
|
||||||
from watcher._i18n import _
|
from watcher._i18n import _
|
||||||
from watcher.applier.actions import base
|
from watcher.applier.actions import base
|
||||||
from watcher.common import exception
|
from watcher.common import exception
|
||||||
from watcher.common import nova_helper
|
from watcher.common import nova_helper
|
||||||
from watcher.common import utils
|
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
@@ -62,28 +59,36 @@ class Migrate(base.BaseAction):
|
|||||||
DESTINATION_NODE = 'destination_node'
|
DESTINATION_NODE = 'destination_node'
|
||||||
SOURCE_NODE = 'source_node'
|
SOURCE_NODE = 'source_node'
|
||||||
|
|
||||||
def check_resource_id(self, value):
|
|
||||||
if (value is not None and
|
|
||||||
len(value) > 0 and not
|
|
||||||
utils.is_uuid_like(value)):
|
|
||||||
raise voluptuous.Invalid(_("The parameter "
|
|
||||||
"resource_id is invalid."))
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def schema(self):
|
def schema(self):
|
||||||
return voluptuous.Schema({
|
return {
|
||||||
voluptuous.Required(self.RESOURCE_ID): self.check_resource_id,
|
'type': 'object',
|
||||||
voluptuous.Required(
|
'properties': {
|
||||||
self.MIGRATION_TYPE, default=self.LIVE_MIGRATION):
|
'destination_node': {
|
||||||
voluptuous.Any(
|
"anyof": [
|
||||||
*[self.LIVE_MIGRATION, self.COLD_MIGRATION]),
|
{'type': 'string', "minLength": 1},
|
||||||
voluptuous.Required(self.DESTINATION_NODE):
|
{'type': 'None'}
|
||||||
voluptuous.All(voluptuous.Any(*six.string_types),
|
]
|
||||||
voluptuous.Length(min=1)),
|
},
|
||||||
voluptuous.Required(self.SOURCE_NODE):
|
'migration_type': {
|
||||||
voluptuous.All(voluptuous.Any(*six.string_types),
|
'type': 'string',
|
||||||
voluptuous.Length(min=1)),
|
"enum": ["live", "cold"]
|
||||||
})
|
},
|
||||||
|
'resource_id': {
|
||||||
|
'type': 'string',
|
||||||
|
"minlength": 1,
|
||||||
|
"pattern": ("^([a-fA-F0-9]){8}-([a-fA-F0-9]){4}-"
|
||||||
|
"([a-fA-F0-9]){4}-([a-fA-F0-9]){4}-"
|
||||||
|
"([a-fA-F0-9]){12}$")
|
||||||
|
},
|
||||||
|
'source_node': {
|
||||||
|
'type': 'string',
|
||||||
|
"minLength": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'required': ['migration_type', 'resource_id', 'source_node'],
|
||||||
|
'additionalProperties': False,
|
||||||
|
}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def instance_uuid(self):
|
def instance_uuid(self):
|
||||||
@@ -137,13 +142,28 @@ class Migrate(base.BaseAction):
|
|||||||
LOG.critical("Unexpected error occurred. Migration failed for "
|
LOG.critical("Unexpected error occurred. Migration failed for "
|
||||||
"instance %s. Leaving instance on previous "
|
"instance %s. Leaving instance on previous "
|
||||||
"host.", self.instance_uuid)
|
"host.", self.instance_uuid)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def migrate(self, destination):
|
def _abort_cold_migrate(self, nova):
|
||||||
|
# TODO(adisky): currently watcher uses its own version of cold migrate
|
||||||
|
# implement cold migrate using nova dependent on the blueprint
|
||||||
|
# https://blueprints.launchpad.net/nova/+spec/cold-migration-with-target
|
||||||
|
# Abort operation for cold migrate is dependent on blueprint
|
||||||
|
# https://blueprints.launchpad.net/nova/+spec/abort-cold-migration
|
||||||
|
LOG.warning("Abort operation for cold migration is not implemented")
|
||||||
|
|
||||||
|
def _abort_live_migrate(self, nova, source, destination):
|
||||||
|
return nova.abort_live_migrate(instance_id=self.instance_uuid,
|
||||||
|
source=source, destination=destination)
|
||||||
|
|
||||||
|
def migrate(self, destination=None):
|
||||||
nova = nova_helper.NovaHelper(osc=self.osc)
|
nova = nova_helper.NovaHelper(osc=self.osc)
|
||||||
LOG.debug("Migrate instance %s to %s", self.instance_uuid,
|
if destination is None:
|
||||||
destination)
|
LOG.debug("Migrating instance %s, destination node will be "
|
||||||
|
"determined by nova-scheduler", self.instance_uuid)
|
||||||
|
else:
|
||||||
|
LOG.debug("Migrate instance %s to %s", self.instance_uuid,
|
||||||
|
destination)
|
||||||
instance = nova.find_instance(self.instance_uuid)
|
instance = nova.find_instance(self.instance_uuid)
|
||||||
if instance:
|
if instance:
|
||||||
if self.migration_type == self.LIVE_MIGRATION:
|
if self.migration_type == self.LIVE_MIGRATION:
|
||||||
@@ -165,8 +185,17 @@ class Migrate(base.BaseAction):
|
|||||||
return self.migrate(destination=self.source_node)
|
return self.migrate(destination=self.source_node)
|
||||||
|
|
||||||
def abort(self):
|
def abort(self):
|
||||||
# TODO(adisky): implement abort for migration
|
nova = nova_helper.NovaHelper(osc=self.osc)
|
||||||
LOG.warning("Abort for migration not implemented")
|
instance = nova.find_instance(self.instance_uuid)
|
||||||
|
if instance:
|
||||||
|
if self.migration_type == self.COLD_MIGRATION:
|
||||||
|
return self._abort_cold_migrate(nova)
|
||||||
|
elif self.migration_type == self.LIVE_MIGRATION:
|
||||||
|
return self._abort_live_migrate(
|
||||||
|
nova, source=self.source_node,
|
||||||
|
destination=self.destination_node)
|
||||||
|
else:
|
||||||
|
raise exception.InstanceNotFound(name=self.instance_uuid)
|
||||||
|
|
||||||
def pre_condition(self):
|
def pre_condition(self):
|
||||||
# TODO(jed): check if the instance exists / check if the instance is on
|
# TODO(jed): check if the instance exists / check if the instance is on
|
||||||
|
|||||||
@@ -18,8 +18,6 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
from oslo_log import log
|
from oslo_log import log
|
||||||
import six
|
|
||||||
import voluptuous
|
|
||||||
|
|
||||||
from watcher.applier.actions import base
|
from watcher.applier.actions import base
|
||||||
|
|
||||||
@@ -42,10 +40,16 @@ class Nop(base.BaseAction):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def schema(self):
|
def schema(self):
|
||||||
return voluptuous.Schema({
|
return {
|
||||||
voluptuous.Required(self.MESSAGE): voluptuous.Any(
|
'type': 'object',
|
||||||
voluptuous.Any(*six.string_types), None)
|
'properties': {
|
||||||
})
|
'message': {
|
||||||
|
'type': ['string', 'null']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'required': ['message'],
|
||||||
|
'additionalProperties': False,
|
||||||
|
}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def message(self):
|
def message(self):
|
||||||
@@ -71,3 +75,4 @@ class Nop(base.BaseAction):
|
|||||||
|
|
||||||
def abort(self):
|
def abort(self):
|
||||||
LOG.debug("Abort action NOP")
|
LOG.debug("Abort action NOP")
|
||||||
|
return True
|
||||||
|
|||||||
@@ -18,13 +18,9 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
from oslo_log import log
|
from oslo_log import log
|
||||||
import six
|
|
||||||
import voluptuous
|
|
||||||
|
|
||||||
from watcher._i18n import _
|
|
||||||
from watcher.applier.actions import base
|
from watcher.applier.actions import base
|
||||||
from watcher.common import nova_helper
|
from watcher.common import nova_helper
|
||||||
from watcher.common import utils
|
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
@@ -49,21 +45,26 @@ class Resize(base.BaseAction):
|
|||||||
# input parameters constants
|
# input parameters constants
|
||||||
FLAVOR = 'flavor'
|
FLAVOR = 'flavor'
|
||||||
|
|
||||||
def check_resource_id(self, value):
|
|
||||||
if (value is not None and
|
|
||||||
len(value) > 0 and not
|
|
||||||
utils.is_uuid_like(value)):
|
|
||||||
raise voluptuous.Invalid(_("The parameter "
|
|
||||||
"resource_id is invalid."))
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def schema(self):
|
def schema(self):
|
||||||
return voluptuous.Schema({
|
return {
|
||||||
voluptuous.Required(self.RESOURCE_ID): self.check_resource_id,
|
'type': 'object',
|
||||||
voluptuous.Required(self.FLAVOR):
|
'properties': {
|
||||||
voluptuous.All(voluptuous.Any(*six.string_types),
|
'resource_id': {
|
||||||
voluptuous.Length(min=1)),
|
'type': 'string',
|
||||||
})
|
'minlength': 1,
|
||||||
|
'pattern': ('^([a-fA-F0-9]){8}-([a-fA-F0-9]){4}-'
|
||||||
|
'([a-fA-F0-9]){4}-([a-fA-F0-9]){4}-'
|
||||||
|
'([a-fA-F0-9]){12}$')
|
||||||
|
},
|
||||||
|
'flavor': {
|
||||||
|
'type': 'string',
|
||||||
|
'minlength': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'required': ['resource_id', 'flavor'],
|
||||||
|
'additionalProperties': False,
|
||||||
|
}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def instance_uuid(self):
|
def instance_uuid(self):
|
||||||
|
|||||||
@@ -20,8 +20,6 @@
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
from oslo_log import log
|
from oslo_log import log
|
||||||
import voluptuous
|
|
||||||
|
|
||||||
from watcher.applier.actions import base
|
from watcher.applier.actions import base
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
@@ -43,10 +41,17 @@ class Sleep(base.BaseAction):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def schema(self):
|
def schema(self):
|
||||||
return voluptuous.Schema({
|
return {
|
||||||
voluptuous.Required(self.DURATION, default=1):
|
'type': 'object',
|
||||||
voluptuous.All(float, voluptuous.Range(min=0))
|
'properties': {
|
||||||
})
|
'duration': {
|
||||||
|
'type': 'number',
|
||||||
|
'minimum': 0
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'required': ['duration'],
|
||||||
|
'additionalProperties': False,
|
||||||
|
}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def duration(self):
|
def duration(self):
|
||||||
@@ -73,3 +78,4 @@ class Sleep(base.BaseAction):
|
|||||||
|
|
||||||
def abort(self):
|
def abort(self):
|
||||||
LOG.debug("Abort action sleep")
|
LOG.debug("Abort action sleep")
|
||||||
|
return True
|
||||||
|
|||||||
252
watcher/applier/actions/volume_migration.py
Normal file
252
watcher/applier/actions/volume_migration.py
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
# Copyright 2017 NEC Corporation
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
# implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import jsonschema
|
||||||
|
|
||||||
|
from oslo_log import log
|
||||||
|
|
||||||
|
from cinderclient import client as cinder_client
|
||||||
|
from watcher._i18n import _
|
||||||
|
from watcher.applier.actions import base
|
||||||
|
from watcher.common import cinder_helper
|
||||||
|
from watcher.common import exception
|
||||||
|
from watcher.common import keystone_helper
|
||||||
|
from watcher.common import nova_helper
|
||||||
|
from watcher.common import utils
|
||||||
|
from watcher import conf
|
||||||
|
|
||||||
|
CONF = conf.CONF
|
||||||
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class VolumeMigrate(base.BaseAction):
|
||||||
|
"""Migrates a volume to destination node or type
|
||||||
|
|
||||||
|
By using this action, you will be able to migrate cinder volume.
|
||||||
|
Migration type 'swap' can only be used for migrating attached volume.
|
||||||
|
Migration type 'cold' can only be used for migrating detached volume.
|
||||||
|
|
||||||
|
The action schema is::
|
||||||
|
|
||||||
|
schema = Schema({
|
||||||
|
'resource_id': str, # should be a UUID
|
||||||
|
'migration_type': str, # choices -> "swap", "cold"
|
||||||
|
'destination_node': str,
|
||||||
|
'destination_type': str,
|
||||||
|
)}
|
||||||
|
|
||||||
|
The `resource_id` is the UUID of cinder volume to migrate.
|
||||||
|
The `destination_node` is the destination block storage pool name.
|
||||||
|
(list of available pools are returned by this command: ``cinder
|
||||||
|
get-pools``) which is mandatory for migrating detached volume
|
||||||
|
to the one with same volume type.
|
||||||
|
The `destination_type` is the destination block storage type name.
|
||||||
|
(list of available types are returned by this command: ``cinder
|
||||||
|
type-list``) which is mandatory for migrating detached volume or
|
||||||
|
swapping attached volume to the one with different volume type.
|
||||||
|
"""
|
||||||
|
|
||||||
|
MIGRATION_TYPE = 'migration_type'
|
||||||
|
SWAP = 'swap'
|
||||||
|
COLD = 'cold'
|
||||||
|
DESTINATION_NODE = "destination_node"
|
||||||
|
DESTINATION_TYPE = "destination_type"
|
||||||
|
|
||||||
|
def __init__(self, config, osc=None):
|
||||||
|
super(VolumeMigrate, self).__init__(config)
|
||||||
|
self.temp_username = utils.random_string(10)
|
||||||
|
self.temp_password = utils.random_string(10)
|
||||||
|
self.cinder_util = cinder_helper.CinderHelper(osc=self.osc)
|
||||||
|
self.nova_util = nova_helper.NovaHelper(osc=self.osc)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def schema(self):
|
||||||
|
return {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'resource_id': {
|
||||||
|
'type': 'string',
|
||||||
|
"minlength": 1,
|
||||||
|
"pattern": ("^([a-fA-F0-9]){8}-([a-fA-F0-9]){4}-"
|
||||||
|
"([a-fA-F0-9]){4}-([a-fA-F0-9]){4}-"
|
||||||
|
"([a-fA-F0-9]){12}$")
|
||||||
|
},
|
||||||
|
'migration_type': {
|
||||||
|
'type': 'string',
|
||||||
|
"enum": ["swap", "cold"]
|
||||||
|
},
|
||||||
|
'destination_node': {
|
||||||
|
"anyof": [
|
||||||
|
{'type': 'string', "minLength": 1},
|
||||||
|
{'type': 'None'}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'destination_type': {
|
||||||
|
"anyof": [
|
||||||
|
{'type': 'string', "minLength": 1},
|
||||||
|
{'type': 'None'}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'required': ['resource_id', 'migration_type'],
|
||||||
|
'additionalProperties': False,
|
||||||
|
}
|
||||||
|
|
||||||
|
def validate_parameters(self):
|
||||||
|
try:
|
||||||
|
jsonschema.validate(self.input_parameters, self.schema)
|
||||||
|
return True
|
||||||
|
except jsonschema.ValidationError as e:
|
||||||
|
raise e
|
||||||
|
|
||||||
|
@property
|
||||||
|
def volume_id(self):
|
||||||
|
return self.input_parameters.get(self.RESOURCE_ID)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def migration_type(self):
|
||||||
|
return self.input_parameters.get(self.MIGRATION_TYPE)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def destination_node(self):
|
||||||
|
return self.input_parameters.get(self.DESTINATION_NODE)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def destination_type(self):
|
||||||
|
return self.input_parameters.get(self.DESTINATION_TYPE)
|
||||||
|
|
||||||
|
def _cold_migrate(self, volume, dest_node, dest_type):
|
||||||
|
if not self.cinder_util.can_cold(volume, dest_node):
|
||||||
|
raise exception.Invalid(
|
||||||
|
message=(_("Invalid state for cold migration")))
|
||||||
|
|
||||||
|
if dest_node:
|
||||||
|
return self.cinder_util.migrate(volume, dest_node)
|
||||||
|
elif dest_type:
|
||||||
|
return self.cinder_util.retype(volume, dest_type)
|
||||||
|
else:
|
||||||
|
raise exception.Invalid(
|
||||||
|
message=(_("destination host or destination type is "
|
||||||
|
"required when migration type is cold")))
|
||||||
|
|
||||||
|
def _can_swap(self, volume):
|
||||||
|
"""Judge volume can be swapped"""
|
||||||
|
|
||||||
|
if not volume.attachments:
|
||||||
|
return False
|
||||||
|
instance_id = volume.attachments[0]['server_id']
|
||||||
|
instance_status = self.nova_util.find_instance(instance_id).status
|
||||||
|
|
||||||
|
if (volume.status == 'in-use' and
|
||||||
|
instance_status in ('ACTIVE', 'PAUSED', 'RESIZED')):
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _create_user(self, volume, user):
|
||||||
|
"""Create user with volume attribute and user information"""
|
||||||
|
keystone_util = keystone_helper.KeystoneHelper(osc=self.osc)
|
||||||
|
project_id = getattr(volume, 'os-vol-tenant-attr:tenant_id')
|
||||||
|
user['project'] = project_id
|
||||||
|
user['domain'] = keystone_util.get_project(project_id).domain_id
|
||||||
|
user['roles'] = ['admin']
|
||||||
|
return keystone_util.create_user(user)
|
||||||
|
|
||||||
|
def _get_cinder_client(self, session):
|
||||||
|
"""Get cinder client by session"""
|
||||||
|
return cinder_client.Client(
|
||||||
|
CONF.cinder_client.api_version,
|
||||||
|
session=session,
|
||||||
|
endpoint_type=CONF.cinder_client.endpoint_type)
|
||||||
|
|
||||||
|
def _swap_volume(self, volume, dest_type):
|
||||||
|
"""Swap volume to dest_type
|
||||||
|
|
||||||
|
Limitation note: only for compute libvirt driver
|
||||||
|
"""
|
||||||
|
if not dest_type:
|
||||||
|
raise exception.Invalid(
|
||||||
|
message=(_("destination type is required when "
|
||||||
|
"migration type is swap")))
|
||||||
|
|
||||||
|
if not self._can_swap(volume):
|
||||||
|
raise exception.Invalid(
|
||||||
|
message=(_("Invalid state for swapping volume")))
|
||||||
|
|
||||||
|
user_info = {
|
||||||
|
'name': self.temp_username,
|
||||||
|
'password': self.temp_password}
|
||||||
|
user = self._create_user(volume, user_info)
|
||||||
|
keystone_util = keystone_helper.KeystoneHelper(osc=self.osc)
|
||||||
|
try:
|
||||||
|
session = keystone_util.create_session(
|
||||||
|
user.id, self.temp_password)
|
||||||
|
temp_cinder = self._get_cinder_client(session)
|
||||||
|
|
||||||
|
# swap volume
|
||||||
|
new_volume = self.cinder_util.create_volume(
|
||||||
|
temp_cinder, volume, dest_type)
|
||||||
|
self.nova_util.swap_volume(volume, new_volume)
|
||||||
|
|
||||||
|
# delete old volume
|
||||||
|
self.cinder_util.delete_volume(volume)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
keystone_util.delete_user(user)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _migrate(self, volume_id, dest_node, dest_type):
|
||||||
|
|
||||||
|
try:
|
||||||
|
volume = self.cinder_util.get_volume(volume_id)
|
||||||
|
if self.migration_type == self.COLD:
|
||||||
|
return self._cold_migrate(volume, dest_node, dest_type)
|
||||||
|
elif self.migration_type == self.SWAP:
|
||||||
|
if dest_node:
|
||||||
|
LOG.warning("dest_node is ignored")
|
||||||
|
return self._swap_volume(volume, dest_type)
|
||||||
|
else:
|
||||||
|
raise exception.Invalid(
|
||||||
|
message=(_("Migration of type '%(migration_type)s' is not "
|
||||||
|
"supported.") %
|
||||||
|
{'migration_type': self.migration_type}))
|
||||||
|
except exception.Invalid as ei:
|
||||||
|
LOG.exception(ei)
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
LOG.critical("Unexpected exception occurred.")
|
||||||
|
LOG.exception(e)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def execute(self):
|
||||||
|
return self._migrate(self.volume_id,
|
||||||
|
self.destination_node,
|
||||||
|
self.destination_type)
|
||||||
|
|
||||||
|
def revert(self):
|
||||||
|
LOG.warning("revert not supported")
|
||||||
|
|
||||||
|
def abort(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def pre_condition(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def post_condition(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_description(self):
|
||||||
|
return "Moving a volume to destination_node or destination_type"
|
||||||
44
watcher/applier/sync.py
Normal file
44
watcher/applier/sync.py
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
# -*- encoding: utf-8 -*-
|
||||||
|
# Copyright (c) 2017 ZTE
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
# implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
from watcher.applier.loading import default
|
||||||
|
from watcher.common import context
|
||||||
|
from watcher.common import exception
|
||||||
|
from watcher import objects
|
||||||
|
|
||||||
|
|
||||||
|
class Syncer(object):
|
||||||
|
"""Syncs all available actions with the Watcher DB"""
|
||||||
|
|
||||||
|
def sync(self):
|
||||||
|
ctx = context.make_context()
|
||||||
|
action_loader = default.DefaultActionLoader()
|
||||||
|
available_actions = action_loader.list_available()
|
||||||
|
for action_type in available_actions.keys():
|
||||||
|
load_action = action_loader.load(action_type)
|
||||||
|
load_description = load_action.get_description()
|
||||||
|
try:
|
||||||
|
action_desc = objects.ActionDescription.get_by_type(
|
||||||
|
ctx, action_type)
|
||||||
|
if action_desc.description != load_description:
|
||||||
|
action_desc.description = load_description
|
||||||
|
action_desc.save()
|
||||||
|
except exception.ActionDescriptionNotFound:
|
||||||
|
obj_action_desc = objects.ActionDescription(ctx)
|
||||||
|
obj_action_desc.action_type = action_type
|
||||||
|
obj_action_desc.description = load_description
|
||||||
|
obj_action_desc.create()
|
||||||
@@ -88,12 +88,9 @@ class BaseWorkFlowEngine(loadable.Loadable):
|
|||||||
def notify(self, action, state):
|
def notify(self, action, state):
|
||||||
db_action = objects.Action.get_by_uuid(self.context, action.uuid,
|
db_action = objects.Action.get_by_uuid(self.context, action.uuid,
|
||||||
eager=True)
|
eager=True)
|
||||||
if (db_action.state in [objects.action.State.CANCELLING,
|
|
||||||
objects.action.State.CANCELLED] and
|
|
||||||
state == objects.action.State.SUCCEEDED):
|
|
||||||
return
|
|
||||||
db_action.state = state
|
db_action.state = state
|
||||||
db_action.save()
|
db_action.save()
|
||||||
|
return db_action
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def execute(self, actions):
|
def execute(self, actions):
|
||||||
@@ -153,9 +150,9 @@ class BaseTaskFlowActionContainer(flow_task.Task):
|
|||||||
self.engine.context, self._db_action.action_plan_id)
|
self.engine.context, self._db_action.action_plan_id)
|
||||||
if action_plan.state in CANCEL_STATE:
|
if action_plan.state in CANCEL_STATE:
|
||||||
raise exception.ActionPlanCancelled(uuid=action_plan.uuid)
|
raise exception.ActionPlanCancelled(uuid=action_plan.uuid)
|
||||||
self.do_pre_execute()
|
db_action = self.do_pre_execute()
|
||||||
notifications.action.send_execution_notification(
|
notifications.action.send_execution_notification(
|
||||||
self.engine.context, self._db_action,
|
self.engine.context, db_action,
|
||||||
fields.NotificationAction.EXECUTION,
|
fields.NotificationAction.EXECUTION,
|
||||||
fields.NotificationPhase.START)
|
fields.NotificationPhase.START)
|
||||||
except exception.ActionPlanCancelled as e:
|
except exception.ActionPlanCancelled as e:
|
||||||
@@ -163,9 +160,10 @@ class BaseTaskFlowActionContainer(flow_task.Task):
|
|||||||
raise
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOG.exception(e)
|
LOG.exception(e)
|
||||||
self.engine.notify(self._db_action, objects.action.State.FAILED)
|
db_action = self.engine.notify(self._db_action,
|
||||||
|
objects.action.State.FAILED)
|
||||||
notifications.action.send_execution_notification(
|
notifications.action.send_execution_notification(
|
||||||
self.engine.context, self._db_action,
|
self.engine.context, db_action,
|
||||||
fields.NotificationAction.EXECUTION,
|
fields.NotificationAction.EXECUTION,
|
||||||
fields.NotificationPhase.ERROR,
|
fields.NotificationPhase.ERROR,
|
||||||
priority=fields.NotificationPriority.ERROR)
|
priority=fields.NotificationPriority.ERROR)
|
||||||
@@ -173,19 +171,19 @@ class BaseTaskFlowActionContainer(flow_task.Task):
|
|||||||
def execute(self, *args, **kwargs):
|
def execute(self, *args, **kwargs):
|
||||||
def _do_execute_action(*args, **kwargs):
|
def _do_execute_action(*args, **kwargs):
|
||||||
try:
|
try:
|
||||||
self.do_execute(*args, **kwargs)
|
db_action = self.do_execute(*args, **kwargs)
|
||||||
notifications.action.send_execution_notification(
|
notifications.action.send_execution_notification(
|
||||||
self.engine.context, self._db_action,
|
self.engine.context, db_action,
|
||||||
fields.NotificationAction.EXECUTION,
|
fields.NotificationAction.EXECUTION,
|
||||||
fields.NotificationPhase.END)
|
fields.NotificationPhase.END)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOG.exception(e)
|
LOG.exception(e)
|
||||||
LOG.error('The workflow engine has failed'
|
LOG.error('The workflow engine has failed'
|
||||||
'to execute the action: %s', self.name)
|
'to execute the action: %s', self.name)
|
||||||
self.engine.notify(self._db_action,
|
db_action = self.engine.notify(self._db_action,
|
||||||
objects.action.State.FAILED)
|
objects.action.State.FAILED)
|
||||||
notifications.action.send_execution_notification(
|
notifications.action.send_execution_notification(
|
||||||
self.engine.context, self._db_action,
|
self.engine.context, db_action,
|
||||||
fields.NotificationAction.EXECUTION,
|
fields.NotificationAction.EXECUTION,
|
||||||
fields.NotificationPhase.ERROR,
|
fields.NotificationPhase.ERROR,
|
||||||
priority=fields.NotificationPriority.ERROR)
|
priority=fields.NotificationPriority.ERROR)
|
||||||
@@ -204,7 +202,7 @@ class BaseTaskFlowActionContainer(flow_task.Task):
|
|||||||
objects.action.State.FAILED] or
|
objects.action.State.FAILED] or
|
||||||
action_plan_object.state in CANCEL_STATE):
|
action_plan_object.state in CANCEL_STATE):
|
||||||
break
|
break
|
||||||
time.sleep(2)
|
time.sleep(1)
|
||||||
try:
|
try:
|
||||||
# NOTE: kill the action execution thread, if action plan is
|
# NOTE: kill the action execution thread, if action plan is
|
||||||
# cancelled for all other cases wait for the result from action
|
# cancelled for all other cases wait for the result from action
|
||||||
@@ -231,9 +229,10 @@ class BaseTaskFlowActionContainer(flow_task.Task):
|
|||||||
self.do_post_execute()
|
self.do_post_execute()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOG.exception(e)
|
LOG.exception(e)
|
||||||
self.engine.notify(self._db_action, objects.action.State.FAILED)
|
db_action = self.engine.notify(self._db_action,
|
||||||
|
objects.action.State.FAILED)
|
||||||
notifications.action.send_execution_notification(
|
notifications.action.send_execution_notification(
|
||||||
self.engine.context, self._db_action,
|
self.engine.context, db_action,
|
||||||
fields.NotificationAction.EXECUTION,
|
fields.NotificationAction.EXECUTION,
|
||||||
fields.NotificationPhase.ERROR,
|
fields.NotificationPhase.ERROR,
|
||||||
priority=fields.NotificationPriority.ERROR)
|
priority=fields.NotificationPriority.ERROR)
|
||||||
@@ -246,15 +245,19 @@ class BaseTaskFlowActionContainer(flow_task.Task):
|
|||||||
# if due to some other exception keep the flow intact.
|
# if due to some other exception keep the flow intact.
|
||||||
if action_plan.state not in CANCEL_STATE:
|
if action_plan.state not in CANCEL_STATE:
|
||||||
self.do_revert()
|
self.do_revert()
|
||||||
|
return
|
||||||
|
|
||||||
action_object = objects.Action.get_by_uuid(
|
action_object = objects.Action.get_by_uuid(
|
||||||
self.engine.context, self._db_action.uuid, eager=True)
|
self.engine.context, self._db_action.uuid, eager=True)
|
||||||
if action_object.state == objects.action.State.ONGOING:
|
if action_object.state == objects.action.State.ONGOING:
|
||||||
action_object.state = objects.action.State.CANCELLING
|
action_object.state = objects.action.State.CANCELLING
|
||||||
action_object.save()
|
action_object.save()
|
||||||
self.abort()
|
self.abort()
|
||||||
if action_object.state == objects.action.State.PENDING:
|
elif action_object.state == objects.action.State.PENDING:
|
||||||
action_object.state = objects.action.State.CANCELLED
|
action_object.state = objects.action.State.CANCELLED
|
||||||
action_object.save()
|
action_object.save()
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
def abort(self, *args, **kwargs):
|
def abort(self, *args, **kwargs):
|
||||||
self.do_abort(*args, **kwargs)
|
self.do_abort(*args, **kwargs)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user