Retire Packaging Deb project repos
This commit is part of a series to retire the Packaging Deb project. Step 2 is to remove all content from the project repos, replacing it with a README notification where to find ongoing work, and how to recover the repo if needed at some future point (as in https://docs.openstack.org/infra/manual/drivers.html#retiring-a-project). Change-Id: I36400d5ff47dc7ab7f90fd0648ef8684ddbbd724
12
.coveragerc
@ -1,12 +0,0 @@
|
|||||||
[run]
|
|
||||||
branch = True
|
|
||||||
source = watcher
|
|
||||||
omit =
|
|
||||||
watcher/tests/*
|
|
||||||
watcher/hacking/*
|
|
||||||
|
|
||||||
[report]
|
|
||||||
ignore_errors = True
|
|
||||||
exclude_lines =
|
|
||||||
@abc.abstract
|
|
||||||
raise NotImplementedError
|
|
74
.gitignore
vendored
@ -1,74 +0,0 @@
|
|||||||
*.py[cod]
|
|
||||||
|
|
||||||
# C extensions
|
|
||||||
*.so
|
|
||||||
|
|
||||||
# Packages
|
|
||||||
*.egg*
|
|
||||||
dist
|
|
||||||
build
|
|
||||||
eggs
|
|
||||||
parts
|
|
||||||
bin
|
|
||||||
var
|
|
||||||
sdist
|
|
||||||
develop-eggs
|
|
||||||
.installed.cfg
|
|
||||||
lib
|
|
||||||
lib64
|
|
||||||
|
|
||||||
# Installer logs
|
|
||||||
pip-log.txt
|
|
||||||
|
|
||||||
# Unit test / coverage reports
|
|
||||||
.coverage*
|
|
||||||
.tox
|
|
||||||
nosetests.xml
|
|
||||||
.testrepository
|
|
||||||
.venv
|
|
||||||
.idea
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
*.mo
|
|
||||||
|
|
||||||
# Mr Developer
|
|
||||||
.mr.developer.cfg
|
|
||||||
.project
|
|
||||||
.pydevproject
|
|
||||||
|
|
||||||
# Complexity
|
|
||||||
output/*.html
|
|
||||||
output/*/index.html
|
|
||||||
|
|
||||||
# Sphinx
|
|
||||||
doc/build
|
|
||||||
doc/source/api/*
|
|
||||||
doc/source/samples
|
|
||||||
doc/source/watcher.conf.sample
|
|
||||||
!doc/source/api/index.rst
|
|
||||||
!doc/source/api/v1.rst
|
|
||||||
|
|
||||||
# pbr generates these
|
|
||||||
AUTHORS
|
|
||||||
ChangeLog
|
|
||||||
|
|
||||||
# Editors
|
|
||||||
*~
|
|
||||||
.*.swp
|
|
||||||
.*sw?
|
|
||||||
|
|
||||||
sftp-config.json
|
|
||||||
/.idea/
|
|
||||||
/cover/
|
|
||||||
.settings/
|
|
||||||
.eclipse
|
|
||||||
|
|
||||||
cover
|
|
||||||
/demo/
|
|
||||||
|
|
||||||
|
|
||||||
# Files created by releasenotes build
|
|
||||||
releasenotes/build
|
|
||||||
|
|
||||||
# Desktop Service Store
|
|
||||||
*.DS_Store
|
|
@ -1,4 +0,0 @@
|
|||||||
[gerrit]
|
|
||||||
host=review.openstack.org
|
|
||||||
port=29418
|
|
||||||
project=openstack/watcher.git
|
|
3
.mailmap
@ -1,3 +0,0 @@
|
|||||||
# Format is:
|
|
||||||
# <preferred e-mail> <other e-mail 1>
|
|
||||||
# <preferred e-mail> <other e-mail 2>
|
|
@ -1,7 +0,0 @@
|
|||||||
[DEFAULT]
|
|
||||||
test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \
|
|
||||||
OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \
|
|
||||||
OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-160} \
|
|
||||||
${PYTHON:-python} -m subunit.run discover -t ./ ${OS_TEST_PATH:-./watcher/tests} $LISTOPT $IDOPTION
|
|
||||||
test_id_option=--load-list $IDFILE
|
|
||||||
test_list_option=--list
|
|
@ -1,16 +0,0 @@
|
|||||||
If you would like to contribute to the development of OpenStack,
|
|
||||||
you must follow the steps in this page:
|
|
||||||
|
|
||||||
https://docs.openstack.org/infra/manual/developers.html
|
|
||||||
|
|
||||||
Once those steps have been completed, changes to OpenStack
|
|
||||||
should be submitted for review via the Gerrit tool, following
|
|
||||||
the workflow documented at:
|
|
||||||
|
|
||||||
https://docs.openstack.org/infra/manual/developers.html#development-workflow
|
|
||||||
|
|
||||||
Pull requests submitted through GitHub will be ignored.
|
|
||||||
|
|
||||||
Bugs should be filed on Launchpad, not GitHub:
|
|
||||||
|
|
||||||
https://bugs.launchpad.net/watcher
|
|
11
HACKING.rst
@ -1,11 +0,0 @@
|
|||||||
..
|
|
||||||
Except where otherwise noted, this document is licensed under Creative
|
|
||||||
Commons Attribution 3.0 License. You can view the license at:
|
|
||||||
|
|
||||||
https://creativecommons.org/licenses/by/3.0/
|
|
||||||
|
|
||||||
==========================
|
|
||||||
watcher Style Commandments
|
|
||||||
==========================
|
|
||||||
|
|
||||||
Read the OpenStack Style Commandments https://docs.openstack.org/developer/hacking/
|
|
176
LICENSE
@ -1,176 +0,0 @@
|
|||||||
|
|
||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
14
README
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
This project is no longer maintained.
|
||||||
|
|
||||||
|
The contents of this repository are still available in the Git
|
||||||
|
source code management system. To see the contents of this
|
||||||
|
repository before it reached its end of life, please check out the
|
||||||
|
previous commit with "git checkout HEAD^1".
|
||||||
|
|
||||||
|
For ongoing work on maintaining OpenStack packages in the Debian
|
||||||
|
distribution, please see the Debian OpenStack packaging team at
|
||||||
|
https://wiki.debian.org/OpenStack/.
|
||||||
|
|
||||||
|
For any further questions, please email
|
||||||
|
openstack-dev@lists.openstack.org or join #openstack-dev on
|
||||||
|
Freenode.
|
31
README.rst
@ -1,31 +0,0 @@
|
|||||||
========================
|
|
||||||
Team and repository tags
|
|
||||||
========================
|
|
||||||
|
|
||||||
.. image:: https://governance.openstack.org/badges/watcher.svg
|
|
||||||
:target: https://governance.openstack.org/reference/tags/index.html
|
|
||||||
|
|
||||||
.. Change things from this point on
|
|
||||||
|
|
||||||
..
|
|
||||||
Except where otherwise noted, this document is licensed under Creative
|
|
||||||
Commons Attribution 3.0 License. You can view the license at:
|
|
||||||
|
|
||||||
https://creativecommons.org/licenses/by/3.0/
|
|
||||||
|
|
||||||
=======
|
|
||||||
Watcher
|
|
||||||
=======
|
|
||||||
|
|
||||||
OpenStack Watcher provides a flexible and scalable resource optimization
|
|
||||||
service for multi-tenant OpenStack-based clouds.
|
|
||||||
Watcher provides a robust framework to realize a wide range of cloud
|
|
||||||
optimization goals, including the reduction of data center
|
|
||||||
operating costs, increased system performance via intelligent virtual machine
|
|
||||||
migration, increased energy efficiency-and more!
|
|
||||||
|
|
||||||
* Free software: Apache license
|
|
||||||
* Wiki: https://wiki.openstack.org/wiki/Watcher
|
|
||||||
* Source: https://github.com/openstack/watcher
|
|
||||||
* Bugs: https://bugs.launchpad.net/watcher
|
|
||||||
* Documentation: https://docs.openstack.org/watcher/latest/
|
|
@ -1,42 +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 is an example Apache2 configuration file for using the
|
|
||||||
# Watcher API through mod_wsgi. This version assumes you are
|
|
||||||
# running devstack to configure the software.
|
|
||||||
|
|
||||||
Listen %WATCHER_SERVICE_PORT%
|
|
||||||
|
|
||||||
<VirtualHost *:%WATCHER_SERVICE_PORT%>
|
|
||||||
WSGIDaemonProcess watcher-api user=%USER% processes=%APIWORKERS% threads=1 display-name=%{GROUP}
|
|
||||||
WSGIScriptAlias / %WATCHER_WSGI_DIR%/app.wsgi
|
|
||||||
WSGIApplicationGroup %{GLOBAL}
|
|
||||||
WSGIProcessGroup watcher-api
|
|
||||||
WSGIPassAuthorization On
|
|
||||||
|
|
||||||
ErrorLogFormat "%M"
|
|
||||||
ErrorLog /var/log/%APACHE_NAME%/watcher-api.log
|
|
||||||
CustomLog /var/log/%APACHE_NAME%/watcher-api-access.log combined
|
|
||||||
|
|
||||||
|
|
||||||
<Directory %WATCHER_WSGI_DIR%>
|
|
||||||
WSGIProcessGroup watcher-api
|
|
||||||
WSGIApplicationGroup %{GLOBAL}
|
|
||||||
<IfVersion >= 2.4>
|
|
||||||
Require all granted
|
|
||||||
</IfVersion>
|
|
||||||
<IfVersion < 2.4>
|
|
||||||
Order allow,deny
|
|
||||||
Allow from all
|
|
||||||
</IfVersion>
|
|
||||||
</Directory>
|
|
||||||
</VirtualHost>
|
|
@ -1,313 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
# lib/watcher
|
|
||||||
# Functions to control the configuration and operation of the watcher services
|
|
||||||
|
|
||||||
# Dependencies:
|
|
||||||
#
|
|
||||||
# - ``functions`` file
|
|
||||||
# - ``SERVICE_{TENANT_NAME|PASSWORD}`` must be defined
|
|
||||||
# - ``DEST``, ``DATA_DIR``, ``STACK_USER`` must be defined
|
|
||||||
|
|
||||||
# ``stack.sh`` calls the entry points in this order:
|
|
||||||
#
|
|
||||||
# - is_watcher_enabled
|
|
||||||
# - install_watcher
|
|
||||||
# - configure_watcher
|
|
||||||
# - create_watcher_conf
|
|
||||||
# - init_watcher
|
|
||||||
# - start_watcher
|
|
||||||
# - stop_watcher
|
|
||||||
# - cleanup_watcher
|
|
||||||
|
|
||||||
# Save trace setting
|
|
||||||
_XTRACE_WATCHER=$(set +o | grep xtrace)
|
|
||||||
set +o xtrace
|
|
||||||
|
|
||||||
|
|
||||||
# Defaults
|
|
||||||
# --------
|
|
||||||
|
|
||||||
# Set up default directories
|
|
||||||
WATCHER_REPO=${WATCHER_REPO:-${GIT_BASE}/openstack/watcher.git}
|
|
||||||
WATCHER_BRANCH=${WATCHER_BRANCH:-master}
|
|
||||||
WATCHER_DIR=$DEST/watcher
|
|
||||||
|
|
||||||
GITREPO["python-watcherclient"]=${WATCHERCLIENT_REPO:-${GIT_BASE}/openstack/python-watcherclient.git}
|
|
||||||
GITBRANCH["python-watcherclient"]=${WATCHERCLIENT_BRANCH:-master}
|
|
||||||
GITDIR["python-watcherclient"]=$DEST/python-watcherclient
|
|
||||||
|
|
||||||
WATCHER_STATE_PATH=${WATCHER_STATE_PATH:=$DATA_DIR/watcher}
|
|
||||||
WATCHER_AUTH_CACHE_DIR=${WATCHER_AUTH_CACHE_DIR:-/var/cache/watcher}
|
|
||||||
|
|
||||||
WATCHER_CONF_DIR=/etc/watcher
|
|
||||||
WATCHER_CONF=$WATCHER_CONF_DIR/watcher.conf
|
|
||||||
WATCHER_POLICY_JSON=$WATCHER_CONF_DIR/policy.json
|
|
||||||
|
|
||||||
WATCHER_DEVSTACK_DIR=$WATCHER_DIR/devstack
|
|
||||||
WATCHER_DEVSTACK_FILES_DIR=$WATCHER_DEVSTACK_DIR/files
|
|
||||||
|
|
||||||
NOVA_CONF_DIR=/etc/nova
|
|
||||||
NOVA_CONF=$NOVA_CONF_DIR/nova.conf
|
|
||||||
|
|
||||||
if is_ssl_enabled_service "watcher" || is_service_enabled tls-proxy; then
|
|
||||||
WATCHER_SERVICE_PROTOCOL="https"
|
|
||||||
fi
|
|
||||||
|
|
||||||
WATCHER_USE_MOD_WSGI=$(trueorfalse True WATCHER_USE_MOD_WSGI)
|
|
||||||
|
|
||||||
if is_suse; then
|
|
||||||
WATCHER_WSGI_DIR=${WATCHER_WSGI_DIR:-/srv/www/htdocs/watcher}
|
|
||||||
else
|
|
||||||
WATCHER_WSGI_DIR=${WATCHER_WSGI_DIR:-/var/www/watcher}
|
|
||||||
fi
|
|
||||||
# Public facing bits
|
|
||||||
WATCHER_SERVICE_HOST=${WATCHER_SERVICE_HOST:-$HOST_IP}
|
|
||||||
WATCHER_SERVICE_PORT=${WATCHER_SERVICE_PORT:-9322}
|
|
||||||
WATCHER_SERVICE_PORT_INT=${WATCHER_SERVICE_PORT_INT:-19322}
|
|
||||||
WATCHER_SERVICE_PROTOCOL=${WATCHER_SERVICE_PROTOCOL:-$SERVICE_PROTOCOL}
|
|
||||||
|
|
||||||
# Support entry points installation of console scripts
|
|
||||||
if [[ -d $WATCHER_DIR/bin ]]; then
|
|
||||||
WATCHER_BIN_DIR=$WATCHER_DIR/bin
|
|
||||||
else
|
|
||||||
WATCHER_BIN_DIR=$(get_python_exec_prefix)
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Entry Points
|
|
||||||
# ------------
|
|
||||||
|
|
||||||
# Test if any watcher services are enabled
|
|
||||||
# is_watcher_enabled
|
|
||||||
function is_watcher_enabled {
|
|
||||||
[[ ,${ENABLED_SERVICES} =~ ,"watcher-" ]] && return 0
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
#_cleanup_watcher_apache_wsgi - Remove wsgi files,
|
|
||||||
#disable and remove apache vhost file
|
|
||||||
function _cleanup_watcher_apache_wsgi {
|
|
||||||
sudo rm -rf $WATCHER_WSGI_DIR
|
|
||||||
sudo rm -f $(apache_site_config_for watcher-api)
|
|
||||||
restart_apache_server
|
|
||||||
}
|
|
||||||
|
|
||||||
# cleanup_watcher() - Remove residual data files, anything left over from previous
|
|
||||||
# runs that a clean run would need to clean up
|
|
||||||
function cleanup_watcher {
|
|
||||||
sudo rm -rf $WATCHER_STATE_PATH $WATCHER_AUTH_CACHE_DIR
|
|
||||||
if [[ "$WATCHER_USE_MOD_WSGI" == "True" ]]; then
|
|
||||||
_cleanup_watcher_apache_wsgi
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# configure_watcher() - Set config files, create data dirs, etc
|
|
||||||
function configure_watcher {
|
|
||||||
# Put config files in ``/etc/watcher`` for everyone to find
|
|
||||||
sudo install -d -o $STACK_USER $WATCHER_CONF_DIR
|
|
||||||
|
|
||||||
install_default_policy watcher
|
|
||||||
|
|
||||||
# Rebuild the config file from scratch
|
|
||||||
create_watcher_conf
|
|
||||||
}
|
|
||||||
|
|
||||||
# create_watcher_accounts() - Set up common required watcher accounts
|
|
||||||
#
|
|
||||||
# Project User Roles
|
|
||||||
# ------------------------------------------------------------------
|
|
||||||
# SERVICE_TENANT_NAME watcher service
|
|
||||||
function create_watcher_accounts {
|
|
||||||
create_service_user "watcher" "admin"
|
|
||||||
|
|
||||||
local watcher_service=$(get_or_create_service "watcher" \
|
|
||||||
"infra-optim" "Watcher Infrastructure Optimization Service")
|
|
||||||
get_or_create_endpoint $watcher_service \
|
|
||||||
"$REGION_NAME" \
|
|
||||||
"$WATCHER_SERVICE_PROTOCOL://$WATCHER_SERVICE_HOST:$WATCHER_SERVICE_PORT" \
|
|
||||||
"$WATCHER_SERVICE_PROTOCOL://$WATCHER_SERVICE_HOST:$WATCHER_SERVICE_PORT" \
|
|
||||||
"$WATCHER_SERVICE_PROTOCOL://$WATCHER_SERVICE_HOST:$WATCHER_SERVICE_PORT"
|
|
||||||
}
|
|
||||||
|
|
||||||
# _config_watcher_apache_wsgi() - Set WSGI config files of watcher
|
|
||||||
function _config_watcher_apache_wsgi {
|
|
||||||
local watcher_apache_conf
|
|
||||||
if [[ "$WATCHER_USE_MOD_WSGI" == "True" ]]; then
|
|
||||||
sudo mkdir -p $WATCHER_WSGI_DIR
|
|
||||||
sudo cp $WATCHER_DIR/watcher/api/app.wsgi $WATCHER_WSGI_DIR/app.wsgi
|
|
||||||
watcher_apache_conf=$(apache_site_config_for watcher-api)
|
|
||||||
sudo cp $WATCHER_DEVSTACK_FILES_DIR/apache-watcher-api.template $watcher_apache_conf
|
|
||||||
sudo sed -e "
|
|
||||||
s|%WATCHER_SERVICE_PORT%|$WATCHER_SERVICE_PORT|g;
|
|
||||||
s|%WATCHER_WSGI_DIR%|$WATCHER_WSGI_DIR|g;
|
|
||||||
s|%USER%|$STACK_USER|g;
|
|
||||||
s|%APIWORKERS%|$API_WORKERS|g;
|
|
||||||
s|%APACHE_NAME%|$APACHE_NAME|g;
|
|
||||||
" -i $watcher_apache_conf
|
|
||||||
enable_apache_site watcher-api
|
|
||||||
tail_log watcher-access /var/log/$APACHE_NAME/watcher-api-access.log
|
|
||||||
tail_log watcher-api /var/log/$APACHE_NAME/watcher-api.log
|
|
||||||
fi
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
# create_watcher_conf() - Create a new watcher.conf file
|
|
||||||
function create_watcher_conf {
|
|
||||||
# (Re)create ``watcher.conf``
|
|
||||||
rm -f $WATCHER_CONF
|
|
||||||
|
|
||||||
iniset $WATCHER_CONF DEFAULT debug "$ENABLE_DEBUG_LOG_LEVEL"
|
|
||||||
iniset $WATCHER_CONF DEFAULT control_exchange watcher
|
|
||||||
|
|
||||||
iniset $WATCHER_CONF database connection $(database_connection_url watcher)
|
|
||||||
iniset $WATCHER_CONF api host "$WATCHER_SERVICE_HOST"
|
|
||||||
iniset $WATCHER_CONF api port "$WATCHER_SERVICE_PORT"
|
|
||||||
|
|
||||||
iniset $WATCHER_CONF oslo_policy policy_file $WATCHER_POLICY_JSON
|
|
||||||
|
|
||||||
iniset $WATCHER_CONF oslo_messaging_rabbit rabbit_userid $RABBIT_USERID
|
|
||||||
iniset $WATCHER_CONF oslo_messaging_rabbit rabbit_password $RABBIT_PASSWORD
|
|
||||||
iniset $WATCHER_CONF oslo_messaging_rabbit rabbit_host $RABBIT_HOST
|
|
||||||
|
|
||||||
iniset $WATCHER_CONF oslo_messaging_notifications driver "messagingv2"
|
|
||||||
|
|
||||||
iniset $NOVA_CONF oslo_messaging_notifications topics "notifications,watcher_notifications"
|
|
||||||
iniset $NOVA_CONF notifications notify_on_state_change "vm_and_task_state"
|
|
||||||
|
|
||||||
configure_auth_token_middleware $WATCHER_CONF watcher $WATCHER_AUTH_CACHE_DIR
|
|
||||||
configure_auth_token_middleware $WATCHER_CONF watcher $WATCHER_AUTH_CACHE_DIR "watcher_clients_auth"
|
|
||||||
|
|
||||||
if is_fedora || is_suse; then
|
|
||||||
# watcher defaults to /usr/local/bin, but fedora and suse pip like to
|
|
||||||
# install things in /usr/bin
|
|
||||||
iniset $WATCHER_CONF DEFAULT bindir "/usr/bin"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -n "$WATCHER_STATE_PATH" ]; then
|
|
||||||
iniset $WATCHER_CONF DEFAULT state_path "$WATCHER_STATE_PATH"
|
|
||||||
iniset $WATCHER_CONF oslo_concurrency lock_path "$WATCHER_STATE_PATH"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$SYSLOG" != "False" ]; then
|
|
||||||
iniset $WATCHER_CONF DEFAULT use_syslog "True"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Format logging
|
|
||||||
if [ "$LOG_COLOR" == "True" ] && [ "$SYSLOG" == "False" ]; then
|
|
||||||
setup_colorized_logging $WATCHER_CONF DEFAULT
|
|
||||||
else
|
|
||||||
# Show user_name and project_name instead of user_id and project_id
|
|
||||||
iniset $WATCHER_CONF DEFAULT logging_context_format_string "%(asctime)s.%(msecs)03d %(levelname)s %(name)s [%(request_id)s %(project_domain)s %(user_name)s %(project_name)s] %(instance)s%(message)s"
|
|
||||||
fi
|
|
||||||
|
|
||||||
#config apache files
|
|
||||||
if [[ "$WATCHER_USE_MOD_WSGI" == "True" ]]; then
|
|
||||||
_config_watcher_apache_wsgi
|
|
||||||
fi
|
|
||||||
# Register SSL certificates if provided
|
|
||||||
if is_ssl_enabled_service watcher; then
|
|
||||||
ensure_certificates WATCHER
|
|
||||||
|
|
||||||
iniset $WATCHER_CONF DEFAULT ssl_cert_file "$WATCHER_SSL_CERT"
|
|
||||||
iniset $WATCHER_CONF DEFAULT ssl_key_file "$WATCHER_SSL_KEY"
|
|
||||||
|
|
||||||
iniset $WATCHER_CONF DEFAULT enabled_ssl_apis "$WATCHER_ENABLED_APIS"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if is_service_enabled ceilometer; then
|
|
||||||
iniset $WATCHER_CONF watcher_messaging notifier_driver "messaging"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# create_watcher_cache_dir() - Part of the init_watcher() process
|
|
||||||
function create_watcher_cache_dir {
|
|
||||||
# Create cache dir
|
|
||||||
sudo install -d -o $STACK_USER $WATCHER_AUTH_CACHE_DIR
|
|
||||||
rm -rf $WATCHER_AUTH_CACHE_DIR/*
|
|
||||||
}
|
|
||||||
|
|
||||||
# init_watcher() - Initialize databases, etc.
|
|
||||||
function init_watcher {
|
|
||||||
# clean up from previous (possibly aborted) runs
|
|
||||||
# create required data files
|
|
||||||
if is_service_enabled $DATABASE_BACKENDS && is_service_enabled watcher-api; then
|
|
||||||
# (Re)create watcher database
|
|
||||||
recreate_database watcher
|
|
||||||
|
|
||||||
# Create watcher schema
|
|
||||||
$WATCHER_BIN_DIR/watcher-db-manage --config-file $WATCHER_CONF upgrade
|
|
||||||
fi
|
|
||||||
create_watcher_cache_dir
|
|
||||||
}
|
|
||||||
|
|
||||||
# install_watcherclient() - Collect source and prepare
|
|
||||||
function install_watcherclient {
|
|
||||||
if use_library_from_git "python-watcherclient"; then
|
|
||||||
git_clone_by_name "python-watcherclient"
|
|
||||||
setup_dev_lib "python-watcherclient"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# install_watcher() - Collect source and prepare
|
|
||||||
function install_watcher {
|
|
||||||
git_clone $WATCHER_REPO $WATCHER_DIR $WATCHER_BRANCH
|
|
||||||
setup_develop $WATCHER_DIR
|
|
||||||
if [[ "$WATCHER_USE_MOD_WSGI" == "True" ]]; then
|
|
||||||
install_apache_wsgi
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# start_watcher_api() - Start the API process ahead of other things
|
|
||||||
function start_watcher_api {
|
|
||||||
# Get right service port for testing
|
|
||||||
|
|
||||||
local service_port=$WATCHER_SERVICE_PORT
|
|
||||||
local service_protocol=$WATCHER_SERVICE_PROTOCOL
|
|
||||||
if is_service_enabled tls-proxy; then
|
|
||||||
service_port=$WATCHER_SERVICE_PORT_INT
|
|
||||||
service_protocol="http"
|
|
||||||
fi
|
|
||||||
if [[ "$WATCHER_USE_MOD_WSGI" == "True" ]]; then
|
|
||||||
restart_apache_server
|
|
||||||
else
|
|
||||||
run_process watcher-api "$WATCHER_BIN_DIR/watcher-api --config-file $WATCHER_CONF"
|
|
||||||
fi
|
|
||||||
echo "Waiting for watcher-api to start..."
|
|
||||||
if ! wait_for_service $SERVICE_TIMEOUT $service_protocol://$WATCHER_SERVICE_HOST:$service_port; then
|
|
||||||
die $LINENO "watcher-api did not start"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Start proxies if enabled
|
|
||||||
if is_service_enabled tls-proxy; then
|
|
||||||
start_tls_proxy '*' $WATCHER_SERVICE_PORT $WATCHER_SERVICE_HOST $WATCHER_SERVICE_PORT_INT &
|
|
||||||
start_tls_proxy '*' $EC2_SERVICE_PORT $WATCHER_SERVICE_HOST $WATCHER_SERVICE_PORT_INT &
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# start_watcher() - Start running processes, including screen
|
|
||||||
function start_watcher {
|
|
||||||
# ``run_process`` checks ``is_service_enabled``, it is not needed here
|
|
||||||
start_watcher_api
|
|
||||||
run_process watcher-decision-engine "$WATCHER_BIN_DIR/watcher-decision-engine --config-file $WATCHER_CONF"
|
|
||||||
run_process watcher-applier "$WATCHER_BIN_DIR/watcher-applier --config-file $WATCHER_CONF"
|
|
||||||
}
|
|
||||||
|
|
||||||
# stop_watcher() - Stop running processes (non-screen)
|
|
||||||
function stop_watcher {
|
|
||||||
if [[ "$WATCHER_USE_MOD_WSGI" == "True" ]]; then
|
|
||||||
disable_apache_site watcher-api
|
|
||||||
else
|
|
||||||
stop_process watcher-api
|
|
||||||
fi
|
|
||||||
for serv in watcher-decision-engine watcher-applier; do
|
|
||||||
stop_process $serv
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
# Restore xtrace
|
|
||||||
$_XTRACE_WATCHER
|
|
||||||
|
|
||||||
# Tell emacs to use shell-script-mode
|
|
||||||
## Local variables:
|
|
||||||
## mode: shell-script
|
|
||||||
## End:
|
|
@ -1,49 +0,0 @@
|
|||||||
# Sample ``local.conf`` for compute node for Watcher development
|
|
||||||
# NOTE: Copy this file to the root DevStack directory for it to work properly.
|
|
||||||
|
|
||||||
[[local|localrc]]
|
|
||||||
|
|
||||||
ADMIN_PASSWORD=nomoresecrete
|
|
||||||
DATABASE_PASSWORD=stackdb
|
|
||||||
RABBIT_PASSWORD=stackqueue
|
|
||||||
SERVICE_PASSWORD=$ADMIN_PASSWORD
|
|
||||||
SERVICE_TOKEN=azertytoken
|
|
||||||
|
|
||||||
HOST_IP=192.168.42.2 # Change this to this compute node's IP address
|
|
||||||
FLAT_INTERFACE=eth0
|
|
||||||
|
|
||||||
FIXED_RANGE=10.254.1.0/24 # Change this to whatever your network is
|
|
||||||
NETWORK_GATEWAY=10.254.1.1 # Change this for your network
|
|
||||||
|
|
||||||
MULTI_HOST=1
|
|
||||||
|
|
||||||
SERVICE_HOST=192.168.42.1 # Change this to the IP of your controller node
|
|
||||||
MYSQL_HOST=$SERVICE_HOST
|
|
||||||
RABBIT_HOST=$SERVICE_HOST
|
|
||||||
GLANCE_HOSTPORT=${SERVICE_HOST}:9292
|
|
||||||
|
|
||||||
DATABASE_TYPE=mysql
|
|
||||||
|
|
||||||
# Enable services (including neutron)
|
|
||||||
ENABLED_SERVICES=n-cpu,n-api-meta,c-vol,q-agt,placement-client
|
|
||||||
|
|
||||||
NOVA_VNC_ENABLED=True
|
|
||||||
NOVNCPROXY_URL="http://$SERVICE_HOST:6080/vnc_auto.html"
|
|
||||||
VNCSERVER_LISTEN=0.0.0.0
|
|
||||||
VNCSERVER_PROXYCLIENT_ADDRESS=$HOST_IP
|
|
||||||
|
|
||||||
NOVA_INSTANCES_PATH=/opt/stack/data/instances
|
|
||||||
|
|
||||||
# Enable the Ceilometer plugin for the compute agent
|
|
||||||
enable_plugin ceilometer git://git.openstack.org/openstack/ceilometer
|
|
||||||
disable_service ceilometer-acentral,ceilometer-collector,ceilometer-api
|
|
||||||
|
|
||||||
LOGFILE=$DEST/logs/stack.sh.log
|
|
||||||
LOGDAYS=2
|
|
||||||
|
|
||||||
[[post-config|$NOVA_CONF]]
|
|
||||||
[DEFAULT]
|
|
||||||
compute_monitors=cpu.virt_driver
|
|
||||||
notify_on_state_change = vm_and_task_state
|
|
||||||
[notifications]
|
|
||||||
notify_on_state_change = vm_and_task_state
|
|
@ -1,59 +0,0 @@
|
|||||||
# Sample ``local.conf`` for controller node for Watcher development
|
|
||||||
# NOTE: Copy this file to the root DevStack directory for it to work properly.
|
|
||||||
|
|
||||||
[[local|localrc]]
|
|
||||||
|
|
||||||
ADMIN_PASSWORD=nomoresecrete
|
|
||||||
DATABASE_PASSWORD=stackdb
|
|
||||||
RABBIT_PASSWORD=stackqueue
|
|
||||||
SERVICE_PASSWORD=$ADMIN_PASSWORD
|
|
||||||
SERVICE_TOKEN=azertytoken
|
|
||||||
|
|
||||||
HOST_IP=192.168.42.1 # Change this to your controller node IP address
|
|
||||||
FLAT_INTERFACE=eth0
|
|
||||||
|
|
||||||
FIXED_RANGE=10.254.1.0/24 # Change this to whatever your network is
|
|
||||||
NETWORK_GATEWAY=10.254.1.1 # Change this for your network
|
|
||||||
|
|
||||||
MULTI_HOST=1
|
|
||||||
|
|
||||||
|
|
||||||
#Set this to FALSE if do not want to run watcher-api behind mod-wsgi
|
|
||||||
#WATCHER_USE_MOD_WSGI=TRUE
|
|
||||||
|
|
||||||
# This is the controller node, so disable nova-compute
|
|
||||||
disable_service n-cpu
|
|
||||||
|
|
||||||
# Disable nova-network and use neutron instead
|
|
||||||
disable_service n-net
|
|
||||||
ENABLED_SERVICES+=,q-svc,q-dhcp,q-meta,q-agt,q-l3,neutron
|
|
||||||
|
|
||||||
# Enable remote console access
|
|
||||||
enable_service n-cauth
|
|
||||||
|
|
||||||
# Enable the Watcher Dashboard plugin
|
|
||||||
enable_plugin watcher-dashboard git://git.openstack.org/openstack/watcher-dashboard
|
|
||||||
|
|
||||||
# Enable the Watcher plugin
|
|
||||||
enable_plugin watcher git://git.openstack.org/openstack/watcher
|
|
||||||
|
|
||||||
# Enable the Ceilometer plugin
|
|
||||||
enable_plugin ceilometer git://git.openstack.org/openstack/ceilometer
|
|
||||||
|
|
||||||
# This is the controller node, so disable the ceilometer compute agent
|
|
||||||
disable_service ceilometer-acompute
|
|
||||||
# Enable the ceilometer api explicitly(bug:1667678)
|
|
||||||
enable_service ceilometer-api
|
|
||||||
|
|
||||||
# Enable the Gnocchi plugin
|
|
||||||
enable_plugin gnocchi https://git.openstack.org/openstack/gnocchi
|
|
||||||
|
|
||||||
LOGFILE=$DEST/logs/stack.sh.log
|
|
||||||
LOGDAYS=2
|
|
||||||
|
|
||||||
[[post-config|$NOVA_CONF]]
|
|
||||||
[DEFAULT]
|
|
||||||
compute_monitors=cpu.virt_driver
|
|
||||||
notify_on_state_change = vm_and_task_state
|
|
||||||
[notifications]
|
|
||||||
notify_on_state_change = vm_and_task_state
|
|
@ -1,53 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
# plugin.sh - DevStack plugin script to install watcher
|
|
||||||
|
|
||||||
# Save trace setting
|
|
||||||
_XTRACE_WATCHER_PLUGIN=$(set +o | grep xtrace)
|
|
||||||
set -o xtrace
|
|
||||||
|
|
||||||
echo_summary "watcher's plugin.sh was called..."
|
|
||||||
source $DEST/watcher/devstack/lib/watcher
|
|
||||||
|
|
||||||
# Show all of defined environment variables
|
|
||||||
(set -o posix; set)
|
|
||||||
|
|
||||||
if is_service_enabled watcher-api watcher-decision-engine watcher-applier; then
|
|
||||||
if [[ "$1" == "stack" && "$2" == "pre-install" ]]; then
|
|
||||||
echo_summary "Before Installing watcher"
|
|
||||||
elif [[ "$1" == "stack" && "$2" == "install" ]]; then
|
|
||||||
echo_summary "Installing watcher"
|
|
||||||
install_watcher
|
|
||||||
|
|
||||||
LIBS_FROM_GIT="${LIBS_FROM_GIT},python-watcherclient"
|
|
||||||
|
|
||||||
install_watcherclient
|
|
||||||
cleanup_watcher
|
|
||||||
elif [[ "$1" == "stack" && "$2" == "post-config" ]]; then
|
|
||||||
echo_summary "Configuring watcher"
|
|
||||||
configure_watcher
|
|
||||||
|
|
||||||
if is_service_enabled key; then
|
|
||||||
create_watcher_accounts
|
|
||||||
fi
|
|
||||||
|
|
||||||
elif [[ "$1" == "stack" && "$2" == "extra" ]]; then
|
|
||||||
# Initialize watcher
|
|
||||||
init_watcher
|
|
||||||
|
|
||||||
# Start the watcher components
|
|
||||||
echo_summary "Starting watcher"
|
|
||||||
start_watcher
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$1" == "unstack" ]]; then
|
|
||||||
stop_watcher
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$1" == "clean" ]]; then
|
|
||||||
cleanup_watcher
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Restore xtrace
|
|
||||||
$_XTRACE_WATCHER_PLUGIN
|
|
@ -1,9 +0,0 @@
|
|||||||
# DevStack settings
|
|
||||||
|
|
||||||
# Make sure rabbit is enabled
|
|
||||||
enable_service rabbit
|
|
||||||
|
|
||||||
# Enable Watcher services
|
|
||||||
enable_service watcher-api
|
|
||||||
enable_service watcher-decision-engine
|
|
||||||
enable_service watcher-applier
|
|
172
doc/ext/term.py
@ -1,172 +0,0 @@
|
|||||||
# Copyright (c) 2015 b<>com
|
|
||||||
#
|
|
||||||
# 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 __future__ import unicode_literals
|
|
||||||
|
|
||||||
import importlib
|
|
||||||
import inspect
|
|
||||||
|
|
||||||
from docutils import nodes
|
|
||||||
from docutils.parsers import rst
|
|
||||||
from docutils import statemachine
|
|
||||||
|
|
||||||
from watcher.version import version_info
|
|
||||||
|
|
||||||
|
|
||||||
class BaseWatcherDirective(rst.Directive):
|
|
||||||
|
|
||||||
def __init__(self, name, arguments, options, content, lineno,
|
|
||||||
content_offset, block_text, state, state_machine):
|
|
||||||
super(BaseWatcherDirective, self).__init__(
|
|
||||||
name, arguments, options, content, lineno,
|
|
||||||
content_offset, block_text, state, state_machine)
|
|
||||||
self.result = statemachine.ViewList()
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
raise NotImplementedError('Must override run() is subclass.')
|
|
||||||
|
|
||||||
def add_line(self, line, *lineno):
|
|
||||||
"""Append one line of generated reST to the output."""
|
|
||||||
self.result.append(line, rst.directives.unchanged, *lineno)
|
|
||||||
|
|
||||||
def add_textblock(self, textblock):
|
|
||||||
for line in textblock.splitlines():
|
|
||||||
self.add_line(line)
|
|
||||||
|
|
||||||
def add_object_docstring(self, obj):
|
|
||||||
obj_raw_docstring = obj.__doc__ or ""
|
|
||||||
|
|
||||||
# Maybe it's within the __init__
|
|
||||||
if not obj_raw_docstring and hasattr(obj, "__init__"):
|
|
||||||
if obj.__init__.__doc__:
|
|
||||||
obj_raw_docstring = obj.__init__.__doc__
|
|
||||||
|
|
||||||
if not obj_raw_docstring:
|
|
||||||
# Raise a warning to make the tests fail wit doc8
|
|
||||||
raise self.error("No docstring available for %s!" % obj)
|
|
||||||
|
|
||||||
obj_docstring = inspect.cleandoc(obj_raw_docstring)
|
|
||||||
self.add_textblock(obj_docstring)
|
|
||||||
|
|
||||||
|
|
||||||
class WatcherTerm(BaseWatcherDirective):
|
|
||||||
"""Directive to import an RST formatted docstring into the Watcher glossary
|
|
||||||
|
|
||||||
**How to use it**
|
|
||||||
|
|
||||||
# inside your .py file
|
|
||||||
class DocumentedObject(object):
|
|
||||||
'''My *.rst* docstring'''
|
|
||||||
|
|
||||||
|
|
||||||
# Inside your .rst file
|
|
||||||
.. watcher-term:: import.path.to.your.DocumentedObject
|
|
||||||
|
|
||||||
This directive will then import the docstring and then interpret it.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# You need to put an import path as an argument for this directive to work
|
|
||||||
required_arguments = 1
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
cls_path = self.arguments[0]
|
|
||||||
|
|
||||||
try:
|
|
||||||
try:
|
|
||||||
cls = importlib.import_module(cls_path)
|
|
||||||
except ImportError:
|
|
||||||
module_name, cls_name = cls_path.rsplit('.', 1)
|
|
||||||
mod = importlib.import_module(module_name)
|
|
||||||
cls = getattr(mod, cls_name)
|
|
||||||
except Exception as exc:
|
|
||||||
raise self.error(exc)
|
|
||||||
|
|
||||||
self.add_object_docstring(cls)
|
|
||||||
|
|
||||||
node = nodes.paragraph()
|
|
||||||
node.document = self.state.document
|
|
||||||
self.state.nested_parse(self.result, 0, node)
|
|
||||||
return node.children
|
|
||||||
|
|
||||||
|
|
||||||
class WatcherFunc(BaseWatcherDirective):
|
|
||||||
"""Directive to import a value returned by a func into the Watcher doc
|
|
||||||
|
|
||||||
**How to use it**
|
|
||||||
|
|
||||||
# inside your .py file
|
|
||||||
class Bar(object):
|
|
||||||
|
|
||||||
def foo(object):
|
|
||||||
return foo_string
|
|
||||||
|
|
||||||
|
|
||||||
# Inside your .rst file
|
|
||||||
.. watcher-func:: import.path.to.your.Bar.foo node_classname
|
|
||||||
|
|
||||||
node_classname is decumented here:
|
|
||||||
http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html
|
|
||||||
|
|
||||||
This directive will then import the value and then interpret it.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# You need to put an import path as an argument for this directive to work
|
|
||||||
# required_arguments = 1
|
|
||||||
# optional_arguments = 1
|
|
||||||
|
|
||||||
option_spec = {'format': rst.directives.unchanged}
|
|
||||||
has_content = True
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
if not self.content:
|
|
||||||
error = self.state_machine.reporter.error(
|
|
||||||
'The "%s" directive is empty; content required.' % self.name,
|
|
||||||
nodes.literal_block(self.block_text, self.block_text),
|
|
||||||
line=self.lineno)
|
|
||||||
return [error]
|
|
||||||
|
|
||||||
func_path = self.content[0]
|
|
||||||
try:
|
|
||||||
cls_path, func_name = func_path.rsplit('.', 1)
|
|
||||||
module_name, cls_name = cls_path.rsplit('.', 1)
|
|
||||||
mod = importlib.import_module(module_name)
|
|
||||||
cls = getattr(mod, cls_name)
|
|
||||||
except Exception as exc:
|
|
||||||
raise self.error(exc)
|
|
||||||
|
|
||||||
cls_obj = cls()
|
|
||||||
func = getattr(cls_obj, func_name)
|
|
||||||
textblock = func()
|
|
||||||
if not isinstance(textblock, str):
|
|
||||||
textblock = str(textblock)
|
|
||||||
|
|
||||||
self.add_textblock(textblock)
|
|
||||||
|
|
||||||
try:
|
|
||||||
node_class = getattr(nodes,
|
|
||||||
self.options.get('format', 'paragraph'))
|
|
||||||
except Exception as exc:
|
|
||||||
raise self.error(exc)
|
|
||||||
|
|
||||||
node = node_class()
|
|
||||||
node.document = self.state.document
|
|
||||||
self.state.nested_parse(self.result, 0, node)
|
|
||||||
return [node]
|
|
||||||
|
|
||||||
|
|
||||||
def setup(app):
|
|
||||||
app.add_directive('watcher-term', WatcherTerm)
|
|
||||||
app.add_directive('watcher-func', WatcherFunc)
|
|
||||||
return {'version': version_info.version_string()}
|
|
@ -1,133 +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 provides a sphinx extension able to list the implemented versioned
|
|
||||||
notifications into the developer documentation.
|
|
||||||
|
|
||||||
It is used via a single directive in the .rst file
|
|
||||||
|
|
||||||
.. versioned_notifications::
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
from sphinx.util.compat import Directive
|
|
||||||
from docutils import nodes
|
|
||||||
|
|
||||||
from watcher.notifications import base as notification
|
|
||||||
from watcher.objects import base
|
|
||||||
|
|
||||||
|
|
||||||
class VersionedNotificationDirective(Directive):
|
|
||||||
|
|
||||||
SAMPLE_ROOT = 'doc/notification_samples/'
|
|
||||||
TOGGLE_SCRIPT = """
|
|
||||||
<script>
|
|
||||||
jQuery(document).ready(function(){
|
|
||||||
jQuery('#%s-div').toggle('show');
|
|
||||||
jQuery('#%s-hideshow').on('click', function(event) {
|
|
||||||
jQuery('#%s-div').toggle('show');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
"""
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
notifications = self._collect_notifications()
|
|
||||||
return self._build_markup(notifications)
|
|
||||||
|
|
||||||
def _collect_notifications(self):
|
|
||||||
base.WatcherObjectRegistry.register_notification_objects()
|
|
||||||
notifications = []
|
|
||||||
ovos = base.WatcherObjectRegistry.obj_classes()
|
|
||||||
for name, cls in ovos.items():
|
|
||||||
cls = cls[0]
|
|
||||||
if (issubclass(cls, notification.NotificationBase) and
|
|
||||||
cls != notification.NotificationBase):
|
|
||||||
|
|
||||||
payload_name = cls.fields['payload'].objname
|
|
||||||
payload_cls = ovos[payload_name][0]
|
|
||||||
for sample in cls.samples:
|
|
||||||
notifications.append((cls.__name__,
|
|
||||||
payload_cls.__name__,
|
|
||||||
sample))
|
|
||||||
return sorted(notifications)
|
|
||||||
|
|
||||||
def _build_markup(self, notifications):
|
|
||||||
content = []
|
|
||||||
cols = ['Event type', 'Notification class', 'Payload class', 'Sample']
|
|
||||||
table = nodes.table()
|
|
||||||
content.append(table)
|
|
||||||
group = nodes.tgroup(cols=len(cols))
|
|
||||||
table.append(group)
|
|
||||||
|
|
||||||
head = nodes.thead()
|
|
||||||
group.append(head)
|
|
||||||
|
|
||||||
for _ in cols:
|
|
||||||
group.append(nodes.colspec(colwidth=1))
|
|
||||||
|
|
||||||
body = nodes.tbody()
|
|
||||||
group.append(body)
|
|
||||||
|
|
||||||
# fill the table header
|
|
||||||
row = nodes.row()
|
|
||||||
body.append(row)
|
|
||||||
for col_name in cols:
|
|
||||||
col = nodes.entry()
|
|
||||||
row.append(col)
|
|
||||||
text = nodes.strong(text=col_name)
|
|
||||||
col.append(text)
|
|
||||||
|
|
||||||
# fill the table content, one notification per row
|
|
||||||
for name, payload, sample_file in notifications:
|
|
||||||
event_type = sample_file[0: -5].replace('-', '.')
|
|
||||||
|
|
||||||
row = nodes.row()
|
|
||||||
body.append(row)
|
|
||||||
col = nodes.entry()
|
|
||||||
row.append(col)
|
|
||||||
text = nodes.literal(text=event_type)
|
|
||||||
col.append(text)
|
|
||||||
|
|
||||||
col = nodes.entry()
|
|
||||||
row.append(col)
|
|
||||||
text = nodes.literal(text=name)
|
|
||||||
col.append(text)
|
|
||||||
|
|
||||||
col = nodes.entry()
|
|
||||||
row.append(col)
|
|
||||||
text = nodes.literal(text=payload)
|
|
||||||
col.append(text)
|
|
||||||
|
|
||||||
col = nodes.entry()
|
|
||||||
row.append(col)
|
|
||||||
|
|
||||||
with open(self.SAMPLE_ROOT + sample_file, 'r') as f:
|
|
||||||
sample_content = f.read()
|
|
||||||
|
|
||||||
event_type = sample_file[0: -5]
|
|
||||||
html_str = self.TOGGLE_SCRIPT % ((event_type, ) * 3)
|
|
||||||
html_str += ("<input type='button' id='%s-hideshow' "
|
|
||||||
"value='hide/show sample'>" % event_type)
|
|
||||||
html_str += ("<div id='%s-div'><pre>%s</pre></div>"
|
|
||||||
% (event_type, sample_content))
|
|
||||||
|
|
||||||
raw = nodes.raw('', html_str, format="html")
|
|
||||||
col.append(raw)
|
|
||||||
|
|
||||||
return content
|
|
||||||
|
|
||||||
|
|
||||||
def setup(app):
|
|
||||||
app.add_directive('versioned_notifications',
|
|
||||||
VersionedNotificationDirective)
|
|
@ -1,40 +0,0 @@
|
|||||||
{
|
|
||||||
"priority": "INFO",
|
|
||||||
"payload": {
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.name": "ActionCreatePayload",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
|
||||||
"input_parameters": {
|
|
||||||
"param2": 2,
|
|
||||||
"param1": 1
|
|
||||||
},
|
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
|
||||||
"updated_at": null,
|
|
||||||
"state": "PENDING",
|
|
||||||
"action_plan": {
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.name": "TerseActionPlanPayload",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
|
||||||
"global_efficacy": {},
|
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
|
||||||
"updated_at": null,
|
|
||||||
"state": "ONGOING",
|
|
||||||
"audit_uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
|
||||||
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
|
||||||
"deleted_at": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"parents": [],
|
|
||||||
"action_type": "nop",
|
|
||||||
"deleted_at": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"publisher_id": "infra-optim:node0",
|
|
||||||
"timestamp": "2017-01-01 00:00:00.000000",
|
|
||||||
"event_type": "action.create",
|
|
||||||
"message_id": "530b409c-9b6b-459b-8f08-f93dbfeb4d41"
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
{
|
|
||||||
"priority": "INFO",
|
|
||||||
"payload": {
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.name": "ActionDeletePayload",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
|
||||||
"input_parameters": {
|
|
||||||
"param2": 2,
|
|
||||||
"param1": 1
|
|
||||||
},
|
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
|
||||||
"updated_at": null,
|
|
||||||
"state": "DELETED",
|
|
||||||
"action_plan": {
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.name": "TerseActionPlanPayload",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
|
||||||
"global_efficacy": {},
|
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
|
||||||
"updated_at": null,
|
|
||||||
"state": "ONGOING",
|
|
||||||
"audit_uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
|
||||||
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
|
||||||
"deleted_at": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"parents": [],
|
|
||||||
"action_type": "nop",
|
|
||||||
"deleted_at": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"publisher_id": "infra-optim:node0",
|
|
||||||
"timestamp": "2017-01-01 00:00:00.000000",
|
|
||||||
"event_type": "action.delete",
|
|
||||||
"message_id": "530b409c-9b6b-459b-8f08-f93dbfeb4d41"
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
{
|
|
||||||
"priority": "INFO",
|
|
||||||
"payload": {
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.name": "ActionExecutionPayload",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
|
||||||
"input_parameters": {
|
|
||||||
"param2": 2,
|
|
||||||
"param1": 1
|
|
||||||
},
|
|
||||||
"fault": null,
|
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
|
||||||
"updated_at": null,
|
|
||||||
"state": "SUCCEEDED",
|
|
||||||
"action_plan": {
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.name": "TerseActionPlanPayload",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
|
||||||
"global_efficacy": {},
|
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
|
||||||
"updated_at": null,
|
|
||||||
"state": "ONGOING",
|
|
||||||
"audit_uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
|
||||||
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
|
||||||
"deleted_at": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"parents": [],
|
|
||||||
"action_type": "nop",
|
|
||||||
"deleted_at": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"event_type": "action.execution.end",
|
|
||||||
"publisher_id": "infra-optim:node0",
|
|
||||||
"timestamp": "2017-01-01 00:00:00.000000",
|
|
||||||
"message_id": "530b409c-9b6b-459b-8f08-f93dbfeb4d41"
|
|
||||||
}
|
|
@ -1,51 +0,0 @@
|
|||||||
{
|
|
||||||
"priority": "ERROR",
|
|
||||||
"payload": {
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.name": "ActionExecutionPayload",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
|
||||||
"input_parameters": {
|
|
||||||
"param2": 2,
|
|
||||||
"param1": 1
|
|
||||||
},
|
|
||||||
"fault": {
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.name": "ExceptionPayload",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"module_name": "watcher.tests.notifications.test_action_notification",
|
|
||||||
"exception": "WatcherException",
|
|
||||||
"exception_message": "TEST",
|
|
||||||
"function_name": "test_send_action_execution_with_error"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
|
||||||
"updated_at": null,
|
|
||||||
"state": "FAILED",
|
|
||||||
"action_plan": {
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.name": "TerseActionPlanPayload",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
|
||||||
"global_efficacy": {},
|
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
|
||||||
"updated_at": null,
|
|
||||||
"state": "ONGOING",
|
|
||||||
"audit_uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
|
||||||
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
|
||||||
"deleted_at": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"parents": [],
|
|
||||||
"action_type": "nop",
|
|
||||||
"deleted_at": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"event_type": "action.execution.error",
|
|
||||||
"publisher_id": "infra-optim:node0",
|
|
||||||
"timestamp": "2017-01-01 00:00:00.000000",
|
|
||||||
"message_id": "530b409c-9b6b-459b-8f08-f93dbfeb4d41"
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
{
|
|
||||||
"priority": "INFO",
|
|
||||||
"payload": {
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.name": "ActionExecutionPayload",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
|
||||||
"input_parameters": {
|
|
||||||
"param2": 2,
|
|
||||||
"param1": 1
|
|
||||||
},
|
|
||||||
"fault": null,
|
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
|
||||||
"updated_at": null,
|
|
||||||
"state": "ONGOING",
|
|
||||||
"action_plan": {
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.name": "TerseActionPlanPayload",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
|
||||||
"global_efficacy": {},
|
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
|
||||||
"updated_at": null,
|
|
||||||
"state": "ONGOING",
|
|
||||||
"audit_uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
|
||||||
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
|
||||||
"deleted_at": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"parents": [],
|
|
||||||
"action_type": "nop",
|
|
||||||
"deleted_at": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"event_type": "action.execution.start",
|
|
||||||
"publisher_id": "infra-optim:node0",
|
|
||||||
"timestamp": "2017-01-01 00:00:00.000000",
|
|
||||||
"message_id": "530b409c-9b6b-459b-8f08-f93dbfeb4d41"
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
{
|
|
||||||
"priority": "INFO",
|
|
||||||
"payload": {
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.name": "ActionUpdatePayload",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
|
||||||
"input_parameters": {
|
|
||||||
"param2": 2,
|
|
||||||
"param1": 1
|
|
||||||
},
|
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
|
||||||
"updated_at": null,
|
|
||||||
"state_update": {
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.name": "ActionStateUpdatePayload",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"old_state": "PENDING",
|
|
||||||
"state": "ONGOING"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"state": "ONGOING",
|
|
||||||
"action_plan": {
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.name": "TerseActionPlanPayload",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
|
||||||
"global_efficacy": {},
|
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
|
||||||
"updated_at": null,
|
|
||||||
"state": "ONGOING",
|
|
||||||
"audit_uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
|
||||||
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
|
||||||
"deleted_at": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"parents": [],
|
|
||||||
"action_type": "nop",
|
|
||||||
"deleted_at": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"event_type": "action.update",
|
|
||||||
"publisher_id": "infra-optim:node0",
|
|
||||||
"timestamp": "2017-01-01 00:00:00.000000",
|
|
||||||
"message_id": "530b409c-9b6b-459b-8f08-f93dbfeb4d41"
|
|
||||||
}
|
|
@ -1,54 +0,0 @@
|
|||||||
{
|
|
||||||
"publisher_id": "infra-optim:node0",
|
|
||||||
"payload": {
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
|
||||||
"strategy": {
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
|
||||||
"display_name": "test strategy",
|
|
||||||
"name": "TEST",
|
|
||||||
"updated_at": null,
|
|
||||||
"parameters_spec": {},
|
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
|
||||||
"deleted_at": null
|
|
||||||
},
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.name": "StrategyPayload"
|
|
||||||
},
|
|
||||||
"created_at": null,
|
|
||||||
"audit_uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
|
||||||
"audit": {
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"audit_type": "ONESHOT",
|
|
||||||
"scope": [],
|
|
||||||
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
|
||||||
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
|
||||||
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
|
||||||
"parameters": {},
|
|
||||||
"interval": null,
|
|
||||||
"deleted_at": null,
|
|
||||||
"state": "PENDING",
|
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
|
||||||
"updated_at": null
|
|
||||||
},
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.name": "TerseAuditPayload"
|
|
||||||
},
|
|
||||||
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
|
||||||
"global_efficacy": {},
|
|
||||||
"deleted_at": null,
|
|
||||||
"state": "RECOMMENDED",
|
|
||||||
"updated_at": null
|
|
||||||
},
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.name": "ActionPlanCreatePayload"
|
|
||||||
},
|
|
||||||
"priority": "INFO",
|
|
||||||
"message_id": "5148bff1-ea06-4ad6-8e4e-8c85ca5eb629",
|
|
||||||
"event_type": "action_plan.create",
|
|
||||||
"timestamp": "2016-10-18 09:52:05.219414"
|
|
||||||
}
|
|
@ -1,54 +0,0 @@
|
|||||||
{
|
|
||||||
"publisher_id": "infra-optim:node0",
|
|
||||||
"timestamp": "2016-10-18 09:52:05.219414",
|
|
||||||
"payload": {
|
|
||||||
"watcher_object.data": {
|
|
||||||
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
|
||||||
"audit_uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
|
||||||
"audit": {
|
|
||||||
"watcher_object.data": {
|
|
||||||
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
|
||||||
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
|
||||||
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
|
||||||
"interval": null,
|
|
||||||
"audit_type": "ONESHOT",
|
|
||||||
"scope": [],
|
|
||||||
"updated_at": null,
|
|
||||||
"deleted_at": null,
|
|
||||||
"state": "PENDING",
|
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
|
||||||
"parameters": {}
|
|
||||||
},
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.name": "TerseAuditPayload",
|
|
||||||
"watcher_object.namespace": "watcher"
|
|
||||||
},
|
|
||||||
"global_efficacy": {},
|
|
||||||
"updated_at": null,
|
|
||||||
"deleted_at": null,
|
|
||||||
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
|
||||||
"strategy": {
|
|
||||||
"watcher_object.data": {
|
|
||||||
"uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
|
||||||
"name": "TEST",
|
|
||||||
"display_name": "test strategy",
|
|
||||||
"deleted_at": null,
|
|
||||||
"updated_at": null,
|
|
||||||
"parameters_spec": {}
|
|
||||||
},
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.name": "StrategyPayload",
|
|
||||||
"watcher_object.namespace": "watcher"
|
|
||||||
},
|
|
||||||
"state": "DELETED"
|
|
||||||
},
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.name": "ActionPlanDeletePayload",
|
|
||||||
"watcher_object.namespace": "watcher"
|
|
||||||
},
|
|
||||||
"event_type": "action_plan.delete",
|
|
||||||
"message_id": "3d137686-a1fd-4683-ab40-c4210aac2140",
|
|
||||||
"priority": "INFO"
|
|
||||||
}
|
|
@ -1,55 +0,0 @@
|
|||||||
{
|
|
||||||
"event_type": "action_plan.execution.end",
|
|
||||||
"payload": {
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.name": "ActionPlanActionPayload",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
|
||||||
"deleted_at": null,
|
|
||||||
"audit_uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
|
||||||
"audit": {
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.name": "TerseAuditPayload",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
|
||||||
"deleted_at": null,
|
|
||||||
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
|
||||||
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
|
||||||
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
|
||||||
"scope": [],
|
|
||||||
"audit_type": "ONESHOT",
|
|
||||||
"state": "SUCCEEDED",
|
|
||||||
"parameters": {},
|
|
||||||
"interval": null,
|
|
||||||
"updated_at": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
|
||||||
"fault": null,
|
|
||||||
"state": "ONGOING",
|
|
||||||
"global_efficacy": {},
|
|
||||||
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
|
||||||
"strategy": {
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.name": "StrategyPayload",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
|
||||||
"deleted_at": null,
|
|
||||||
"name": "TEST",
|
|
||||||
"uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
|
||||||
"parameters_spec": {},
|
|
||||||
"display_name": "test strategy",
|
|
||||||
"updated_at": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"updated_at": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"priority": "INFO",
|
|
||||||
"message_id": "3984dc2b-8aef-462b-a220-8ae04237a56e",
|
|
||||||
"timestamp": "2016-10-18 09:52:05.219414",
|
|
||||||
"publisher_id": "infra-optim:node0"
|
|
||||||
}
|
|
@ -1,65 +0,0 @@
|
|||||||
{
|
|
||||||
"event_type": "action_plan.execution.error",
|
|
||||||
"publisher_id": "infra-optim:node0",
|
|
||||||
"priority": "ERROR",
|
|
||||||
"message_id": "9a45c5ae-0e21-4300-8fa0-5555d52a66d9",
|
|
||||||
"payload": {
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.name": "ActionPlanActionPayload",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"fault": {
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.name": "ExceptionPayload",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"exception_message": "TEST",
|
|
||||||
"module_name": "watcher.tests.notifications.test_action_plan_notification",
|
|
||||||
"function_name": "test_send_action_plan_action_with_error",
|
|
||||||
"exception": "WatcherException"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
|
||||||
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
|
||||||
"strategy": {
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.name": "StrategyPayload",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
|
||||||
"name": "TEST",
|
|
||||||
"updated_at": null,
|
|
||||||
"display_name": "test strategy",
|
|
||||||
"parameters_spec": {},
|
|
||||||
"deleted_at": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"updated_at": null,
|
|
||||||
"deleted_at": null,
|
|
||||||
"audit_uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
|
||||||
"audit": {
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.name": "TerseAuditPayload",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"parameters": {},
|
|
||||||
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
|
||||||
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
|
||||||
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
|
||||||
"scope": [],
|
|
||||||
"updated_at": null,
|
|
||||||
"audit_type": "ONESHOT",
|
|
||||||
"interval": null,
|
|
||||||
"deleted_at": null,
|
|
||||||
"state": "PENDING"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"global_efficacy": {},
|
|
||||||
"state": "ONGOING"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"timestamp": "2016-10-18 09:52:05.219414"
|
|
||||||
}
|
|
@ -1,55 +0,0 @@
|
|||||||
{
|
|
||||||
"event_type": "action_plan.execution.start",
|
|
||||||
"payload": {
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.name": "ActionPlanActionPayload",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
|
||||||
"deleted_at": null,
|
|
||||||
"audit_uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
|
||||||
"audit": {
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.name": "TerseAuditPayload",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
|
||||||
"deleted_at": null,
|
|
||||||
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
|
||||||
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
|
||||||
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
|
||||||
"scope": [],
|
|
||||||
"audit_type": "ONESHOT",
|
|
||||||
"state": "PENDING",
|
|
||||||
"parameters": {},
|
|
||||||
"interval": null,
|
|
||||||
"updated_at": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
|
||||||
"fault": null,
|
|
||||||
"state": "ONGOING",
|
|
||||||
"global_efficacy": {},
|
|
||||||
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
|
||||||
"strategy": {
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.name": "StrategyPayload",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
|
||||||
"deleted_at": null,
|
|
||||||
"name": "TEST",
|
|
||||||
"uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
|
||||||
"parameters_spec": {},
|
|
||||||
"display_name": "test strategy",
|
|
||||||
"updated_at": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"updated_at": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"priority": "INFO",
|
|
||||||
"message_id": "3984dc2b-8aef-462b-a220-8ae04237a56e",
|
|
||||||
"timestamp": "2016-10-18 09:52:05.219414",
|
|
||||||
"publisher_id": "infra-optim:node0"
|
|
||||||
}
|
|
@ -1,63 +0,0 @@
|
|||||||
{
|
|
||||||
"payload": {
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"audit_uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
|
||||||
"audit": {
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"audit_type": "ONESHOT",
|
|
||||||
"scope": [],
|
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
|
||||||
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
|
||||||
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
|
||||||
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
|
||||||
"interval": null,
|
|
||||||
"updated_at": null,
|
|
||||||
"state": "PENDING",
|
|
||||||
"deleted_at": null,
|
|
||||||
"parameters": {}
|
|
||||||
},
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.name": "TerseAuditPayload"
|
|
||||||
},
|
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
|
||||||
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
|
||||||
"updated_at": null,
|
|
||||||
"state_update": {
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"old_state": "PENDING",
|
|
||||||
"state": "ONGOING"
|
|
||||||
},
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.name": "ActionPlanStateUpdatePayload"
|
|
||||||
},
|
|
||||||
"state": "ONGOING",
|
|
||||||
"deleted_at": null,
|
|
||||||
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
|
||||||
"strategy": {
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"name": "TEST",
|
|
||||||
"uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
|
||||||
"display_name": "test strategy",
|
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
|
||||||
"updated_at": null,
|
|
||||||
"deleted_at": null,
|
|
||||||
"parameters_spec": {}
|
|
||||||
},
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.name": "StrategyPayload"
|
|
||||||
},
|
|
||||||
"global_efficacy": {}
|
|
||||||
},
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.name": "ActionPlanUpdatePayload"
|
|
||||||
},
|
|
||||||
"publisher_id": "infra-optim:node0",
|
|
||||||
"priority": "INFO",
|
|
||||||
"timestamp": "2016-10-18 09:52:05.219414",
|
|
||||||
"event_type": "action_plan.update",
|
|
||||||
"message_id": "0a8a7329-fd5a-4ec6-97d7-2b776ce51a4c"
|
|
||||||
}
|
|
@ -1,71 +0,0 @@
|
|||||||
{
|
|
||||||
"priority": "INFO",
|
|
||||||
"payload": {
|
|
||||||
"watcher_object.data": {
|
|
||||||
"audit_type": "ONESHOT",
|
|
||||||
"parameters": {
|
|
||||||
"para2": "hello",
|
|
||||||
"para1": 3.2
|
|
||||||
},
|
|
||||||
"state": "PENDING",
|
|
||||||
"updated_at": null,
|
|
||||||
"deleted_at": null,
|
|
||||||
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
|
||||||
"goal": {
|
|
||||||
"watcher_object.data": {
|
|
||||||
"uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
|
||||||
"name": "dummy",
|
|
||||||
"updated_at": null,
|
|
||||||
"deleted_at": null,
|
|
||||||
"efficacy_specification": [],
|
|
||||||
"created_at": "2016-11-04T16:25:35Z",
|
|
||||||
"display_name": "Dummy goal"
|
|
||||||
},
|
|
||||||
"watcher_object.name": "GoalPayload",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.namespace": "watcher"
|
|
||||||
},
|
|
||||||
"interval": null,
|
|
||||||
"scope": [],
|
|
||||||
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
|
||||||
"strategy": {
|
|
||||||
"watcher_object.data": {
|
|
||||||
"parameters_spec": {
|
|
||||||
"properties": {
|
|
||||||
"para2": {
|
|
||||||
"type": "string",
|
|
||||||
"default": "hello",
|
|
||||||
"description": "string parameter example"
|
|
||||||
},
|
|
||||||
"para1": {
|
|
||||||
"description": "number parameter example",
|
|
||||||
"maximum": 10.2,
|
|
||||||
"type": "number",
|
|
||||||
"default": 3.2,
|
|
||||||
"minimum": 1.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"name": "dummy",
|
|
||||||
"uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
|
||||||
"updated_at": null,
|
|
||||||
"deleted_at": null,
|
|
||||||
"created_at": "2016-11-04T16:25:35Z",
|
|
||||||
"display_name": "Dummy strategy"
|
|
||||||
},
|
|
||||||
"watcher_object.name": "StrategyPayload",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.namespace": "watcher"
|
|
||||||
},
|
|
||||||
"created_at": "2016-11-04T16:29:20Z",
|
|
||||||
"uuid": "4a97b9dd-2023-43dc-b713-815bdd94d4d6"
|
|
||||||
},
|
|
||||||
"watcher_object.name": "AuditCreatePayload",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.namespace": "watcher"
|
|
||||||
},
|
|
||||||
"publisher_id": "infra-optim:localhost",
|
|
||||||
"timestamp": "2016-11-04 16:31:36.264673 ",
|
|
||||||
"event_type": "audit.create",
|
|
||||||
"message_id": "cbcf9f2c-7c53-4b4d-91ec-db49cca024b6"
|
|
||||||
}
|
|
@ -1,71 +0,0 @@
|
|||||||
{
|
|
||||||
"priority": "INFO",
|
|
||||||
"payload": {
|
|
||||||
"watcher_object.data": {
|
|
||||||
"audit_type": "ONESHOT",
|
|
||||||
"parameters": {
|
|
||||||
"para2": "hello",
|
|
||||||
"para1": 3.2
|
|
||||||
},
|
|
||||||
"state": "DELETED",
|
|
||||||
"updated_at": null,
|
|
||||||
"deleted_at": null,
|
|
||||||
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
|
||||||
"goal": {
|
|
||||||
"watcher_object.data": {
|
|
||||||
"uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
|
||||||
"name": "dummy",
|
|
||||||
"updated_at": null,
|
|
||||||
"deleted_at": null,
|
|
||||||
"efficacy_specification": [],
|
|
||||||
"created_at": "2016-11-04T16:25:35Z",
|
|
||||||
"display_name": "Dummy goal"
|
|
||||||
},
|
|
||||||
"watcher_object.name": "GoalPayload",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.namespace": "watcher"
|
|
||||||
},
|
|
||||||
"interval": null,
|
|
||||||
"scope": [],
|
|
||||||
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
|
||||||
"strategy": {
|
|
||||||
"watcher_object.data": {
|
|
||||||
"parameters_spec": {
|
|
||||||
"properties": {
|
|
||||||
"para2": {
|
|
||||||
"type": "string",
|
|
||||||
"default": "hello",
|
|
||||||
"description": "string parameter example"
|
|
||||||
},
|
|
||||||
"para1": {
|
|
||||||
"description": "number parameter example",
|
|
||||||
"maximum": 10.2,
|
|
||||||
"type": "number",
|
|
||||||
"default": 3.2,
|
|
||||||
"minimum": 1.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"name": "dummy",
|
|
||||||
"uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
|
||||||
"updated_at": null,
|
|
||||||
"deleted_at": null,
|
|
||||||
"created_at": "2016-11-04T16:25:35Z",
|
|
||||||
"display_name": "Dummy strategy"
|
|
||||||
},
|
|
||||||
"watcher_object.name": "StrategyPayload",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.namespace": "watcher"
|
|
||||||
},
|
|
||||||
"created_at": "2016-11-04T16:29:20Z",
|
|
||||||
"uuid": "4a97b9dd-2023-43dc-b713-815bdd94d4d6"
|
|
||||||
},
|
|
||||||
"watcher_object.name": "AuditDeletePayload",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.namespace": "watcher"
|
|
||||||
},
|
|
||||||
"publisher_id": "infra-optim:localhost",
|
|
||||||
"timestamp": "2016-11-04 16:31:36.264673 ",
|
|
||||||
"event_type": "audit.delete",
|
|
||||||
"message_id": "cbcf9f2c-7c53-4b4d-91ec-db49cca024b6"
|
|
||||||
}
|
|
@ -1,72 +0,0 @@
|
|||||||
{
|
|
||||||
"priority": "INFO",
|
|
||||||
"payload": {
|
|
||||||
"watcher_object.data": {
|
|
||||||
"audit_type": "ONESHOT",
|
|
||||||
"parameters": {
|
|
||||||
"para2": "hello",
|
|
||||||
"para1": 3.2
|
|
||||||
},
|
|
||||||
"state": "ONGOING",
|
|
||||||
"updated_at": null,
|
|
||||||
"deleted_at": null,
|
|
||||||
"fault": null,
|
|
||||||
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
|
||||||
"goal": {
|
|
||||||
"watcher_object.data": {
|
|
||||||
"uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
|
||||||
"name": "dummy",
|
|
||||||
"updated_at": null,
|
|
||||||
"deleted_at": null,
|
|
||||||
"efficacy_specification": [],
|
|
||||||
"created_at": "2016-11-04T16:25:35Z",
|
|
||||||
"display_name": "Dummy goal"
|
|
||||||
},
|
|
||||||
"watcher_object.name": "GoalPayload",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.namespace": "watcher"
|
|
||||||
},
|
|
||||||
"interval": null,
|
|
||||||
"scope": [],
|
|
||||||
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
|
||||||
"strategy": {
|
|
||||||
"watcher_object.data": {
|
|
||||||
"parameters_spec": {
|
|
||||||
"properties": {
|
|
||||||
"para2": {
|
|
||||||
"type": "string",
|
|
||||||
"default": "hello",
|
|
||||||
"description": "string parameter example"
|
|
||||||
},
|
|
||||||
"para1": {
|
|
||||||
"description": "number parameter example",
|
|
||||||
"maximum": 10.2,
|
|
||||||
"type": "number",
|
|
||||||
"default": 3.2,
|
|
||||||
"minimum": 1.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"name": "dummy",
|
|
||||||
"uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
|
||||||
"updated_at": null,
|
|
||||||
"deleted_at": null,
|
|
||||||
"created_at": "2016-11-04T16:25:35Z",
|
|
||||||
"display_name": "Dummy strategy"
|
|
||||||
},
|
|
||||||
"watcher_object.name": "StrategyPayload",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.namespace": "watcher"
|
|
||||||
},
|
|
||||||
"created_at": "2016-11-04T16:29:20Z",
|
|
||||||
"uuid": "4a97b9dd-2023-43dc-b713-815bdd94d4d6"
|
|
||||||
},
|
|
||||||
"watcher_object.name": "AuditActionPayload",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.namespace": "watcher"
|
|
||||||
},
|
|
||||||
"publisher_id": "infra-optim:localhost",
|
|
||||||
"timestamp": "2016-11-04 16:31:36.264673 ",
|
|
||||||
"event_type": "audit.planner.end",
|
|
||||||
"message_id": "cbcf9f2c-7c53-4b4d-91ec-db49cca024b6"
|
|
||||||
}
|
|
@ -1,82 +0,0 @@
|
|||||||
{
|
|
||||||
"priority": "ERROR",
|
|
||||||
"payload": {
|
|
||||||
"watcher_object.data": {
|
|
||||||
"audit_type": "ONESHOT",
|
|
||||||
"parameters": {
|
|
||||||
"para2": "hello",
|
|
||||||
"para1": 3.2
|
|
||||||
},
|
|
||||||
"state": "ONGOING",
|
|
||||||
"updated_at": null,
|
|
||||||
"deleted_at": null,
|
|
||||||
"fault": {
|
|
||||||
"watcher_object.data": {
|
|
||||||
"exception": "WatcherException",
|
|
||||||
"exception_message": "TEST",
|
|
||||||
"function_name": "test_send_audit_action_with_error",
|
|
||||||
"module_name": "watcher.tests.notifications.test_audit_notification"
|
|
||||||
},
|
|
||||||
"watcher_object.name": "ExceptionPayload",
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.version": "1.0"
|
|
||||||
},
|
|
||||||
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
|
||||||
"goal": {
|
|
||||||
"watcher_object.data": {
|
|
||||||
"uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
|
||||||
"name": "dummy",
|
|
||||||
"updated_at": null,
|
|
||||||
"deleted_at": null,
|
|
||||||
"efficacy_specification": [],
|
|
||||||
"created_at": "2016-11-04T16:25:35Z",
|
|
||||||
"display_name": "Dummy goal"
|
|
||||||
},
|
|
||||||
"watcher_object.name": "GoalPayload",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.namespace": "watcher"
|
|
||||||
},
|
|
||||||
"interval": null,
|
|
||||||
"scope": [],
|
|
||||||
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
|
||||||
"strategy": {
|
|
||||||
"watcher_object.data": {
|
|
||||||
"parameters_spec": {
|
|
||||||
"properties": {
|
|
||||||
"para2": {
|
|
||||||
"type": "string",
|
|
||||||
"default": "hello",
|
|
||||||
"description": "string parameter example"
|
|
||||||
},
|
|
||||||
"para1": {
|
|
||||||
"description": "number parameter example",
|
|
||||||
"maximum": 10.2,
|
|
||||||
"type": "number",
|
|
||||||
"default": 3.2,
|
|
||||||
"minimum": 1.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"name": "dummy",
|
|
||||||
"uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
|
||||||
"updated_at": null,
|
|
||||||
"deleted_at": null,
|
|
||||||
"created_at": "2016-11-04T16:25:35Z",
|
|
||||||
"display_name": "Dummy strategy"
|
|
||||||
},
|
|
||||||
"watcher_object.name": "StrategyPayload",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.namespace": "watcher"
|
|
||||||
},
|
|
||||||
"created_at": "2016-11-04T16:29:20Z",
|
|
||||||
"uuid": "4a97b9dd-2023-43dc-b713-815bdd94d4d6"
|
|
||||||
},
|
|
||||||
"watcher_object.name": "AuditActionPayload",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.namespace": "watcher"
|
|
||||||
},
|
|
||||||
"publisher_id": "infra-optim:localhost",
|
|
||||||
"timestamp": "2016-11-04 16:31:36.264673 ",
|
|
||||||
"event_type": "audit.planner.error",
|
|
||||||
"message_id": "cbcf9f2c-7c53-4b4d-91ec-db49cca024b6"
|
|
||||||
}
|
|
@ -1,72 +0,0 @@
|
|||||||
{
|
|
||||||
"priority": "INFO",
|
|
||||||
"payload": {
|
|
||||||
"watcher_object.data": {
|
|
||||||
"audit_type": "ONESHOT",
|
|
||||||
"parameters": {
|
|
||||||
"para2": "hello",
|
|
||||||
"para1": 3.2
|
|
||||||
},
|
|
||||||
"state": "ONGOING",
|
|
||||||
"updated_at": null,
|
|
||||||
"deleted_at": null,
|
|
||||||
"fault": null,
|
|
||||||
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
|
||||||
"goal": {
|
|
||||||
"watcher_object.data": {
|
|
||||||
"uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
|
||||||
"name": "dummy",
|
|
||||||
"updated_at": null,
|
|
||||||
"deleted_at": null,
|
|
||||||
"efficacy_specification": [],
|
|
||||||
"created_at": "2016-11-04T16:25:35Z",
|
|
||||||
"display_name": "Dummy goal"
|
|
||||||
},
|
|
||||||
"watcher_object.name": "GoalPayload",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.namespace": "watcher"
|
|
||||||
},
|
|
||||||
"interval": null,
|
|
||||||
"scope": [],
|
|
||||||
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
|
||||||
"strategy": {
|
|
||||||
"watcher_object.data": {
|
|
||||||
"parameters_spec": {
|
|
||||||
"properties": {
|
|
||||||
"para2": {
|
|
||||||
"type": "string",
|
|
||||||
"default": "hello",
|
|
||||||
"description": "string parameter example"
|
|
||||||
},
|
|
||||||
"para1": {
|
|
||||||
"description": "number parameter example",
|
|
||||||
"maximum": 10.2,
|
|
||||||
"type": "number",
|
|
||||||
"default": 3.2,
|
|
||||||
"minimum": 1.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"name": "dummy",
|
|
||||||
"uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
|
||||||
"updated_at": null,
|
|
||||||
"deleted_at": null,
|
|
||||||
"created_at": "2016-11-04T16:25:35Z",
|
|
||||||
"display_name": "Dummy strategy"
|
|
||||||
},
|
|
||||||
"watcher_object.name": "StrategyPayload",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.namespace": "watcher"
|
|
||||||
},
|
|
||||||
"created_at": "2016-11-04T16:29:20Z",
|
|
||||||
"uuid": "4a97b9dd-2023-43dc-b713-815bdd94d4d6"
|
|
||||||
},
|
|
||||||
"watcher_object.name": "AuditActionPayload",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.namespace": "watcher"
|
|
||||||
},
|
|
||||||
"publisher_id": "infra-optim:localhost",
|
|
||||||
"timestamp": "2016-11-04 16:31:36.264673 ",
|
|
||||||
"event_type": "audit.planner.start",
|
|
||||||
"message_id": "cbcf9f2c-7c53-4b4d-91ec-db49cca024b6"
|
|
||||||
}
|
|
@ -1,72 +0,0 @@
|
|||||||
{
|
|
||||||
"priority": "INFO",
|
|
||||||
"payload": {
|
|
||||||
"watcher_object.data": {
|
|
||||||
"audit_type": "ONESHOT",
|
|
||||||
"parameters": {
|
|
||||||
"para2": "hello",
|
|
||||||
"para1": 3.2
|
|
||||||
},
|
|
||||||
"state": "ONGOING",
|
|
||||||
"updated_at": null,
|
|
||||||
"deleted_at": null,
|
|
||||||
"fault": null,
|
|
||||||
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
|
||||||
"goal": {
|
|
||||||
"watcher_object.data": {
|
|
||||||
"uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
|
||||||
"name": "dummy",
|
|
||||||
"updated_at": null,
|
|
||||||
"deleted_at": null,
|
|
||||||
"efficacy_specification": [],
|
|
||||||
"created_at": "2016-11-04T16:25:35Z",
|
|
||||||
"display_name": "Dummy goal"
|
|
||||||
},
|
|
||||||
"watcher_object.name": "GoalPayload",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.namespace": "watcher"
|
|
||||||
},
|
|
||||||
"interval": null,
|
|
||||||
"scope": [],
|
|
||||||
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
|
||||||
"strategy": {
|
|
||||||
"watcher_object.data": {
|
|
||||||
"parameters_spec": {
|
|
||||||
"properties": {
|
|
||||||
"para2": {
|
|
||||||
"type": "string",
|
|
||||||
"default": "hello",
|
|
||||||
"description": "string parameter example"
|
|
||||||
},
|
|
||||||
"para1": {
|
|
||||||
"description": "number parameter example",
|
|
||||||
"maximum": 10.2,
|
|
||||||
"type": "number",
|
|
||||||
"default": 3.2,
|
|
||||||
"minimum": 1.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"name": "dummy",
|
|
||||||
"uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
|
||||||
"updated_at": null,
|
|
||||||
"deleted_at": null,
|
|
||||||
"created_at": "2016-11-04T16:25:35Z",
|
|
||||||
"display_name": "Dummy strategy"
|
|
||||||
},
|
|
||||||
"watcher_object.name": "StrategyPayload",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.namespace": "watcher"
|
|
||||||
},
|
|
||||||
"created_at": "2016-11-04T16:29:20Z",
|
|
||||||
"uuid": "4a97b9dd-2023-43dc-b713-815bdd94d4d6"
|
|
||||||
},
|
|
||||||
"watcher_object.name": "AuditActionPayload",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.namespace": "watcher"
|
|
||||||
},
|
|
||||||
"publisher_id": "infra-optim:localhost",
|
|
||||||
"timestamp": "2016-11-04 16:31:36.264673 ",
|
|
||||||
"event_type": "audit.strategy.end",
|
|
||||||
"message_id": "cbcf9f2c-7c53-4b4d-91ec-db49cca024b6"
|
|
||||||
}
|
|
@ -1,82 +0,0 @@
|
|||||||
{
|
|
||||||
"priority": "ERROR",
|
|
||||||
"payload": {
|
|
||||||
"watcher_object.data": {
|
|
||||||
"audit_type": "ONESHOT",
|
|
||||||
"parameters": {
|
|
||||||
"para2": "hello",
|
|
||||||
"para1": 3.2
|
|
||||||
},
|
|
||||||
"state": "ONGOING",
|
|
||||||
"updated_at": null,
|
|
||||||
"deleted_at": null,
|
|
||||||
"fault": {
|
|
||||||
"watcher_object.data": {
|
|
||||||
"exception": "WatcherException",
|
|
||||||
"exception_message": "TEST",
|
|
||||||
"function_name": "test_send_audit_action_with_error",
|
|
||||||
"module_name": "watcher.tests.notifications.test_audit_notification"
|
|
||||||
},
|
|
||||||
"watcher_object.name": "ExceptionPayload",
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.version": "1.0"
|
|
||||||
},
|
|
||||||
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
|
||||||
"goal": {
|
|
||||||
"watcher_object.data": {
|
|
||||||
"uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
|
||||||
"name": "dummy",
|
|
||||||
"updated_at": null,
|
|
||||||
"deleted_at": null,
|
|
||||||
"efficacy_specification": [],
|
|
||||||
"created_at": "2016-11-04T16:25:35Z",
|
|
||||||
"display_name": "Dummy goal"
|
|
||||||
},
|
|
||||||
"watcher_object.name": "GoalPayload",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.namespace": "watcher"
|
|
||||||
},
|
|
||||||
"interval": null,
|
|
||||||
"scope": [],
|
|
||||||
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
|
||||||
"strategy": {
|
|
||||||
"watcher_object.data": {
|
|
||||||
"parameters_spec": {
|
|
||||||
"properties": {
|
|
||||||
"para2": {
|
|
||||||
"type": "string",
|
|
||||||
"default": "hello",
|
|
||||||
"description": "string parameter example"
|
|
||||||
},
|
|
||||||
"para1": {
|
|
||||||
"description": "number parameter example",
|
|
||||||
"maximum": 10.2,
|
|
||||||
"type": "number",
|
|
||||||
"default": 3.2,
|
|
||||||
"minimum": 1.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"name": "dummy",
|
|
||||||
"uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
|
||||||
"updated_at": null,
|
|
||||||
"deleted_at": null,
|
|
||||||
"created_at": "2016-11-04T16:25:35Z",
|
|
||||||
"display_name": "Dummy strategy"
|
|
||||||
},
|
|
||||||
"watcher_object.name": "StrategyPayload",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.namespace": "watcher"
|
|
||||||
},
|
|
||||||
"created_at": "2016-11-04T16:29:20Z",
|
|
||||||
"uuid": "4a97b9dd-2023-43dc-b713-815bdd94d4d6"
|
|
||||||
},
|
|
||||||
"watcher_object.name": "AuditActionPayload",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.namespace": "watcher"
|
|
||||||
},
|
|
||||||
"publisher_id": "infra-optim:localhost",
|
|
||||||
"timestamp": "2016-11-04 16:31:36.264673 ",
|
|
||||||
"event_type": "audit.strategy.error",
|
|
||||||
"message_id": "cbcf9f2c-7c53-4b4d-91ec-db49cca024b6"
|
|
||||||
}
|
|
@ -1,72 +0,0 @@
|
|||||||
{
|
|
||||||
"priority": "INFO",
|
|
||||||
"payload": {
|
|
||||||
"watcher_object.data": {
|
|
||||||
"audit_type": "ONESHOT",
|
|
||||||
"parameters": {
|
|
||||||
"para2": "hello",
|
|
||||||
"para1": 3.2
|
|
||||||
},
|
|
||||||
"state": "ONGOING",
|
|
||||||
"updated_at": null,
|
|
||||||
"deleted_at": null,
|
|
||||||
"fault": null,
|
|
||||||
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
|
||||||
"goal": {
|
|
||||||
"watcher_object.data": {
|
|
||||||
"uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
|
||||||
"name": "dummy",
|
|
||||||
"updated_at": null,
|
|
||||||
"deleted_at": null,
|
|
||||||
"efficacy_specification": [],
|
|
||||||
"created_at": "2016-11-04T16:25:35Z",
|
|
||||||
"display_name": "Dummy goal"
|
|
||||||
},
|
|
||||||
"watcher_object.name": "GoalPayload",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.namespace": "watcher"
|
|
||||||
},
|
|
||||||
"interval": null,
|
|
||||||
"scope": [],
|
|
||||||
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
|
||||||
"strategy": {
|
|
||||||
"watcher_object.data": {
|
|
||||||
"parameters_spec": {
|
|
||||||
"properties": {
|
|
||||||
"para2": {
|
|
||||||
"type": "string",
|
|
||||||
"default": "hello",
|
|
||||||
"description": "string parameter example"
|
|
||||||
},
|
|
||||||
"para1": {
|
|
||||||
"description": "number parameter example",
|
|
||||||
"maximum": 10.2,
|
|
||||||
"type": "number",
|
|
||||||
"default": 3.2,
|
|
||||||
"minimum": 1.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"name": "dummy",
|
|
||||||
"uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
|
||||||
"updated_at": null,
|
|
||||||
"deleted_at": null,
|
|
||||||
"created_at": "2016-11-04T16:25:35Z",
|
|
||||||
"display_name": "Dummy strategy"
|
|
||||||
},
|
|
||||||
"watcher_object.name": "StrategyPayload",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.namespace": "watcher"
|
|
||||||
},
|
|
||||||
"created_at": "2016-11-04T16:29:20Z",
|
|
||||||
"uuid": "4a97b9dd-2023-43dc-b713-815bdd94d4d6"
|
|
||||||
},
|
|
||||||
"watcher_object.name": "AuditActionPayload",
|
|
||||||
"watcher_object.version": "1.0",
|
|
||||||
"watcher_object.namespace": "watcher"
|
|
||||||
},
|
|
||||||
"publisher_id": "infra-optim:localhost",
|
|
||||||
"timestamp": "2016-11-04 16:31:36.264673 ",
|
|
||||||
"event_type": "audit.strategy.start",
|
|
||||||
"message_id": "cbcf9f2c-7c53-4b4d-91ec-db49cca024b6"
|
|
||||||
}
|
|
@ -1,80 +0,0 @@
|
|||||||
{
|
|
||||||
"publisher_id": "infra-optim:localhost",
|
|
||||||
"timestamp": "2016-11-04 16:51:38.722986 ",
|
|
||||||
"payload": {
|
|
||||||
"watcher_object.name": "AuditUpdatePayload",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
|
||||||
"strategy": {
|
|
||||||
"watcher_object.name": "StrategyPayload",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"name": "dummy",
|
|
||||||
"parameters_spec": {
|
|
||||||
"properties": {
|
|
||||||
"para2": {
|
|
||||||
"default": "hello",
|
|
||||||
"type": "string",
|
|
||||||
"description": "string parameter example"
|
|
||||||
},
|
|
||||||
"para1": {
|
|
||||||
"maximum": 10.2,
|
|
||||||
"default": 3.2,
|
|
||||||
"minimum": 1.0,
|
|
||||||
"description": "number parameter example",
|
|
||||||
"type": "number"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"updated_at": null,
|
|
||||||
"display_name": "Dummy strategy",
|
|
||||||
"deleted_at": null,
|
|
||||||
"uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
|
||||||
"created_at": "2016-11-04T16:25:35Z"
|
|
||||||
},
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.version": "1.0"
|
|
||||||
},
|
|
||||||
"scope": [],
|
|
||||||
"created_at": "2016-11-04T16:51:21Z",
|
|
||||||
"uuid": "f1e0d912-afd9-4bf2-91ef-c99cd08cc1ef",
|
|
||||||
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
|
||||||
"goal": {
|
|
||||||
"watcher_object.name": "GoalPayload",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"efficacy_specification": [],
|
|
||||||
"updated_at": null,
|
|
||||||
"name": "dummy",
|
|
||||||
"display_name": "Dummy goal",
|
|
||||||
"deleted_at": null,
|
|
||||||
"uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
|
||||||
"created_at": "2016-11-04T16:25:35Z"
|
|
||||||
},
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.version": "1.0"
|
|
||||||
},
|
|
||||||
"parameters": {
|
|
||||||
"para2": "hello",
|
|
||||||
"para1": 3.2
|
|
||||||
},
|
|
||||||
"deleted_at": null,
|
|
||||||
"state_update": {
|
|
||||||
"watcher_object.name": "AuditStateUpdatePayload",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"state": "ONGOING",
|
|
||||||
"old_state": "PENDING"
|
|
||||||
},
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.version": "1.0"
|
|
||||||
},
|
|
||||||
"interval": null,
|
|
||||||
"updated_at": null,
|
|
||||||
"state": "ONGOING",
|
|
||||||
"audit_type": "ONESHOT"
|
|
||||||
},
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.version": "1.0"
|
|
||||||
},
|
|
||||||
"priority": "INFO",
|
|
||||||
"event_type": "audit.update",
|
|
||||||
"message_id": "697fdf55-7252-4b6c-a2c2-5b9e85f6342c"
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"event_type": "infra-optim.exception",
|
|
||||||
"payload": {
|
|
||||||
"watcher_object.data": {
|
|
||||||
"exception": "NoAvailableStrategyForGoal",
|
|
||||||
"exception_message": "No strategy could be found to achieve the server_consolidation goal.",
|
|
||||||
"function_name": "_aggregate_create_in_db",
|
|
||||||
"module_name": "watcher.objects.aggregate"
|
|
||||||
},
|
|
||||||
"watcher_object.name": "ExceptionPayload",
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.version": "1.0"
|
|
||||||
},
|
|
||||||
"priority": "ERROR",
|
|
||||||
"publisher_id": "watcher-api:fake-mini"
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
{
|
|
||||||
"payload": {
|
|
||||||
"watcher_object.name": "ServiceUpdatePayload",
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"status_update": {
|
|
||||||
"watcher_object.name": "ServiceStatusUpdatePayload",
|
|
||||||
"watcher_object.namespace": "watcher",
|
|
||||||
"watcher_object.data": {
|
|
||||||
"old_state": "ACTIVE",
|
|
||||||
"state": "FAILED"
|
|
||||||
},
|
|
||||||
"watcher_object.version": "1.0"
|
|
||||||
},
|
|
||||||
"last_seen_up": "2016-09-22T08:32:06Z",
|
|
||||||
"name": "watcher-service",
|
|
||||||
"sevice_host": "controller"
|
|
||||||
},
|
|
||||||
"watcher_object.version": "1.0"
|
|
||||||
},
|
|
||||||
"event_type": "service.update",
|
|
||||||
"priority": "INFO",
|
|
||||||
"message_id": "3984dc2b-8aef-462b-a220-8ae04237a56e",
|
|
||||||
"timestamp": "2016-10-18 09:52:05.219414",
|
|
||||||
"publisher_id": "infra-optim:node0"
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
..
|
|
||||||
Except where otherwise noted, this document is licensed under Creative
|
|
||||||
Commons Attribution 3.0 License. You can view the license at:
|
|
||||||
|
|
||||||
https://creativecommons.org/licenses/by/3.0/
|
|
||||||
|
|
||||||
|
|
||||||
Installing API behind mod_wsgi
|
|
||||||
==============================
|
|
||||||
|
|
||||||
#. Install the Apache Service::
|
|
||||||
|
|
||||||
Fedora 21/RHEL7/CentOS7:
|
|
||||||
sudo yum install httpd
|
|
||||||
|
|
||||||
Fedora 22 (or higher):
|
|
||||||
sudo dnf install httpd
|
|
||||||
|
|
||||||
Debian/Ubuntu:
|
|
||||||
apt-get install apache2
|
|
||||||
|
|
||||||
#. Copy ``etc/apache2/watcher.conf`` under the apache sites::
|
|
||||||
|
|
||||||
Fedora/RHEL7/CentOS7:
|
|
||||||
sudo cp etc/apache2/watcher /etc/httpd/conf.d/watcher.conf
|
|
||||||
|
|
||||||
Debian/Ubuntu:
|
|
||||||
sudo cp etc/apache2/watcher /etc/apache2/sites-available/watcher.conf
|
|
||||||
|
|
||||||
#. Edit ``<apache-configuration-dir>/watcher.conf`` according to installation
|
|
||||||
and environment.
|
|
||||||
|
|
||||||
* Modify the ``WSGIDaemonProcess`` directive to set the ``user`` and
|
|
||||||
``group`` values to appropriate user on your server.
|
|
||||||
* Modify the ``WSGIScriptAlias`` directive to point to the
|
|
||||||
watcher/api/app.wsgi script.
|
|
||||||
* Modify the ``Directory`` directive to set the path to the Watcher API
|
|
||||||
code.
|
|
||||||
* Modify the ``ErrorLog and CustomLog`` to redirect the logs to the right
|
|
||||||
directory.
|
|
||||||
|
|
||||||
#. Enable the apache watcher site and reload::
|
|
||||||
|
|
||||||
Fedora/RHEL7/CentOS7:
|
|
||||||
sudo systemctl reload httpd
|
|
||||||
|
|
||||||
Debian/Ubuntu:
|
|
||||||
sudo a2ensite watcher
|
|
||||||
sudo service apache2 reload
|
|
@ -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
|
|
@ -1,460 +0,0 @@
|
|||||||
..
|
|
||||||
Except where otherwise noted, this document is licensed under Creative
|
|
||||||
Commons Attribution 3.0 License. You can view the license at:
|
|
||||||
|
|
||||||
https://creativecommons.org/licenses/by/3.0/
|
|
||||||
|
|
||||||
===================
|
|
||||||
Configuring Watcher
|
|
||||||
===================
|
|
||||||
|
|
||||||
This document is continually updated and reflects the latest
|
|
||||||
available code of the Watcher service.
|
|
||||||
|
|
||||||
Service overview
|
|
||||||
================
|
|
||||||
|
|
||||||
The Watcher system is a collection of services that provides support to
|
|
||||||
optimize your IAAS platform. The Watcher service may, depending upon
|
|
||||||
configuration, interact with several other OpenStack services. This includes:
|
|
||||||
|
|
||||||
- the OpenStack Identity service (`keystone`_) for request authentication and
|
|
||||||
to locate other OpenStack services
|
|
||||||
- the OpenStack Telemetry service (`ceilometer`_) for consuming the resources
|
|
||||||
metrics
|
|
||||||
- the OpenStack Compute service (`nova`_) works with the Watcher service and
|
|
||||||
acts as a user-facing API for instance migration.
|
|
||||||
|
|
||||||
The Watcher service includes the following components:
|
|
||||||
|
|
||||||
- ``watcher-decision-engine``: runs audit on part of your IAAS and return an
|
|
||||||
action plan in order to optimize resource placement.
|
|
||||||
- ``watcher-api``: A RESTful API that processes application requests by sending
|
|
||||||
them to the watcher-decision-engine over RPC.
|
|
||||||
- ``watcher-applier``: applies the action plan.
|
|
||||||
- `python-watcherclient`_: A command-line interface (CLI) for interacting with
|
|
||||||
the Watcher service.
|
|
||||||
- `watcher-dashboard`_: An Horizon plugin for interacting with the Watcher
|
|
||||||
service.
|
|
||||||
|
|
||||||
Additionally, the Watcher service has certain external dependencies, which
|
|
||||||
are very similar to other OpenStack services:
|
|
||||||
|
|
||||||
- A database to store audit and action plan information and state. You can set
|
|
||||||
the database back-end type and location.
|
|
||||||
- A queue. A central hub for passing messages, such as `RabbitMQ`_.
|
|
||||||
|
|
||||||
Optionally, one may wish to utilize the following associated projects for
|
|
||||||
additional functionality:
|
|
||||||
|
|
||||||
- `watcher metering`_: an alternative to collect and push metrics to the
|
|
||||||
Telemetry service.
|
|
||||||
|
|
||||||
.. _`keystone`: https://github.com/openstack/keystone
|
|
||||||
.. _`ceilometer`: https://github.com/openstack/ceilometer
|
|
||||||
.. _`nova`: https://github.com/openstack/nova
|
|
||||||
.. _`python-watcherclient`: https://github.com/openstack/python-watcherclient
|
|
||||||
.. _`watcher-dashboard`: https://github.com/openstack/watcher-dashboard
|
|
||||||
.. _`watcher metering`: https://github.com/b-com/watcher-metering
|
|
||||||
.. _`RabbitMQ`: https://www.rabbitmq.com/
|
|
||||||
|
|
||||||
Install and configure prerequisites
|
|
||||||
===================================
|
|
||||||
|
|
||||||
You can configure Watcher services to run on separate nodes or the same node.
|
|
||||||
In this guide, the components run on one node, typically the Controller node.
|
|
||||||
|
|
||||||
This section shows you how to install and configure the services.
|
|
||||||
|
|
||||||
It assumes that the Identity, Image, Compute, and Networking services
|
|
||||||
have already been set up.
|
|
||||||
|
|
||||||
.. _identity-service_configuration:
|
|
||||||
|
|
||||||
Configure the Identity service for the Watcher service
|
|
||||||
------------------------------------------------------
|
|
||||||
|
|
||||||
#. Create the Watcher service user (eg ``watcher``). The service uses this to
|
|
||||||
authenticate with the Identity Service. Use the
|
|
||||||
``KEYSTONE_SERVICE_PROJECT_NAME`` project (named ``service`` by default in
|
|
||||||
devstack) and give the user the ``admin`` role:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
$ keystone user-create --name=watcher --pass=WATCHER_PASSWORD \
|
|
||||||
--email=watcher@example.com \
|
|
||||||
--tenant=KEYSTONE_SERVICE_PROJECT_NAME
|
|
||||||
$ keystone user-role-add --user=watcher \
|
|
||||||
--tenant=KEYSTONE_SERVICE_PROJECT_NAME --role=admin
|
|
||||||
|
|
||||||
or (by using python-openstackclient 1.8.0+)
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
$ openstack user create --password WATCHER_PASSWORD --enable \
|
|
||||||
--email watcher@example.com watcher \
|
|
||||||
--project=KEYSTONE_SERVICE_PROJECT_NAME
|
|
||||||
$ openstack role add --project KEYSTONE_SERVICE_PROJECT_NAME \
|
|
||||||
--user watcher admin
|
|
||||||
|
|
||||||
|
|
||||||
#. You must register the Watcher Service with the Identity Service so that
|
|
||||||
other OpenStack services can locate it. To register the service:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
$ keystone service-create --name=watcher --type=infra-optim \
|
|
||||||
--description="Infrastructure Optimization service"
|
|
||||||
|
|
||||||
or (by using python-openstackclient 1.8.0+)
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
$ openstack service create --name watcher infra-optim \
|
|
||||||
--description="Infrastructure Optimization service"
|
|
||||||
|
|
||||||
#. Create the endpoints by replacing YOUR_REGION and
|
|
||||||
``WATCHER_API_[PUBLIC|ADMIN|INTERNAL]_IP`` with your region and your
|
|
||||||
Watcher Service's API node IP addresses (or FQDN):
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
$ keystone endpoint-create \
|
|
||||||
--service-id=the_service_id_above \
|
|
||||||
--publicurl=http://WATCHER_API_PUBLIC_IP:9322 \
|
|
||||||
--internalurl=http://WATCHER_API_INTERNAL_IP:9322 \
|
|
||||||
--adminurl=http://WATCHER_API_ADMIN_IP:9322
|
|
||||||
|
|
||||||
or (by using python-openstackclient 1.8.0+)
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
$ openstack endpoint create --region YOUR_REGION watcher \
|
|
||||||
--publicurl http://WATCHER_API_PUBLIC_IP:9322 \
|
|
||||||
--internalurl http://WATCHER_API_INTERNAL_IP:9322 \
|
|
||||||
--adminurl http://WATCHER_API_ADMIN_IP:9322
|
|
||||||
|
|
||||||
.. _watcher-db_configuration:
|
|
||||||
|
|
||||||
Set up the database for Watcher
|
|
||||||
-------------------------------
|
|
||||||
|
|
||||||
The Watcher service stores information in a database. This guide uses the
|
|
||||||
MySQL database that is used by other OpenStack services.
|
|
||||||
|
|
||||||
#. In MySQL, create a ``watcher`` database that is accessible by the
|
|
||||||
``watcher`` user. Replace WATCHER_DBPASSWORD
|
|
||||||
with the actual password::
|
|
||||||
|
|
||||||
$ mysql -u root -p
|
|
||||||
|
|
||||||
mysql> CREATE DATABASE watcher CHARACTER SET utf8;
|
|
||||||
mysql> GRANT ALL PRIVILEGES ON watcher.* TO 'watcher'@'localhost' \
|
|
||||||
IDENTIFIED BY 'WATCHER_DBPASSWORD';
|
|
||||||
mysql> GRANT ALL PRIVILEGES ON watcher.* TO 'watcher'@'%' \
|
|
||||||
IDENTIFIED BY 'WATCHER_DBPASSWORD';
|
|
||||||
|
|
||||||
|
|
||||||
Configure the Watcher service
|
|
||||||
=============================
|
|
||||||
|
|
||||||
The Watcher service is configured via its configuration file. This file
|
|
||||||
is typically located at ``/etc/watcher/watcher.conf``.
|
|
||||||
|
|
||||||
You can easily generate and update a sample configuration file
|
|
||||||
named :ref:`watcher.conf.sample <watcher_sample_configuration_files>` by using
|
|
||||||
these following commands::
|
|
||||||
|
|
||||||
$ git clone git://git.openstack.org/openstack/watcher
|
|
||||||
$ cd watcher/
|
|
||||||
$ tox -e genconfig
|
|
||||||
$ vi etc/watcher/watcher.conf.sample
|
|
||||||
|
|
||||||
|
|
||||||
The configuration file is organized into the following sections:
|
|
||||||
|
|
||||||
* ``[DEFAULT]`` - General configuration
|
|
||||||
* ``[api]`` - API server configuration
|
|
||||||
* ``[database]`` - SQL driver configuration
|
|
||||||
* ``[keystone_authtoken]`` - Keystone Authentication plugin configuration
|
|
||||||
* ``[watcher_clients_auth]`` - Keystone auth configuration for clients
|
|
||||||
* ``[watcher_applier]`` - Watcher Applier module configuration
|
|
||||||
* ``[watcher_decision_engine]`` - Watcher Decision Engine module configuration
|
|
||||||
* ``[oslo_messaging_rabbit]`` - Oslo Messaging RabbitMQ driver configuration
|
|
||||||
* ``[ceilometer_client]`` - Ceilometer client configuration
|
|
||||||
* ``[cinder_client]`` - Cinder client configuration
|
|
||||||
* ``[glance_client]`` - Glance client configuration
|
|
||||||
* ``[nova_client]`` - Nova client configuration
|
|
||||||
* ``[neutron_client]`` - Neutron client configuration
|
|
||||||
|
|
||||||
The Watcher configuration file is expected to be named
|
|
||||||
``watcher.conf``. When starting Watcher, you can specify a different
|
|
||||||
configuration file to use with ``--config-file``. If you do **not** specify a
|
|
||||||
configuration file, Watcher will look in the following directories for a
|
|
||||||
configuration file, in order:
|
|
||||||
|
|
||||||
* ``~/.watcher/``
|
|
||||||
* ``~/``
|
|
||||||
* ``/etc/watcher/``
|
|
||||||
* ``/etc/``
|
|
||||||
|
|
||||||
|
|
||||||
Although some configuration options are mentioned here, it is recommended that
|
|
||||||
you review all the `available options
|
|
||||||
<https://git.openstack.org/cgit/openstack/watcher/tree/etc/watcher/watcher.conf.sample>`_
|
|
||||||
so that the watcher service is configured for your needs.
|
|
||||||
|
|
||||||
#. The Watcher Service stores information in a database. This guide uses the
|
|
||||||
MySQL database that is used by other OpenStack services.
|
|
||||||
|
|
||||||
Configure the location of the database via the ``connection`` option. In the
|
|
||||||
following, replace WATCHER_DBPASSWORD with the password of your ``watcher``
|
|
||||||
user, and replace DB_IP with the IP address where the DB server is located::
|
|
||||||
|
|
||||||
[database]
|
|
||||||
...
|
|
||||||
|
|
||||||
# The SQLAlchemy connection string used to connect to the
|
|
||||||
# database (string value)
|
|
||||||
#connection=<None>
|
|
||||||
connection = mysql://watcher:WATCHER_DBPASSWORD@DB_IP/watcher?charset=utf8
|
|
||||||
|
|
||||||
#. Configure the Watcher Service to use the RabbitMQ message broker by
|
|
||||||
setting one or more of these options. Replace RABBIT_HOST with the
|
|
||||||
IP address of the RabbitMQ server, RABBITMQ_USER and RABBITMQ_PASSWORD
|
|
||||||
by the RabbitMQ server login credentials ::
|
|
||||||
|
|
||||||
[DEFAULT]
|
|
||||||
|
|
||||||
# The messaging driver to use, defaults to rabbit. Other drivers
|
|
||||||
# include qpid and zmq. (string value)
|
|
||||||
#rpc_backend = rabbit
|
|
||||||
|
|
||||||
# The default exchange under which topics are scoped. May be
|
|
||||||
# overridden by an exchange name specified in the transport_url
|
|
||||||
# option. (string value)
|
|
||||||
control_exchange = watcher
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
[oslo_messaging_rabbit]
|
|
||||||
|
|
||||||
# The username used by the message broker (string value)
|
|
||||||
rabbit_userid = RABBITMQ_USER
|
|
||||||
|
|
||||||
# The password of user used by the message broker (string value)
|
|
||||||
rabbit_password = RABBITMQ_PASSWORD
|
|
||||||
|
|
||||||
# The host where the message brokeris installed (string value)
|
|
||||||
rabbit_host = RABBIT_HOST
|
|
||||||
|
|
||||||
# The port used bythe message broker (string value)
|
|
||||||
#rabbit_port = 5672
|
|
||||||
|
|
||||||
|
|
||||||
#. Watcher API shall validate the token provided by every incoming request,
|
|
||||||
via keystonemiddleware, which requires the Watcher service to be configured
|
|
||||||
with the right credentials for the Identity service.
|
|
||||||
|
|
||||||
In the configuration section here below:
|
|
||||||
|
|
||||||
* replace IDENTITY_IP with the IP of the Identity server
|
|
||||||
* replace WATCHER_PASSWORD with the password you chose for the ``watcher``
|
|
||||||
user
|
|
||||||
* replace KEYSTONE_SERVICE_PROJECT_NAME with the name of project created
|
|
||||||
for OpenStack services (e.g. ``service``) ::
|
|
||||||
|
|
||||||
[keystone_authtoken]
|
|
||||||
|
|
||||||
# Authentication type to load (unknown value)
|
|
||||||
# Deprecated group/name - [DEFAULT]/auth_plugin
|
|
||||||
#auth_type = <None>
|
|
||||||
auth_type = password
|
|
||||||
|
|
||||||
# Authentication URL (unknown value)
|
|
||||||
#auth_url = <None>
|
|
||||||
auth_url = http://IDENTITY_IP:35357
|
|
||||||
|
|
||||||
# Username (unknown value)
|
|
||||||
# Deprecated group/name - [DEFAULT]/username
|
|
||||||
#username = <None>
|
|
||||||
username=watcher
|
|
||||||
|
|
||||||
# User's password (unknown value)
|
|
||||||
#password = <None>
|
|
||||||
password = WATCHER_PASSWORD
|
|
||||||
|
|
||||||
# Domain ID containing project (unknown value)
|
|
||||||
#project_domain_id = <None>
|
|
||||||
project_domain_id = default
|
|
||||||
|
|
||||||
# User's domain id (unknown value)
|
|
||||||
#user_domain_id = <None>
|
|
||||||
user_domain_id = default
|
|
||||||
|
|
||||||
# Project name to scope to (unknown value)
|
|
||||||
# Deprecated group/name - [DEFAULT]/tenant-name
|
|
||||||
#project_name = <None>
|
|
||||||
project_name = KEYSTONE_SERVICE_PROJECT_NAME
|
|
||||||
|
|
||||||
#. Watcher's decision engine and applier interact with other OpenStack
|
|
||||||
projects through those projects' clients. In order to instantiate these
|
|
||||||
clients, Watcher needs to request a new session from the Identity service
|
|
||||||
using the right credentials.
|
|
||||||
|
|
||||||
In the configuration section here below:
|
|
||||||
|
|
||||||
* replace IDENTITY_IP with the IP of the Identity server
|
|
||||||
* replace WATCHER_PASSWORD with the password you chose for the ``watcher``
|
|
||||||
user
|
|
||||||
* replace KEYSTONE_SERVICE_PROJECT_NAME with the name of project created
|
|
||||||
for OpenStack services (e.g. ``service``) ::
|
|
||||||
|
|
||||||
[watcher_clients_auth]
|
|
||||||
|
|
||||||
# Authentication type to load (unknown value)
|
|
||||||
# Deprecated group/name - [DEFAULT]/auth_plugin
|
|
||||||
#auth_type = <None>
|
|
||||||
auth_type = password
|
|
||||||
|
|
||||||
# Authentication URL (unknown value)
|
|
||||||
#auth_url = <None>
|
|
||||||
auth_url = http://IDENTITY_IP:35357
|
|
||||||
|
|
||||||
# Username (unknown value)
|
|
||||||
# Deprecated group/name - [DEFAULT]/username
|
|
||||||
#username = <None>
|
|
||||||
username=watcher
|
|
||||||
|
|
||||||
# User's password (unknown value)
|
|
||||||
#password = <None>
|
|
||||||
password = WATCHER_PASSWORD
|
|
||||||
|
|
||||||
# Domain ID containing project (unknown value)
|
|
||||||
#project_domain_id = <None>
|
|
||||||
project_domain_id = default
|
|
||||||
|
|
||||||
# User's domain id (unknown value)
|
|
||||||
#user_domain_id = <None>
|
|
||||||
user_domain_id = default
|
|
||||||
|
|
||||||
# Project name to scope to (unknown value)
|
|
||||||
# Deprecated group/name - [DEFAULT]/tenant-name
|
|
||||||
#project_name = <None>
|
|
||||||
project_name = KEYSTONE_SERVICE_PROJECT_NAME
|
|
||||||
|
|
||||||
#. Configure the clients to use a specific version if desired. For example, to
|
|
||||||
configure Watcher to use a Nova client with version 2.1, use::
|
|
||||||
|
|
||||||
[nova_client]
|
|
||||||
|
|
||||||
# Version of Nova API to use in novaclient. (string value)
|
|
||||||
#api_version = 2
|
|
||||||
api_version = 2.1
|
|
||||||
|
|
||||||
#. Create the Watcher Service database tables::
|
|
||||||
|
|
||||||
$ watcher-db-manage --config-file /etc/watcher/watcher.conf create_schema
|
|
||||||
|
|
||||||
#. Start the Watcher Service::
|
|
||||||
|
|
||||||
$ watcher-api && watcher-decision-engine && watcher-applier
|
|
||||||
|
|
||||||
Configure Nova compute
|
|
||||||
======================
|
|
||||||
|
|
||||||
Please check your hypervisor configuration to correctly handle
|
|
||||||
`instance migration`_.
|
|
||||||
|
|
||||||
.. _`instance migration`: http://docs.openstack.org/admin-guide/compute-live-migration-usage.html
|
|
||||||
|
|
||||||
Configure Measurements
|
|
||||||
======================
|
|
||||||
|
|
||||||
You can configure and install Ceilometer by following the documentation below :
|
|
||||||
|
|
||||||
#. http://docs.openstack.org/developer/ceilometer
|
|
||||||
#. http://docs.openstack.org/kilo/install-guide/install/apt/content/ceilometer-nova.html
|
|
||||||
|
|
||||||
The built-in strategy 'basic_consolidation' provided by watcher requires
|
|
||||||
"**compute.node.cpu.percent**" and "**cpu_util**" measurements to be collected
|
|
||||||
by Ceilometer.
|
|
||||||
The measurements available depend on the hypervisors that OpenStack manages on
|
|
||||||
the specific implementation.
|
|
||||||
You can find the measurements available per hypervisor and OpenStack release on
|
|
||||||
the OpenStack site.
|
|
||||||
You can use 'ceilometer meter-list' to list the available meters.
|
|
||||||
|
|
||||||
For more information:
|
|
||||||
http://docs.openstack.org/developer/ceilometer/measurements.html
|
|
||||||
|
|
||||||
Ceilometer is designed to collect measurements from OpenStack services and from
|
|
||||||
other external components. If you would like to add new meters to the currently
|
|
||||||
existing ones, you need to follow the documentation below:
|
|
||||||
|
|
||||||
#. http://docs.openstack.org/developer/ceilometer/new_meters.html
|
|
||||||
|
|
||||||
The Ceilometer collector uses a pluggable storage system, meaning that you can
|
|
||||||
pick any database system you prefer.
|
|
||||||
The original implementation has been based on MongoDB but you can create your
|
|
||||||
own storage driver using whatever technology you want.
|
|
||||||
For more information : https://wiki.openstack.org/wiki/Gnocchi
|
|
||||||
|
|
||||||
|
|
||||||
Configure Nova Notifications
|
|
||||||
============================
|
|
||||||
|
|
||||||
Watcher can consume notifications generated by the Nova services, in order to
|
|
||||||
build or update, in real time, its cluster data model related to computing
|
|
||||||
resources.
|
|
||||||
|
|
||||||
Nova publishes, by default, notifications on ``notifications`` AMQP queue
|
|
||||||
(configurable) and ``versioned_notifications`` AMQP queue (not
|
|
||||||
configurable). ``notifications`` queue is mainly used by ceilometer, so we can
|
|
||||||
not use it. And some events, related to nova-compute service state, are only
|
|
||||||
sent into the ``versioned_notifications`` queue.
|
|
||||||
|
|
||||||
By default, Watcher listens to AMQP queues named ``watcher_notifications``
|
|
||||||
and ``versioned_notifications``. So you have to update the Nova
|
|
||||||
configuration file on controller and compute nodes, in order
|
|
||||||
to Watcher receives Nova notifications in ``watcher_notifications`` as well.
|
|
||||||
|
|
||||||
* In the file ``/etc/nova/nova.conf``, update the section
|
|
||||||
``[oslo_messaging_notifications]``, by redefining the list of topics
|
|
||||||
into which Nova services will publish events ::
|
|
||||||
|
|
||||||
[oslo_messaging_notifications]
|
|
||||||
driver = messagingv2
|
|
||||||
topics = notifications,watcher_notifications
|
|
||||||
|
|
||||||
* Restart the Nova services.
|
|
||||||
|
|
||||||
|
|
||||||
Workers
|
|
||||||
=======
|
|
||||||
|
|
||||||
You can define a number of workers for the Decision Engine and the Applier.
|
|
||||||
|
|
||||||
If you want to create and run more audits simultaneously, you have to raise
|
|
||||||
the number of workers used by the Decision Engine::
|
|
||||||
|
|
||||||
[watcher_decision_engine]
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
# The maximum number of threads that can be used to execute strategies
|
|
||||||
# (integer value)
|
|
||||||
#max_workers = 2
|
|
||||||
|
|
||||||
|
|
||||||
If you want to execute simultaneously more recommended action plans, you
|
|
||||||
have to raise the number of workers used by the Applier::
|
|
||||||
|
|
||||||
[watcher_applier]
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
# Number of workers for applier, default value is 1. (integer value)
|
|
||||||
# Minimum value: 1
|
|
||||||
#workers = 1
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
|||||||
..
|
|
||||||
Except where otherwise noted, this document is licensed under Creative
|
|
||||||
Commons Attribution 3.0 License. You can view the license at:
|
|
||||||
|
|
||||||
https://creativecommons.org/licenses/by/3.0/
|
|
||||||
|
|
||||||
.. _watcher_gmr:
|
|
||||||
|
|
||||||
=======================
|
|
||||||
Guru Meditation Reports
|
|
||||||
=======================
|
|
||||||
|
|
||||||
Watcher contains a mechanism whereby developers and system administrators can
|
|
||||||
generate a report about the state of a running Watcher service. This report
|
|
||||||
is called a *Guru Meditation Report* (*GMR* for short).
|
|
||||||
|
|
||||||
Generating a GMR
|
|
||||||
================
|
|
||||||
|
|
||||||
A *GMR* can be generated by sending the *USR2* signal to any Watcher process
|
|
||||||
with support (see below). The *GMR* will then be outputted as standard error
|
|
||||||
for that particular process.
|
|
||||||
|
|
||||||
For example, suppose that ``watcher-api`` has process id ``8675``, and was run
|
|
||||||
with ``2>/var/log/watcher/watcher-api-err.log``. Then, ``kill -USR2 8675``
|
|
||||||
will trigger the Guru Meditation report to be printed to
|
|
||||||
``/var/log/watcher/watcher-api-err.log``.
|
|
||||||
|
|
||||||
Structure of a GMR
|
|
||||||
==================
|
|
||||||
|
|
||||||
The *GMR* is designed to be extensible; any particular service may add its
|
|
||||||
own sections. However, the base *GMR* consists of several sections:
|
|
||||||
|
|
||||||
Package
|
|
||||||
Shows information about the package to which this process belongs, including
|
|
||||||
version informations.
|
|
||||||
|
|
||||||
Threads
|
|
||||||
Shows stack traces and thread ids for each of the threads within this
|
|
||||||
process.
|
|
||||||
|
|
||||||
Green Threads
|
|
||||||
Shows stack traces for each of the green threads within this process (green
|
|
||||||
threads don't have thread ids).
|
|
||||||
|
|
||||||
Configuration
|
|
||||||
Lists all the configuration options currently accessible via the CONF object
|
|
||||||
for the current process.
|
|
||||||
|
|
||||||
Plugins
|
|
||||||
Lists all the plugins currently accessible by the Watcher service.
|
|
@ -1,14 +0,0 @@
|
|||||||
===================
|
|
||||||
Administrator Guide
|
|
||||||
===================
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 2
|
|
||||||
|
|
||||||
apache-mod-wsgi
|
|
||||||
conf-files
|
|
||||||
configuration
|
|
||||||
gmr
|
|
||||||
policy
|
|
||||||
ways-to-install
|
|
||||||
../strategies/index
|
|
@ -1,142 +0,0 @@
|
|||||||
..
|
|
||||||
Copyright 2016 OpenStack Foundation
|
|
||||||
All Rights Reserved.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
Policies
|
|
||||||
========
|
|
||||||
|
|
||||||
Watcher's public API calls may be restricted to certain sets of users using a
|
|
||||||
policy configuration file. This document explains exactly how policies are
|
|
||||||
configured and what they apply to.
|
|
||||||
|
|
||||||
A policy is composed of a set of rules that are used in determining if a
|
|
||||||
particular action may be performed by the authorized tenant.
|
|
||||||
|
|
||||||
Constructing a Policy Configuration File
|
|
||||||
----------------------------------------
|
|
||||||
|
|
||||||
A policy configuration file is a simply JSON object that contain sets of
|
|
||||||
rules. Each top-level key is the name of a rule. Each rule
|
|
||||||
is a string that describes an action that may be performed in the Watcher API.
|
|
||||||
|
|
||||||
The actions that may have a rule enforced on them are:
|
|
||||||
|
|
||||||
* ``strategy:get_all``, ``strategy:detail`` - List available strategies
|
|
||||||
|
|
||||||
* ``GET /v1/strategies``
|
|
||||||
* ``GET /v1/strategies/detail``
|
|
||||||
|
|
||||||
* ``strategy:get`` - Retrieve a specific strategy entity
|
|
||||||
|
|
||||||
* ``GET /v1/strategies/<STRATEGY_UUID>``
|
|
||||||
* ``GET /v1/strategies/<STRATEGY_NAME>``
|
|
||||||
|
|
||||||
|
|
||||||
* ``goal:get_all``, ``goal:detail`` - List available goals
|
|
||||||
|
|
||||||
* ``GET /v1/goals``
|
|
||||||
* ``GET /v1/goals/detail``
|
|
||||||
|
|
||||||
* ``goal:get`` - Retrieve a specific goal entity
|
|
||||||
|
|
||||||
* ``GET /v1/goals/<GOAL_UUID>``
|
|
||||||
* ``GET /v1/goals/<GOAL_NAME>``
|
|
||||||
|
|
||||||
|
|
||||||
* ``audit_template:get_all``, ``audit_template:detail`` - List available
|
|
||||||
audit_templates
|
|
||||||
|
|
||||||
* ``GET /v1/audit_templates``
|
|
||||||
* ``GET /v1/audit_templates/detail``
|
|
||||||
|
|
||||||
* ``audit_template:get`` - Retrieve a specific audit template entity
|
|
||||||
|
|
||||||
* ``GET /v1/audit_templates/<AUDIT_TEMPLATE_UUID>``
|
|
||||||
* ``GET /v1/audit_templates/<AUDIT_TEMPLATE_NAME>``
|
|
||||||
|
|
||||||
* ``audit_template:create`` - Create an audit template entity
|
|
||||||
|
|
||||||
* ``POST /v1/audit_templates``
|
|
||||||
|
|
||||||
* ``audit_template:delete`` - Delete an audit template entity
|
|
||||||
|
|
||||||
* ``DELETE /v1/audit_templates/<AUDIT_TEMPLATE_UUID>``
|
|
||||||
* ``DELETE /v1/audit_templates/<AUDIT_TEMPLATE_NAME>``
|
|
||||||
|
|
||||||
* ``audit_template:update`` - Update an audit template entity
|
|
||||||
|
|
||||||
* ``PATCH /v1/audit_templates/<AUDIT_TEMPLATE_UUID>``
|
|
||||||
* ``PATCH /v1/audit_templates/<AUDIT_TEMPLATE_NAME>``
|
|
||||||
|
|
||||||
|
|
||||||
* ``audit:get_all``, ``audit:detail`` - List available audits
|
|
||||||
|
|
||||||
* ``GET /v1/audits``
|
|
||||||
* ``GET /v1/audits/detail``
|
|
||||||
|
|
||||||
* ``audit:get`` - Retrieve a specific audit entity
|
|
||||||
|
|
||||||
* ``GET /v1/audits/<AUDIT_UUID>``
|
|
||||||
|
|
||||||
* ``audit:create`` - Create an audit entity
|
|
||||||
|
|
||||||
* ``POST /v1/audits``
|
|
||||||
|
|
||||||
* ``audit:delete`` - Delete an audit entity
|
|
||||||
|
|
||||||
* ``DELETE /v1/audits/<AUDIT_UUID>``
|
|
||||||
|
|
||||||
* ``audit:update`` - Update an audit entity
|
|
||||||
|
|
||||||
* ``PATCH /v1/audits/<AUDIT_UUID>``
|
|
||||||
|
|
||||||
|
|
||||||
* ``action_plan:get_all``, ``action_plan:detail`` - List available action plans
|
|
||||||
|
|
||||||
* ``GET /v1/action_plans``
|
|
||||||
* ``GET /v1/action_plans/detail``
|
|
||||||
|
|
||||||
* ``action_plan:get`` - Retrieve a specific action plan entity
|
|
||||||
|
|
||||||
* ``GET /v1/action_plans/<ACTION_PLAN_UUID>``
|
|
||||||
|
|
||||||
* ``action_plan:delete`` - Delete an action plan entity
|
|
||||||
|
|
||||||
* ``DELETE /v1/action_plans/<ACTION_PLAN_UUID>``
|
|
||||||
|
|
||||||
* ``action_plan:update`` - Update an action plan entity
|
|
||||||
|
|
||||||
* ``PATCH /v1/audits/<ACTION_PLAN_UUID>``
|
|
||||||
|
|
||||||
|
|
||||||
* ``action:get_all``, ``action:detail`` - List available action
|
|
||||||
|
|
||||||
* ``GET /v1/actions``
|
|
||||||
* ``GET /v1/actions/detail``
|
|
||||||
|
|
||||||
* ``action:get`` - Retrieve a specific action plan entity
|
|
||||||
|
|
||||||
* ``GET /v1/actions/<ACTION_UUID>``
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
To limit an action to a particular role or roles, you list the roles like so ::
|
|
||||||
|
|
||||||
{
|
|
||||||
"audit:create": ["role:admin", "role:superuser"]
|
|
||||||
}
|
|
||||||
|
|
||||||
The above would add a rule that only allowed users that had roles of either
|
|
||||||
"admin" or "superuser" to launch an audit.
|
|
@ -1,162 +0,0 @@
|
|||||||
..
|
|
||||||
Except where otherwise noted, this document is licensed under Creative
|
|
||||||
Commons Attribution 3.0 License. You can view the license at:
|
|
||||||
|
|
||||||
https://creativecommons.org/licenses/by/3.0/
|
|
||||||
|
|
||||||
=======================
|
|
||||||
Ways to install Watcher
|
|
||||||
=======================
|
|
||||||
|
|
||||||
This document describes some ways to install Watcher in order to use it.
|
|
||||||
If you are intending to develop on or with Watcher,
|
|
||||||
please read :doc:`../dev/environment`.
|
|
||||||
|
|
||||||
Prerequisites
|
|
||||||
-------------
|
|
||||||
|
|
||||||
The source install instructions specifically avoid using platform specific
|
|
||||||
packages, instead using the source for the code and the Python Package Index
|
|
||||||
(PyPi_).
|
|
||||||
|
|
||||||
.. _PyPi: https://pypi.python.org/pypi
|
|
||||||
|
|
||||||
It's expected that your system already has python2.7_, latest version of pip_,
|
|
||||||
and git_ available.
|
|
||||||
|
|
||||||
.. _python2.7: https://www.python.org
|
|
||||||
.. _pip: https://pip.pypa.io/en/latest/installing/
|
|
||||||
.. _git: https://git-scm.com/
|
|
||||||
|
|
||||||
Your system shall also have some additional system libraries:
|
|
||||||
|
|
||||||
On Ubuntu (tested on 14.04LTS):
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
$ sudo apt-get install python-dev libssl-dev libmysqlclient-dev libffi-dev
|
|
||||||
|
|
||||||
On Fedora-based distributions e.g., Fedora/RHEL/CentOS/Scientific Linux
|
|
||||||
(tested on CentOS 7.1):
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
$ sudo yum install gcc python-devel openssl-devel libffi-devel mysql-devel
|
|
||||||
|
|
||||||
|
|
||||||
Installing from Source
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
Clone the Watcher repository:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
$ git clone https://git.openstack.org/openstack/watcher.git
|
|
||||||
$ cd watcher
|
|
||||||
|
|
||||||
Install the Watcher modules:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
# python setup.py install
|
|
||||||
|
|
||||||
The following commands should be available on the command-line path:
|
|
||||||
|
|
||||||
* ``watcher-api`` the Watcher Web service used to handle RESTful requests
|
|
||||||
* ``watcher-decision-engine`` the Watcher Decision Engine used to build action
|
|
||||||
plans, according to optimization goals to achieve.
|
|
||||||
* ``watcher-applier`` the Watcher Applier module, used to apply action plan
|
|
||||||
* ``watcher-db-manage`` used to bootstrap Watcher data
|
|
||||||
|
|
||||||
You will find sample configuration files in ``etc/watcher``:
|
|
||||||
|
|
||||||
* ``watcher.conf.sample``
|
|
||||||
|
|
||||||
Install the Watcher modules dependencies:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
# pip install -r requirements.txt
|
|
||||||
|
|
||||||
From here, refer to :doc:`configuration` to declare Watcher as a new service
|
|
||||||
into Keystone and to configure its different modules. Once configured, you
|
|
||||||
should be able to run the Watcher services by issuing these commands:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
$ watcher-api
|
|
||||||
$ watcher-decision-engine
|
|
||||||
$ watcher-applier
|
|
||||||
|
|
||||||
By default, this will show logging on the console from which it was started.
|
|
||||||
Once started, you can use the `Watcher Client`_ to play with Watcher service.
|
|
||||||
|
|
||||||
.. _`Watcher Client`: https://git.openstack.org/cgit/openstack/python-watcherclient
|
|
||||||
|
|
||||||
Installing from packages: PyPI
|
|
||||||
--------------------------------
|
|
||||||
|
|
||||||
Watcher package is available on PyPI repository. To install Watcher on your
|
|
||||||
system:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
$ sudo pip install python-watcher
|
|
||||||
|
|
||||||
The Watcher services along with its dependencies should then be automatically
|
|
||||||
installed on your system.
|
|
||||||
|
|
||||||
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
|
|
||||||
in :doc:`configuration`.
|
|
||||||
|
|
||||||
|
|
||||||
Installing from packages: Debian (experimental)
|
|
||||||
-----------------------------------------------
|
|
||||||
|
|
||||||
Experimental Debian packages are available on `Debian repositories`_. The best
|
|
||||||
way to use them is to install them into a Docker_ container.
|
|
||||||
|
|
||||||
Here is single Dockerfile snippet you can use to run your Docker container:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
FROM debian:experimental
|
|
||||||
MAINTAINER David TARDIVEL <david.tardivel@b-com.com>
|
|
||||||
|
|
||||||
RUN apt-get update
|
|
||||||
RUN apt-get dist-upgrade -y
|
|
||||||
RUN apt-get install -y vim net-tools
|
|
||||||
RUN apt-get install -yt experimental watcher-api
|
|
||||||
|
|
||||||
CMD ["/usr/bin/watcher-api"]
|
|
||||||
|
|
||||||
Build your container from this Dockerfile:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
$ docker build -t watcher/api .
|
|
||||||
|
|
||||||
To run your container, execute this command:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
$ docker run -d -p 9322:9322 watcher/api
|
|
||||||
|
|
||||||
Check in your logs Watcher API is started
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
$ docker logs <container ID>
|
|
||||||
|
|
||||||
You can run similar container with Watcher Decision Engine (package
|
|
||||||
``watcher-decision-engine``) and with the Watcher Applier (package
|
|
||||||
``watcher-applier``).
|
|
||||||
|
|
||||||
.. _Docker: https://www.docker.com/
|
|
||||||
.. _`Debian repositories`: https://packages.debian.org/experimental/allpackages
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
|||||||
.. toctree::
|
|
||||||
:maxdepth: 1
|
|
||||||
|
|
||||||
v1
|
|
@ -1,88 +0,0 @@
|
|||||||
..
|
|
||||||
Except where otherwise noted, this document is licensed under Creative
|
|
||||||
Commons Attribution 3.0 License. You can view the license at:
|
|
||||||
|
|
||||||
https://creativecommons.org/licenses/by/3.0/
|
|
||||||
|
|
||||||
====================
|
|
||||||
RESTful Web API (v1)
|
|
||||||
====================
|
|
||||||
|
|
||||||
Goals
|
|
||||||
=====
|
|
||||||
|
|
||||||
.. rest-controller:: watcher.api.controllers.v1.goal:GoalsController
|
|
||||||
:webprefix: /v1/goal
|
|
||||||
|
|
||||||
.. autotype:: watcher.api.controllers.v1.goal.GoalCollection
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. autotype:: watcher.api.controllers.v1.goal.Goal
|
|
||||||
: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
|
|
||||||
===============
|
|
||||||
|
|
||||||
.. rest-controller:: watcher.api.controllers.v1.audit_template:AuditTemplatesController
|
|
||||||
:webprefix: /v1/audit_templates
|
|
||||||
|
|
||||||
.. autotype:: watcher.api.controllers.v1.audit_template.AuditTemplateCollection
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. autotype:: watcher.api.controllers.v1.audit_template.AuditTemplate
|
|
||||||
:members:
|
|
||||||
|
|
||||||
Audits
|
|
||||||
======
|
|
||||||
|
|
||||||
.. rest-controller:: watcher.api.controllers.v1.audit:AuditsController
|
|
||||||
:webprefix: /v1/audits
|
|
||||||
|
|
||||||
.. autotype:: watcher.api.controllers.v1.audit.AuditCollection
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. autotype:: watcher.api.controllers.v1.audit.Audit
|
|
||||||
:members:
|
|
||||||
|
|
||||||
Links
|
|
||||||
=====
|
|
||||||
|
|
||||||
.. autotype:: watcher.api.controllers.link.Link
|
|
||||||
:members:
|
|
||||||
|
|
||||||
Action Plans
|
|
||||||
============
|
|
||||||
|
|
||||||
.. rest-controller:: watcher.api.controllers.v1.action_plan:ActionPlansController
|
|
||||||
:webprefix: /v1/action_plans
|
|
||||||
|
|
||||||
.. autotype:: watcher.api.controllers.v1.action_plan.ActionPlanCollection
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. autotype:: watcher.api.controllers.v1.action_plan.ActionPlan
|
|
||||||
:members:
|
|
||||||
|
|
||||||
|
|
||||||
Actions
|
|
||||||
=======
|
|
||||||
|
|
||||||
.. rest-controller:: watcher.api.controllers.v1.action:ActionsController
|
|
||||||
:webprefix: /v1/actions
|
|
||||||
|
|
||||||
.. autotype:: watcher.api.controllers.v1.action.ActionCollection
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. autotype:: watcher.api.controllers.v1.action.Action
|
|
||||||
:members:
|
|
@ -1,464 +0,0 @@
|
|||||||
..
|
|
||||||
Except where otherwise noted, this document is licensed under Creative
|
|
||||||
Commons Attribution 3.0 License. You can view the license at:
|
|
||||||
|
|
||||||
https://creativecommons.org/licenses/by/3.0/
|
|
||||||
|
|
||||||
.. _architecture:
|
|
||||||
|
|
||||||
===================
|
|
||||||
System Architecture
|
|
||||||
===================
|
|
||||||
|
|
||||||
|
|
||||||
This page presents the current technical Architecture of the Watcher system.
|
|
||||||
|
|
||||||
.. _architecture_overview:
|
|
||||||
|
|
||||||
Overview
|
|
||||||
========
|
|
||||||
|
|
||||||
Below you will find a diagram, showing the main components of Watcher:
|
|
||||||
|
|
||||||
.. image:: ./images/architecture.svg
|
|
||||||
:width: 110%
|
|
||||||
|
|
||||||
|
|
||||||
.. _components_definition:
|
|
||||||
|
|
||||||
Components
|
|
||||||
==========
|
|
||||||
|
|
||||||
.. _amqp_bus_definition:
|
|
||||||
|
|
||||||
AMQP Bus
|
|
||||||
--------
|
|
||||||
|
|
||||||
The AMQP message bus handles internal asynchronous communications between the
|
|
||||||
different Watcher components.
|
|
||||||
|
|
||||||
.. _cluster_datasource_definition:
|
|
||||||
|
|
||||||
Datasource
|
|
||||||
----------
|
|
||||||
|
|
||||||
This component stores the metrics related to the cluster.
|
|
||||||
|
|
||||||
It can potentially rely on any appropriate storage system (InfluxDB, OpenTSDB,
|
|
||||||
MongoDB,...) but will probably be more performant when using
|
|
||||||
`Time Series Databases <https://en.wikipedia.org/wiki/Time_series_database>`_
|
|
||||||
which are optimized for handling time series data, which are arrays of numbers
|
|
||||||
indexed by time (a datetime or a datetime range).
|
|
||||||
|
|
||||||
.. _archi_watcher_api_definition:
|
|
||||||
|
|
||||||
Watcher API
|
|
||||||
-----------
|
|
||||||
|
|
||||||
This component implements the REST API provided by the Watcher system to the
|
|
||||||
external world.
|
|
||||||
|
|
||||||
It enables the :ref:`Administrator <administrator_definition>` of a
|
|
||||||
:ref:`Cluster <cluster_definition>` to control and monitor the Watcher system
|
|
||||||
via any interaction mechanism connected to this API:
|
|
||||||
|
|
||||||
- :ref:`CLI <archi_watcher_cli_definition>`
|
|
||||||
- Horizon plugin
|
|
||||||
- Python SDK
|
|
||||||
|
|
||||||
You can also read the detailed description of `Watcher API`_.
|
|
||||||
|
|
||||||
.. _archi_watcher_applier_definition:
|
|
||||||
|
|
||||||
Watcher Applier
|
|
||||||
---------------
|
|
||||||
|
|
||||||
This component is in charge of executing the
|
|
||||||
:ref:`Action Plan <action_plan_definition>` built by the
|
|
||||||
:ref:`Watcher Decision Engine <watcher_decision_engine_definition>`.
|
|
||||||
|
|
||||||
It connects to the :ref:`message bus <amqp_bus_definition>` and launches the
|
|
||||||
:ref:`Action Plan <action_plan_definition>` whenever a triggering message is
|
|
||||||
received on a dedicated AMQP queue.
|
|
||||||
|
|
||||||
The triggering message contains the Action Plan UUID.
|
|
||||||
|
|
||||||
It then gets the detailed information about the
|
|
||||||
:ref:`Action Plan <action_plan_definition>` from the
|
|
||||||
:ref:`Watcher Database <watcher_database_definition>` which contains the list
|
|
||||||
of :ref:`Actions <action_definition>` to launch.
|
|
||||||
|
|
||||||
It then loops on each :ref:`Action <action_definition>`, gets the associated
|
|
||||||
class and calls the execute() method of this class.
|
|
||||||
Most of the time, this method will first request a token to the Keystone API
|
|
||||||
and if it is allowed, sends a request to the REST API of the OpenStack service
|
|
||||||
which handles this kind of :ref:`atomic Action <action_definition>`.
|
|
||||||
|
|
||||||
Note that as soon as :ref:`Watcher Applier <watcher_applier_definition>` starts
|
|
||||||
handling a given :ref:`Action <action_definition>` from the list, a
|
|
||||||
notification message is sent on the :ref:`message bus <amqp_bus_definition>`
|
|
||||||
indicating that the state of the action has changed to **ONGOING**.
|
|
||||||
|
|
||||||
If the :ref:`Action <action_definition>` is successful,
|
|
||||||
the :ref:`Watcher Applier <watcher_applier_definition>` sends a notification
|
|
||||||
message on :ref:`the bus <amqp_bus_definition>` informing the other components
|
|
||||||
of this.
|
|
||||||
|
|
||||||
|
|
||||||
If the :ref:`Action <action_definition>` fails, the
|
|
||||||
:ref:`Watcher Applier <watcher_applier_definition>` tries to rollback to the
|
|
||||||
previous state of the :ref:`Managed resource <managed_resource_definition>`
|
|
||||||
(i.e. before the command was sent to the underlying OpenStack service).
|
|
||||||
|
|
||||||
.. _archi_watcher_cli_definition:
|
|
||||||
|
|
||||||
Watcher CLI
|
|
||||||
-----------
|
|
||||||
|
|
||||||
The watcher command-line interface (CLI) can be used to interact with the
|
|
||||||
Watcher system in order to control it or to know its current status.
|
|
||||||
|
|
||||||
Please, read `the detailed documentation about Watcher CLI
|
|
||||||
<https://factory.b-com.com/www/watcher/doc/python-watcherclient/>`_.
|
|
||||||
|
|
||||||
.. _archi_watcher_dashboard_definition:
|
|
||||||
|
|
||||||
Watcher Dashboard
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
The Watcher Dashboard can be used to interact with the Watcher system through
|
|
||||||
Horizon in order to control it or to know its current status.
|
|
||||||
|
|
||||||
Please, read `the detailed documentation about Watcher Dashboard
|
|
||||||
<http://docs.openstack.org/developer/watcher-dashboard/>`_.
|
|
||||||
|
|
||||||
.. _archi_watcher_database_definition:
|
|
||||||
|
|
||||||
Watcher Database
|
|
||||||
----------------
|
|
||||||
|
|
||||||
This database stores all the Watcher domain objects which can be requested
|
|
||||||
by the :ref:`Watcher API <archi_watcher_api_definition>` or the
|
|
||||||
:ref:`Watcher CLI <archi_watcher_cli_definition>`:
|
|
||||||
|
|
||||||
- :ref:`Goals <goal_definition>`
|
|
||||||
- :ref:`Strategies <strategy_definition>`
|
|
||||||
- :ref:`Audit templates <audit_template_definition>`
|
|
||||||
- :ref:`Audits <audit_definition>`
|
|
||||||
- :ref:`Action plans <action_plan_definition>`
|
|
||||||
- :ref:`Efficacy indicators <efficacy_indicator_definition>` via the Action
|
|
||||||
Plan API.
|
|
||||||
- :ref:`Actions <action_definition>`
|
|
||||||
|
|
||||||
The Watcher domain being here "*optimization of some resources provided by an
|
|
||||||
OpenStack system*".
|
|
||||||
|
|
||||||
.. _archi_watcher_decision_engine_definition:
|
|
||||||
|
|
||||||
Watcher Decision Engine
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
This component is responsible for computing a set of potential optimization
|
|
||||||
:ref:`Actions <action_definition>` in order to fulfill
|
|
||||||
the :ref:`Goal <goal_definition>` of an :ref:`Audit <audit_definition>`.
|
|
||||||
|
|
||||||
It first reads the parameters of the :ref:`Audit <audit_definition>` to know
|
|
||||||
the :ref:`Goal <goal_definition>` to achieve.
|
|
||||||
|
|
||||||
Unless specified, it then selects the most appropriate :ref:`strategy
|
|
||||||
<strategy_definition>` from the list of available strategies achieving this
|
|
||||||
goal.
|
|
||||||
|
|
||||||
The :ref:`Strategy <strategy_definition>` is then dynamically loaded (via
|
|
||||||
`stevedore <http://docs.openstack.org/developer/stevedore/>`_). The
|
|
||||||
:ref:`Watcher Decision Engine <watcher_decision_engine_definition>` executes
|
|
||||||
the strategy.
|
|
||||||
|
|
||||||
In order to compute the potential :ref:`Solution <solution_definition>` for the
|
|
||||||
Audit, the :ref:`Strategy <strategy_definition>` relies on different sets of
|
|
||||||
data:
|
|
||||||
|
|
||||||
- :ref:`Cluster data models <cluster_data_model_definition>` that are
|
|
||||||
periodically synchronized through pluggable cluster data model collectors.
|
|
||||||
These models contain the current state of various
|
|
||||||
:ref:`Managed resources <managed_resource_definition>` (e.g., the data stored
|
|
||||||
in the Nova database). These models gives a strategy the ability to reason on
|
|
||||||
the current state of a given :ref:`cluster <cluster_definition>`.
|
|
||||||
- The data stored in the :ref:`Cluster Datasource
|
|
||||||
<cluster_datasource_definition>` which provides information about the past of
|
|
||||||
the :ref:`Cluster <cluster_definition>`.
|
|
||||||
|
|
||||||
Here below is a sequence diagram showing how the Decision Engine builds and
|
|
||||||
maintains the :ref:`cluster data models <cluster_data_model_definition>` that
|
|
||||||
are used by the strategies.
|
|
||||||
|
|
||||||
.. image:: ./images/sequence_architecture_cdmc_sync.png
|
|
||||||
:width: 100%
|
|
||||||
|
|
||||||
The execution of a strategy then yields a solution composed of a set of
|
|
||||||
:ref:`Actions <action_definition>` as well as a set of :ref:`efficacy
|
|
||||||
indicators <efficacy_indicator_definition>`.
|
|
||||||
|
|
||||||
These :ref:`Actions <action_definition>` are scheduled in time by the
|
|
||||||
:ref:`Watcher Planner <watcher_planner_definition>` (i.e., it generates an
|
|
||||||
:ref:`Action Plan <action_plan_definition>`).
|
|
||||||
|
|
||||||
.. _data_model:
|
|
||||||
|
|
||||||
Data model
|
|
||||||
==========
|
|
||||||
|
|
||||||
The following diagram shows the data model of Watcher, especially the
|
|
||||||
functional dependency of objects from the actors (Admin, Customer) point of
|
|
||||||
view (Goals, Audits, Action Plans, ...):
|
|
||||||
|
|
||||||
.. image:: ./images/functional_data_model.svg
|
|
||||||
:width: 100%
|
|
||||||
|
|
||||||
Here below is a diagram representing the main objects in Watcher from a
|
|
||||||
database perspective:
|
|
||||||
|
|
||||||
.. image:: ./images/watcher_db_schema_diagram.png
|
|
||||||
|
|
||||||
|
|
||||||
.. _sequence_diagrams:
|
|
||||||
|
|
||||||
Sequence diagrams
|
|
||||||
=================
|
|
||||||
|
|
||||||
The following paragraph shows the messages exchanged between the different
|
|
||||||
components of Watcher for the most often used scenarios.
|
|
||||||
|
|
||||||
.. _sequence_diagrams_create_audit_template:
|
|
||||||
|
|
||||||
Create a new Audit Template
|
|
||||||
---------------------------
|
|
||||||
|
|
||||||
The :ref:`Administrator <administrator_definition>` first creates an
|
|
||||||
:ref:`Audit template <audit_template_definition>` providing at least the
|
|
||||||
following parameters:
|
|
||||||
|
|
||||||
- A name
|
|
||||||
- A goal to achieve
|
|
||||||
- An optional strategy
|
|
||||||
|
|
||||||
.. image:: ./images/sequence_create_audit_template.png
|
|
||||||
:width: 100%
|
|
||||||
|
|
||||||
The `Watcher API`_ makes sure that both the specified goal (mandatory) and
|
|
||||||
its associated strategy (optional) are registered inside the :ref:`Watcher
|
|
||||||
Database <watcher_database_definition>` before storing a new audit template in
|
|
||||||
the :ref:`Watcher Database <watcher_database_definition>`.
|
|
||||||
|
|
||||||
.. _sequence_diagrams_create_and_launch_audit:
|
|
||||||
|
|
||||||
Create and launch a new Audit
|
|
||||||
-----------------------------
|
|
||||||
|
|
||||||
The :ref:`Administrator <administrator_definition>` can then launch a new
|
|
||||||
:ref:`Audit <audit_definition>` by providing at least the unique UUID of the
|
|
||||||
previously created :ref:`Audit template <audit_template_definition>`:
|
|
||||||
|
|
||||||
.. image:: ./images/sequence_create_and_launch_audit.png
|
|
||||||
:width: 100%
|
|
||||||
|
|
||||||
The :ref:`Administrator <administrator_definition>` also can specify type of
|
|
||||||
Audit and interval (in case of CONTINUOUS type). There is two types of Audit:
|
|
||||||
ONESHOT and CONTINUOUS. Oneshot Audit is launched once and if it succeeded
|
|
||||||
executed new action plan list will be provided. Continuous Audit creates
|
|
||||||
action plans with specified interval (in seconds); if action plan
|
|
||||||
has been created, all previous action plans get CANCELLED state.
|
|
||||||
|
|
||||||
A message is sent on the :ref:`AMQP bus <amqp_bus_definition>` which triggers
|
|
||||||
the Audit in the
|
|
||||||
:ref:`Watcher Decision Engine <watcher_decision_engine_definition>`:
|
|
||||||
|
|
||||||
.. image:: ./images/sequence_trigger_audit_in_decision_engine.png
|
|
||||||
:width: 100%
|
|
||||||
|
|
||||||
The :ref:`Watcher Decision Engine <watcher_decision_engine_definition>` reads
|
|
||||||
the Audit parameters from the
|
|
||||||
:ref:`Watcher Database <watcher_database_definition>`. It instantiates the
|
|
||||||
appropriate :ref:`strategy <strategy_definition>` (using entry points)
|
|
||||||
given both the :ref:`goal <goal_definition>` and the strategy associated to the
|
|
||||||
parent :ref:`audit template <audit_template_definition>` of the :ref:`audit
|
|
||||||
<audit_definition>`. If no strategy is associated to the audit template, the
|
|
||||||
strategy is dynamically selected by the Decision Engine.
|
|
||||||
|
|
||||||
The :ref:`Watcher Decision Engine <watcher_decision_engine_definition>` also
|
|
||||||
builds the :ref:`Cluster Data Model <cluster_data_model_definition>`. This
|
|
||||||
data model is needed by the :ref:`Strategy <strategy_definition>` to know the
|
|
||||||
current state and topology of the audited
|
|
||||||
:ref:`OpenStack cluster <cluster_definition>`.
|
|
||||||
|
|
||||||
The :ref:`Watcher Decision Engine <watcher_decision_engine_definition>` calls
|
|
||||||
the **execute()** method of the instantiated
|
|
||||||
:ref:`Strategy <strategy_definition>` and provides the data model as an input
|
|
||||||
parameter. This method computes a :ref:`Solution <strategy_definition>` to
|
|
||||||
achieve the goal and returns it to the
|
|
||||||
:ref:`Decision Engine <watcher_decision_engine_definition>`. At this point,
|
|
||||||
actions are not scheduled yet.
|
|
||||||
|
|
||||||
The :ref:`Watcher Decision Engine <watcher_decision_engine_definition>`
|
|
||||||
dynamically loads the :ref:`Watcher Planner <watcher_planner_definition>`
|
|
||||||
implementation which is configured in Watcher (via entry points) and calls the
|
|
||||||
**schedule()** method of this class with the solution as an input parameter.
|
|
||||||
This method finds an appropriate scheduling of
|
|
||||||
:ref:`Actions <action_definition>` taking into account some scheduling rules
|
|
||||||
(such as priorities between actions).
|
|
||||||
It generates a new :ref:`Action Plan <action_plan_definition>` with status
|
|
||||||
**RECOMMENDED** and saves it into the :ref:`Watcher Database
|
|
||||||
<watcher_database_definition>`. The saved action plan is now a scheduled flow
|
|
||||||
of actions to which a global efficacy is associated alongside a number of
|
|
||||||
:ref:`Efficacy Indicators <efficacy_indicator_definition>` as specified by the
|
|
||||||
related :ref:`goal <goal_definition>`.
|
|
||||||
|
|
||||||
If every step executed successfully, the
|
|
||||||
:ref:`Watcher Decision Engine <watcher_decision_engine_definition>` updates
|
|
||||||
the current status of the Audit to **SUCCEEDED** in the
|
|
||||||
:ref:`Watcher Database <watcher_database_definition>` and sends a notification
|
|
||||||
on the bus to inform other components that the :ref:`Audit <audit_definition>`
|
|
||||||
was successful.
|
|
||||||
|
|
||||||
This internal workflow the Decision Engine follows to conduct an audit can be
|
|
||||||
seen in the sequence diagram here below:
|
|
||||||
|
|
||||||
.. image:: ./images/sequence_from_audit_execution_to_actionplan_creation.png
|
|
||||||
:width: 100%
|
|
||||||
|
|
||||||
.. _sequence_diagrams_launch_action_plan:
|
|
||||||
|
|
||||||
Launch Action Plan
|
|
||||||
------------------
|
|
||||||
|
|
||||||
The :ref:`Administrator <administrator_definition>` can then launch the
|
|
||||||
recommended :ref:`Action Plan <action_plan_definition>`:
|
|
||||||
|
|
||||||
.. image:: ./images/sequence_launch_action_plan.png
|
|
||||||
:width: 100%
|
|
||||||
|
|
||||||
A message is sent on the :ref:`AMQP bus <amqp_bus_definition>` which triggers
|
|
||||||
the :ref:`Action Plan <action_plan_definition>` in the
|
|
||||||
:ref:`Watcher Applier <watcher_applier_definition>`:
|
|
||||||
|
|
||||||
.. image:: ./images/sequence_launch_action_plan_in_applier.png
|
|
||||||
:width: 100%
|
|
||||||
|
|
||||||
The :ref:`Watcher Applier <watcher_applier_definition>` will get the
|
|
||||||
description of the flow of :ref:`Actions <action_definition>` from the
|
|
||||||
:ref:`Watcher Database <watcher_database_definition>` and for each
|
|
||||||
:ref:`Action <action_definition>` it will instantiate a corresponding
|
|
||||||
:ref:`Action <action_definition>` handler python class.
|
|
||||||
|
|
||||||
The :ref:`Watcher Applier <watcher_applier_definition>` will then call the
|
|
||||||
following methods of the :ref:`Action <action_definition>` handler:
|
|
||||||
|
|
||||||
- **validate_parameters()**: this method will make sure that all the
|
|
||||||
provided input parameters are valid:
|
|
||||||
|
|
||||||
- If all parameters are valid, the Watcher Applier moves on to the next
|
|
||||||
step.
|
|
||||||
- If it is not, an error is raised and the action is not executed. A
|
|
||||||
notification is sent on the bus informing other components of the
|
|
||||||
failure.
|
|
||||||
|
|
||||||
- **preconditions()**: this method will make sure that all conditions are met
|
|
||||||
before executing the action (for example, it makes sure that an instance
|
|
||||||
still exists before trying to migrate it).
|
|
||||||
- **execute()**: this method is what triggers real commands on other
|
|
||||||
OpenStack services (such as Nova, ...) in order to change target resource
|
|
||||||
state. If the action is successfully executed, a notification message is
|
|
||||||
sent on the bus indicating that the new state of the action is
|
|
||||||
**SUCCEEDED**.
|
|
||||||
|
|
||||||
If every action of the action flow has been executed successfully, a
|
|
||||||
notification is sent on the bus to indicate that the whole
|
|
||||||
:ref:`Action Plan <action_plan_definition>` has **SUCCEEDED**.
|
|
||||||
|
|
||||||
|
|
||||||
.. _state_machine_diagrams:
|
|
||||||
|
|
||||||
State Machine diagrams
|
|
||||||
======================
|
|
||||||
|
|
||||||
.. _audit_state_machine:
|
|
||||||
|
|
||||||
Audit State Machine
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
An :ref:`Audit <audit_definition>` has a life-cycle and its current state may
|
|
||||||
be one of the following:
|
|
||||||
|
|
||||||
- **PENDING** : a request for an :ref:`Audit <audit_definition>` has been
|
|
||||||
submitted (either manually by the
|
|
||||||
:ref:`Administrator <administrator_definition>` or automatically via some
|
|
||||||
event handling mechanism) and is in the queue for being processed by the
|
|
||||||
:ref:`Watcher Decision Engine <watcher_decision_engine_definition>`
|
|
||||||
- **ONGOING** : the :ref:`Audit <audit_definition>` is currently being
|
|
||||||
processed by the
|
|
||||||
:ref:`Watcher Decision Engine <watcher_decision_engine_definition>`
|
|
||||||
- **SUCCEEDED** : the :ref:`Audit <audit_definition>` has been executed
|
|
||||||
successfully and at least one solution was found
|
|
||||||
- **FAILED** : an error occurred while executing the
|
|
||||||
:ref:`Audit <audit_definition>`
|
|
||||||
- **DELETED** : the :ref:`Audit <audit_definition>` is still stored in the
|
|
||||||
:ref:`Watcher database <watcher_database_definition>` but is not returned
|
|
||||||
any more through the Watcher APIs.
|
|
||||||
- **CANCELLED** : the :ref:`Audit <audit_definition>` was in **PENDING** or
|
|
||||||
**ONGOING** state and was cancelled by the
|
|
||||||
:ref:`Administrator <administrator_definition>`
|
|
||||||
- **SUSPENDED** : the :ref:`Audit <audit_definition>` was in **ONGOING**
|
|
||||||
state and was suspended by the
|
|
||||||
:ref:`Administrator <administrator_definition>`
|
|
||||||
|
|
||||||
The following diagram shows the different possible states of an
|
|
||||||
:ref:`Audit <audit_definition>` and what event makes the state change to a new
|
|
||||||
value:
|
|
||||||
|
|
||||||
.. image:: ./images/audit_state_machine.png
|
|
||||||
:width: 100%
|
|
||||||
|
|
||||||
.. _action_plan_state_machine:
|
|
||||||
|
|
||||||
Action Plan State Machine
|
|
||||||
-------------------------
|
|
||||||
|
|
||||||
An :ref:`Action Plan <action_plan_definition>` has a life-cycle and its current
|
|
||||||
state may be one of the following:
|
|
||||||
|
|
||||||
- **RECOMMENDED** : the :ref:`Action Plan <action_plan_definition>` is waiting
|
|
||||||
for a validation from the :ref:`Administrator <administrator_definition>`
|
|
||||||
- **PENDING** : a request for an :ref:`Action Plan <action_plan_definition>`
|
|
||||||
has been submitted (due to an
|
|
||||||
:ref:`Administrator <administrator_definition>` executing an
|
|
||||||
:ref:`Audit <audit_definition>`) and is in the queue for
|
|
||||||
being processed by the :ref:`Watcher Applier <watcher_applier_definition>`
|
|
||||||
- **ONGOING** : the :ref:`Action Plan <action_plan_definition>` is currently
|
|
||||||
being processed by the :ref:`Watcher Applier <watcher_applier_definition>`
|
|
||||||
- **SUCCEEDED** : the :ref:`Action Plan <action_plan_definition>` has been
|
|
||||||
executed successfully (i.e. all :ref:`Actions <action_definition>` that it
|
|
||||||
contains have been executed successfully)
|
|
||||||
- **FAILED** : an error occurred while executing the
|
|
||||||
:ref:`Action Plan <action_plan_definition>`
|
|
||||||
- **DELETED** : the :ref:`Action Plan <action_plan_definition>` is still
|
|
||||||
stored in the :ref:`Watcher database <watcher_database_definition>` but is
|
|
||||||
not returned any more through the Watcher APIs.
|
|
||||||
- **CANCELLED** : the :ref:`Action Plan <action_plan_definition>` was in
|
|
||||||
**RECOMMENDED**, **PENDING** or **ONGOING** state and was cancelled by the
|
|
||||||
:ref:`Administrator <administrator_definition>`
|
|
||||||
- **SUPERSEDED** : the :ref:`Action Plan <action_plan_definition>` was in
|
|
||||||
RECOMMENDED state and was automatically superseded by Watcher, due to an
|
|
||||||
expiration delay or an update of the
|
|
||||||
:ref:`Cluster data model <cluster_data_model_definition>`
|
|
||||||
|
|
||||||
|
|
||||||
The following diagram shows the different possible states of an
|
|
||||||
:ref:`Action Plan <action_plan_definition>` and what event makes the state
|
|
||||||
change to a new value:
|
|
||||||
|
|
||||||
.. image:: ./images/action_plan_state_machine.png
|
|
||||||
:width: 100%
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. _Watcher API: webapi/v1.html
|
|
@ -1,145 +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.
|
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from watcher import version as watcher_version
|
|
||||||
from watcher import objects
|
|
||||||
|
|
||||||
objects.register_all()
|
|
||||||
|
|
||||||
# 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('../../'))
|
|
||||||
sys.path.insert(0, os.path.abspath('../'))
|
|
||||||
sys.path.insert(0, os.path.abspath('./'))
|
|
||||||
|
|
||||||
# -- General configuration ----------------------------------------------------
|
|
||||||
|
|
||||||
# Add any Sphinx extension module names here, as strings. They can be
|
|
||||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
|
||||||
extensions = [
|
|
||||||
'oslo_config.sphinxconfiggen',
|
|
||||||
'openstackdocstheme',
|
|
||||||
'sphinx.ext.autodoc',
|
|
||||||
'sphinx.ext.viewcode',
|
|
||||||
'sphinxcontrib.httpdomain',
|
|
||||||
'sphinxcontrib.pecanwsme.rest',
|
|
||||||
'stevedore.sphinxext',
|
|
||||||
'wsmeext.sphinxext',
|
|
||||||
'ext.term',
|
|
||||||
'ext.versioned_notifications',
|
|
||||||
]
|
|
||||||
|
|
||||||
wsme_protocols = ['restjson']
|
|
||||||
config_generator_config_file = '../../etc/watcher/watcher-config-generator.conf'
|
|
||||||
sample_config_basename = 'watcher'
|
|
||||||
|
|
||||||
# autodoc generation is a bit aggressive and a nuisance when doing heavy
|
|
||||||
# text edit cycles.
|
|
||||||
# execute "export SPHINX_DEBUG=1" in your terminal to disable
|
|
||||||
|
|
||||||
# The suffix of source filenames.
|
|
||||||
source_suffix = '.rst'
|
|
||||||
|
|
||||||
# The master toctree document.
|
|
||||||
master_doc = 'index'
|
|
||||||
|
|
||||||
# General information about the project.
|
|
||||||
project = u'Watcher'
|
|
||||||
copyright = u'OpenStack Foundation'
|
|
||||||
|
|
||||||
# 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.
|
|
||||||
# The full version, including alpha/beta/rc tags.
|
|
||||||
release = watcher_version.version_info.release_string()
|
|
||||||
# The short X.Y version.
|
|
||||||
version = watcher_version.version_info.version_string()
|
|
||||||
|
|
||||||
# A list of ignored prefixes for module index sorting.
|
|
||||||
modindex_common_prefix = ['watcher.']
|
|
||||||
|
|
||||||
exclude_patterns = [
|
|
||||||
# The man directory includes some snippet files that are included
|
|
||||||
# in other documents during the build but that should not be
|
|
||||||
# included in the toctree themselves, so tell Sphinx to ignore
|
|
||||||
# them when scanning for input files.
|
|
||||||
'man/footer.rst',
|
|
||||||
'man/general-options.rst',
|
|
||||||
'strategies/strategy-template.rst',
|
|
||||||
'image_src/plantuml/README.rst',
|
|
||||||
]
|
|
||||||
|
|
||||||
# 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
|
|
||||||
|
|
||||||
# The name of the Pygments (syntax highlighting) style to use.
|
|
||||||
pygments_style = 'sphinx'
|
|
||||||
|
|
||||||
# -- Options for man page output --------------------------------------------
|
|
||||||
|
|
||||||
# Grouping the document tree for man pages.
|
|
||||||
# List of tuples 'sourcefile', 'target', u'title', u'Authors name', 'manual'
|
|
||||||
|
|
||||||
man_pages = [
|
|
||||||
('man/watcher-api', 'watcher-api', u'Watcher API Server',
|
|
||||||
[u'OpenStack'], 1),
|
|
||||||
('man/watcher-applier', 'watcher-applier', u'Watcher Applier',
|
|
||||||
[u'OpenStack'], 1),
|
|
||||||
('man/watcher-db-manage', 'watcher-db-manage',
|
|
||||||
u'Watcher Db Management Utility', [u'OpenStack'], 1),
|
|
||||||
('man/watcher-decision-engine', 'watcher-decision-engine',
|
|
||||||
u'Watcher Decision Engine', [u'OpenStack'], 1),
|
|
||||||
]
|
|
||||||
|
|
||||||
# -- Options for HTML output --------------------------------------------------
|
|
||||||
|
|
||||||
# The theme to use for HTML and HTML Help pages. Major themes that come with
|
|
||||||
# Sphinx are currently 'default' and 'sphinxdoc'.
|
|
||||||
# html_theme_path = ["."]
|
|
||||||
# html_theme = '_theme'
|
|
||||||
html_theme = 'openstackdocs'
|
|
||||||
# html_static_path = ['static']
|
|
||||||
# html_theme_options = {}
|
|
||||||
|
|
||||||
# Output file base name for HTML help builder.
|
|
||||||
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
|
|
||||||
# (source start file, target name, title, author, documentclass
|
|
||||||
# [howto/manual]).
|
|
||||||
latex_documents = [
|
|
||||||
('index',
|
|
||||||
'%s.tex' % project,
|
|
||||||
u'%s Documentation' % project,
|
|
||||||
u'OpenStack Foundation', 'manual'),
|
|
||||||
]
|
|
||||||
|
|
||||||
# Example configuration for intersphinx: refer to the Python standard library.
|
|
||||||
# intersphinx_mapping = {'http://docs.python.org/': None}
|
|
@ -1 +0,0 @@
|
|||||||
../../etc/watcher/watcher-config-generator.conf
|
|
@ -1,72 +0,0 @@
|
|||||||
..
|
|
||||||
Except where otherwise noted, this document is licensed under Creative
|
|
||||||
Commons Attribution 3.0 License. You can view the license at:
|
|
||||||
|
|
||||||
https://creativecommons.org/licenses/by/3.0/
|
|
||||||
|
|
||||||
.. _contributing:
|
|
||||||
|
|
||||||
=======================
|
|
||||||
Contributing to Watcher
|
|
||||||
=======================
|
|
||||||
|
|
||||||
If you're interested in contributing to the Watcher project,
|
|
||||||
the following will help get you started.
|
|
||||||
|
|
||||||
Contributor License Agreement
|
|
||||||
-----------------------------
|
|
||||||
|
|
||||||
.. index::
|
|
||||||
single: license; agreement
|
|
||||||
|
|
||||||
In order to contribute to the Watcher project, you need to have
|
|
||||||
signed OpenStack's contributor's agreement.
|
|
||||||
|
|
||||||
.. seealso::
|
|
||||||
|
|
||||||
* http://docs.openstack.org/infra/manual/developers.html
|
|
||||||
* http://wiki.openstack.org/CLA
|
|
||||||
|
|
||||||
LaunchPad Project
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
Most of the tools used for OpenStack depend on a launchpad.net ID for
|
|
||||||
authentication. After signing up for a launchpad account, join the
|
|
||||||
"openstack" team to have access to the mailing list and receive
|
|
||||||
notifications of important events.
|
|
||||||
|
|
||||||
.. seealso::
|
|
||||||
|
|
||||||
* http://launchpad.net
|
|
||||||
* http://launchpad.net/watcher
|
|
||||||
* http://launchpad.net/~openstack
|
|
||||||
|
|
||||||
|
|
||||||
Project Hosting Details
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
Bug tracker
|
|
||||||
http://launchpad.net/watcher
|
|
||||||
|
|
||||||
Mailing list (prefix subjects with ``[watcher]`` for faster responses)
|
|
||||||
http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev
|
|
||||||
|
|
||||||
Wiki
|
|
||||||
http://wiki.openstack.org/Watcher
|
|
||||||
|
|
||||||
Code Hosting
|
|
||||||
https://git.openstack.org/cgit/openstack/watcher
|
|
||||||
|
|
||||||
Code Review
|
|
||||||
https://review.openstack.org/#/q/status:open+project:openstack/watcher,n,z
|
|
||||||
|
|
||||||
IRC Channel
|
|
||||||
``#openstack-watcher`` (changelog_)
|
|
||||||
|
|
||||||
Weekly Meetings
|
|
||||||
On Wednesdays at 14:00 UTC on even weeks in the ``#openstack-meeting-4``
|
|
||||||
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/
|
|
||||||
.. _meetings logs: http://eavesdrop.openstack.org/meetings/watcher/
|
|
@ -1,241 +0,0 @@
|
|||||||
..
|
|
||||||
Except where otherwise noted, this document is licensed under Creative
|
|
||||||
Commons Attribution 3.0 License. You can view the license at:
|
|
||||||
|
|
||||||
https://creativecommons.org/licenses/by/3.0/
|
|
||||||
|
|
||||||
=============================================
|
|
||||||
Set up a development environment via DevStack
|
|
||||||
=============================================
|
|
||||||
|
|
||||||
Watcher is currently able to optimize compute resources - specifically Nova
|
|
||||||
compute hosts - via operations such as live migrations. In order for you to
|
|
||||||
fully be able to exercise what Watcher can do, it is necessary to have a
|
|
||||||
multinode environment to use.
|
|
||||||
|
|
||||||
You can set up the Watcher services quickly and easily using a Watcher
|
|
||||||
DevStack plugin. See `PluginModelDocs`_ for information on DevStack's plugin
|
|
||||||
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
|
|
||||||
Watcher plugin::
|
|
||||||
|
|
||||||
enable_plugin watcher git://git.openstack.org/openstack/watcher
|
|
||||||
|
|
||||||
For more detailed instructions, see `Detailed DevStack Instructions`_. Check
|
|
||||||
out the `DevStack documentation`_ for more information regarding DevStack.
|
|
||||||
|
|
||||||
.. _PluginModelDocs: http://docs.openstack.org/developer/devstack/plugins.html
|
|
||||||
.. _DevStack documentation: http://docs.openstack.org/developer/devstack/
|
|
||||||
|
|
||||||
Detailed DevStack Instructions
|
|
||||||
==============================
|
|
||||||
|
|
||||||
#. Obtain N (where N >= 1) servers (virtual machines preferred for DevStack).
|
|
||||||
One of these servers will be the controller node while the others will be
|
|
||||||
compute nodes. N is preferably >= 3 so that you have at least 2 compute
|
|
||||||
nodes, but in order to stand up the Watcher services only 1 server is
|
|
||||||
needed (i.e., no computes are needed if you want to just experiment with
|
|
||||||
the Watcher services). These servers can be VMs running on your local
|
|
||||||
machine via VirtualBox if you prefer. DevStack currently recommends that
|
|
||||||
you use Ubuntu 14.04 LTS. The servers should also have connections to the
|
|
||||||
same network such that they are all able to communicate with one another.
|
|
||||||
|
|
||||||
#. For each server, clone the DevStack repository and create the stack user::
|
|
||||||
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install git
|
|
||||||
git clone https://git.openstack.org/openstack-dev/devstack
|
|
||||||
sudo ./devstack/tools/create-stack-user.sh
|
|
||||||
|
|
||||||
Now you have a stack user that is used to run the DevStack processes. You
|
|
||||||
may want to give your stack user a password to allow SSH via a password::
|
|
||||||
|
|
||||||
sudo passwd stack
|
|
||||||
|
|
||||||
#. Switch to the stack user and clone the DevStack repo again::
|
|
||||||
|
|
||||||
sudo su stack
|
|
||||||
cd ~
|
|
||||||
git clone https://git.openstack.org/openstack-dev/devstack
|
|
||||||
|
|
||||||
#. For each compute node, copy the provided `local.conf.compute`_ example file
|
|
||||||
to the compute node's system at ~/devstack/local.conf. Make sure the
|
|
||||||
HOST_IP and SERVICE_HOST values are changed appropriately - i.e., HOST_IP
|
|
||||||
is set to the IP address of the compute node and SERVICE_HOST is set to the
|
|
||||||
IP address of the controller node.
|
|
||||||
|
|
||||||
If you need specific metrics collected (or want to use something other
|
|
||||||
than Ceilometer), be sure to configure it. For example, in the
|
|
||||||
`local.conf.compute`_ example file, the appropriate ceilometer plugins and
|
|
||||||
services are enabled and disabled. If you were using something other than
|
|
||||||
Ceilometer, then you would likely want to configure it likewise. The
|
|
||||||
example file also sets the compute monitors nova configuration option to
|
|
||||||
use the CPU virt driver. If you needed other metrics, it may be necessary
|
|
||||||
to configure similar configuration options for the projects providing those
|
|
||||||
metrics.
|
|
||||||
|
|
||||||
#. For the controller node, copy the provided `local.conf.controller`_ example
|
|
||||||
file to the controller node's system at ~/devstack/local.conf. Make sure
|
|
||||||
the HOST_IP value is changed appropriately - i.e., HOST_IP is set to the IP
|
|
||||||
address of the controller node.
|
|
||||||
|
|
||||||
Note: if you want to use another Watcher git repository (such as a local
|
|
||||||
one), then change the enable plugin line::
|
|
||||||
|
|
||||||
enable_plugin watcher <your_local_git_repo> [optional_branch]
|
|
||||||
|
|
||||||
If you do this, then the Watcher DevStack plugin will try to pull the
|
|
||||||
python-watcherclient repo from <your_local_git_repo>/../, so either make
|
|
||||||
sure that is also available or specify WATCHERCLIENT_REPO in the local.conf
|
|
||||||
file.
|
|
||||||
|
|
||||||
Note: if you want to use a specific branch, specify WATCHER_BRANCH in the
|
|
||||||
local.conf file. By default it will use the master branch.
|
|
||||||
|
|
||||||
Note: watcher-api will default run under apache/httpd, set the variable
|
|
||||||
WATCHER_USE_MOD_WSGI=FALSE if you do not wish to run under apache/httpd.
|
|
||||||
For development environment it is suggested to set WATHCER_USE_MOD_WSGI
|
|
||||||
to FALSE. For Production environment it is suggested to keep it at the
|
|
||||||
default TRUE value.
|
|
||||||
|
|
||||||
#. Start stacking from the controller node::
|
|
||||||
|
|
||||||
./devstack/stack.sh
|
|
||||||
|
|
||||||
#. Start stacking on each of the compute nodes using the same command.
|
|
||||||
|
|
||||||
#. Configure the environment for live migration via NFS. See the
|
|
||||||
`Multi-Node DevStack Environment`_ section for more details.
|
|
||||||
|
|
||||||
.. _local.conf.controller: https://github.com/openstack/watcher/tree/master/devstack/local.conf.controller
|
|
||||||
.. _local.conf.compute: https://github.com/openstack/watcher/tree/master/devstack/local.conf.compute
|
|
||||||
|
|
||||||
Multi-Node DevStack Environment
|
|
||||||
===============================
|
|
||||||
|
|
||||||
Since deploying Watcher with only a single compute node is not very useful, a
|
|
||||||
few tips are given here for enabling a multi-node environment with live
|
|
||||||
migration.
|
|
||||||
|
|
||||||
Configuring NFS Server
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
If you would like to use live migration for shared storage, then the controller
|
|
||||||
can serve as the NFS server if needed::
|
|
||||||
|
|
||||||
sudo apt-get install nfs-kernel-server
|
|
||||||
sudo mkdir -p /nfs/instances
|
|
||||||
sudo chown stack:stack /nfs/instances
|
|
||||||
|
|
||||||
Add an entry to `/etc/exports` with the appropriate gateway and netmask
|
|
||||||
information::
|
|
||||||
|
|
||||||
/nfs/instances <gateway>/<netmask>(rw,fsid=0,insecure,no_subtree_check,async,no_root_squash)
|
|
||||||
|
|
||||||
Export the NFS directories::
|
|
||||||
|
|
||||||
sudo exportfs -ra
|
|
||||||
|
|
||||||
Make sure the NFS server is running::
|
|
||||||
|
|
||||||
sudo service nfs-kernel-server status
|
|
||||||
|
|
||||||
If the server is not running, then start it::
|
|
||||||
|
|
||||||
sudo service nfs-kernel-server start
|
|
||||||
|
|
||||||
Configuring NFS on Compute Node
|
|
||||||
-------------------------------
|
|
||||||
|
|
||||||
Each compute node needs to use the NFS server to hold the instance data::
|
|
||||||
|
|
||||||
sudo apt-get install rpcbind nfs-common
|
|
||||||
mkdir -p /opt/stack/data/instances
|
|
||||||
sudo mount <nfs-server-ip>:/nfs/instances /opt/stack/data/instances
|
|
||||||
|
|
||||||
If you would like to have the NFS directory automatically mounted on reboot,
|
|
||||||
then add the following to `/etc/fstab`::
|
|
||||||
|
|
||||||
<nfs-server-ip>:/nfs/instances /opt/stack/data/instances nfs auto 0 0
|
|
||||||
|
|
||||||
Edit `/etc/libvirt/libvirtd.conf` to make sure the following values are set::
|
|
||||||
|
|
||||||
listen_tls = 0
|
|
||||||
listen_tcp = 1
|
|
||||||
auth_tcp = "none"
|
|
||||||
|
|
||||||
Edit `/etc/default/libvirt-bin`::
|
|
||||||
|
|
||||||
libvirtd_opts="-d -l"
|
|
||||||
|
|
||||||
Restart the libvirt service::
|
|
||||||
|
|
||||||
sudo service libvirt-bin restart
|
|
||||||
|
|
||||||
Setting up SSH keys between compute nodes to enable live migration
|
|
||||||
------------------------------------------------------------------
|
|
||||||
|
|
||||||
In order for live migration to work, SSH keys need to be exchanged between
|
|
||||||
each compute node:
|
|
||||||
|
|
||||||
1. The SOURCE root user's public RSA key (likely in /root/.ssh/id_rsa.pub)
|
|
||||||
needs to be in the DESTINATION stack user's authorized_keys file
|
|
||||||
(~stack/.ssh/authorized_keys). This can be accomplished by manually
|
|
||||||
copying the contents from the file on the SOURCE to the DESTINATION. If
|
|
||||||
you have a password configured for the stack user, then you can use the
|
|
||||||
following command to accomplish the same thing::
|
|
||||||
|
|
||||||
ssh-copy-id -i /root/.ssh/id_rsa.pub stack@DESTINATION
|
|
||||||
|
|
||||||
2. The DESTINATION host's public ECDSA key (/etc/ssh/ssh_host_ecdsa_key.pub)
|
|
||||||
needs to be in the SOURCE root user's known_hosts file
|
|
||||||
(/root/.ssh/known_hosts). This can be accomplished by running the
|
|
||||||
following on the SOURCE machine (hostname must be used)::
|
|
||||||
|
|
||||||
ssh-keyscan -H DEST_HOSTNAME | sudo tee -a /root/.ssh/known_hosts
|
|
||||||
|
|
||||||
In essence, this means that every compute node's root user's public RSA key
|
|
||||||
must exist in every other compute node's stack user's authorized_keys file and
|
|
||||||
every compute node's public ECDSA key needs to be in every other compute
|
|
||||||
node's root user's known_hosts file.
|
|
||||||
|
|
||||||
Disable serial console
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
Serial console needs to be disabled for live migration to work.
|
|
||||||
|
|
||||||
On both the controller and compute node, in /etc/nova/nova.conf
|
|
||||||
|
|
||||||
[serial_console]
|
|
||||||
enabled = False
|
|
||||||
|
|
||||||
Alternatively, in devstack's local.conf:
|
|
||||||
|
|
||||||
[[post-config|$NOVA_CONF]]
|
|
||||||
[serial_console]
|
|
||||||
#enabled=false
|
|
||||||
|
|
||||||
|
|
||||||
VNC server configuration
|
|
||||||
------------------------
|
|
||||||
|
|
||||||
The VNC server listening parameter needs to be set to any address so
|
|
||||||
that the server can accept connections from all of the compute nodes.
|
|
||||||
|
|
||||||
On both the controller and compute node, in /etc/nova/nova.conf
|
|
||||||
|
|
||||||
vncserver_listen = 0.0.0.0
|
|
||||||
|
|
||||||
Alternatively, in devstack's local.conf:
|
|
||||||
|
|
||||||
VNCSERVER_LISTEN=0.0.0.0
|
|
||||||
|
|
||||||
|
|
||||||
Environment final checkup
|
|
||||||
-------------------------
|
|
||||||
|
|
||||||
If you are willing to make sure everything is in order in your DevStack
|
|
||||||
environment, you can run the Watcher Tempest tests which will validate its API
|
|
||||||
but also that you can perform the typical Watcher workflows. To do so, have a
|
|
||||||
look at the :ref:`Tempest tests <tempest_tests>` section which will explain to
|
|
||||||
you how to run them.
|
|
@ -1,275 +0,0 @@
|
|||||||
..
|
|
||||||
Except where otherwise noted, this document is licensed under Creative
|
|
||||||
Commons Attribution 3.0 License. You can view the license at:
|
|
||||||
|
|
||||||
https://creativecommons.org/licenses/by/3.0/
|
|
||||||
|
|
||||||
.. _watcher_developement_environment:
|
|
||||||
|
|
||||||
=========================================
|
|
||||||
Set up a development environment manually
|
|
||||||
=========================================
|
|
||||||
|
|
||||||
This document describes getting the source from watcher `Git repository`_
|
|
||||||
for development purposes.
|
|
||||||
|
|
||||||
To install Watcher from packaging, refer instead to Watcher `User
|
|
||||||
Documentation`_.
|
|
||||||
|
|
||||||
.. _`Git Repository`: https://git.openstack.org/cgit/openstack/watcher
|
|
||||||
.. _`User Documentation`: https://docs.openstack.org/watcher/latest/
|
|
||||||
|
|
||||||
Prerequisites
|
|
||||||
=============
|
|
||||||
|
|
||||||
This document assumes you are using Ubuntu or Fedora, and that you have the
|
|
||||||
following tools available on your system:
|
|
||||||
|
|
||||||
- Python_ 2.7 and 3.4
|
|
||||||
- git_
|
|
||||||
- setuptools_
|
|
||||||
- pip_
|
|
||||||
- msgfmt (part of the gettext package)
|
|
||||||
- virtualenv and virtualenvwrapper_
|
|
||||||
|
|
||||||
**Reminder**: If you're successfully using a different platform, or a
|
|
||||||
different version of the above, please document your configuration here!
|
|
||||||
|
|
||||||
.. _Python: https://www.python.org/
|
|
||||||
.. _git: https://git-scm.com/
|
|
||||||
.. _setuptools: https://pypi.python.org/pypi/setuptools
|
|
||||||
.. _virtualenvwrapper: https://virtualenvwrapper.readthedocs.io/en/latest/install.html
|
|
||||||
|
|
||||||
Getting the latest code
|
|
||||||
=======================
|
|
||||||
|
|
||||||
Make a clone of the code from our `Git repository`:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
$ git clone https://git.openstack.org/openstack/watcher.git
|
|
||||||
|
|
||||||
When that is complete, you can:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
$ cd watcher
|
|
||||||
|
|
||||||
Installing dependencies
|
|
||||||
=======================
|
|
||||||
|
|
||||||
Watcher maintains two lists of dependencies::
|
|
||||||
|
|
||||||
requirements.txt
|
|
||||||
test-requirements.txt
|
|
||||||
|
|
||||||
The first is the list of dependencies needed for running Watcher, the second
|
|
||||||
list includes dependencies used for active development and testing of Watcher
|
|
||||||
itself.
|
|
||||||
|
|
||||||
These dependencies can be installed from PyPi_ using the Python tool pip_.
|
|
||||||
|
|
||||||
.. _PyPi: http://pypi.python.org/
|
|
||||||
.. _pip: http://pypi.python.org/pypi/pip
|
|
||||||
|
|
||||||
However, your system *may* need additional dependencies that `pip` (and by
|
|
||||||
extension, PyPi) cannot satisfy. These dependencies should be installed
|
|
||||||
prior to using `pip`, and the installation method may vary depending on
|
|
||||||
your platform.
|
|
||||||
|
|
||||||
* Ubuntu 14.04::
|
|
||||||
|
|
||||||
$ sudo apt-get install python-dev libssl-dev libmysqlclient-dev libffi-dev
|
|
||||||
|
|
||||||
* Fedora 19+::
|
|
||||||
|
|
||||||
$ sudo yum install openssl-devel libffi-devel mysql-devel
|
|
||||||
|
|
||||||
* CentOS 7::
|
|
||||||
|
|
||||||
$ sudo yum install gcc python-devel libxml2-devel libxslt-devel mariadb-devel
|
|
||||||
|
|
||||||
PyPi Packages and VirtualEnv
|
|
||||||
----------------------------
|
|
||||||
|
|
||||||
We recommend establishing a virtualenv to run Watcher within. virtualenv
|
|
||||||
limits the Python environment to just what you're installing as dependencies,
|
|
||||||
useful to keep a clean environment for working on Watcher.
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
$ mkvirtualenv watcher
|
|
||||||
$ git clone https://git.openstack.org/openstack/watcher
|
|
||||||
|
|
||||||
# Use 'python setup.py' to link Watcher into Python's site-packages
|
|
||||||
$ cd watcher && python setup.py install
|
|
||||||
|
|
||||||
# Install the dependencies for running Watcher
|
|
||||||
$ pip install -r ./requirements.txt
|
|
||||||
|
|
||||||
# Install the dependencies for developing, testing, and running Watcher
|
|
||||||
$ pip install -r ./test-requirements.txt
|
|
||||||
|
|
||||||
This will create a local virtual environment in the directory ``$WORKON_HOME``.
|
|
||||||
The virtual environment can be disabled using the command:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
$ deactivate
|
|
||||||
|
|
||||||
You can re-activate this virtualenv for your current shell using:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
$ workon watcher
|
|
||||||
|
|
||||||
For more information on virtual environments, see virtualenv_.
|
|
||||||
|
|
||||||
.. _virtualenv: http://www.virtualenv.org/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Verifying Watcher is set up
|
|
||||||
===========================
|
|
||||||
|
|
||||||
Once set up, either directly or within a virtualenv, you should be able to
|
|
||||||
invoke Python and import the libraries. If you're using a virtualenv, don't
|
|
||||||
forget to activate it:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
$ workon watcher
|
|
||||||
|
|
||||||
You should then be able to `import watcher` using Python without issue:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
$ python -c "import watcher"
|
|
||||||
|
|
||||||
If you can import watcher without a traceback, you should be ready to develop.
|
|
||||||
|
|
||||||
Run Watcher tests
|
|
||||||
=================
|
|
||||||
|
|
||||||
Watcher provides both :ref:`unit tests <unit_tests>` and
|
|
||||||
:ref:`functional/tempest tests <tempest_tests>`. Please refer to :doc:`testing`
|
|
||||||
to understand how to run them.
|
|
||||||
|
|
||||||
|
|
||||||
Build the Watcher documentation
|
|
||||||
===============================
|
|
||||||
|
|
||||||
You can easily build the HTML documentation from ``doc/source`` files, by using
|
|
||||||
``tox``:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
$ workon watcher
|
|
||||||
|
|
||||||
(watcher) $ cd watcher
|
|
||||||
(watcher) $ tox -edocs
|
|
||||||
|
|
||||||
The HTML files are available into ``doc/build`` directory.
|
|
||||||
|
|
||||||
|
|
||||||
Configure the Watcher services
|
|
||||||
==============================
|
|
||||||
|
|
||||||
Watcher services require a configuration file. Use tox to generate
|
|
||||||
a sample configuration file that can be used to get started:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
$ tox -e genconfig
|
|
||||||
$ cp etc/watcher.conf.sample etc/watcher.conf
|
|
||||||
|
|
||||||
Most of the default configuration should be enough to get you going, but you
|
|
||||||
still need to configure the following sections:
|
|
||||||
|
|
||||||
- The ``[database]`` section to configure the
|
|
||||||
:ref:`Watcher database <watcher-db_configuration>`
|
|
||||||
- The ``[keystone_authtoken]`` section to configure the
|
|
||||||
:ref:`Identity service <identity-service_configuration>` i.e. Keystone
|
|
||||||
- The ``[watcher_messaging]`` section to configure the OpenStack AMQP-based
|
|
||||||
message bus
|
|
||||||
|
|
||||||
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
|
|
||||||
continuing.
|
|
||||||
|
|
||||||
|
|
||||||
Create Watcher SQL database
|
|
||||||
===========================
|
|
||||||
|
|
||||||
When initially getting set up, after you've configured which databases to use,
|
|
||||||
you're probably going to need to run the following to your database schema in
|
|
||||||
place:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
$ workon watcher
|
|
||||||
|
|
||||||
(watcher) $ watcher-db-manage create_schema
|
|
||||||
|
|
||||||
|
|
||||||
Running Watcher services
|
|
||||||
========================
|
|
||||||
|
|
||||||
To run the Watcher API service, use:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
$ workon watcher
|
|
||||||
|
|
||||||
(watcher) $ watcher-api
|
|
||||||
|
|
||||||
To run the Watcher Decision Engine service, use:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
$ workon watcher
|
|
||||||
|
|
||||||
(watcher) $ watcher-decision-engine
|
|
||||||
|
|
||||||
To run the Watcher Applier service, use:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
$ workon watcher
|
|
||||||
|
|
||||||
(watcher) $ watcher-applier
|
|
||||||
|
|
||||||
Default configuration of these services are available into ``/etc/watcher``
|
|
||||||
directory. See :doc:`../deploy/configuration` for details on how Watcher is
|
|
||||||
configured. By default, Watcher is configured with SQL backends.
|
|
||||||
|
|
||||||
|
|
||||||
Interact with Watcher
|
|
||||||
=====================
|
|
||||||
|
|
||||||
You can also interact with Watcher through its REST API. There is a Python
|
|
||||||
Watcher client library `python-watcherclient`_ which interacts exclusively
|
|
||||||
through the REST API, and which Watcher itself uses to provide its command-line
|
|
||||||
interface.
|
|
||||||
|
|
||||||
.. _`python-watcherclient`: https://github.com/openstack/python-watcherclient
|
|
||||||
|
|
||||||
There is also an Horizon plugin for Watcher `watcher-dashboard`_ which
|
|
||||||
allows to interact with Watcher through a web-based interface.
|
|
||||||
|
|
||||||
.. _`watcher-dashboard`: https://github.com/openstack/watcher-dashboard
|
|
||||||
|
|
||||||
|
|
||||||
Exercising the Watcher Services locally
|
|
||||||
=======================================
|
|
||||||
|
|
||||||
If you would like to exercise the Watcher services in isolation within a local
|
|
||||||
virtual environment, you can do this without starting any other OpenStack
|
|
||||||
services. For example, this is useful for rapidly prototyping and debugging
|
|
||||||
interactions over the RPC channel, testing database migrations, and so forth.
|
|
||||||
|
|
||||||
You will find in the `watcher-tools`_ project, Ansible playbooks and Docker
|
|
||||||
template files to easily play with Watcher services within a minimal OpenStack
|
|
||||||
isolated environment (Identity, Message Bus, SQL database, Horizon, ...).
|
|
||||||
|
|
||||||
.. _`watcher-tools`: https://github.com/b-com/watcher-tools
|
|
@ -1,8 +0,0 @@
|
|||||||
.. toctree::
|
|
||||||
:maxdepth: 1
|
|
||||||
|
|
||||||
environment
|
|
||||||
devstack
|
|
||||||
notifications
|
|
||||||
testing
|
|
||||||
rally_link
|
|
@ -1,13 +0,0 @@
|
|||||||
..
|
|
||||||
Except where otherwise noted, this document is licensed under Creative
|
|
||||||
Commons Attribution 3.0 License. You can view the license at:
|
|
||||||
|
|
||||||
https://creativecommons.org/licenses/by/3.0/
|
|
||||||
|
|
||||||
.. _watcher_notifications:
|
|
||||||
|
|
||||||
========================
|
|
||||||
Notifications in Watcher
|
|
||||||
========================
|
|
||||||
|
|
||||||
.. versioned_notifications::
|
|
@ -1,219 +0,0 @@
|
|||||||
..
|
|
||||||
Except where otherwise noted, this document is licensed under Creative
|
|
||||||
Commons Attribution 3.0 License. You can view the license at:
|
|
||||||
|
|
||||||
https://creativecommons.org/licenses/by/3.0/
|
|
||||||
|
|
||||||
.. _implement_action_plugin:
|
|
||||||
|
|
||||||
==================
|
|
||||||
Build a new action
|
|
||||||
==================
|
|
||||||
|
|
||||||
Watcher Applier has an external :ref:`action <action_definition>` plugin
|
|
||||||
interface which gives anyone the ability to integrate an external
|
|
||||||
:ref:`action <action_definition>` in order to extend the initial set of actions
|
|
||||||
Watcher provides.
|
|
||||||
|
|
||||||
This section gives some guidelines on how to implement and integrate custom
|
|
||||||
actions with Watcher.
|
|
||||||
|
|
||||||
|
|
||||||
Creating a new plugin
|
|
||||||
=====================
|
|
||||||
|
|
||||||
First of all you have to extend the base :py:class:`BaseAction` class which
|
|
||||||
defines a set of abstract methods and/or properties that you will have to
|
|
||||||
implement:
|
|
||||||
|
|
||||||
- The :py:attr:`~.BaseAction.schema` is an abstract property that you have to
|
|
||||||
implement. This is the first function to be called by the
|
|
||||||
:ref:`applier <watcher_applier_definition>` before any further processing
|
|
||||||
and its role is to validate the input parameters that were provided to it.
|
|
||||||
- The :py:meth:`~.BaseAction.pre_condition` is called before the execution of
|
|
||||||
an action. This method is a hook that can be used to perform some
|
|
||||||
initializations or to make some more advanced validation on its input
|
|
||||||
parameters. If you wish to block the execution based on this factor, you
|
|
||||||
simply have to ``raise`` an exception.
|
|
||||||
- The :py:meth:`~.BaseAction.post_condition` is called after the execution of
|
|
||||||
an action. As this function is called regardless of whether an action
|
|
||||||
succeeded or not, this can prove itself useful to perform cleanup
|
|
||||||
operations.
|
|
||||||
- The :py:meth:`~.BaseAction.execute` is the main component of an action.
|
|
||||||
This is where you should implement the logic of your action.
|
|
||||||
- The :py:meth:`~.BaseAction.revert` allows you to roll back the targeted
|
|
||||||
resource to its original state following a faulty execution. Indeed, this
|
|
||||||
method is called by the workflow engine whenever an action raises an
|
|
||||||
exception.
|
|
||||||
|
|
||||||
Here is an example showing how you can write a plugin called ``DummyAction``:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
# Filepath = <PROJECT_DIR>/thirdparty/dummy.py
|
|
||||||
# Import path = thirdparty.dummy
|
|
||||||
import voluptuous
|
|
||||||
|
|
||||||
from watcher.applier.actions import base
|
|
||||||
|
|
||||||
|
|
||||||
class DummyAction(base.BaseAction):
|
|
||||||
|
|
||||||
@property
|
|
||||||
def schema(self):
|
|
||||||
return voluptuous.Schema({})
|
|
||||||
|
|
||||||
def execute(self):
|
|
||||||
# Does nothing
|
|
||||||
pass # Only returning False is considered as a failure
|
|
||||||
|
|
||||||
def revert(self):
|
|
||||||
# Does nothing
|
|
||||||
pass
|
|
||||||
|
|
||||||
def pre_condition(self):
|
|
||||||
# No pre-checks are done here
|
|
||||||
pass
|
|
||||||
|
|
||||||
def post_condition(self):
|
|
||||||
# Nothing done here
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
This implementation is the most basic one. So in order to get a better
|
|
||||||
understanding on how to implement a more advanced action, have a look at the
|
|
||||||
:py:class:`~watcher.applier.actions.migration.Migrate` class.
|
|
||||||
|
|
||||||
Input validation
|
|
||||||
----------------
|
|
||||||
|
|
||||||
As you can see in the previous example, we are using `Voluptuous`_ to validate
|
|
||||||
the input parameters of an action. So if you want to learn more about how to
|
|
||||||
work with `Voluptuous`_, you can have a look at their `documentation`_:
|
|
||||||
|
|
||||||
.. _Voluptuous: https://github.com/alecthomas/voluptuous
|
|
||||||
.. _documentation: https://github.com/alecthomas/voluptuous/blob/master/README.md
|
|
||||||
|
|
||||||
|
|
||||||
Define configuration parameters
|
|
||||||
===============================
|
|
||||||
|
|
||||||
At this point, you have a fully functional action. However, in more complex
|
|
||||||
implementation, you may want to define some configuration options so one can
|
|
||||||
tune the action to its needs. To do so, you can implement the
|
|
||||||
:py:meth:`~.Loadable.get_config_opts` class method as followed:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from oslo_config import cfg
|
|
||||||
|
|
||||||
class DummyAction(base.BaseAction):
|
|
||||||
|
|
||||||
# [...]
|
|
||||||
|
|
||||||
def execute(self):
|
|
||||||
assert self.config.test_opt == 0
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_config_opts(cls):
|
|
||||||
return super(
|
|
||||||
DummyAction, cls).get_config_opts() + [
|
|
||||||
cfg.StrOpt('test_opt', help="Demo Option.", default=0),
|
|
||||||
# Some more options ...
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
The configuration options defined within this class method will be included
|
|
||||||
within the global ``watcher.conf`` configuration file under a section named by
|
|
||||||
convention: ``{namespace}.{plugin_name}``. In our case, the ``watcher.conf``
|
|
||||||
configuration would have to be modified as followed:
|
|
||||||
|
|
||||||
.. code-block:: ini
|
|
||||||
|
|
||||||
[watcher_actions.dummy]
|
|
||||||
# Option used for testing.
|
|
||||||
test_opt = test_value
|
|
||||||
|
|
||||||
Then, the configuration options you define within this method will then be
|
|
||||||
injected in each instantiated object via the ``config`` parameter of the
|
|
||||||
:py:meth:`~.BaseAction.__init__` method.
|
|
||||||
|
|
||||||
|
|
||||||
Abstract Plugin Class
|
|
||||||
=====================
|
|
||||||
|
|
||||||
Here below is the abstract ``BaseAction`` class that every single action
|
|
||||||
should implement:
|
|
||||||
|
|
||||||
.. autoclass:: watcher.applier.actions.base.BaseAction
|
|
||||||
:members:
|
|
||||||
:special-members: __init__
|
|
||||||
:noindex:
|
|
||||||
|
|
||||||
.. py:attribute:: schema
|
|
||||||
|
|
||||||
Defines a Schema that the input parameters shall comply to
|
|
||||||
|
|
||||||
:returns: A schema declaring the input parameters this action should be
|
|
||||||
provided along with their respective constraints
|
|
||||||
(e.g. type, value range, ...)
|
|
||||||
:rtype: :py:class:`voluptuous.Schema` instance
|
|
||||||
|
|
||||||
|
|
||||||
Register a new entry point
|
|
||||||
==========================
|
|
||||||
|
|
||||||
In order for the Watcher Applier to load your new action, the
|
|
||||||
action must be registered as a named entry point under the
|
|
||||||
``watcher_actions`` entry point of your ``setup.py`` file. If you are using
|
|
||||||
pbr_, this entry point should be placed in your ``setup.cfg`` file.
|
|
||||||
|
|
||||||
The name you give to your entry point has to be unique.
|
|
||||||
|
|
||||||
Here below is how you would proceed to register ``DummyAction`` using pbr_:
|
|
||||||
|
|
||||||
.. code-block:: ini
|
|
||||||
|
|
||||||
[entry_points]
|
|
||||||
watcher_actions =
|
|
||||||
dummy = thirdparty.dummy:DummyAction
|
|
||||||
|
|
||||||
.. _pbr: http://docs.openstack.org/developer/pbr/
|
|
||||||
|
|
||||||
|
|
||||||
Using action plugins
|
|
||||||
====================
|
|
||||||
|
|
||||||
The Watcher Applier service will automatically discover any installed plugins
|
|
||||||
when it is restarted. If a Python package containing a custom plugin is
|
|
||||||
installed within the same environment as Watcher, Watcher will automatically
|
|
||||||
make that plugin available for use.
|
|
||||||
|
|
||||||
At this point, you can use your new action plugin in your :ref:`strategy plugin
|
|
||||||
<implement_strategy_plugin>` if you reference it via the use of the
|
|
||||||
:py:meth:`~.Solution.add_action` method:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
# [...]
|
|
||||||
self.solution.add_action(
|
|
||||||
action_type="dummy", # Name of the entry point we registered earlier
|
|
||||||
applies_to="",
|
|
||||||
input_parameters={})
|
|
||||||
|
|
||||||
By doing so, your action will be saved within the Watcher Database, ready to be
|
|
||||||
processed by the planner for creating an action plan which can then be executed
|
|
||||||
by the Watcher Applier via its workflow engine.
|
|
||||||
|
|
||||||
At the last, remember to add the action into the weights in ``watcher.conf``,
|
|
||||||
otherwise you will get an error when the action be referenced in a strategy.
|
|
||||||
|
|
||||||
|
|
||||||
Scheduling of an action plugin
|
|
||||||
==============================
|
|
||||||
|
|
||||||
Watcher provides a basic built-in :ref:`planner <watcher_planner_definition>`
|
|
||||||
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
|
|
||||||
planner <implement_planner_plugin>` that will be able to take into account your
|
|
||||||
new action plugin.
|
|
@ -1,100 +0,0 @@
|
|||||||
..
|
|
||||||
Except where otherwise noted, this document is licensed under Creative
|
|
||||||
Commons Attribution 3.0 License. You can view the license at:
|
|
||||||
|
|
||||||
https://creativecommons.org/licenses/by/3.0/
|
|
||||||
|
|
||||||
.. _plugin-base_setup:
|
|
||||||
|
|
||||||
=======================================
|
|
||||||
Create a third-party plugin for Watcher
|
|
||||||
=======================================
|
|
||||||
|
|
||||||
Watcher provides a plugin architecture which allows anyone to extend the
|
|
||||||
existing functionalities by implementing third-party plugins. This process can
|
|
||||||
be cumbersome so this documentation is there to help you get going as quickly
|
|
||||||
as possible.
|
|
||||||
|
|
||||||
|
|
||||||
Pre-requisites
|
|
||||||
==============
|
|
||||||
|
|
||||||
We assume that you have set up a working Watcher development environment. So if
|
|
||||||
this not already the case, you can check out our documentation which explains
|
|
||||||
how to set up a :ref:`development environment
|
|
||||||
<watcher_developement_environment>`.
|
|
||||||
|
|
||||||
.. _development environment:
|
|
||||||
|
|
||||||
Third party project scaffolding
|
|
||||||
===============================
|
|
||||||
|
|
||||||
First off, we need to create the project structure. To do so, we can use
|
|
||||||
`cookiecutter`_ and the `OpenStack cookiecutter`_ project scaffolder to
|
|
||||||
generate the skeleton of our project::
|
|
||||||
|
|
||||||
$ virtualenv thirdparty
|
|
||||||
$ source thirdparty/bin/activate
|
|
||||||
$ pip install cookiecutter
|
|
||||||
$ cookiecutter https://github.com/openstack-dev/cookiecutter
|
|
||||||
|
|
||||||
The last command will ask you for many information, and If you set
|
|
||||||
``module_name`` and ``repo_name`` as ``thirdparty``, you should end up with a
|
|
||||||
structure that looks like this::
|
|
||||||
|
|
||||||
$ cd thirdparty
|
|
||||||
$ tree .
|
|
||||||
.
|
|
||||||
├── babel.cfg
|
|
||||||
├── CONTRIBUTING.rst
|
|
||||||
├── doc
|
|
||||||
│ └── source
|
|
||||||
│ ├── conf.py
|
|
||||||
│ ├── contributing.rst
|
|
||||||
│ ├── index.rst
|
|
||||||
│ ├── installation.rst
|
|
||||||
│ ├── readme.rst
|
|
||||||
│ └── usage.rst
|
|
||||||
├── HACKING.rst
|
|
||||||
├── LICENSE
|
|
||||||
├── MANIFEST.in
|
|
||||||
├── README.rst
|
|
||||||
├── requirements.txt
|
|
||||||
├── setup.cfg
|
|
||||||
├── setup.py
|
|
||||||
├── test-requirements.txt
|
|
||||||
├── thirdparty
|
|
||||||
│ ├── __init__.py
|
|
||||||
│ └── tests
|
|
||||||
│ ├── base.py
|
|
||||||
│ ├── __init__.py
|
|
||||||
│ └── test_thirdparty.py
|
|
||||||
└── tox.ini
|
|
||||||
|
|
||||||
**Note:** You should add `python-watcher`_ as a dependency in the
|
|
||||||
requirements.txt file::
|
|
||||||
|
|
||||||
# Watcher-specific requirements
|
|
||||||
python-watcher
|
|
||||||
|
|
||||||
.. _cookiecutter: https://github.com/audreyr/cookiecutter
|
|
||||||
.. _OpenStack cookiecutter: https://github.com/openstack-dev/cookiecutter
|
|
||||||
.. _python-watcher: https://pypi.python.org/pypi/python-watcher
|
|
||||||
|
|
||||||
Implementing a plugin for Watcher
|
|
||||||
=================================
|
|
||||||
|
|
||||||
Now that the project skeleton has been created, you can start the
|
|
||||||
implementation of your plugin. As of now, you can implement the following
|
|
||||||
plugins for Watcher:
|
|
||||||
|
|
||||||
- A :ref:`goal plugin <implement_goal_plugin>`
|
|
||||||
- A :ref:`strategy plugin <implement_strategy_plugin>`
|
|
||||||
- An :ref:`action plugin <implement_action_plugin>`
|
|
||||||
- A :ref:`planner plugin <implement_planner_plugin>`
|
|
||||||
- A workflow engine plugin
|
|
||||||
- A :ref:`cluster data model collector plugin
|
|
||||||
<implement_cluster_data_model_collector_plugin>`
|
|
||||||
|
|
||||||
If you want to learn more on how to implement them, you can refer to their
|
|
||||||
dedicated documentation.
|
|
@ -1,272 +0,0 @@
|
|||||||
..
|
|
||||||
Except where otherwise noted, this document is licensed under Creative
|
|
||||||
Commons Attribution 3.0 License. You can view the license at:
|
|
||||||
|
|
||||||
https://creativecommons.org/licenses/by/3.0/
|
|
||||||
|
|
||||||
.. _implement_cluster_data_model_collector_plugin:
|
|
||||||
|
|
||||||
========================================
|
|
||||||
Build a new cluster data model collector
|
|
||||||
========================================
|
|
||||||
|
|
||||||
Watcher Decision Engine has an external cluster data model (CDM) plugin
|
|
||||||
interface which gives anyone the ability to integrate an external cluster data
|
|
||||||
model collector (CDMC) in order to extend the initial set of cluster data model
|
|
||||||
collectors Watcher provides.
|
|
||||||
|
|
||||||
This section gives some guidelines on how to implement and integrate custom
|
|
||||||
cluster data model collectors within Watcher.
|
|
||||||
|
|
||||||
|
|
||||||
Creating a new plugin
|
|
||||||
=====================
|
|
||||||
|
|
||||||
In order to create a new cluster data model collector, you have to:
|
|
||||||
|
|
||||||
- Extend the :py:class:`~.base.BaseClusterDataModelCollector` class.
|
|
||||||
- Implement its :py:meth:`~.BaseClusterDataModelCollector.execute` abstract
|
|
||||||
method to return your entire cluster data model that this method should
|
|
||||||
build.
|
|
||||||
- Implement its :py:meth:`~.Goal.notification_endpoints` abstract property to
|
|
||||||
return the list of all the :py:class:`~.base.NotificationEndpoint` instances
|
|
||||||
that will be responsible for handling incoming notifications in order to
|
|
||||||
incrementally update your cluster data model.
|
|
||||||
|
|
||||||
First of all, you have to extend the :class:`~.BaseClusterDataModelCollector`
|
|
||||||
base class which defines the :py:meth:`~.BaseClusterDataModelCollector.execute`
|
|
||||||
abstract method you will have to implement. This method is responsible for
|
|
||||||
building an entire cluster data model.
|
|
||||||
|
|
||||||
Here is an example showing how you can write a plugin called
|
|
||||||
``DummyClusterDataModelCollector``:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
# Filepath = <PROJECT_DIR>/thirdparty/dummy.py
|
|
||||||
# Import path = thirdparty.dummy
|
|
||||||
|
|
||||||
from watcher.decision_engine.model import model_root
|
|
||||||
from watcher.decision_engine.model.collector import base
|
|
||||||
|
|
||||||
|
|
||||||
class DummyClusterDataModelCollector(base.BaseClusterDataModelCollector):
|
|
||||||
|
|
||||||
def execute(self):
|
|
||||||
model = model_root.ModelRoot()
|
|
||||||
# Do something here...
|
|
||||||
return model
|
|
||||||
|
|
||||||
@property
|
|
||||||
def notification_endpoints(self):
|
|
||||||
return []
|
|
||||||
|
|
||||||
This implementation is the most basic one. So in order to get a better
|
|
||||||
understanding on how to implement a more advanced cluster data model collector,
|
|
||||||
have a look at the :py:class:`~.NovaClusterDataModelCollector` class.
|
|
||||||
|
|
||||||
Define a custom model
|
|
||||||
=====================
|
|
||||||
|
|
||||||
As you may have noticed in the above example, we are reusing an existing model
|
|
||||||
provided by Watcher. However, this model can be easily customized by
|
|
||||||
implementing a new class that would implement the :py:class:`~.Model` abstract
|
|
||||||
base class. Here below is simple example on how to proceed in implementing a
|
|
||||||
custom Model:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
# Filepath = <PROJECT_DIR>/thirdparty/dummy.py
|
|
||||||
# Import path = thirdparty.dummy
|
|
||||||
|
|
||||||
from watcher.decision_engine.model import base as modelbase
|
|
||||||
from watcher.decision_engine.model.collector import base
|
|
||||||
|
|
||||||
|
|
||||||
class MyModel(modelbase.Model):
|
|
||||||
|
|
||||||
def to_string(self):
|
|
||||||
return 'MyModel'
|
|
||||||
|
|
||||||
|
|
||||||
class DummyClusterDataModelCollector(base.BaseClusterDataModelCollector):
|
|
||||||
|
|
||||||
def execute(self):
|
|
||||||
model = MyModel()
|
|
||||||
# Do something here...
|
|
||||||
return model
|
|
||||||
|
|
||||||
@property
|
|
||||||
def notification_endpoints(self):
|
|
||||||
return []
|
|
||||||
|
|
||||||
Here below is the abstract ``Model`` class that every single cluster data model
|
|
||||||
should implement:
|
|
||||||
|
|
||||||
.. autoclass:: watcher.decision_engine.model.base.Model
|
|
||||||
:members:
|
|
||||||
:special-members: __init__
|
|
||||||
:noindex:
|
|
||||||
|
|
||||||
Define configuration parameters
|
|
||||||
===============================
|
|
||||||
|
|
||||||
At this point, you have a fully functional cluster data model collector.
|
|
||||||
By default, cluster data model collectors define a ``period`` option (see
|
|
||||||
:py:meth:`~.BaseClusterDataModelCollector.get_config_opts`) that corresponds
|
|
||||||
to the interval of time between each synchronization of the in-memory model.
|
|
||||||
|
|
||||||
However, in more complex implementation, you may want to define some
|
|
||||||
configuration options so one can tune the cluster data model collector to your
|
|
||||||
needs. To do so, you can implement the :py:meth:`~.Loadable.get_config_opts`
|
|
||||||
class method as followed:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from oslo_config import cfg
|
|
||||||
from watcher.decision_engine.model import model_root
|
|
||||||
from watcher.decision_engine.model.collector import base
|
|
||||||
|
|
||||||
|
|
||||||
class DummyClusterDataModelCollector(base.BaseClusterDataModelCollector):
|
|
||||||
|
|
||||||
def execute(self):
|
|
||||||
model = model_root.ModelRoot()
|
|
||||||
# Do something here...
|
|
||||||
return model
|
|
||||||
|
|
||||||
@property
|
|
||||||
def notification_endpoints(self):
|
|
||||||
return []
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_config_opts(cls):
|
|
||||||
return super(
|
|
||||||
DummyClusterDataModelCollector, cls).get_config_opts() + [
|
|
||||||
cfg.StrOpt('test_opt', help="Demo Option.", default=0),
|
|
||||||
# Some more options ...
|
|
||||||
]
|
|
||||||
|
|
||||||
The configuration options defined within this class method will be included
|
|
||||||
within the global ``watcher.conf`` configuration file under a section named by
|
|
||||||
convention: ``{namespace}.{plugin_name}`` (see section :ref:`Register a new
|
|
||||||
entry point <register_new_cdmc_entrypoint>`). The namespace for CDMC plugins is
|
|
||||||
``watcher_cluster_data_model_collectors``, so in our case, the ``watcher.conf``
|
|
||||||
configuration would have to be modified as followed:
|
|
||||||
|
|
||||||
.. code-block:: ini
|
|
||||||
|
|
||||||
[watcher_cluster_data_model_collectors.dummy]
|
|
||||||
# Option used for testing.
|
|
||||||
test_opt = test_value
|
|
||||||
|
|
||||||
Then, the configuration options you define within this method will then be
|
|
||||||
injected in each instantiated object via the ``config`` parameter of the
|
|
||||||
:py:meth:`~.BaseClusterDataModelCollector.__init__` method.
|
|
||||||
|
|
||||||
|
|
||||||
Abstract Plugin Class
|
|
||||||
=====================
|
|
||||||
|
|
||||||
Here below is the abstract ``BaseClusterDataModelCollector`` class that every
|
|
||||||
single cluster data model collector should implement:
|
|
||||||
|
|
||||||
.. autoclass:: watcher.decision_engine.model.collector.base.BaseClusterDataModelCollector
|
|
||||||
:members:
|
|
||||||
:special-members: __init__
|
|
||||||
:noindex:
|
|
||||||
|
|
||||||
|
|
||||||
.. _register_new_cdmc_entrypoint:
|
|
||||||
|
|
||||||
Register a new entry point
|
|
||||||
==========================
|
|
||||||
|
|
||||||
In order for the Watcher Decision Engine to load your new cluster data model
|
|
||||||
collector, the latter must be registered as a named entry point under the
|
|
||||||
``watcher_cluster_data_model_collectors`` entry point namespace of your
|
|
||||||
``setup.py`` file. If you are using pbr_, this entry point should be placed in
|
|
||||||
your ``setup.cfg`` file.
|
|
||||||
|
|
||||||
The name you give to your entry point has to be unique.
|
|
||||||
|
|
||||||
Here below is how to register ``DummyClusterDataModelCollector`` using pbr_:
|
|
||||||
|
|
||||||
.. code-block:: ini
|
|
||||||
|
|
||||||
[entry_points]
|
|
||||||
watcher_cluster_data_model_collectors =
|
|
||||||
dummy = thirdparty.dummy:DummyClusterDataModelCollector
|
|
||||||
|
|
||||||
.. _pbr: http://docs.openstack.org/developer/pbr/
|
|
||||||
|
|
||||||
|
|
||||||
Add new notification endpoints
|
|
||||||
==============================
|
|
||||||
|
|
||||||
At this point, you have a fully functional cluster data model collector.
|
|
||||||
However, this CDMC is only refreshed periodically via a background scheduler.
|
|
||||||
As you may sometimes execute a strategy with a stale CDM due to a high activity
|
|
||||||
on your infrastructure, you can define some notification endpoints that will be
|
|
||||||
responsible for incrementally updating the CDM based on notifications emitted
|
|
||||||
by other services such as Nova. To do so, you can implement and register a new
|
|
||||||
``DummyEndpoint`` notification endpoint regarding a ``dummy`` event as shown
|
|
||||||
below:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from watcher.decision_engine.model import model_root
|
|
||||||
from watcher.decision_engine.model.collector import base
|
|
||||||
|
|
||||||
|
|
||||||
class DummyNotification(base.NotificationEndpoint):
|
|
||||||
|
|
||||||
@property
|
|
||||||
def filter_rule(self):
|
|
||||||
return filtering.NotificationFilter(
|
|
||||||
publisher_id=r'.*',
|
|
||||||
event_type=r'^dummy$',
|
|
||||||
)
|
|
||||||
|
|
||||||
def info(self, ctxt, publisher_id, event_type, payload, metadata):
|
|
||||||
# Do some CDM modifications here...
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class DummyClusterDataModelCollector(base.BaseClusterDataModelCollector):
|
|
||||||
|
|
||||||
def execute(self):
|
|
||||||
model = model_root.ModelRoot()
|
|
||||||
# Do something here...
|
|
||||||
return model
|
|
||||||
|
|
||||||
@property
|
|
||||||
def notification_endpoints(self):
|
|
||||||
return [DummyNotification(self)]
|
|
||||||
|
|
||||||
|
|
||||||
Note that if the event you are trying to listen to is published by a new
|
|
||||||
service, you may have to also add a new topic Watcher will have to subscribe to
|
|
||||||
in the ``notification_topics`` option of the ``[watcher_decision_engine]``
|
|
||||||
section.
|
|
||||||
|
|
||||||
|
|
||||||
Using cluster data model collector plugins
|
|
||||||
==========================================
|
|
||||||
|
|
||||||
The Watcher Decision Engine service will automatically discover any installed
|
|
||||||
plugins when it is restarted. If a Python package containing a custom plugin is
|
|
||||||
installed within the same environment as Watcher, Watcher will automatically
|
|
||||||
make that plugin available for use.
|
|
||||||
|
|
||||||
At this point, you can use your new cluster data model plugin in your
|
|
||||||
:ref:`strategy plugin <implement_strategy_plugin>` by using the
|
|
||||||
:py:attr:`~.BaseStrategy.collector_manager` property as followed:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
# [...]
|
|
||||||
dummy_collector = self.collector_manager.get_cluster_model_collector(
|
|
||||||
"dummy") # "dummy" is the name of the entry point we declared earlier
|
|
||||||
dummy_model = dummy_collector.get_latest_cluster_data_model()
|
|
||||||
# Do some stuff with this model
|
|
@ -1,215 +0,0 @@
|
|||||||
..
|
|
||||||
Except where otherwise noted, this document is licensed under Creative
|
|
||||||
Commons Attribution 3.0 License. You can view the license at:
|
|
||||||
|
|
||||||
https://creativecommons.org/licenses/by/3.0/
|
|
||||||
|
|
||||||
.. _implement_goal_plugin:
|
|
||||||
|
|
||||||
================
|
|
||||||
Build a new goal
|
|
||||||
================
|
|
||||||
|
|
||||||
Watcher Decision Engine has an external :ref:`goal <goal_definition>`
|
|
||||||
plugin interface which gives anyone the ability to integrate an external
|
|
||||||
goal which can be achieved by a :ref:`strategy <strategy_definition>`.
|
|
||||||
|
|
||||||
This section gives some guidelines on how to implement and integrate custom
|
|
||||||
goals with Watcher. If you wish to create a third-party package for your
|
|
||||||
plugin, you can refer to our :ref:`documentation for third-party package
|
|
||||||
creation <plugin-base_setup>`.
|
|
||||||
|
|
||||||
|
|
||||||
Pre-requisites
|
|
||||||
==============
|
|
||||||
|
|
||||||
Before using any goal, please make sure that none of the existing goals fit
|
|
||||||
your needs. Indeed, the underlying value of defining a goal is to be able to
|
|
||||||
compare the efficacy of the action plans resulting from the various strategies
|
|
||||||
satisfying the same goal. By doing so, Watcher can assist the administrator
|
|
||||||
in his choices.
|
|
||||||
|
|
||||||
|
|
||||||
Create a new plugin
|
|
||||||
===================
|
|
||||||
|
|
||||||
In order to create a new goal, you have to:
|
|
||||||
|
|
||||||
- Extend the :py:class:`~.base.Goal` class.
|
|
||||||
- Implement its :py:meth:`~.Goal.get_name` class method to return the
|
|
||||||
**unique** ID of the new goal you want to create. This unique ID should
|
|
||||||
be the same as the name of :ref:`the entry point you will declare later on
|
|
||||||
<goal_plugin_add_entrypoint>`.
|
|
||||||
- Implement its :py:meth:`~.Goal.get_display_name` class method to
|
|
||||||
return the translated display name of the goal you want to create.
|
|
||||||
Note: Do not use a variable to return the translated string so it can be
|
|
||||||
automatically collected by the translation tool.
|
|
||||||
- Implement its :py:meth:`~.Goal.get_translatable_display_name`
|
|
||||||
class method to return the translation key (actually the english display
|
|
||||||
name) of your new goal. The value return should be the same as the
|
|
||||||
string translated in :py:meth:`~.Goal.get_display_name`.
|
|
||||||
- Implement its :py:meth:`~.Goal.get_efficacy_specification` method to return
|
|
||||||
the :ref:`efficacy specification <efficacy_specification_definition>` for
|
|
||||||
your goal.
|
|
||||||
|
|
||||||
Here is an example showing how you can define a new ``NewGoal`` goal plugin:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
# filepath: thirdparty/new.py
|
|
||||||
# import path: thirdparty.new
|
|
||||||
|
|
||||||
from watcher._i18n import _
|
|
||||||
from watcher.decision_engine.goal import base
|
|
||||||
from watcher.decision_engine.goal.efficacy import specs
|
|
||||||
|
|
||||||
class NewGoal(base.Goal):
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_name(cls):
|
|
||||||
return "new_goal" # Will be the name of the entry point
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_display_name(cls):
|
|
||||||
return _("New Goal")
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_translatable_display_name(cls):
|
|
||||||
return "New Goal"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_efficacy_specification(cls):
|
|
||||||
return specs.Unclassified()
|
|
||||||
|
|
||||||
|
|
||||||
As you may have noticed, the :py:meth:`~.Goal.get_efficacy_specification`
|
|
||||||
method returns an :py:meth:`~.Unclassified` instance which
|
|
||||||
is provided by Watcher. This efficacy specification is useful during the
|
|
||||||
development process of your goal as it corresponds to an empty specification.
|
|
||||||
If you want to learn more about what efficacy specifications are used for or to
|
|
||||||
define your own efficacy specification, please refer to the :ref:`related
|
|
||||||
section below <implement_efficacy_specification>`.
|
|
||||||
|
|
||||||
|
|
||||||
Abstract Plugin Class
|
|
||||||
=====================
|
|
||||||
|
|
||||||
Here below is the abstract :py:class:`~.base.Goal` class:
|
|
||||||
|
|
||||||
.. autoclass:: watcher.decision_engine.goal.base.Goal
|
|
||||||
:members:
|
|
||||||
:noindex:
|
|
||||||
|
|
||||||
.. _goal_plugin_add_entrypoint:
|
|
||||||
|
|
||||||
Add a new entry point
|
|
||||||
=====================
|
|
||||||
|
|
||||||
In order for the Watcher Decision Engine to load your new goal, the
|
|
||||||
goal must be registered as a named entry point under the ``watcher_goals``
|
|
||||||
entry point namespace of your ``setup.py`` file. If you are using pbr_, this
|
|
||||||
entry point should be placed in your ``setup.cfg`` file.
|
|
||||||
|
|
||||||
The name you give to your entry point has to be unique and should be the same
|
|
||||||
as the value returned by the :py:meth:`~.base.Goal.get_name` class method of
|
|
||||||
your goal.
|
|
||||||
|
|
||||||
Here below is how you would proceed to register ``NewGoal`` using pbr_:
|
|
||||||
|
|
||||||
.. code-block:: ini
|
|
||||||
|
|
||||||
[entry_points]
|
|
||||||
watcher_goals =
|
|
||||||
new_goal = thirdparty.new:NewGoal
|
|
||||||
|
|
||||||
|
|
||||||
To get a better understanding on how to implement a more advanced goal,
|
|
||||||
have a look at the :py:class:`~.ServerConsolidation` class.
|
|
||||||
|
|
||||||
.. _pbr: http://docs.openstack.org/developer/pbr/
|
|
||||||
|
|
||||||
.. _implement_efficacy_specification:
|
|
||||||
|
|
||||||
Implement a customized efficacy specification
|
|
||||||
=============================================
|
|
||||||
|
|
||||||
What is it for?
|
|
||||||
---------------
|
|
||||||
|
|
||||||
Efficacy specifications define a set of specifications for a given goal.
|
|
||||||
These specifications actually define a list of indicators which are to be used
|
|
||||||
to compute a global efficacy that outlines how well a strategy performed when
|
|
||||||
trying to achieve the goal it is associated to.
|
|
||||||
|
|
||||||
The idea behind such specification is to give the administrator the possibility
|
|
||||||
to run an audit using different strategies satisfying the same goal and be able
|
|
||||||
to judge how they performed at a glance.
|
|
||||||
|
|
||||||
|
|
||||||
Implementation
|
|
||||||
--------------
|
|
||||||
|
|
||||||
In order to create a new efficacy specification, you have to:
|
|
||||||
|
|
||||||
- Extend the :py:class:`~.EfficacySpecification` class.
|
|
||||||
- Implement :py:meth:`~.EfficacySpecification.get_indicators_specifications`
|
|
||||||
by returning a list of :py:class:`~.IndicatorSpecification` instances.
|
|
||||||
|
|
||||||
* Each :py:class:`~.IndicatorSpecification` instance should actually extend
|
|
||||||
the latter.
|
|
||||||
* Each indicator specification should have a **unique name** which should be
|
|
||||||
a valid Python variable name.
|
|
||||||
* They should implement the :py:attr:`~.EfficacySpecification.schema`
|
|
||||||
abstract property by returning a :py:class:`~.voluptuous.Schema` instance.
|
|
||||||
This schema is the contract the strategy will have to comply with when
|
|
||||||
setting the value associated to the indicator specification within its
|
|
||||||
solution (see the :ref:`architecture of Watcher
|
|
||||||
<sequence_diagrams_create_and_launch_audit>` for more information on
|
|
||||||
the audit execution workflow).
|
|
||||||
|
|
||||||
- Implement the :py:meth:`~.EfficacySpecification.get_global_efficacy` method:
|
|
||||||
it should compute the global efficacy for the goal it achieves based on the
|
|
||||||
efficacy indicators you just defined.
|
|
||||||
|
|
||||||
Here below is an example of an efficacy specification containing one indicator
|
|
||||||
specification:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from watcher._i18n import _
|
|
||||||
from watcher.decision_engine.goal.efficacy import base as efficacy_base
|
|
||||||
from watcher.decision_engine.goal.efficacy import indicators
|
|
||||||
from watcher.decision_engine.solution import efficacy
|
|
||||||
|
|
||||||
|
|
||||||
class IndicatorExample(IndicatorSpecification):
|
|
||||||
def __init__(self):
|
|
||||||
super(IndicatorExample, self).__init__(
|
|
||||||
name="indicator_example",
|
|
||||||
description=_("Example of indicator specification."),
|
|
||||||
unit=None,
|
|
||||||
)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def schema(self):
|
|
||||||
return voluptuous.Schema(voluptuous.Range(min=0), required=True)
|
|
||||||
|
|
||||||
|
|
||||||
class UnclassifiedStrategySpecification(efficacy_base.EfficacySpecification):
|
|
||||||
|
|
||||||
def get_indicators_specifications(self):
|
|
||||||
return [IndicatorExample()]
|
|
||||||
|
|
||||||
def get_global_efficacy(self, indicators_map):
|
|
||||||
return efficacy.Indicator(
|
|
||||||
name="global_efficacy_indicator",
|
|
||||||
description="Example of global efficacy indicator",
|
|
||||||
unit="%",
|
|
||||||
value=indicators_map.indicator_example % 100)
|
|
||||||
|
|
||||||
|
|
||||||
To get a better understanding on how to implement an efficacy specification,
|
|
||||||
have a look at :py:class:`~.ServerConsolidationSpecification`.
|
|
||||||
|
|
||||||
Also, if you want to see a concrete example of an indicator specification,
|
|
||||||
have a look at :py:class:`~.ReleasedComputeNodesCount`.
|
|
@ -1,11 +0,0 @@
|
|||||||
.. toctree::
|
|
||||||
:maxdepth: 1
|
|
||||||
|
|
||||||
base-setup
|
|
||||||
action-plugin
|
|
||||||
cdmc-plugin
|
|
||||||
goal-plugin
|
|
||||||
planner-plugin
|
|
||||||
scoring-engine-plugin
|
|
||||||
strategy-plugin
|
|
||||||
plugins
|
|
@ -1,174 +0,0 @@
|
|||||||
..
|
|
||||||
Except where otherwise noted, this document is licensed under Creative
|
|
||||||
Commons Attribution 3.0 License. You can view the license at:
|
|
||||||
|
|
||||||
https://creativecommons.org/licenses/by/3.0/
|
|
||||||
|
|
||||||
.. _implement_planner_plugin:
|
|
||||||
|
|
||||||
===================
|
|
||||||
Build a new planner
|
|
||||||
===================
|
|
||||||
|
|
||||||
Watcher :ref:`Decision Engine <watcher_decision_engine_definition>` has an
|
|
||||||
external :ref:`planner <watcher_planner_definition>` plugin interface which
|
|
||||||
gives anyone the ability to integrate an external :ref:`planner
|
|
||||||
<watcher_planner_definition>` in order to extend the initial set of planners
|
|
||||||
Watcher provides.
|
|
||||||
|
|
||||||
This section gives some guidelines on how to implement and integrate custom
|
|
||||||
planners with Watcher.
|
|
||||||
|
|
||||||
.. _Decision Engine: watcher_decision_engine_definition
|
|
||||||
|
|
||||||
Creating a new plugin
|
|
||||||
=====================
|
|
||||||
|
|
||||||
First of all you have to extend the base :py:class:`~.BasePlanner` class which
|
|
||||||
defines an abstract method that you will have to implement. The
|
|
||||||
:py:meth:`~.BasePlanner.schedule` is the method being called by the Decision
|
|
||||||
Engine to schedule a given solution (:py:class:`~.BaseSolution`) into an
|
|
||||||
:ref:`action plan <action_plan_definition>` by ordering/sequencing an unordered
|
|
||||||
set of actions contained in the proposed solution (for more details, see
|
|
||||||
:ref:`definition of a solution <solution_definition>`).
|
|
||||||
|
|
||||||
Here is an example showing how you can write a planner plugin called
|
|
||||||
``DummyPlanner``:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
# Filepath = third-party/third_party/dummy.py
|
|
||||||
# Import path = third_party.dummy
|
|
||||||
from oslo_utils import uuidutils
|
|
||||||
from watcher.decision_engine.planner import base
|
|
||||||
|
|
||||||
|
|
||||||
class DummyPlanner(base.BasePlanner):
|
|
||||||
|
|
||||||
def _create_action_plan(self, context, audit_id):
|
|
||||||
action_plan_dict = {
|
|
||||||
'uuid': uuidutils.generate_uuid(),
|
|
||||||
'audit_id': audit_id,
|
|
||||||
'first_action_id': None,
|
|
||||||
'state': objects.action_plan.State.RECOMMENDED
|
|
||||||
}
|
|
||||||
|
|
||||||
new_action_plan = objects.ActionPlan(context, **action_plan_dict)
|
|
||||||
new_action_plan.create(context)
|
|
||||||
new_action_plan.save()
|
|
||||||
return new_action_plan
|
|
||||||
|
|
||||||
def schedule(self, context, audit_id, solution):
|
|
||||||
# Empty action plan
|
|
||||||
action_plan = self._create_action_plan(context, audit_id)
|
|
||||||
# todo: You need to create the workflow of actions here
|
|
||||||
# and attach it to the action plan
|
|
||||||
return action_plan
|
|
||||||
|
|
||||||
This implementation is the most basic one. So if you want to have more advanced
|
|
||||||
examples, have a look at the implementation of planners already provided by
|
|
||||||
Watcher like :py:class:`~.DefaultPlanner`. A list with all available planner
|
|
||||||
plugins can be found :ref:`here <watcher_planners>`.
|
|
||||||
|
|
||||||
|
|
||||||
Define configuration parameters
|
|
||||||
===============================
|
|
||||||
|
|
||||||
At this point, you have a fully functional planner. However, in more complex
|
|
||||||
implementation, you may want to define some configuration options so one can
|
|
||||||
tune the planner to its needs. To do so, you can implement the
|
|
||||||
:py:meth:`~.Loadable.get_config_opts` class method as followed:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from oslo_config import cfg
|
|
||||||
|
|
||||||
class DummyPlanner(base.BasePlanner):
|
|
||||||
|
|
||||||
# [...]
|
|
||||||
|
|
||||||
def schedule(self, context, audit_uuid, solution):
|
|
||||||
assert self.config.test_opt == 0
|
|
||||||
# [...]
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_config_opts(cls):
|
|
||||||
return super(
|
|
||||||
DummyPlanner, cls).get_config_opts() + [
|
|
||||||
cfg.StrOpt('test_opt', help="Demo Option.", default=0),
|
|
||||||
# Some more options ...
|
|
||||||
]
|
|
||||||
|
|
||||||
The configuration options defined within this class method will be included
|
|
||||||
within the global ``watcher.conf`` configuration file under a section named by
|
|
||||||
convention: ``{namespace}.{plugin_name}``. In our case, the ``watcher.conf``
|
|
||||||
configuration would have to be modified as followed:
|
|
||||||
|
|
||||||
.. code-block:: ini
|
|
||||||
|
|
||||||
[watcher_planners.dummy]
|
|
||||||
# Option used for testing.
|
|
||||||
test_opt = test_value
|
|
||||||
|
|
||||||
Then, the configuration options you define within this method will then be
|
|
||||||
injected in each instantiated object via the ``config`` parameter of the
|
|
||||||
:py:meth:`~.BasePlanner.__init__` method.
|
|
||||||
|
|
||||||
|
|
||||||
Abstract Plugin Class
|
|
||||||
=====================
|
|
||||||
|
|
||||||
Here below is the abstract ``BasePlanner`` class that every single planner
|
|
||||||
should implement:
|
|
||||||
|
|
||||||
.. autoclass:: watcher.decision_engine.planner.base.BasePlanner
|
|
||||||
:members:
|
|
||||||
:special-members: __init__
|
|
||||||
:noindex:
|
|
||||||
|
|
||||||
|
|
||||||
Register a new entry point
|
|
||||||
==========================
|
|
||||||
|
|
||||||
In order for the Watcher Decision Engine to load your new planner, the
|
|
||||||
latter must be registered as a new entry point under the
|
|
||||||
``watcher_planners`` entry point namespace of your ``setup.py`` file. If you
|
|
||||||
are using pbr_, this entry point should be placed in your ``setup.cfg`` file.
|
|
||||||
|
|
||||||
The name you give to your entry point has to be unique.
|
|
||||||
|
|
||||||
Here below is how you would proceed to register ``DummyPlanner`` using pbr_:
|
|
||||||
|
|
||||||
.. code-block:: ini
|
|
||||||
|
|
||||||
[entry_points]
|
|
||||||
watcher_planners =
|
|
||||||
dummy = third_party.dummy:DummyPlanner
|
|
||||||
|
|
||||||
.. _pbr: http://docs.openstack.org/developer/pbr/
|
|
||||||
|
|
||||||
|
|
||||||
Using planner plugins
|
|
||||||
=====================
|
|
||||||
|
|
||||||
The :ref:`Watcher Decision Engine <watcher_decision_engine_definition>` service
|
|
||||||
will automatically discover any installed plugins when it is started. This
|
|
||||||
means that if Watcher is already running when you install your plugin, you will
|
|
||||||
have to restart the related Watcher services. If a Python package containing a
|
|
||||||
custom plugin is installed within the same environment as Watcher, Watcher will
|
|
||||||
automatically make that plugin available for use.
|
|
||||||
|
|
||||||
At this point, Watcher will use your new planner if you referenced it in the
|
|
||||||
``planner`` option under the ``[watcher_planner]`` section of your
|
|
||||||
``watcher.conf`` configuration file when you started it. For example, if you
|
|
||||||
want to use the ``dummy`` planner you just installed, you would have to
|
|
||||||
select it as followed:
|
|
||||||
|
|
||||||
.. code-block:: ini
|
|
||||||
|
|
||||||
[watcher_planner]
|
|
||||||
planner = dummy
|
|
||||||
|
|
||||||
As you may have noticed, only a single planner implementation can be activated
|
|
||||||
at a time, so make sure it is generic enough to support all your strategies
|
|
||||||
and actions.
|
|
@ -1,76 +0,0 @@
|
|||||||
..
|
|
||||||
Except where otherwise noted, this document is licensed under Creative
|
|
||||||
Commons Attribution 3.0 License. You can view the license at:
|
|
||||||
|
|
||||||
https://creativecommons.org/licenses/by/3.0/
|
|
||||||
|
|
||||||
|
|
||||||
=================
|
|
||||||
Available Plugins
|
|
||||||
=================
|
|
||||||
|
|
||||||
In this section we present all the plugins that are shipped along with Watcher.
|
|
||||||
If you want to know which plugins your Watcher services have access to, you can
|
|
||||||
use the :ref:`Guru Meditation Reports <watcher_gmr>` to display them.
|
|
||||||
|
|
||||||
.. _watcher_goals:
|
|
||||||
|
|
||||||
Goals
|
|
||||||
=====
|
|
||||||
|
|
||||||
.. list-plugins:: watcher_goals
|
|
||||||
:detailed:
|
|
||||||
|
|
||||||
.. _watcher_scoring_engines:
|
|
||||||
|
|
||||||
Scoring Engines
|
|
||||||
===============
|
|
||||||
|
|
||||||
.. list-plugins:: watcher_scoring_engines
|
|
||||||
:detailed:
|
|
||||||
|
|
||||||
.. _watcher_scoring_engine_containers:
|
|
||||||
|
|
||||||
Scoring Engine Containers
|
|
||||||
=========================
|
|
||||||
|
|
||||||
.. list-plugins:: watcher_scoring_engine_containers
|
|
||||||
:detailed:
|
|
||||||
|
|
||||||
.. _watcher_strategies:
|
|
||||||
|
|
||||||
Strategies
|
|
||||||
==========
|
|
||||||
|
|
||||||
.. list-plugins:: watcher_strategies
|
|
||||||
:detailed:
|
|
||||||
|
|
||||||
.. _watcher_actions:
|
|
||||||
|
|
||||||
Actions
|
|
||||||
=======
|
|
||||||
|
|
||||||
.. list-plugins:: watcher_actions
|
|
||||||
:detailed:
|
|
||||||
|
|
||||||
.. _watcher_workflow_engines:
|
|
||||||
|
|
||||||
Workflow Engines
|
|
||||||
================
|
|
||||||
|
|
||||||
.. list-plugins:: watcher_workflow_engines
|
|
||||||
:detailed:
|
|
||||||
|
|
||||||
.. _watcher_planners:
|
|
||||||
|
|
||||||
Planners
|
|
||||||
========
|
|
||||||
|
|
||||||
.. list-plugins:: watcher_planners
|
|
||||||
:detailed:
|
|
||||||
|
|
||||||
Cluster Data Model Collectors
|
|
||||||
=============================
|
|
||||||
|
|
||||||
.. list-plugins:: watcher_cluster_data_model_collectors
|
|
||||||
:detailed:
|
|
@ -1,210 +0,0 @@
|
|||||||
..
|
|
||||||
Except where otherwise noted, this document is licensed under Creative
|
|
||||||
Commons Attribution 3.0 License. You can view the license at:
|
|
||||||
|
|
||||||
https://creativecommons.org/licenses/by/3.0/
|
|
||||||
|
|
||||||
.. _implement_scoring_engine_plugin:
|
|
||||||
|
|
||||||
==========================
|
|
||||||
Build a new scoring engine
|
|
||||||
==========================
|
|
||||||
|
|
||||||
Watcher Decision Engine has an external :ref:`scoring engine
|
|
||||||
<scoring_engine_definition>` plugin interface which gives anyone the ability
|
|
||||||
to integrate an external scoring engine in order to make use of it in a
|
|
||||||
:ref:`strategy <strategy_definition>`.
|
|
||||||
|
|
||||||
This section gives some guidelines on how to implement and integrate custom
|
|
||||||
scoring engines with Watcher. If you wish to create a third-party package for
|
|
||||||
your plugin, you can refer to our :ref:`documentation for third-party package
|
|
||||||
creation <plugin-base_setup>`.
|
|
||||||
|
|
||||||
|
|
||||||
Pre-requisites
|
|
||||||
==============
|
|
||||||
|
|
||||||
Because scoring engines execute a purely mathematical tasks, they typically do
|
|
||||||
not have any additional dependencies. Additional requirements might be defined
|
|
||||||
by specific scoring engine implementations. For example, some scoring engines
|
|
||||||
might require to prepare learning data, which has to be loaded during the
|
|
||||||
scoring engine startup. Some other might require some external services to be
|
|
||||||
available (e.g. if the scoring infrastructure is running in the cloud).
|
|
||||||
|
|
||||||
|
|
||||||
Create a new scoring engine plugin
|
|
||||||
==================================
|
|
||||||
|
|
||||||
In order to create a new scoring engine you have to:
|
|
||||||
|
|
||||||
- Extend the :py:class:`~.ScoringEngine` class
|
|
||||||
- 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
|
|
||||||
should be the same as the name of :ref:`the entry point we will declare later
|
|
||||||
on <scoring_engine_plugin_add_entrypoint>`.
|
|
||||||
- Implement its :py:meth:`~.ScoringEngine.get_description` method to return the
|
|
||||||
user-friendly description of the implemented scoring engine. It might contain
|
|
||||||
information about algorithm used, learning data etc.
|
|
||||||
- Implement its :py:meth:`~.ScoringEngine.get_metainfo` method to return the
|
|
||||||
machine-friendly metadata about this scoring engine. For example, it could be
|
|
||||||
a JSON formatted text with information about the data model used, its input
|
|
||||||
and output data format, column names, etc.
|
|
||||||
- Implement its :py:meth:`~.ScoringEngine.calculate_score` method to return the
|
|
||||||
result calculated by this scoring engine.
|
|
||||||
|
|
||||||
Here is an example showing how you can write a plugin called ``NewScorer``:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
# filepath: thirdparty/new.py
|
|
||||||
# import path: thirdparty.new
|
|
||||||
from watcher.decision_engine.scoring import base
|
|
||||||
|
|
||||||
|
|
||||||
class NewScorer(base.ScoringEngine):
|
|
||||||
|
|
||||||
def get_name(self):
|
|
||||||
return 'new_scorer'
|
|
||||||
|
|
||||||
def get_description(self):
|
|
||||||
return ''
|
|
||||||
|
|
||||||
def get_metainfo(self):
|
|
||||||
return """{
|
|
||||||
"feature_columns": [
|
|
||||||
"column1",
|
|
||||||
"column2",
|
|
||||||
"column3"],
|
|
||||||
"result_columns": [
|
|
||||||
"value",
|
|
||||||
"probability"]
|
|
||||||
}"""
|
|
||||||
|
|
||||||
def calculate_score(self, features):
|
|
||||||
return '[12, 0.83]'
|
|
||||||
|
|
||||||
As you can see in the above example, the
|
|
||||||
:py:meth:`~.ScoringEngine.calculate_score` method returns a string. Both this
|
|
||||||
class and the client (caller) should perform all the necessary serialization
|
|
||||||
or deserialization.
|
|
||||||
|
|
||||||
|
|
||||||
(Optional) Create a new scoring engine container plugin
|
|
||||||
=======================================================
|
|
||||||
|
|
||||||
Optionally, it's possible to implement a container plugin, which can return a
|
|
||||||
list of scoring engines. This list can be re-evaluated multiple times during
|
|
||||||
the lifecycle of :ref:`Watcher Decision Engine
|
|
||||||
<watcher_decision_engine_definition>` and synchronized with :ref:`Watcher
|
|
||||||
Database <watcher_database_definition>` using the ``watcher-sync`` command line
|
|
||||||
tool.
|
|
||||||
|
|
||||||
Below is an example of a container using some scoring engine implementation
|
|
||||||
that is simply made of a client responsible for communicating with a real
|
|
||||||
scoring engine deployed as a web service on external servers:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
class NewScoringContainer(base.ScoringEngineContainer):
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_scoring_engine_list(self):
|
|
||||||
return [
|
|
||||||
RemoteScoringEngine(
|
|
||||||
name='scoring_engine1',
|
|
||||||
description='Some remote Scoring Engine 1',
|
|
||||||
remote_url='http://engine1.example.com/score'),
|
|
||||||
RemoteScoringEngine(
|
|
||||||
name='scoring_engine2',
|
|
||||||
description='Some remote Scoring Engine 2',
|
|
||||||
remote_url='http://engine2.example.com/score'),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
Abstract Plugin Class
|
|
||||||
=====================
|
|
||||||
|
|
||||||
Here below is the abstract :py:class:`~.ScoringEngine` class:
|
|
||||||
|
|
||||||
.. autoclass:: watcher.decision_engine.scoring.base.ScoringEngine
|
|
||||||
:members:
|
|
||||||
:special-members: __init__
|
|
||||||
:noindex:
|
|
||||||
|
|
||||||
|
|
||||||
Abstract Plugin Container Class
|
|
||||||
===============================
|
|
||||||
|
|
||||||
Here below is the abstract :py:class:`~.ScoringContainer` class:
|
|
||||||
|
|
||||||
.. autoclass:: watcher.decision_engine.scoring.base.ScoringEngineContainer
|
|
||||||
:members:
|
|
||||||
:special-members: __init__
|
|
||||||
:noindex:
|
|
||||||
|
|
||||||
|
|
||||||
.. _scoring_engine_plugin_add_entrypoint:
|
|
||||||
|
|
||||||
Add a new entry point
|
|
||||||
=====================
|
|
||||||
|
|
||||||
In order for the Watcher Decision Engine to load your new scoring engine, it
|
|
||||||
must be registered as a named entry point under the ``watcher_scoring_engines``
|
|
||||||
entry point of your ``setup.py`` file. If you are using pbr_, this entry point
|
|
||||||
should be placed in your ``setup.cfg`` file.
|
|
||||||
|
|
||||||
The name you give to your entry point has to be unique and should be the same
|
|
||||||
as the value returned by the :py:meth:`~.ScoringEngine.get_name` method of your
|
|
||||||
strategy.
|
|
||||||
|
|
||||||
Here below is how you would proceed to register ``NewScorer`` using pbr_:
|
|
||||||
|
|
||||||
.. code-block:: ini
|
|
||||||
|
|
||||||
[entry_points]
|
|
||||||
watcher_scoring_engines =
|
|
||||||
new_scorer = thirdparty.new:NewScorer
|
|
||||||
|
|
||||||
|
|
||||||
To get a better understanding on how to implement a more advanced scoring
|
|
||||||
engine, have a look at the :py:class:`~.DummyScorer` class. This implementation
|
|
||||||
is not really using machine learning, but other than that it contains all the
|
|
||||||
pieces which the "real" implementation would have.
|
|
||||||
|
|
||||||
In addition, for some use cases there is a need to register a list (possibly
|
|
||||||
dynamic, depending on the implementation and configuration) of scoring engines
|
|
||||||
in a single plugin, so there is no need to restart :ref:`Watcher Decision
|
|
||||||
Engine <watcher_decision_engine_definition>` every time such list changes. For
|
|
||||||
these cases, an additional ``watcher_scoring_engine_containers`` entry point
|
|
||||||
can be used.
|
|
||||||
|
|
||||||
For the example how to use scoring engine containers, please have a look at
|
|
||||||
the :py:class:`~.DummyScoringContainer` and the way it is configured in
|
|
||||||
``setup.cfg``. For new containers it could be done like this:
|
|
||||||
|
|
||||||
.. code-block:: ini
|
|
||||||
|
|
||||||
[entry_points]
|
|
||||||
watcher_scoring_engine_containers =
|
|
||||||
new_scoring_container = thirdparty.new:NewContainer
|
|
||||||
|
|
||||||
.. _pbr: http://docs.openstack.org/developer/pbr/
|
|
||||||
|
|
||||||
|
|
||||||
Using scoring engine plugins
|
|
||||||
============================
|
|
||||||
|
|
||||||
The Watcher Decision Engine service will automatically discover any installed
|
|
||||||
plugins when it is restarted. If a Python package containing a custom plugin is
|
|
||||||
installed within the same environment as Watcher, Watcher will automatically
|
|
||||||
make that plugin available for use.
|
|
||||||
|
|
||||||
At this point, Watcher will scan and register inside the :ref:`Watcher Database
|
|
||||||
<watcher_database_definition>` all the scoring engines you implemented upon
|
|
||||||
restarting the :ref:`Watcher Decision Engine
|
|
||||||
<watcher_decision_engine_definition>`.
|
|
||||||
|
|
||||||
In addition, ``watcher-sync`` tool can be used to trigger :ref:`Watcher
|
|
||||||
Database <watcher_database_definition>` synchronization. This might be used for
|
|
||||||
"dynamic" scoring containers, which can return different scoring engines based
|
|
||||||
on some external configuration (if they support that).
|
|
@ -1,314 +0,0 @@
|
|||||||
..
|
|
||||||
Except where otherwise noted, this document is licensed under Creative
|
|
||||||
Commons Attribution 3.0 License. You can view the license at:
|
|
||||||
|
|
||||||
https://creativecommons.org/licenses/by/3.0/
|
|
||||||
|
|
||||||
.. _implement_strategy_plugin:
|
|
||||||
|
|
||||||
=================================
|
|
||||||
Build a new optimization strategy
|
|
||||||
=================================
|
|
||||||
|
|
||||||
Watcher Decision Engine has an external :ref:`strategy <strategy_definition>`
|
|
||||||
plugin interface which gives anyone the ability to integrate an external
|
|
||||||
strategy in order to make use of placement algorithms.
|
|
||||||
|
|
||||||
This section gives some guidelines on how to implement and integrate custom
|
|
||||||
strategies with Watcher. If you wish to create a third-party package for your
|
|
||||||
plugin, you can refer to our :ref:`documentation for third-party package
|
|
||||||
creation <plugin-base_setup>`.
|
|
||||||
|
|
||||||
|
|
||||||
Pre-requisites
|
|
||||||
==============
|
|
||||||
|
|
||||||
Before using any strategy, you should make sure you have your Telemetry service
|
|
||||||
configured so that it would provide you all the metrics you need to be able to
|
|
||||||
use your strategy.
|
|
||||||
|
|
||||||
|
|
||||||
Create a new strategy plugin
|
|
||||||
============================
|
|
||||||
|
|
||||||
In order to create a new strategy, you have to:
|
|
||||||
|
|
||||||
- Extend the :py:class:`~.UnclassifiedStrategy` class
|
|
||||||
- Implement its :py:meth:`~.BaseStrategy.get_name` class method to return the
|
|
||||||
**unique** ID of the new strategy you want to create. This unique ID should
|
|
||||||
be the same as the name of :ref:`the entry point we will declare later on
|
|
||||||
<strategy_plugin_add_entrypoint>`.
|
|
||||||
- Implement its :py:meth:`~.BaseStrategy.get_display_name` class method to
|
|
||||||
return the translated display name of the strategy you want to create.
|
|
||||||
Note: Do not use a variable to return the translated string so it can be
|
|
||||||
automatically collected by the translation tool.
|
|
||||||
- Implement its :py:meth:`~.BaseStrategy.get_translatable_display_name`
|
|
||||||
class method to return the translation key (actually the English display
|
|
||||||
name) of your new strategy. The value return should be the same as the
|
|
||||||
string translated in :py:meth:`~.BaseStrategy.get_display_name`.
|
|
||||||
- Implement its :py:meth:`~.BaseStrategy.execute` method to return the
|
|
||||||
solution you computed within your strategy.
|
|
||||||
|
|
||||||
Here is an example showing how you can write a plugin called ``NewStrategy``:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
# filepath: thirdparty/new.py
|
|
||||||
# import path: thirdparty.new
|
|
||||||
import abc
|
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
from watcher._i18n import _
|
|
||||||
from watcher.decision_engine.strategy.strategies import base
|
|
||||||
|
|
||||||
|
|
||||||
class NewStrategy(base.UnclassifiedStrategy):
|
|
||||||
|
|
||||||
def __init__(self, osc=None):
|
|
||||||
super(NewStrategy, self).__init__(osc)
|
|
||||||
|
|
||||||
def execute(self, original_model):
|
|
||||||
self.solution.add_action(action_type="nop",
|
|
||||||
input_parameters=parameters)
|
|
||||||
# Do some more stuff here ...
|
|
||||||
return self.solution
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_name(cls):
|
|
||||||
return "new_strategy"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_display_name(cls):
|
|
||||||
return _("New strategy")
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_translatable_display_name(cls):
|
|
||||||
return "New strategy"
|
|
||||||
|
|
||||||
|
|
||||||
As you can see in the above example, the :py:meth:`~.BaseStrategy.execute`
|
|
||||||
method returns a :py:class:`~.BaseSolution` instance as required. This solution
|
|
||||||
is what wraps the abstract set of actions the strategy recommends to you. This
|
|
||||||
solution is then processed by a :ref:`planner <watcher_planner_definition>` to
|
|
||||||
produce an action plan which contains the sequenced flow of actions to be
|
|
||||||
executed by the :ref:`Watcher Applier <watcher_applier_definition>`. This
|
|
||||||
solution also contains the various :ref:`efficacy indicators
|
|
||||||
<efficacy_indicator_definition>` alongside its computed :ref:`global efficacy
|
|
||||||
<efficacy_definition>`.
|
|
||||||
|
|
||||||
Please note that your strategy class will expect to find the same constructor
|
|
||||||
signature as BaseStrategy to instantiate you strategy. Therefore, you should
|
|
||||||
ensure that your ``__init__`` signature is identical to the
|
|
||||||
:py:class:`~.BaseStrategy` one.
|
|
||||||
|
|
||||||
|
|
||||||
Strategy efficacy
|
|
||||||
=================
|
|
||||||
|
|
||||||
As stated before, the ``NewStrategy`` class extends a class called
|
|
||||||
:py:class:`~.UnclassifiedStrategy`. This class actually implements a set of
|
|
||||||
abstract methods which are defined within the :py:class:`~.BaseStrategy` parent
|
|
||||||
class.
|
|
||||||
|
|
||||||
One thing this :py:class:`~.UnclassifiedStrategy` class defines is that our
|
|
||||||
``NewStrategy`` achieves the ``unclassified`` goal. This goal is a peculiar one
|
|
||||||
as it does not contain any indicator nor does it calculate a global efficacy.
|
|
||||||
This proves itself to be quite useful during the development of a new strategy
|
|
||||||
for which the goal has yet to be defined or in case a :ref:`new goal
|
|
||||||
<implement_goal_plugin>` has yet to be implemented.
|
|
||||||
|
|
||||||
|
|
||||||
Define Strategy Parameters
|
|
||||||
==========================
|
|
||||||
|
|
||||||
For each new added strategy, you can add parameters spec so that an operator
|
|
||||||
can input strategy parameters when creating an audit to control the
|
|
||||||
:py:meth:`~.BaseStrategy.execute` behavior of strategy. This is useful to
|
|
||||||
define some threshold for your strategy, and tune them at runtime.
|
|
||||||
|
|
||||||
To define parameters, just implements :py:meth:`~.BaseStrategy.get_schema` to
|
|
||||||
return parameters spec with `jsonschema
|
|
||||||
<http://json-schema.org/>`_ format.
|
|
||||||
It is strongly encouraged that provide default value for each parameter, or
|
|
||||||
else reference fails if operator specify no parameters.
|
|
||||||
|
|
||||||
Here is an example showing how you can define 2 parameters for
|
|
||||||
``DummyStrategy``:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
class DummyStrategy(base.DummyBaseStrategy):
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_schema(cls):
|
|
||||||
return {
|
|
||||||
"properties": {
|
|
||||||
"para1": {
|
|
||||||
"description": "number parameter example",
|
|
||||||
"type": "number",
|
|
||||||
"default": 3.2,
|
|
||||||
"minimum": 1.0,
|
|
||||||
"maximum": 10.2,
|
|
||||||
},
|
|
||||||
"para2": {
|
|
||||||
"description": "string parameter example",
|
|
||||||
"type": "string",
|
|
||||||
"default": "hello",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
You can reference parameters in :py:meth:`~.BaseStrategy.execute`:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
class DummyStrategy(base.DummyBaseStrategy):
|
|
||||||
|
|
||||||
def execute(self):
|
|
||||||
para1 = self.input_parameters.para1
|
|
||||||
para2 = self.input_parameters.para2
|
|
||||||
|
|
||||||
if para1 > 5:
|
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
Operator can specify parameters with following commands:
|
|
||||||
|
|
||||||
.. code:: bash
|
|
||||||
|
|
||||||
$ watcher audit create -a <your_audit_template> -p para1=6.0 -p para2=hi
|
|
||||||
|
|
||||||
Pls. check user-guide for details.
|
|
||||||
|
|
||||||
|
|
||||||
Abstract Plugin Class
|
|
||||||
=====================
|
|
||||||
|
|
||||||
Here below is the abstract :py:class:`~.BaseStrategy` class:
|
|
||||||
|
|
||||||
.. autoclass:: watcher.decision_engine.strategy.strategies.base.BaseStrategy
|
|
||||||
:members:
|
|
||||||
:special-members: __init__
|
|
||||||
:noindex:
|
|
||||||
|
|
||||||
.. _strategy_plugin_add_entrypoint:
|
|
||||||
|
|
||||||
Add a new entry point
|
|
||||||
=====================
|
|
||||||
|
|
||||||
In order for the Watcher Decision Engine to load your new strategy, the
|
|
||||||
strategy must be registered as a named entry point under the
|
|
||||||
``watcher_strategies`` entry point of your ``setup.py`` file. If you are using
|
|
||||||
pbr_, this entry point should be placed in your ``setup.cfg`` file.
|
|
||||||
|
|
||||||
The name you give to your entry point has to be unique and should be the same
|
|
||||||
as the value returned by the :py:meth:`~.BaseStrategy.get_name` class method of
|
|
||||||
your strategy.
|
|
||||||
|
|
||||||
Here below is how you would proceed to register ``NewStrategy`` using pbr_:
|
|
||||||
|
|
||||||
.. code-block:: ini
|
|
||||||
|
|
||||||
[entry_points]
|
|
||||||
watcher_strategies =
|
|
||||||
new_strategy = thirdparty.new:NewStrategy
|
|
||||||
|
|
||||||
|
|
||||||
To get a better understanding on how to implement a more advanced strategy,
|
|
||||||
have a look at the :py:class:`~.BasicConsolidation` class.
|
|
||||||
|
|
||||||
.. _pbr: http://docs.openstack.org/developer/pbr/
|
|
||||||
|
|
||||||
Using strategy plugins
|
|
||||||
======================
|
|
||||||
|
|
||||||
The Watcher Decision Engine service will automatically discover any installed
|
|
||||||
plugins when it is restarted. If a Python package containing a custom plugin is
|
|
||||||
installed within the same environment as Watcher, Watcher will automatically
|
|
||||||
make that plugin available for use.
|
|
||||||
|
|
||||||
At this point, Watcher will scan and register inside the :ref:`Watcher Database
|
|
||||||
<watcher_database_definition>` all the strategies (alongside the goals they
|
|
||||||
should satisfy) you implemented upon restarting the :ref:`Watcher Decision
|
|
||||||
Engine <watcher_decision_engine_definition>`.
|
|
||||||
|
|
||||||
You should take care when installing strategy plugins. By their very nature,
|
|
||||||
there are no guarantees that utilizing them as is will be supported, as
|
|
||||||
they may require a set of metrics which is not yet available within the
|
|
||||||
Telemetry service. In such a case, please do make sure that you first
|
|
||||||
check/configure the latter so your new strategy can be fully functional.
|
|
||||||
|
|
||||||
Querying metrics
|
|
||||||
----------------
|
|
||||||
|
|
||||||
A large set of metrics, generated by OpenStack modules, can be used in your
|
|
||||||
strategy implementation. To collect these metrics, Watcher provides a
|
|
||||||
`Helper`_ for two data sources which are `Ceilometer`_ and `Monasca`_. If you
|
|
||||||
wish to query metrics from a different data source, you can implement your own
|
|
||||||
and directly use it from within your new strategy. Indeed, strategies in
|
|
||||||
Watcher have the cluster data models decoupled from the data sources which
|
|
||||||
means that you may keep the former while changing the latter.
|
|
||||||
The recommended way for you to support a new data source is to implement a new
|
|
||||||
helper that would encapsulate within separate methods the queries you need to
|
|
||||||
perform. To then use it, you would just have to instantiate it within your
|
|
||||||
strategy.
|
|
||||||
|
|
||||||
If you want to use Ceilometer but with your own metrics database backend,
|
|
||||||
please refer to the `Ceilometer developer guide`_. The list of the available
|
|
||||||
Ceilometer backends is located here_. The `Ceilosca`_ project is a good example
|
|
||||||
of how to create your own pluggable backend. Moreover, if your strategy
|
|
||||||
requires new metrics not covered by Ceilometer, you can add them through a
|
|
||||||
`Ceilometer plugin`_.
|
|
||||||
|
|
||||||
|
|
||||||
.. _`Helper`: https://github.com/openstack/watcher/blob/master/watcher/decision_engine/cluster/history/ceilometer.py
|
|
||||||
.. _`Ceilometer developer guide`: http://docs.openstack.org/developer/ceilometer/architecture.html#storing-the-data
|
|
||||||
.. _`Ceilometer`: http://docs.openstack.org/developer/ceilometer/
|
|
||||||
.. _`Monasca`: https://github.com/openstack/monasca-api/blob/master/docs/monasca-api-spec.md
|
|
||||||
.. _`here`: http://docs.openstack.org/developer/ceilometer/install/dbreco.html#choosing-a-database-backend
|
|
||||||
.. _`Ceilometer plugin`: http://docs.openstack.org/developer/ceilometer/plugins.html
|
|
||||||
.. _`Ceilosca`: https://github.com/openstack/monasca-ceilometer/blob/master/ceilosca/ceilometer/storage/impl_monasca.py
|
|
||||||
|
|
||||||
Read usage metrics using the Watcher Datasource Helper
|
|
||||||
------------------------------------------------------
|
|
||||||
|
|
||||||
The following code snippet shows how to invoke a Datasource Helper class:
|
|
||||||
|
|
||||||
.. code-block:: py
|
|
||||||
|
|
||||||
from watcher.datasource import ceilometer as ceil
|
|
||||||
from watcher.datasource import monasca as mon
|
|
||||||
|
|
||||||
@property
|
|
||||||
def ceilometer(self):
|
|
||||||
if self._ceilometer is None:
|
|
||||||
self._ceilometer = ceil.CeilometerHelper(osc=self.osc)
|
|
||||||
return self._ceilometer
|
|
||||||
|
|
||||||
@property
|
|
||||||
def monasca(self):
|
|
||||||
if self._monasca is None:
|
|
||||||
self._monasca = mon.MonascaHelper(osc=self.osc)
|
|
||||||
return self._monasca
|
|
||||||
|
|
||||||
Using that you can now query the values for that specific metric:
|
|
||||||
|
|
||||||
.. code-block:: py
|
|
||||||
|
|
||||||
if self.config.datasource == "ceilometer":
|
|
||||||
resource_id = "%s_%s" % (node.uuid, node.hostname)
|
|
||||||
return self.ceilometer.statistic_aggregation(
|
|
||||||
resource_id=resource_id,
|
|
||||||
meter_name='compute.node.cpu.percent',
|
|
||||||
period="7200",
|
|
||||||
aggregate='avg',
|
|
||||||
)
|
|
||||||
elif self.config.datasource == "monasca":
|
|
||||||
statistics = self.monasca.statistic_aggregation(
|
|
||||||
meter_name='compute.node.cpu.percent',
|
|
||||||
dimensions=dict(hostname=node.uuid),
|
|
||||||
period=7200,
|
|
||||||
aggregate='avg'
|
|
||||||
)
|
|
@ -1 +0,0 @@
|
|||||||
.. include:: ../../../rally-jobs/README.rst
|
|
@ -1,50 +0,0 @@
|
|||||||
..
|
|
||||||
Except where otherwise noted, this document is licensed under Creative
|
|
||||||
Commons Attribution 3.0 License. You can view the license at:
|
|
||||||
|
|
||||||
https://creativecommons.org/licenses/by/3.0/
|
|
||||||
|
|
||||||
=======
|
|
||||||
Testing
|
|
||||||
=======
|
|
||||||
|
|
||||||
.. _unit_tests:
|
|
||||||
|
|
||||||
Unit tests
|
|
||||||
==========
|
|
||||||
|
|
||||||
All unit tests should be run using `tox`_. To run the same unit tests that are
|
|
||||||
executing onto `Gerrit`_ which includes ``py35``, ``py27`` and ``pep8``, you
|
|
||||||
can issue the following command::
|
|
||||||
|
|
||||||
$ workon watcher
|
|
||||||
(watcher) $ pip install tox
|
|
||||||
(watcher) $ cd watcher
|
|
||||||
(watcher) $ tox
|
|
||||||
|
|
||||||
If you want to only run one of the aforementioned, you can then issue one of
|
|
||||||
the following::
|
|
||||||
|
|
||||||
$ workon watcher
|
|
||||||
(watcher) $ tox -e py35
|
|
||||||
(watcher) $ tox -e py27
|
|
||||||
(watcher) $ tox -e pep8
|
|
||||||
|
|
||||||
.. _tox: https://tox.readthedocs.org/
|
|
||||||
.. _Gerrit: http://review.openstack.org/
|
|
||||||
|
|
||||||
You may pass options to the test programs using positional arguments. To run a
|
|
||||||
specific unit test, you can pass extra options to `os-testr`_ after putting
|
|
||||||
the ``--`` separator. So using the ``-r`` option followed by a regex string,
|
|
||||||
you can run the desired test::
|
|
||||||
|
|
||||||
$ workon watcher
|
|
||||||
(watcher) $ tox -e py27 -- -r watcher.tests.api
|
|
||||||
|
|
||||||
.. _os-testr: http://docs.openstack.org/developer/os-testr/
|
|
||||||
|
|
||||||
When you're done, deactivate the virtualenv::
|
|
||||||
|
|
||||||
$ deactivate
|
|
||||||
|
|
||||||
.. include:: ../../../watcher_tempest_plugin/README.rst
|
|
@ -1,386 +0,0 @@
|
|||||||
..
|
|
||||||
Except where otherwise noted, this document is licensed under Creative
|
|
||||||
Commons Attribution 3.0 License. You can view the license at:
|
|
||||||
|
|
||||||
https://creativecommons.org/licenses/by/3.0/
|
|
||||||
|
|
||||||
========
|
|
||||||
Glossary
|
|
||||||
========
|
|
||||||
|
|
||||||
.. glossary::
|
|
||||||
:sorted:
|
|
||||||
|
|
||||||
This page explains the different terms used in the Watcher system.
|
|
||||||
|
|
||||||
They are sorted in alphabetical order.
|
|
||||||
|
|
||||||
.. _action_definition:
|
|
||||||
|
|
||||||
Action
|
|
||||||
======
|
|
||||||
|
|
||||||
.. watcher-term:: watcher.api.controllers.v1.action
|
|
||||||
|
|
||||||
.. _action_plan_definition:
|
|
||||||
|
|
||||||
Action Plan
|
|
||||||
===========
|
|
||||||
|
|
||||||
.. watcher-term:: watcher.api.controllers.v1.action_plan
|
|
||||||
|
|
||||||
.. _administrator_definition:
|
|
||||||
|
|
||||||
Administrator
|
|
||||||
=============
|
|
||||||
|
|
||||||
The :ref:`Administrator <administrator_definition>` is any user who has admin
|
|
||||||
access on the OpenStack cluster. This user is allowed to create new projects
|
|
||||||
for tenants, create new users and assign roles to each user.
|
|
||||||
|
|
||||||
The :ref:`Administrator <administrator_definition>` usually has remote access
|
|
||||||
to any host of the cluster in order to change the configuration and restart any
|
|
||||||
OpenStack service, including Watcher.
|
|
||||||
|
|
||||||
In the context of Watcher, the :ref:`Administrator <administrator_definition>`
|
|
||||||
is a role for users which allows them to run any Watcher commands, such as:
|
|
||||||
|
|
||||||
- Create/Delete an :ref:`Audit Template <audit_template_definition>`
|
|
||||||
- Launch an :ref:`Audit <audit_definition>`
|
|
||||||
- Get the :ref:`Action Plan <action_plan_definition>`
|
|
||||||
- Launch a recommended :ref:`Action Plan <action_plan_definition>` manually
|
|
||||||
- Archive previous :ref:`Audits <audit_definition>` and
|
|
||||||
:ref:`Action Plans <action_plan_definition>`
|
|
||||||
|
|
||||||
|
|
||||||
The :ref:`Administrator <administrator_definition>` is also allowed to modify
|
|
||||||
any Watcher configuration files and to restart Watcher services.
|
|
||||||
|
|
||||||
.. _audit_definition:
|
|
||||||
|
|
||||||
Audit
|
|
||||||
=====
|
|
||||||
|
|
||||||
.. watcher-term:: watcher.api.controllers.v1.audit
|
|
||||||
|
|
||||||
.. _audit_template_definition:
|
|
||||||
|
|
||||||
Audit Template
|
|
||||||
==============
|
|
||||||
|
|
||||||
.. watcher-term:: watcher.api.controllers.v1.audit_template
|
|
||||||
|
|
||||||
.. _availability_zone_definition:
|
|
||||||
|
|
||||||
Availability Zone
|
|
||||||
=================
|
|
||||||
|
|
||||||
Please, read `the official OpenStack definition of an Availability Zone <http://docs.openstack.org/developer/nova/aggregates.html#availability-zones-azs>`_.
|
|
||||||
|
|
||||||
.. _cluster_definition:
|
|
||||||
|
|
||||||
Cluster
|
|
||||||
=======
|
|
||||||
|
|
||||||
A :ref:`Cluster <cluster_definition>` is a set of physical machines which
|
|
||||||
provide compute, storage and networking resources and are managed by the same
|
|
||||||
OpenStack Controller node.
|
|
||||||
A :ref:`Cluster <cluster_definition>` represents a set of resources that a
|
|
||||||
cloud provider is able to offer to his/her
|
|
||||||
:ref:`customers <customer_definition>`.
|
|
||||||
|
|
||||||
A data center may contain several clusters.
|
|
||||||
|
|
||||||
The :ref:`Cluster <cluster_definition>` may be divided in one or several
|
|
||||||
:ref:`Availability Zone(s) <availability_zone_definition>`.
|
|
||||||
|
|
||||||
.. _cluster_data_model_definition:
|
|
||||||
|
|
||||||
Cluster Data Model (CDM)
|
|
||||||
========================
|
|
||||||
|
|
||||||
.. watcher-term:: watcher.decision_engine.model.collector.base
|
|
||||||
|
|
||||||
|
|
||||||
.. _controller_node_definition:
|
|
||||||
|
|
||||||
Controller Node
|
|
||||||
===============
|
|
||||||
|
|
||||||
A controller node is a machine that typically runs the following core OpenStack
|
|
||||||
services:
|
|
||||||
|
|
||||||
- Keystone: for identity and service management
|
|
||||||
- Cinder scheduler: for volumes management
|
|
||||||
- Glance controller: for image management
|
|
||||||
- Neutron controller: for network management
|
|
||||||
- Nova controller: for global compute resources management with services
|
|
||||||
such as nova-scheduler, nova-conductor and nova-network.
|
|
||||||
|
|
||||||
In many configurations, Watcher will reside on a controller node even if it
|
|
||||||
can potentially be hosted on a dedicated machine.
|
|
||||||
|
|
||||||
.. _compute_node_definition:
|
|
||||||
|
|
||||||
Compute node
|
|
||||||
============
|
|
||||||
|
|
||||||
Please, read `the official OpenStack definition of a Compute Node
|
|
||||||
<http://docs.openstack.org/ops-guide/arch-compute-nodes.html>`_.
|
|
||||||
|
|
||||||
.. _customer_definition:
|
|
||||||
|
|
||||||
Customer
|
|
||||||
========
|
|
||||||
|
|
||||||
A :ref:`Customer <customer_definition>` is the person or company which
|
|
||||||
subscribes to the cloud provider offering. A customer may have several
|
|
||||||
:ref:`Project(s) <project_definition>`
|
|
||||||
hosted on the same :ref:`Cluster <cluster_definition>` or dispatched on
|
|
||||||
different clusters.
|
|
||||||
|
|
||||||
In the private cloud context, the :ref:`Customers <customer_definition>` are
|
|
||||||
different groups within the same organization (different departments, project
|
|
||||||
teams, branch offices and so on). Cloud infrastructure includes the ability to
|
|
||||||
precisely track each customer's service usage so that it can be charged back to
|
|
||||||
them, or at least reported to them.
|
|
||||||
|
|
||||||
.. _goal_definition:
|
|
||||||
|
|
||||||
Goal
|
|
||||||
====
|
|
||||||
|
|
||||||
.. watcher-term:: watcher.api.controllers.v1.goal
|
|
||||||
|
|
||||||
|
|
||||||
.. _host_aggregates_definition:
|
|
||||||
|
|
||||||
Host Aggregate
|
|
||||||
==============
|
|
||||||
|
|
||||||
Please, read `the official OpenStack definition of a Host Aggregate
|
|
||||||
<http://docs.openstack.org/developer/nova/aggregates.html>`_.
|
|
||||||
|
|
||||||
.. _instance_definition:
|
|
||||||
|
|
||||||
Instance
|
|
||||||
========
|
|
||||||
|
|
||||||
A running virtual machine, or a virtual machine in a known state such as
|
|
||||||
suspended, that can be used like a hardware server.
|
|
||||||
|
|
||||||
.. _managed_resource_definition:
|
|
||||||
|
|
||||||
Managed resource
|
|
||||||
================
|
|
||||||
|
|
||||||
A :ref:`Managed resource <managed_resource_definition>` is one instance of
|
|
||||||
:ref:`Managed resource type <managed_resource_type_definition>` in a topology
|
|
||||||
with particular properties and dependencies on other
|
|
||||||
:ref:`Managed resources <managed_resource_definition>` (relationships).
|
|
||||||
|
|
||||||
For example, a :ref:`Managed resource <managed_resource_definition>` can be one
|
|
||||||
virtual machine (i.e., an :ref:`instance <instance_definition>`) hosted on a
|
|
||||||
:ref:`compute node <compute_node_definition>` and connected to another virtual
|
|
||||||
machine through a network link (represented also as a
|
|
||||||
:ref:`Managed resource <managed_resource_definition>` in the
|
|
||||||
:ref:`Cluster Data Model <cluster_data_model_definition>`).
|
|
||||||
|
|
||||||
.. _managed_resource_type_definition:
|
|
||||||
|
|
||||||
Managed resource type
|
|
||||||
=====================
|
|
||||||
|
|
||||||
A :ref:`Managed resource type <managed_resource_definition>` is a type of
|
|
||||||
hardware or software element of the :ref:`Cluster <cluster_definition>` that
|
|
||||||
the Watcher system can act on.
|
|
||||||
|
|
||||||
Here are some examples of
|
|
||||||
:ref:`Managed resource types <managed_resource_definition>`:
|
|
||||||
|
|
||||||
- `Nova Host Aggregates <http://docs.openstack.org/developer/heat/template_guide/openstack.html#OS::Nova::HostAggregate>`_
|
|
||||||
- `Nova Servers <http://docs.openstack.org/developer/heat/template_guide/openstack.html#OS::Nova::Server>`_
|
|
||||||
- `Cinder Volumes <http://docs.openstack.org/developer/heat/template_guide/openstack.html#OS::Cinder::Volume>`_
|
|
||||||
- `Neutron Routers <http://docs.openstack.org/developer/heat/template_guide/openstack.html#OS::Neutron::Router>`_
|
|
||||||
- `Neutron Networks <http://docs.openstack.org/developer/heat/template_guide/openstack.html#OS::Neutron::Net>`_
|
|
||||||
- `Neutron load-balancers <http://docs.openstack.org/developer/heat/template_guide/openstack.html#OS::Neutron::LoadBalancer>`_
|
|
||||||
- `Sahara Hadoop Cluster <http://docs.openstack.org/developer/heat/template_guide/openstack.html#OS::Sahara::Cluster>`_
|
|
||||||
- ...
|
|
||||||
|
|
||||||
It can be any of the `the official list of available resource types defined in
|
|
||||||
OpenStack for HEAT
|
|
||||||
<http://docs.openstack.org/developer/heat/template_guide/openstack.html>`_.
|
|
||||||
|
|
||||||
.. _efficacy_indicator_definition:
|
|
||||||
|
|
||||||
Efficacy Indicator
|
|
||||||
==================
|
|
||||||
|
|
||||||
.. watcher-term:: watcher.api.controllers.v1.efficacy_indicator
|
|
||||||
|
|
||||||
.. _efficacy_specification_definition:
|
|
||||||
|
|
||||||
Efficacy Specification
|
|
||||||
======================
|
|
||||||
|
|
||||||
.. watcher-term:: watcher.decision_engine.goal.efficacy.base
|
|
||||||
|
|
||||||
.. _efficacy_definition:
|
|
||||||
|
|
||||||
Optimization Efficacy
|
|
||||||
=====================
|
|
||||||
|
|
||||||
The :ref:`Optimization Efficacy <efficacy_definition>` is the objective
|
|
||||||
measure of how much of the :ref:`Goal <goal_definition>` has been achieved in
|
|
||||||
respect with constraints and :ref:`SLAs <sla_definition>` defined by the
|
|
||||||
:ref:`Customer <customer_definition>`.
|
|
||||||
|
|
||||||
The way efficacy is evaluated will depend on the :ref:`Goal <goal_definition>`
|
|
||||||
to achieve.
|
|
||||||
|
|
||||||
Of course, the efficacy will be relevant only as long as the
|
|
||||||
:ref:`Action Plan <action_plan_definition>` is relevant
|
|
||||||
(i.e., the current state of the :ref:`Cluster <cluster_definition>`
|
|
||||||
has not changed in a way that a new :ref:`Audit <audit_definition>` would need
|
|
||||||
to be launched).
|
|
||||||
|
|
||||||
For example, if the :ref:`Goal <goal_definition>` is to lower the energy
|
|
||||||
consumption, the :ref:`Efficacy <efficacy_definition>` will be computed
|
|
||||||
using several :ref:`efficacy indicators <efficacy_indicator_definition>`
|
|
||||||
(KPIs):
|
|
||||||
|
|
||||||
- the percentage of energy gain (which must be the highest possible)
|
|
||||||
- the number of :ref:`SLA violations <sla_violation_definition>`
|
|
||||||
(which must be the lowest possible)
|
|
||||||
- the number of virtual machine migrations (which must be the lowest possible)
|
|
||||||
|
|
||||||
All those indicators are computed within a given timeframe, which is the
|
|
||||||
time taken to execute the whole :ref:`Action Plan <action_plan_definition>`.
|
|
||||||
|
|
||||||
The efficacy also enables the :ref:`Administrator <administrator_definition>`
|
|
||||||
to objectively compare different :ref:`Strategies <strategy_definition>` for
|
|
||||||
the same goal and same workload of the :ref:`Cluster <cluster_definition>`.
|
|
||||||
|
|
||||||
.. _project_definition:
|
|
||||||
|
|
||||||
Project
|
|
||||||
=======
|
|
||||||
|
|
||||||
:ref:`Projects <project_definition>` represent the base unit of “ownership”
|
|
||||||
in OpenStack, in that all :ref:`resources <managed_resource_definition>` in
|
|
||||||
OpenStack should be owned by a specific :ref:`project <project_definition>`.
|
|
||||||
In OpenStack Identity, a :ref:`project <project_definition>` must be owned by a
|
|
||||||
specific domain.
|
|
||||||
|
|
||||||
Please, read `the official OpenStack definition of a Project
|
|
||||||
<http://docs.openstack.org/glossary/content/glossary.html>`_.
|
|
||||||
|
|
||||||
.. _scoring_engine_definition:
|
|
||||||
|
|
||||||
Scoring Engine
|
|
||||||
==============
|
|
||||||
|
|
||||||
.. watcher-term:: watcher.api.controllers.v1.scoring_engine
|
|
||||||
|
|
||||||
.. _sla_definition:
|
|
||||||
|
|
||||||
SLA
|
|
||||||
===
|
|
||||||
|
|
||||||
:ref:`SLA <sla_definition>` means Service Level Agreement.
|
|
||||||
|
|
||||||
The resources are negotiated between the :ref:`Customer <customer_definition>`
|
|
||||||
and the Cloud Provider in a contract.
|
|
||||||
|
|
||||||
Most of the time, this contract is composed of two documents:
|
|
||||||
|
|
||||||
- :ref:`SLA <sla_definition>` : Service Level Agreement
|
|
||||||
- :ref:`SLO <slo_definition>` : Service Level Objectives
|
|
||||||
|
|
||||||
Note that the :ref:`SLA <sla_definition>` is more general than the
|
|
||||||
:ref:`SLO <slo_definition>` in the sense that the former specifies what service
|
|
||||||
is to be provided, how it is supported, times, locations, costs, performance,
|
|
||||||
and responsibilities of the parties involved while the
|
|
||||||
:ref:`SLO <slo_definition>` focuses on more measurable characteristics such as
|
|
||||||
availability, throughput, frequency, response time or quality.
|
|
||||||
|
|
||||||
You can also read `the Wikipedia page for SLA <https://en.wikipedia.org/wiki/Service-level_agreement>`_
|
|
||||||
which provides a good definition.
|
|
||||||
|
|
||||||
.. _sla_violation_definition:
|
|
||||||
|
|
||||||
SLA violation
|
|
||||||
=============
|
|
||||||
|
|
||||||
A :ref:`SLA violation <sla_violation_definition>` happens when a
|
|
||||||
:ref:`SLA <sla_definition>` defined with a given
|
|
||||||
:ref:`Customer <customer_definition>` could not be respected by the
|
|
||||||
cloud provider within the timeframe defined by the official contract document.
|
|
||||||
|
|
||||||
.. _slo_definition:
|
|
||||||
|
|
||||||
SLO
|
|
||||||
===
|
|
||||||
|
|
||||||
A Service Level Objective (SLO) is a key element of a
|
|
||||||
:ref:`SLA <sla_definition>` between a service provider and a
|
|
||||||
:ref:`Customer <customer_definition>`. SLOs are agreed as a means of measuring
|
|
||||||
the performance of the Service Provider and are outlined as a way of avoiding
|
|
||||||
disputes between the two parties based on misunderstanding.
|
|
||||||
|
|
||||||
You can also read `the Wikipedia page for SLO <https://en.wikipedia.org/wiki/Service_level_objective>`_
|
|
||||||
which provides a good definition.
|
|
||||||
|
|
||||||
.. _solution_definition:
|
|
||||||
|
|
||||||
Solution
|
|
||||||
========
|
|
||||||
|
|
||||||
.. watcher-term:: watcher.decision_engine.solution.base
|
|
||||||
|
|
||||||
.. _strategy_definition:
|
|
||||||
|
|
||||||
Strategy
|
|
||||||
========
|
|
||||||
|
|
||||||
.. watcher-term:: watcher.api.controllers.v1.strategy
|
|
||||||
|
|
||||||
.. _watcher_applier_definition:
|
|
||||||
|
|
||||||
Watcher Applier
|
|
||||||
===============
|
|
||||||
|
|
||||||
.. watcher-term:: watcher.applier.base
|
|
||||||
|
|
||||||
.. _watcher_database_definition:
|
|
||||||
|
|
||||||
Watcher Database
|
|
||||||
================
|
|
||||||
|
|
||||||
This database stores all the Watcher domain objects which can be requested
|
|
||||||
by the Watcher API or the Watcher CLI:
|
|
||||||
|
|
||||||
- Audit templates
|
|
||||||
- Audits
|
|
||||||
- Action plans
|
|
||||||
- Actions
|
|
||||||
- Goals
|
|
||||||
|
|
||||||
The Watcher domain being here "*optimization of some resources provided by an
|
|
||||||
OpenStack system*".
|
|
||||||
|
|
||||||
See :doc:`architecture` for more details on this component.
|
|
||||||
|
|
||||||
.. _watcher_decision_engine_definition:
|
|
||||||
|
|
||||||
Watcher Decision Engine
|
|
||||||
=======================
|
|
||||||
|
|
||||||
.. watcher-term:: watcher.decision_engine.manager
|
|
||||||
|
|
||||||
.. _watcher_planner_definition:
|
|
||||||
|
|
||||||
Watcher Planner
|
|
||||||
===============
|
|
||||||
|
|
||||||
.. watcher-term:: watcher.decision_engine.planner.base
|
|
@ -1,14 +0,0 @@
|
|||||||
plantuml
|
|
||||||
========
|
|
||||||
|
|
||||||
|
|
||||||
To build an image from a source file, you have to upload the plantuml JAR file
|
|
||||||
available on http://plantuml.com/download.html.
|
|
||||||
After, just run this command to build your image:
|
|
||||||
|
|
||||||
.. code-block:: shell
|
|
||||||
|
|
||||||
$ cd doc/source/images
|
|
||||||
$ java -jar /path/to/plantuml.jar doc/source/image_src/plantuml/my_image.txt
|
|
||||||
$ ls doc/source/images/
|
|
||||||
my_image.png
|
|
@ -1,18 +0,0 @@
|
|||||||
@startuml
|
|
||||||
|
|
||||||
[*] --> RECOMMENDED: The Watcher Planner\ncreates the Action Plan
|
|
||||||
RECOMMENDED --> PENDING: Adminisrator launches\nthe Action Plan
|
|
||||||
PENDING --> ONGOING: The Watcher Applier receives the request\nto launch the Action Plan
|
|
||||||
ONGOING --> FAILED: Something failed while executing\nthe Action Plan in the Watcher Applier
|
|
||||||
ONGOING --> SUCCEEDED: The Watcher Applier executed\nthe Action Plan successfully
|
|
||||||
FAILED --> DELETED : Administrator removes\nAction Plan
|
|
||||||
SUCCEEDED --> DELETED : Administrator removes\nAction Plan
|
|
||||||
ONGOING --> CANCELLED : Administrator cancels\nAction Plan
|
|
||||||
RECOMMENDED --> CANCELLED : Administrator cancels\nAction Plan
|
|
||||||
RECOMMENDED --> SUPERSEDED : The Watcher Decision Engine supersedes\nAction Plan
|
|
||||||
PENDING --> CANCELLED : Administrator cancels\nAction Plan
|
|
||||||
CANCELLED --> DELETED
|
|
||||||
SUPERSEDED --> DELETED
|
|
||||||
DELETED --> [*]
|
|
||||||
|
|
||||||
@enduml
|
|
@ -1,17 +0,0 @@
|
|||||||
@startuml
|
|
||||||
|
|
||||||
[*] --> PENDING: Audit requested by Administrator
|
|
||||||
PENDING --> ONGOING: Audit request is received\nby the Watcher Decision Engine
|
|
||||||
ONGOING --> FAILED: Audit fails\n(no solution found, technical error, ...)
|
|
||||||
ONGOING --> SUCCEEDED: The Watcher Decision Engine\ncould find at least one Solution
|
|
||||||
ONGOING --> SUSPENDED: Administrator wants to\nsuspend the Audit
|
|
||||||
SUSPENDED --> ONGOING: Administrator wants to\nresume the Audit
|
|
||||||
FAILED --> DELETED : Administrator wants to\narchive/delete the Audit
|
|
||||||
SUCCEEDED --> DELETED : Administrator wants to\narchive/delete the Audit
|
|
||||||
PENDING --> CANCELLED : Administrator cancels\nthe Audit
|
|
||||||
ONGOING --> CANCELLED : Administrator cancels\nthe Audit
|
|
||||||
CANCELLED --> DELETED : Administrator wants to\narchive/delete the Audit
|
|
||||||
SUSPENDED --> DELETED: Administrator wants to\narchive/delete the Audit
|
|
||||||
DELETED --> [*]
|
|
||||||
|
|
||||||
@enduml
|
|
@ -1,41 +0,0 @@
|
|||||||
@startuml
|
|
||||||
skinparam maxMessageSize 100
|
|
||||||
|
|
||||||
actor "Administrator"
|
|
||||||
|
|
||||||
== Initialization ==
|
|
||||||
|
|
||||||
"Administrator" -> "Decision Engine" : Start all services
|
|
||||||
"Decision Engine" -> "Background Task Scheduler" : Start
|
|
||||||
|
|
||||||
activate "Background Task Scheduler"
|
|
||||||
"Background Task Scheduler" -> "Cluster Model Collector Loader"\
|
|
||||||
: List available cluster data models
|
|
||||||
"Cluster Model Collector Loader" --> "Background Task Scheduler"\
|
|
||||||
: list of BaseClusterModelCollector instances
|
|
||||||
|
|
||||||
loop for every available cluster data model collector
|
|
||||||
"Background Task Scheduler" -> "Background Task Scheduler"\
|
|
||||||
: add periodic synchronization job
|
|
||||||
create "Jobs Pool"
|
|
||||||
"Background Task Scheduler" -> "Jobs Pool" : Create sync job
|
|
||||||
end
|
|
||||||
deactivate "Background Task Scheduler"
|
|
||||||
|
|
||||||
hnote over "Background Task Scheduler" : Idle
|
|
||||||
|
|
||||||
== Job workflow ==
|
|
||||||
|
|
||||||
"Background Task Scheduler" -> "Jobs Pool" : Trigger synchronization job
|
|
||||||
"Jobs Pool" -> "Nova Cluster Data Model Collector" : synchronize
|
|
||||||
|
|
||||||
activate "Nova Cluster Data Model Collector"
|
|
||||||
"Nova Cluster Data Model Collector" -> "Nova API"\
|
|
||||||
: Fetch needed data to build the cluster data model
|
|
||||||
"Nova API" --> "Nova Cluster Data Model Collector" : Needed data
|
|
||||||
"Nova Cluster Data Model Collector" -> "Nova Cluster Data Model Collector"\
|
|
||||||
: Build an in-memory cluster data model
|
|
||||||
]o<-- "Nova Cluster Data Model Collector" : Done
|
|
||||||
deactivate "Nova Cluster Data Model Collector"
|
|
||||||
|
|
||||||
@enduml
|
|
@ -1,24 +0,0 @@
|
|||||||
@startuml
|
|
||||||
|
|
||||||
|
|
||||||
actor Administrator
|
|
||||||
|
|
||||||
Administrator -> "Watcher CLI" : watcher audit create -a <audit_template>
|
|
||||||
|
|
||||||
"Watcher CLI" -> "Watcher API" : POST audit(parameters)
|
|
||||||
"Watcher API" -> "Watcher Database" : create new audit in database (status=PENDING)
|
|
||||||
|
|
||||||
"Watcher API" <-- "Watcher Database" : new audit uuid
|
|
||||||
"Watcher CLI" <-- "Watcher API" : return new audit URL
|
|
||||||
|
|
||||||
Administrator <-- "Watcher CLI" : new audit uuid
|
|
||||||
|
|
||||||
"Watcher API" -> "AMQP Bus" : trigger_audit(new_audit.uuid)
|
|
||||||
"AMQP Bus" -> "Watcher Decision Engine" : trigger_audit(new_audit.uuid) (status=ONGOING)
|
|
||||||
|
|
||||||
ref over "Watcher Decision Engine"
|
|
||||||
Trigger audit in the
|
|
||||||
Watcher Decision Engine
|
|
||||||
end ref
|
|
||||||
|
|
||||||
@enduml
|
|
@ -1,22 +0,0 @@
|
|||||||
@startuml
|
|
||||||
|
|
||||||
actor Administrator
|
|
||||||
|
|
||||||
Administrator -> "Watcher CLI" : watcher audittemplate create <name> <goal> \
|
|
||||||
[--strategy-uuid <strategy>]
|
|
||||||
"Watcher CLI" -> "Watcher API" : POST audit_template(parameters)
|
|
||||||
|
|
||||||
"Watcher API" -> "Watcher Database" : Request if goal exists in database
|
|
||||||
"Watcher API" <-- "Watcher Database" : OK
|
|
||||||
|
|
||||||
"Watcher API" -> "Watcher Database" : Request if strategy exists in database (if provided)
|
|
||||||
"Watcher API" <-- "Watcher Database" : OK
|
|
||||||
|
|
||||||
"Watcher API" -> "Watcher Database" : Create new audit_template in database
|
|
||||||
"Watcher API" <-- "Watcher Database" : New audit template UUID
|
|
||||||
|
|
||||||
"Watcher CLI" <-- "Watcher API" : Return new audit template URL in HTTP Location Header
|
|
||||||
Administrator <-- "Watcher CLI" : New audit template UUID
|
|
||||||
|
|
||||||
@enduml
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
|||||||
@startuml
|
|
||||||
|
|
||||||
skinparam maxMessageSize 200
|
|
||||||
|
|
||||||
"Decision Engine" -> "Decision Engine" : Execute audit
|
|
||||||
activate "Decision Engine"
|
|
||||||
"Decision Engine" -> "Decision Engine" : Set the audit state to ONGOING
|
|
||||||
|
|
||||||
"Decision Engine" -> "Strategy selector" : Select strategy
|
|
||||||
activate "Strategy selector"
|
|
||||||
alt A specific strategy is provided
|
|
||||||
"Strategy selector" -> "Strategy selector" : Load strategy and inject the \
|
|
||||||
cluster data model
|
|
||||||
else Only a goal is specified
|
|
||||||
"Strategy selector" -> "Strategy selector" : select strategy
|
|
||||||
"Strategy selector" -> "Strategy selector" : Load strategy and inject the \
|
|
||||||
cluster data model
|
|
||||||
end
|
|
||||||
"Strategy selector" -> "Decision Engine" : Return loaded Strategy
|
|
||||||
deactivate "Strategy selector"
|
|
||||||
|
|
||||||
"Decision Engine" -> "Strategy" : Execute the strategy
|
|
||||||
activate "Strategy"
|
|
||||||
"Strategy" -> "Strategy" : **pre_execute()**Checks if the strategy \
|
|
||||||
pre-requisites are all set.
|
|
||||||
"Strategy" -> "Strategy" : **do_execute()**Contains the logic of the strategy
|
|
||||||
"Strategy" -> "Strategy" : **post_execute()** Set the efficacy indicators
|
|
||||||
"Strategy" -> "Strategy" : Compute the global efficacy of the solution \
|
|
||||||
based on the provided efficacy indicators
|
|
||||||
"Strategy" -> "Decision Engine" : Return the solution
|
|
||||||
deactivate "Strategy"
|
|
||||||
|
|
||||||
"Decision Engine" -> "Planner" : Plan the solution that was computed by the \
|
|
||||||
strategy
|
|
||||||
activate "Planner"
|
|
||||||
"Planner" -> "Planner" : Store the planned solution as an action plan with its \
|
|
||||||
related actions and efficacy indicators
|
|
||||||
"Planner" --> "Decision Engine" : Done
|
|
||||||
deactivate "Planner"
|
|
||||||
"Decision Engine" -> "Decision Engine" : Update the audit state to SUCCEEDED
|
|
||||||
|
|
||||||
deactivate "Decision Engine"
|
|
||||||
|
|
||||||
@enduml
|
|
@ -1,23 +0,0 @@
|
|||||||
@startuml
|
|
||||||
|
|
||||||
actor Administrator
|
|
||||||
|
|
||||||
Administrator -> "Watcher CLI" : watcher actionplan start <action_plan_uuid>
|
|
||||||
|
|
||||||
"Watcher CLI" -> "Watcher API" : PATCH action_plan(state=PENDING)
|
|
||||||
"Watcher API" -> "Watcher Database" : action_plan.state=PENDING
|
|
||||||
|
|
||||||
"Watcher CLI" <-- "Watcher API" : HTTP 200
|
|
||||||
|
|
||||||
Administrator <-- "Watcher CLI" : OK
|
|
||||||
|
|
||||||
"Watcher API" -> "AMQP Bus" : launch_action_plan(action_plan.uuid)
|
|
||||||
"AMQP Bus" -> "Watcher Applier" : launch_action_plan(action_plan.uuid)
|
|
||||||
|
|
||||||
ref over "Watcher Applier"
|
|
||||||
Launch Action Plan in the
|
|
||||||
Watcher Applier
|
|
||||||
end ref
|
|
||||||
|
|
||||||
@enduml
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
|||||||
@startuml
|
|
||||||
|
|
||||||
"AMQP Bus" -> "Watcher Applier" : launch_action_plan(action_plan.uuid)
|
|
||||||
"Watcher Applier" -> "Watcher Database" : action_plan.state=ONGOING
|
|
||||||
"Watcher Applier" -[#blue]> "AMQP Bus" : notify action plan state = ONGOING
|
|
||||||
"Watcher Applier" -> "Watcher Database" : get_action_list(action_plan.uuid)
|
|
||||||
"Watcher Applier" <-- "Watcher Database" : actions
|
|
||||||
loop for each action of the action flow
|
|
||||||
create Action
|
|
||||||
"Watcher Applier" -> Action : instantiate Action object with target resource id\n and input parameters
|
|
||||||
"Watcher Applier" -> Action : validate_parameters()
|
|
||||||
"Watcher Applier" <-- Action : OK
|
|
||||||
"Watcher Applier" -[#blue]> "AMQP Bus" : notify action state = ONGOING
|
|
||||||
"Watcher Applier" -> Action : preconditions()
|
|
||||||
"Watcher Applier" <-- Action : OK
|
|
||||||
"Watcher Applier" -> Action : execute()
|
|
||||||
alt action is "migrate instance"
|
|
||||||
Action -> "Nova API" : migrate(instance_id, dest_host_id)
|
|
||||||
Action <-- "Nova API" : OK
|
|
||||||
else action is "disable hypervisor"
|
|
||||||
Action -> "Nova API" : host-update(host_id, maintenance=true)
|
|
||||||
Action <-- "Nova API" : OK
|
|
||||||
end
|
|
||||||
"Watcher Applier" <-- Action : OK
|
|
||||||
"Watcher Applier" -> "Watcher Database" : action.state=SUCCEEDED
|
|
||||||
"Watcher Applier" -[#blue]> "AMQP Bus" : notify action state = SUCCEEDED
|
|
||||||
end
|
|
||||||
"Watcher Applier" -> "Watcher Database" : action_plan.state=SUCCEEDED
|
|
||||||
"Watcher Applier" -[#blue]> "AMQP Bus" : notify action plan state = SUCCEEDED
|
|
||||||
|
|
||||||
@enduml
|
|
@ -1,37 +0,0 @@
|
|||||||
@startuml
|
|
||||||
|
|
||||||
actor Administrator
|
|
||||||
|
|
||||||
== Create some Audit settings ==
|
|
||||||
|
|
||||||
Administrator -> Watcher : create new Audit Template (i.e. Audit settings : goal, scope, ...)
|
|
||||||
Watcher -> Watcher : save Audit Template in database
|
|
||||||
Administrator <-- Watcher : Audit Template UUID
|
|
||||||
|
|
||||||
== Launch a new Audit ==
|
|
||||||
|
|
||||||
Administrator -> Watcher : launch new Audit of the Openstack infrastructure resources\nwith a previously created Audit Template
|
|
||||||
Administrator <-- Watcher : Audit UUID
|
|
||||||
Administrator -> Watcher : get the Audit state
|
|
||||||
Administrator <-- Watcher : ONGOING
|
|
||||||
Watcher -> Watcher : compute a solution to achieve optimization goal
|
|
||||||
Administrator -> Watcher : get the Audit state
|
|
||||||
Administrator <-- Watcher : SUCCEEDED
|
|
||||||
|
|
||||||
== Get the result of the Audit ==
|
|
||||||
|
|
||||||
Administrator -> Watcher : get Action Plan
|
|
||||||
Administrator <-- Watcher : recommended Action Plan and estimated efficacy
|
|
||||||
Administrator -> Administrator : verify the recommended actions\nand evaluate the estimated gain vs aggressiveness of the solution
|
|
||||||
|
|
||||||
== Launch the recommended Action Plan ==
|
|
||||||
|
|
||||||
Administrator -> Watcher : launch the Action Plan
|
|
||||||
Administrator <-- Watcher : Action Plan has been launched
|
|
||||||
Watcher -> Watcher : trigger Actions on Openstack services
|
|
||||||
Administrator -> Watcher : get the Action Plan state
|
|
||||||
Administrator <-- Watcher : ONGOING
|
|
||||||
Administrator -> Watcher : get the Action Plan state
|
|
||||||
Administrator <-- Watcher : SUCCEEDED
|
|
||||||
|
|
||||||
@enduml
|
|
@ -1,50 +0,0 @@
|
|||||||
@startuml
|
|
||||||
|
|
||||||
skinparam maxMessageSize 100
|
|
||||||
|
|
||||||
"AMQP Bus" -> "Decision Engine" : trigger audit
|
|
||||||
|
|
||||||
activate "Decision Engine"
|
|
||||||
|
|
||||||
"Decision Engine" -> "Database" : update audit.state = ONGOING
|
|
||||||
"AMQP Bus" <[#blue]- "Decision Engine" : notify new audit state = ONGOING
|
|
||||||
"Decision Engine" -> "Database" : get audit parameters (goal, strategy, ...)
|
|
||||||
"Decision Engine" <-- "Database" : audit parameters (goal, strategy, ...)
|
|
||||||
"Decision Engine" --> "Decision Engine"\
|
|
||||||
: select appropriate optimization strategy (via the Strategy Selector)
|
|
||||||
create Strategy
|
|
||||||
"Decision Engine" -> "Strategy" : execute strategy
|
|
||||||
activate "Strategy"
|
|
||||||
"Strategy" -> "Cluster Data Model Collector" : get cluster data model
|
|
||||||
"Cluster Data Model Collector" --> "Strategy"\
|
|
||||||
: copy of the in-memory cluster data model
|
|
||||||
loop while enough history data for the strategy
|
|
||||||
"Strategy" -> "Ceilometer API" : get necessary metrics
|
|
||||||
"Strategy" <-- "Ceilometer API" : aggregated metrics
|
|
||||||
end
|
|
||||||
"Strategy" -> "Strategy"\
|
|
||||||
: compute/set needed actions for the solution so it achieves its goal
|
|
||||||
"Strategy" -> "Strategy" : compute/set efficacy indicators for the solution
|
|
||||||
"Strategy" -> "Strategy" : compute/set the solution global efficacy
|
|
||||||
"Decision Engine" <-- "Strategy"\
|
|
||||||
: solution (unordered actions, efficacy indicators and global efficacy)
|
|
||||||
deactivate "Strategy"
|
|
||||||
|
|
||||||
create "Planner"
|
|
||||||
"Decision Engine" -> "Planner" : load actions scheduler
|
|
||||||
"Planner" --> "Decision Engine" : planner plugin
|
|
||||||
"Decision Engine" -> "Planner" : schedule actions
|
|
||||||
activate "Planner"
|
|
||||||
"Planner" -> "Planner"\
|
|
||||||
: schedule actions according to scheduling rules/policies
|
|
||||||
"Decision Engine" <-- "Planner" : new action plan
|
|
||||||
deactivate "Planner"
|
|
||||||
"Decision Engine" -> "Database" : save new action plan in database
|
|
||||||
"Decision Engine" -> "Database" : update audit.state = SUCCEEDED
|
|
||||||
"AMQP Bus" <[#blue]- "Decision Engine" : notify new audit state = SUCCEEDED
|
|
||||||
|
|
||||||
deactivate "Decision Engine"
|
|
||||||
|
|
||||||
hnote over "Decision Engine" : Idle
|
|
||||||
|
|
||||||
@enduml
|
|
@ -1,153 +0,0 @@
|
|||||||
@startuml
|
|
||||||
!define table(x) class x << (T,#FFAAAA) >>
|
|
||||||
!define primary_key(x) <u>x</u>
|
|
||||||
!define foreign_key(x) <i><u>x</u></i>
|
|
||||||
hide methods
|
|
||||||
hide stereotypes
|
|
||||||
|
|
||||||
table(goals) {
|
|
||||||
primary_key(id: Integer)
|
|
||||||
uuid : String[36]
|
|
||||||
name : String[63]
|
|
||||||
display_name : String[63]
|
|
||||||
efficacy_specification : JSONEncodedList, nullable
|
|
||||||
|
|
||||||
created_at : DateTime
|
|
||||||
updated_at : DateTime
|
|
||||||
deleted_at : DateTime
|
|
||||||
deleted : Integer
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
table(strategies) {
|
|
||||||
primary_key(id: Integer)
|
|
||||||
foreign_key(goal_id : Integer)
|
|
||||||
uuid : String[36]
|
|
||||||
name : String[63]
|
|
||||||
display_name : String[63]
|
|
||||||
parameters_spec : JSONEncodedDict, nullable
|
|
||||||
|
|
||||||
created_at : DateTime
|
|
||||||
updated_at : DateTime
|
|
||||||
deleted_at : DateTime
|
|
||||||
deleted : Integer
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
table(audit_templates) {
|
|
||||||
primary_key(id: Integer)
|
|
||||||
foreign_key("goal_id : Integer")
|
|
||||||
foreign_key("strategy_id : Integer, nullable")
|
|
||||||
uuid : String[36]
|
|
||||||
name : String[63], nullable
|
|
||||||
description : String[255], nullable
|
|
||||||
scope : JSONEncodedList
|
|
||||||
|
|
||||||
created_at : DateTime
|
|
||||||
updated_at : DateTime
|
|
||||||
deleted_at : DateTime
|
|
||||||
deleted : Integer
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
table(audits) {
|
|
||||||
primary_key(id: Integer)
|
|
||||||
foreign_key("goal_id : Integer")
|
|
||||||
foreign_key("strategy_id : Integer, nullable")
|
|
||||||
uuid : String[36]
|
|
||||||
audit_type : String[20]
|
|
||||||
state : String[20], nullable
|
|
||||||
interval : Integer, nullable
|
|
||||||
parameters : JSONEncodedDict, nullable
|
|
||||||
scope : JSONEncodedList, nullable
|
|
||||||
auto_trigger: Boolean
|
|
||||||
|
|
||||||
created_at : DateTime
|
|
||||||
updated_at : DateTime
|
|
||||||
deleted_at : DateTime
|
|
||||||
deleted : Integer
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
table(action_plans) {
|
|
||||||
primary_key(id: Integer)
|
|
||||||
foreign_key("audit_id : Integer, nullable")
|
|
||||||
foreign_key("strategy_id : Integer")
|
|
||||||
uuid : String[36]
|
|
||||||
state : String[20], nullable
|
|
||||||
global_efficacy : JSONEncodedDict, nullable
|
|
||||||
|
|
||||||
created_at : DateTime
|
|
||||||
updated_at : DateTime
|
|
||||||
deleted_at : DateTime
|
|
||||||
deleted : Integer
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
table(actions) {
|
|
||||||
primary_key(id: Integer)
|
|
||||||
foreign_key("action_plan_id : Integer")
|
|
||||||
uuid : String[36]
|
|
||||||
action_type : String[255]
|
|
||||||
input_parameters : JSONEncodedDict, nullable
|
|
||||||
state : String[20], nullable
|
|
||||||
parents : JSONEncodedList, nullable
|
|
||||||
|
|
||||||
created_at : DateTime
|
|
||||||
updated_at : DateTime
|
|
||||||
deleted_at : DateTime
|
|
||||||
deleted : Integer
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
table(efficacy_indicators) {
|
|
||||||
primary_key(id: Integer)
|
|
||||||
foreign_key("action_plan_id : Integer")
|
|
||||||
uuid : String[36]
|
|
||||||
name : String[63]
|
|
||||||
description : String[255], nullable
|
|
||||||
unit : String[63], nullable
|
|
||||||
value : Numeric
|
|
||||||
|
|
||||||
created_at : DateTime
|
|
||||||
updated_at : DateTime
|
|
||||||
deleted_at : DateTime
|
|
||||||
deleted : Integer
|
|
||||||
}
|
|
||||||
|
|
||||||
table(scoring_engines) {
|
|
||||||
primary_key(id: Integer)
|
|
||||||
uuid : String[36]
|
|
||||||
name : String[63]
|
|
||||||
description : String[255], nullable
|
|
||||||
metainfo : Text, nullable
|
|
||||||
|
|
||||||
created_at : DateTime
|
|
||||||
updated_at : DateTime
|
|
||||||
deleted_at : DateTime
|
|
||||||
deleted : Integer
|
|
||||||
}
|
|
||||||
|
|
||||||
table(service) {
|
|
||||||
primary_key(id: Integer)
|
|
||||||
name: String[255]
|
|
||||||
host: String[255]
|
|
||||||
last_seen_up: DateTime
|
|
||||||
|
|
||||||
created_at : DateTime
|
|
||||||
updated_at : DateTime
|
|
||||||
deleted_at : DateTime
|
|
||||||
deleted : Integer
|
|
||||||
}
|
|
||||||
|
|
||||||
"goals" <.. "strategies" : Foreign Key
|
|
||||||
"goals" <.. "audit_templates" : Foreign Key
|
|
||||||
"strategies" <.. "audit_templates" : Foreign Key
|
|
||||||
"goals" <.. "audits" : Foreign Key
|
|
||||||
"strategies" <.. "audits" : Foreign Key
|
|
||||||
"action_plans" <.. "actions" : Foreign Key
|
|
||||||
"action_plans" <.. "efficacy_indicators" : Foreign Key
|
|
||||||
"strategies" <.. "action_plans" : Foreign Key
|
|
||||||
"audits" <.. "action_plans" : Foreign Key
|
|
||||||
|
|
||||||
@enduml
|
|
Before Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 47 KiB |
@ -1,600 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1146pt" height="548pt" viewBox="0 0 1146 548" version="1.1">
|
|
||||||
<defs>
|
|
||||||
<g>
|
|
||||||
<symbol overflow="visible" id="glyph0-0">
|
|
||||||
<path style="stroke:none;" d="M 0.796875 2.828125 L 0.796875 -11.28125 L 8.796875 -11.28125 L 8.796875 2.828125 Z M 1.703125 1.9375 L 7.90625 1.9375 L 7.90625 -10.390625 L 1.703125 -10.390625 Z M 1.703125 1.9375 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph0-1">
|
|
||||||
<path style="stroke:none;" d="M 8.546875 -2.125 L 3.84375 -2.125 L 3.109375 0 L 0.078125 0 L 4.40625 -11.671875 L 7.984375 -11.671875 L 12.3125 0 L 9.28125 0 Z M 4.59375 -4.296875 L 7.796875 -4.296875 L 6.203125 -8.9375 Z M 4.59375 -4.296875 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph0-2">
|
|
||||||
<path style="stroke:none;" d="M 1.25 -3.40625 L 1.25 -8.75 L 4.0625 -8.75 L 4.0625 -7.875 C 4.0625 -7.40625 4.054688 -6.8125 4.046875 -6.09375 C 4.046875 -5.375 4.046875 -4.894531 4.046875 -4.65625 C 4.046875 -3.957031 4.0625 -3.453125 4.09375 -3.140625 C 4.132812 -2.828125 4.203125 -2.601562 4.296875 -2.46875 C 4.410156 -2.28125 4.554688 -2.132812 4.734375 -2.03125 C 4.921875 -1.9375 5.132812 -1.890625 5.375 -1.890625 C 5.957031 -1.890625 6.414062 -2.113281 6.75 -2.5625 C 7.082031 -3.007812 7.25 -3.632812 7.25 -4.4375 L 7.25 -8.75 L 10.046875 -8.75 L 10.046875 0 L 7.25 0 L 7.25 -1.265625 C 6.832031 -0.753906 6.382812 -0.375 5.90625 -0.125 C 5.4375 0.113281 4.921875 0.234375 4.359375 0.234375 C 3.347656 0.234375 2.578125 -0.078125 2.046875 -0.703125 C 1.515625 -1.328125 1.25 -2.226562 1.25 -3.40625 Z M 1.25 -3.40625 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph0-3">
|
|
||||||
<path style="stroke:none;" d="M 7.296875 -7.46875 L 7.296875 -12.15625 L 10.109375 -12.15625 L 10.109375 0 L 7.296875 0 L 7.296875 -1.265625 C 6.910156 -0.753906 6.484375 -0.375 6.015625 -0.125 C 5.554688 0.113281 5.023438 0.234375 4.421875 0.234375 C 3.335938 0.234375 2.445312 -0.191406 1.75 -1.046875 C 1.0625 -1.910156 0.71875 -3.019531 0.71875 -4.375 C 0.71875 -5.71875 1.0625 -6.816406 1.75 -7.671875 C 2.445312 -8.535156 3.335938 -8.96875 4.421875 -8.96875 C 5.023438 -8.96875 5.554688 -8.84375 6.015625 -8.59375 C 6.484375 -8.351562 6.910156 -7.976562 7.296875 -7.46875 Z M 5.453125 -1.8125 C 6.054688 -1.8125 6.515625 -2.03125 6.828125 -2.46875 C 7.140625 -2.90625 7.296875 -3.539062 7.296875 -4.375 C 7.296875 -5.207031 7.140625 -5.84375 6.828125 -6.28125 C 6.515625 -6.71875 6.054688 -6.9375 5.453125 -6.9375 C 4.859375 -6.9375 4.40625 -6.71875 4.09375 -6.28125 C 3.78125 -5.84375 3.625 -5.207031 3.625 -4.375 C 3.625 -3.539062 3.78125 -2.90625 4.09375 -2.46875 C 4.40625 -2.03125 4.859375 -1.8125 5.453125 -1.8125 Z M 5.453125 -1.8125 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph0-4">
|
|
||||||
<path style="stroke:none;" d="M 1.34375 -8.75 L 4.140625 -8.75 L 4.140625 0 L 1.34375 0 Z M 1.34375 -12.15625 L 4.140625 -12.15625 L 4.140625 -9.875 L 1.34375 -9.875 Z M 1.34375 -12.15625 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph0-5">
|
|
||||||
<path style="stroke:none;" d="M 4.40625 -11.234375 L 4.40625 -8.75 L 7.28125 -8.75 L 7.28125 -6.75 L 4.40625 -6.75 L 4.40625 -3.046875 C 4.40625 -2.640625 4.484375 -2.363281 4.640625 -2.21875 C 4.804688 -2.070312 5.128906 -2 5.609375 -2 L 7.046875 -2 L 7.046875 0 L 4.640625 0 C 3.535156 0 2.753906 -0.226562 2.296875 -0.6875 C 1.835938 -1.15625 1.609375 -1.941406 1.609375 -3.046875 L 1.609375 -6.75 L 0.21875 -6.75 L 0.21875 -8.75 L 1.609375 -8.75 L 1.609375 -11.234375 Z M 4.40625 -11.234375 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph0-6">
|
|
||||||
<path style="stroke:none;" d=""/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph0-7">
|
|
||||||
<path style="stroke:none;" d="M 0.078125 -11.671875 L 10.828125 -11.671875 L 10.828125 -9.390625 L 6.96875 -9.390625 L 6.96875 0 L 3.953125 0 L 3.953125 -9.390625 L 0.078125 -9.390625 Z M 0.078125 -11.671875 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph0-8">
|
|
||||||
<path style="stroke:none;" d="M 10.078125 -4.40625 L 10.078125 -3.609375 L 3.546875 -3.609375 C 3.609375 -2.953125 3.84375 -2.457031 4.25 -2.125 C 4.65625 -1.800781 5.222656 -1.640625 5.953125 -1.640625 C 6.546875 -1.640625 7.148438 -1.722656 7.765625 -1.890625 C 8.378906 -2.066406 9.015625 -2.332031 9.671875 -2.6875 L 9.671875 -0.53125 C 9.003906 -0.28125 8.335938 -0.09375 7.671875 0.03125 C 7.015625 0.164062 6.359375 0.234375 5.703125 0.234375 C 4.117188 0.234375 2.882812 -0.164062 2 -0.96875 C 1.125 -1.78125 0.6875 -2.914062 0.6875 -4.375 C 0.6875 -5.800781 1.117188 -6.921875 1.984375 -7.734375 C 2.847656 -8.554688 4.035156 -8.96875 5.546875 -8.96875 C 6.921875 -8.96875 8.019531 -8.550781 8.84375 -7.71875 C 9.664062 -6.894531 10.078125 -5.789062 10.078125 -4.40625 Z M 7.203125 -5.328125 C 7.203125 -5.859375 7.046875 -6.285156 6.734375 -6.609375 C 6.429688 -6.941406 6.03125 -7.109375 5.53125 -7.109375 C 4.988281 -7.109375 4.546875 -6.953125 4.203125 -6.640625 C 3.867188 -6.335938 3.660156 -5.898438 3.578125 -5.328125 Z M 7.203125 -5.328125 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph0-9">
|
|
||||||
<path style="stroke:none;" d="M 9.453125 -7.296875 C 9.804688 -7.835938 10.226562 -8.25 10.71875 -8.53125 C 11.207031 -8.820312 11.742188 -8.96875 12.328125 -8.96875 C 13.328125 -8.96875 14.085938 -8.65625 14.609375 -8.03125 C 15.140625 -7.414062 15.40625 -6.515625 15.40625 -5.328125 L 15.40625 0 L 12.59375 0 L 12.59375 -4.5625 C 12.601562 -4.632812 12.609375 -4.707031 12.609375 -4.78125 C 12.609375 -4.851562 12.609375 -4.957031 12.609375 -5.09375 C 12.609375 -5.707031 12.515625 -6.15625 12.328125 -6.4375 C 12.148438 -6.71875 11.859375 -6.859375 11.453125 -6.859375 C 10.921875 -6.859375 10.507812 -6.640625 10.21875 -6.203125 C 9.9375 -5.765625 9.789062 -5.128906 9.78125 -4.296875 L 9.78125 0 L 6.96875 0 L 6.96875 -4.5625 C 6.96875 -5.53125 6.882812 -6.15625 6.71875 -6.4375 C 6.550781 -6.71875 6.253906 -6.859375 5.828125 -6.859375 C 5.285156 -6.859375 4.867188 -6.632812 4.578125 -6.1875 C 4.285156 -5.75 4.140625 -5.125 4.140625 -4.3125 L 4.140625 0 L 1.328125 0 L 1.328125 -8.75 L 4.140625 -8.75 L 4.140625 -7.46875 C 4.484375 -7.96875 4.878906 -8.34375 5.328125 -8.59375 C 5.773438 -8.84375 6.265625 -8.96875 6.796875 -8.96875 C 7.398438 -8.96875 7.929688 -8.820312 8.390625 -8.53125 C 8.859375 -8.238281 9.210938 -7.828125 9.453125 -7.296875 Z M 9.453125 -7.296875 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph0-10">
|
|
||||||
<path style="stroke:none;" d="M 4.140625 -1.265625 L 4.140625 3.328125 L 1.34375 3.328125 L 1.34375 -8.75 L 4.140625 -8.75 L 4.140625 -7.46875 C 4.523438 -7.976562 4.953125 -8.351562 5.421875 -8.59375 C 5.890625 -8.84375 6.429688 -8.96875 7.046875 -8.96875 C 8.117188 -8.96875 9 -8.535156 9.6875 -7.671875 C 10.382812 -6.816406 10.734375 -5.71875 10.734375 -4.375 C 10.734375 -3.019531 10.382812 -1.910156 9.6875 -1.046875 C 9 -0.191406 8.117188 0.234375 7.046875 0.234375 C 6.429688 0.234375 5.890625 0.113281 5.421875 -0.125 C 4.953125 -0.375 4.523438 -0.753906 4.140625 -1.265625 Z M 6 -6.9375 C 5.40625 -6.9375 4.945312 -6.710938 4.625 -6.265625 C 4.300781 -5.828125 4.140625 -5.195312 4.140625 -4.375 C 4.140625 -3.539062 4.300781 -2.90625 4.625 -2.46875 C 4.945312 -2.03125 5.40625 -1.8125 6 -1.8125 C 6.601562 -1.8125 7.0625 -2.03125 7.375 -2.46875 C 7.6875 -2.90625 7.84375 -3.539062 7.84375 -4.375 C 7.84375 -5.207031 7.6875 -5.84375 7.375 -6.28125 C 7.0625 -6.71875 6.601562 -6.9375 6 -6.9375 Z M 6 -6.9375 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph0-11">
|
|
||||||
<path style="stroke:none;" d="M 1.34375 -12.15625 L 4.140625 -12.15625 L 4.140625 0 L 1.34375 0 Z M 1.34375 -12.15625 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph0-12">
|
|
||||||
<path style="stroke:none;" d="M 5.265625 -3.9375 C 4.679688 -3.9375 4.242188 -3.835938 3.953125 -3.640625 C 3.660156 -3.441406 3.515625 -3.148438 3.515625 -2.765625 C 3.515625 -2.410156 3.628906 -2.132812 3.859375 -1.9375 C 4.097656 -1.738281 4.429688 -1.640625 4.859375 -1.640625 C 5.378906 -1.640625 5.816406 -1.828125 6.171875 -2.203125 C 6.535156 -2.578125 6.71875 -3.050781 6.71875 -3.625 L 6.71875 -3.9375 Z M 9.546875 -5 L 9.546875 0 L 6.71875 0 L 6.71875 -1.296875 C 6.34375 -0.765625 5.921875 -0.375 5.453125 -0.125 C 4.984375 0.113281 4.414062 0.234375 3.75 0.234375 C 2.84375 0.234375 2.101562 -0.03125 1.53125 -0.5625 C 0.96875 -1.09375 0.6875 -1.78125 0.6875 -2.625 C 0.6875 -3.65625 1.039062 -4.410156 1.75 -4.890625 C 2.457031 -5.367188 3.566406 -5.609375 5.078125 -5.609375 L 6.71875 -5.609375 L 6.71875 -5.828125 C 6.71875 -6.265625 6.539062 -6.585938 6.1875 -6.796875 C 5.84375 -7.003906 5.300781 -7.109375 4.5625 -7.109375 C 3.96875 -7.109375 3.410156 -7.046875 2.890625 -6.921875 C 2.378906 -6.804688 1.898438 -6.628906 1.453125 -6.390625 L 1.453125 -8.515625 C 2.054688 -8.660156 2.660156 -8.769531 3.265625 -8.84375 C 3.867188 -8.925781 4.472656 -8.96875 5.078125 -8.96875 C 6.648438 -8.96875 7.785156 -8.65625 8.484375 -8.03125 C 9.191406 -7.40625 9.546875 -6.394531 9.546875 -5 Z M 9.546875 -5 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph0-13">
|
|
||||||
<path style="stroke:none;" d="M 6.796875 -9.703125 C 5.878906 -9.703125 5.164062 -9.363281 4.65625 -8.6875 C 4.15625 -8.007812 3.90625 -7.054688 3.90625 -5.828125 C 3.90625 -4.597656 4.15625 -3.644531 4.65625 -2.96875 C 5.164062 -2.289062 5.878906 -1.953125 6.796875 -1.953125 C 7.722656 -1.953125 8.4375 -2.289062 8.9375 -2.96875 C 9.445312 -3.644531 9.703125 -4.597656 9.703125 -5.828125 C 9.703125 -7.054688 9.445312 -8.007812 8.9375 -8.6875 C 8.4375 -9.363281 7.722656 -9.703125 6.796875 -9.703125 Z M 6.796875 -11.875 C 8.671875 -11.875 10.140625 -11.335938 11.203125 -10.265625 C 12.265625 -9.191406 12.796875 -7.710938 12.796875 -5.828125 C 12.796875 -3.941406 12.265625 -2.457031 11.203125 -1.375 C 10.140625 -0.300781 8.671875 0.234375 6.796875 0.234375 C 4.929688 0.234375 3.460938 -0.300781 2.390625 -1.375 C 1.328125 -2.457031 0.796875 -3.941406 0.796875 -5.828125 C 0.796875 -7.710938 1.328125 -9.191406 2.390625 -10.265625 C 3.460938 -11.335938 4.929688 -11.875 6.796875 -11.875 Z M 6.796875 -11.875 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph0-14">
|
|
||||||
<path style="stroke:none;" d="M 10.140625 -5.328125 L 10.140625 0 L 7.328125 0 L 7.328125 -4.078125 C 7.328125 -4.835938 7.3125 -5.359375 7.28125 -5.640625 C 7.25 -5.929688 7.191406 -6.144531 7.109375 -6.28125 C 6.992188 -6.457031 6.84375 -6.597656 6.65625 -6.703125 C 6.46875 -6.804688 6.253906 -6.859375 6.015625 -6.859375 C 5.429688 -6.859375 4.972656 -6.628906 4.640625 -6.171875 C 4.304688 -5.722656 4.140625 -5.101562 4.140625 -4.3125 L 4.140625 0 L 1.34375 0 L 1.34375 -8.75 L 4.140625 -8.75 L 4.140625 -7.46875 C 4.566406 -7.976562 5.015625 -8.351562 5.484375 -8.59375 C 5.960938 -8.84375 6.488281 -8.96875 7.0625 -8.96875 C 8.070312 -8.96875 8.835938 -8.65625 9.359375 -8.03125 C 9.878906 -7.414062 10.140625 -6.515625 10.140625 -5.328125 Z M 10.140625 -5.328125 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph0-15">
|
|
||||||
<path style="stroke:none;" d="M 9.59375 -11.296875 L 9.59375 -8.828125 C 8.945312 -9.117188 8.316406 -9.335938 7.703125 -9.484375 C 7.097656 -9.628906 6.523438 -9.703125 5.984375 -9.703125 C 5.265625 -9.703125 4.734375 -9.601562 4.390625 -9.40625 C 4.046875 -9.207031 3.875 -8.898438 3.875 -8.484375 C 3.875 -8.171875 3.988281 -7.925781 4.21875 -7.75 C 4.457031 -7.570312 4.878906 -7.421875 5.484375 -7.296875 L 6.765625 -7.046875 C 8.066406 -6.785156 8.988281 -6.390625 9.53125 -5.859375 C 10.082031 -5.328125 10.359375 -4.570312 10.359375 -3.59375 C 10.359375 -2.300781 9.972656 -1.335938 9.203125 -0.703125 C 8.441406 -0.078125 7.28125 0.234375 5.71875 0.234375 C 4.976562 0.234375 4.234375 0.160156 3.484375 0.015625 C 2.742188 -0.128906 2 -0.335938 1.25 -0.609375 L 1.25 -3.15625 C 2 -2.757812 2.71875 -2.457031 3.40625 -2.25 C 4.101562 -2.050781 4.773438 -1.953125 5.421875 -1.953125 C 6.078125 -1.953125 6.578125 -2.0625 6.921875 -2.28125 C 7.273438 -2.5 7.453125 -2.8125 7.453125 -3.21875 C 7.453125 -3.582031 7.332031 -3.863281 7.09375 -4.0625 C 6.863281 -4.257812 6.394531 -4.4375 5.6875 -4.59375 L 4.515625 -4.859375 C 3.347656 -5.109375 2.492188 -5.503906 1.953125 -6.046875 C 1.421875 -6.597656 1.15625 -7.335938 1.15625 -8.265625 C 1.15625 -9.421875 1.53125 -10.3125 2.28125 -10.9375 C 3.03125 -11.5625 4.109375 -11.875 5.515625 -11.875 C 6.148438 -11.875 6.804688 -11.828125 7.484375 -11.734375 C 8.160156 -11.640625 8.863281 -11.492188 9.59375 -11.296875 Z M 9.59375 -11.296875 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph0-16">
|
|
||||||
<path style="stroke:none;" d="M 8.421875 -8.484375 L 8.421875 -6.203125 C 8.035156 -6.460938 7.648438 -6.65625 7.265625 -6.78125 C 6.890625 -6.90625 6.492188 -6.96875 6.078125 -6.96875 C 5.296875 -6.96875 4.6875 -6.738281 4.25 -6.28125 C 3.820312 -5.820312 3.609375 -5.1875 3.609375 -4.375 C 3.609375 -3.550781 3.820312 -2.910156 4.25 -2.453125 C 4.6875 -2.003906 5.296875 -1.78125 6.078125 -1.78125 C 6.515625 -1.78125 6.929688 -1.84375 7.328125 -1.96875 C 7.722656 -2.101562 8.085938 -2.296875 8.421875 -2.546875 L 8.421875 -0.265625 C 7.984375 -0.0976562 7.535156 0.0234375 7.078125 0.109375 C 6.628906 0.191406 6.179688 0.234375 5.734375 0.234375 C 4.148438 0.234375 2.910156 -0.171875 2.015625 -0.984375 C 1.128906 -1.796875 0.6875 -2.925781 0.6875 -4.375 C 0.6875 -5.8125 1.128906 -6.9375 2.015625 -7.75 C 2.910156 -8.5625 4.148438 -8.96875 5.734375 -8.96875 C 6.191406 -8.96875 6.640625 -8.925781 7.078125 -8.84375 C 7.523438 -8.757812 7.972656 -8.640625 8.421875 -8.484375 Z M 8.421875 -8.484375 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph0-17">
|
|
||||||
<path style="stroke:none;" d="M 1.34375 -12.15625 L 4.140625 -12.15625 L 4.140625 -5.546875 L 7.359375 -8.75 L 10.609375 -8.75 L 6.34375 -4.734375 L 10.953125 0 L 7.5625 0 L 4.140625 -3.65625 L 4.140625 0 L 1.34375 0 Z M 1.34375 -12.15625 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph0-18">
|
|
||||||
<path style="stroke:none;" d="M 10.71875 -0.640625 C 10.164062 -0.359375 9.585938 -0.144531 8.984375 0 C 8.390625 0.15625 7.769531 0.234375 7.125 0.234375 C 5.175781 0.234375 3.632812 -0.304688 2.5 -1.390625 C 1.363281 -2.484375 0.796875 -3.960938 0.796875 -5.828125 C 0.796875 -7.691406 1.363281 -9.164062 2.5 -10.25 C 3.632812 -11.332031 5.175781 -11.875 7.125 -11.875 C 7.769531 -11.875 8.390625 -11.800781 8.984375 -11.65625 C 9.585938 -11.507812 10.164062 -11.296875 10.71875 -11.015625 L 10.71875 -8.59375 C 10.164062 -8.976562 9.617188 -9.257812 9.078125 -9.4375 C 8.535156 -9.613281 7.960938 -9.703125 7.359375 -9.703125 C 6.285156 -9.703125 5.441406 -9.359375 4.828125 -8.671875 C 4.210938 -7.984375 3.90625 -7.035156 3.90625 -5.828125 C 3.90625 -4.617188 4.210938 -3.671875 4.828125 -2.984375 C 5.441406 -2.296875 6.285156 -1.953125 7.359375 -1.953125 C 7.960938 -1.953125 8.535156 -2.039062 9.078125 -2.21875 C 9.617188 -2.394531 10.164062 -2.675781 10.71875 -3.0625 Z M 10.71875 -0.640625 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph0-19">
|
|
||||||
<path style="stroke:none;" d="M 8.1875 -8.484375 L 8.1875 -6.359375 C 7.582031 -6.609375 7 -6.796875 6.4375 -6.921875 C 5.882812 -7.046875 5.363281 -7.109375 4.875 -7.109375 C 4.34375 -7.109375 3.945312 -7.039062 3.6875 -6.90625 C 3.425781 -6.769531 3.296875 -6.566406 3.296875 -6.296875 C 3.296875 -6.066406 3.394531 -5.890625 3.59375 -5.765625 C 3.789062 -5.648438 4.140625 -5.566406 4.640625 -5.515625 L 5.140625 -5.4375 C 6.566406 -5.257812 7.523438 -4.960938 8.015625 -4.546875 C 8.515625 -4.128906 8.765625 -3.472656 8.765625 -2.578125 C 8.765625 -1.648438 8.421875 -0.945312 7.734375 -0.46875 C 7.046875 0 6.019531 0.234375 4.65625 0.234375 C 4.082031 0.234375 3.484375 0.1875 2.859375 0.09375 C 2.242188 0 1.613281 -0.140625 0.96875 -0.328125 L 0.96875 -2.453125 C 1.519531 -2.179688 2.085938 -1.976562 2.671875 -1.84375 C 3.265625 -1.707031 3.863281 -1.640625 4.46875 -1.640625 C 5.007812 -1.640625 5.414062 -1.710938 5.6875 -1.859375 C 5.96875 -2.015625 6.109375 -2.238281 6.109375 -2.53125 C 6.109375 -2.78125 6.015625 -2.96875 5.828125 -3.09375 C 5.640625 -3.21875 5.257812 -3.3125 4.6875 -3.375 L 4.203125 -3.4375 C 2.953125 -3.59375 2.078125 -3.878906 1.578125 -4.296875 C 1.078125 -4.722656 0.828125 -5.367188 0.828125 -6.234375 C 0.828125 -7.160156 1.144531 -7.847656 1.78125 -8.296875 C 2.414062 -8.742188 3.390625 -8.96875 4.703125 -8.96875 C 5.222656 -8.96875 5.765625 -8.925781 6.328125 -8.84375 C 6.898438 -8.769531 7.519531 -8.648438 8.1875 -8.484375 Z M 8.1875 -8.484375 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph0-20">
|
|
||||||
<path style="stroke:none;" d="M 7.84375 -6.375 C 7.601562 -6.488281 7.359375 -6.570312 7.109375 -6.625 C 6.867188 -6.675781 6.628906 -6.703125 6.390625 -6.703125 C 5.671875 -6.703125 5.113281 -6.472656 4.71875 -6.015625 C 4.332031 -5.554688 4.140625 -4.894531 4.140625 -4.03125 L 4.140625 0 L 1.34375 0 L 1.34375 -8.75 L 4.140625 -8.75 L 4.140625 -7.3125 C 4.503906 -7.882812 4.914062 -8.300781 5.375 -8.5625 C 5.84375 -8.832031 6.40625 -8.96875 7.0625 -8.96875 C 7.15625 -8.96875 7.253906 -8.960938 7.359375 -8.953125 C 7.472656 -8.941406 7.632812 -8.925781 7.84375 -8.90625 Z M 7.84375 -6.375 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph0-21">
|
|
||||||
<path style="stroke:none;" d="M 11.953125 -0.875 C 11.203125 -0.507812 10.421875 -0.234375 9.609375 -0.046875 C 8.804688 0.140625 7.976562 0.234375 7.125 0.234375 C 5.175781 0.234375 3.632812 -0.304688 2.5 -1.390625 C 1.363281 -2.484375 0.796875 -3.960938 0.796875 -5.828125 C 0.796875 -7.703125 1.375 -9.175781 2.53125 -10.25 C 3.6875 -11.332031 5.269531 -11.875 7.28125 -11.875 C 8.0625 -11.875 8.804688 -11.800781 9.515625 -11.65625 C 10.222656 -11.507812 10.894531 -11.296875 11.53125 -11.015625 L 11.53125 -8.59375 C 10.875 -8.96875 10.222656 -9.242188 9.578125 -9.421875 C 8.941406 -9.609375 8.300781 -9.703125 7.65625 -9.703125 C 6.457031 -9.703125 5.53125 -9.363281 4.875 -8.6875 C 4.226562 -8.019531 3.90625 -7.066406 3.90625 -5.828125 C 3.90625 -4.585938 4.21875 -3.628906 4.84375 -2.953125 C 5.46875 -2.285156 6.359375 -1.953125 7.515625 -1.953125 C 7.828125 -1.953125 8.113281 -1.972656 8.375 -2.015625 C 8.644531 -2.054688 8.890625 -2.117188 9.109375 -2.203125 L 9.109375 -4.46875 L 7.265625 -4.46875 L 7.265625 -6.484375 L 11.953125 -6.484375 Z M 11.953125 -0.875 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph0-22">
|
|
||||||
<path style="stroke:none;" d="M 5.515625 -6.96875 C 4.890625 -6.96875 4.414062 -6.742188 4.09375 -6.296875 C 3.769531 -5.847656 3.609375 -5.207031 3.609375 -4.375 C 3.609375 -3.53125 3.769531 -2.882812 4.09375 -2.4375 C 4.414062 -2 4.890625 -1.78125 5.515625 -1.78125 C 6.117188 -1.78125 6.582031 -2 6.90625 -2.4375 C 7.226562 -2.882812 7.390625 -3.53125 7.390625 -4.375 C 7.390625 -5.207031 7.226562 -5.847656 6.90625 -6.296875 C 6.582031 -6.742188 6.117188 -6.96875 5.515625 -6.96875 Z M 5.515625 -8.96875 C 7.015625 -8.96875 8.1875 -8.5625 9.03125 -7.75 C 9.882812 -6.9375 10.3125 -5.8125 10.3125 -4.375 C 10.3125 -2.9375 9.882812 -1.804688 9.03125 -0.984375 C 8.1875 -0.171875 7.015625 0.234375 5.515625 0.234375 C 4.003906 0.234375 2.820312 -0.171875 1.96875 -0.984375 C 1.113281 -1.804688 0.6875 -2.9375 0.6875 -4.375 C 0.6875 -5.8125 1.113281 -6.9375 1.96875 -7.75 C 2.820312 -8.5625 4.003906 -8.96875 5.515625 -8.96875 Z M 5.515625 -8.96875 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph0-23">
|
|
||||||
<path style="stroke:none;" d="M 1.46875 -11.671875 L 6.46875 -11.671875 C 7.945312 -11.671875 9.082031 -11.335938 9.875 -10.671875 C 10.675781 -10.015625 11.078125 -9.078125 11.078125 -7.859375 C 11.078125 -6.640625 10.675781 -5.695312 9.875 -5.03125 C 9.082031 -4.375 7.945312 -4.046875 6.46875 -4.046875 L 4.484375 -4.046875 L 4.484375 0 L 1.46875 0 Z M 4.484375 -9.484375 L 4.484375 -6.234375 L 6.140625 -6.234375 C 6.722656 -6.234375 7.171875 -6.375 7.484375 -6.65625 C 7.804688 -6.9375 7.96875 -7.335938 7.96875 -7.859375 C 7.96875 -8.378906 7.804688 -8.78125 7.484375 -9.0625 C 7.171875 -9.34375 6.722656 -9.484375 6.140625 -9.484375 Z M 4.484375 -9.484375 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph0-24">
|
|
||||||
<path style="stroke:none;" d="M 5.75 -6.5 C 6.375 -6.5 6.820312 -6.613281 7.09375 -6.84375 C 7.375 -7.082031 7.515625 -7.46875 7.515625 -8 C 7.515625 -8.53125 7.375 -8.910156 7.09375 -9.140625 C 6.820312 -9.367188 6.375 -9.484375 5.75 -9.484375 L 4.484375 -9.484375 L 4.484375 -6.5 Z M 4.484375 -4.421875 L 4.484375 0 L 1.46875 0 L 1.46875 -11.671875 L 6.0625 -11.671875 C 7.601562 -11.671875 8.726562 -11.410156 9.4375 -10.890625 C 10.15625 -10.378906 10.515625 -9.566406 10.515625 -8.453125 C 10.515625 -7.679688 10.328125 -7.046875 9.953125 -6.546875 C 9.585938 -6.054688 9.03125 -5.691406 8.28125 -5.453125 C 8.6875 -5.359375 9.050781 -5.144531 9.375 -4.8125 C 9.707031 -4.488281 10.039062 -3.988281 10.375 -3.3125 L 12 0 L 8.796875 0 L 7.375 -2.90625 C 7.09375 -3.488281 6.800781 -3.882812 6.5 -4.09375 C 6.207031 -4.3125 5.816406 -4.421875 5.328125 -4.421875 Z M 4.484375 -4.421875 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph0-25">
|
|
||||||
<path style="stroke:none;" d="M 7.296875 -1.484375 C 6.910156 -0.972656 6.484375 -0.597656 6.015625 -0.359375 C 5.554688 -0.117188 5.023438 0 4.421875 0 C 3.347656 0 2.460938 -0.421875 1.765625 -1.265625 C 1.066406 -2.109375 0.71875 -3.179688 0.71875 -4.484375 C 0.71875 -5.785156 1.066406 -6.851562 1.765625 -7.6875 C 2.460938 -8.53125 3.347656 -8.953125 4.421875 -8.953125 C 5.023438 -8.953125 5.554688 -8.832031 6.015625 -8.59375 C 6.484375 -8.351562 6.910156 -7.972656 7.296875 -7.453125 L 7.296875 -8.75 L 10.109375 -8.75 L 10.109375 -0.890625 C 10.109375 0.523438 9.664062 1.601562 8.78125 2.34375 C 7.894531 3.082031 6.609375 3.453125 4.921875 3.453125 C 4.367188 3.453125 3.835938 3.410156 3.328125 3.328125 C 2.816406 3.242188 2.304688 3.117188 1.796875 2.953125 L 1.796875 0.765625 C 2.285156 1.046875 2.765625 1.253906 3.234375 1.390625 C 3.703125 1.535156 4.171875 1.609375 4.640625 1.609375 C 5.554688 1.609375 6.226562 1.40625 6.65625 1 C 7.082031 0.601562 7.296875 -0.0234375 7.296875 -0.890625 Z M 5.453125 -6.9375 C 4.878906 -6.9375 4.429688 -6.722656 4.109375 -6.296875 C 3.785156 -5.867188 3.625 -5.265625 3.625 -4.484375 C 3.625 -3.679688 3.78125 -3.070312 4.09375 -2.65625 C 4.40625 -2.238281 4.859375 -2.03125 5.453125 -2.03125 C 6.035156 -2.03125 6.488281 -2.242188 6.8125 -2.671875 C 7.132812 -3.097656 7.296875 -3.703125 7.296875 -4.484375 C 7.296875 -5.265625 7.132812 -5.867188 6.8125 -6.296875 C 6.488281 -6.722656 6.035156 -6.9375 5.453125 -6.9375 Z M 5.453125 -6.9375 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph0-26">
|
|
||||||
<path style="stroke:none;" d="M 0.203125 -8.75 L 3 -8.75 L 5.34375 -2.8125 L 7.34375 -8.75 L 10.140625 -8.75 L 6.46875 0.828125 C 6.09375 1.804688 5.660156 2.488281 5.171875 2.875 C 4.679688 3.257812 4.03125 3.453125 3.21875 3.453125 L 1.609375 3.453125 L 1.609375 1.625 L 2.484375 1.625 C 2.953125 1.625 3.296875 1.546875 3.515625 1.390625 C 3.734375 1.242188 3.898438 0.972656 4.015625 0.578125 L 4.09375 0.34375 Z M 0.203125 -8.75 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph0-27">
|
|
||||||
<path style="stroke:none;" d="M 1.46875 -11.671875 L 9.59375 -11.671875 L 9.59375 -9.390625 L 4.484375 -9.390625 L 4.484375 -7.21875 L 9.28125 -7.21875 L 9.28125 -4.953125 L 4.484375 -4.953125 L 4.484375 -2.28125 L 9.765625 -2.28125 L 9.765625 0 L 1.46875 0 Z M 1.46875 -11.671875 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph0-28">
|
|
||||||
<path style="stroke:none;" d="M 7.109375 -12.15625 L 7.109375 -10.328125 L 5.5625 -10.328125 C 5.164062 -10.328125 4.890625 -10.253906 4.734375 -10.109375 C 4.578125 -9.960938 4.5 -9.710938 4.5 -9.359375 L 4.5 -8.75 L 7.703125 -8.75 L 7.703125 -9.359375 C 7.703125 -10.316406 7.96875 -11.019531 8.5 -11.46875 C 9.03125 -11.925781 9.851562 -12.15625 10.96875 -12.15625 L 13.109375 -12.15625 L 13.109375 -10.328125 L 11.5625 -10.328125 C 11.164062 -10.328125 10.894531 -10.253906 10.75 -10.109375 C 10.59375 -9.960938 10.515625 -9.710938 10.515625 -9.359375 L 10.515625 -8.75 L 16.5 -8.75 L 16.5 0 L 13.6875 0 L 13.6875 -6.75 L 10.515625 -6.75 L 10.515625 0 L 7.703125 0 L 7.703125 -6.75 L 4.5 -6.75 L 4.5 0 L 1.703125 0 L 1.703125 -6.75 L 0.3125 -6.75 L 0.3125 -8.75 L 1.703125 -8.75 L 1.703125 -9.359375 C 1.703125 -10.316406 1.96875 -11.019531 2.5 -11.46875 C 3.03125 -11.925781 3.851562 -12.15625 4.96875 -12.15625 Z M 13.6875 -12.15625 L 16.5 -12.15625 L 16.5 -9.875 L 13.6875 -9.875 Z M 13.6875 -12.15625 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph0-29">
|
|
||||||
<path style="stroke:none;" d="M 1.46875 -11.671875 L 4.484375 -11.671875 L 4.484375 0 L 1.46875 0 Z M 1.46875 -11.671875 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph1-0">
|
|
||||||
<path style="stroke:none;" d="M 0.65625 2.296875 L 0.65625 -9.171875 L 7.15625 -9.171875 L 7.15625 2.296875 Z M 1.390625 1.578125 L 6.4375 1.578125 L 6.4375 -8.4375 L 1.390625 -8.4375 Z M 1.390625 1.578125 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph1-1">
|
|
||||||
<path style="stroke:none;" d="M 3.90625 -8.34375 L 2.5625 -3.5 L 5.265625 -3.5 Z M 3.140625 -9.484375 L 4.6875 -9.484375 L 7.59375 0 L 6.265625 0 L 5.5625 -2.46875 L 2.25 -2.46875 L 1.5625 0 L 0.234375 0 Z M 3.140625 -9.484375 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph1-2">
|
|
||||||
<path style="stroke:none;" d="M 2.375 -0.890625 L 2.375 2.703125 L 1.203125 2.703125 L 1.203125 -7.109375 L 2.375 -7.109375 L 2.375 -6.203125 C 2.570312 -6.554688 2.832031 -6.820312 3.15625 -7 C 3.476562 -7.1875 3.851562 -7.28125 4.28125 -7.28125 C 5.132812 -7.28125 5.804688 -6.945312 6.296875 -6.28125 C 6.785156 -5.613281 7.03125 -4.691406 7.03125 -3.515625 C 7.03125 -2.367188 6.785156 -1.460938 6.296875 -0.796875 C 5.804688 -0.140625 5.132812 0.1875 4.28125 0.1875 C 3.84375 0.1875 3.460938 0.09375 3.140625 -0.09375 C 2.816406 -0.28125 2.5625 -0.546875 2.375 -0.890625 Z M 5.8125 -3.546875 C 5.8125 -4.453125 5.664062 -5.132812 5.375 -5.59375 C 5.09375 -6.0625 4.671875 -6.296875 4.109375 -6.296875 C 3.535156 -6.296875 3.101562 -6.0625 2.8125 -5.59375 C 2.519531 -5.132812 2.375 -4.453125 2.375 -3.546875 C 2.375 -2.648438 2.519531 -1.96875 2.8125 -1.5 C 3.101562 -1.039062 3.535156 -0.8125 4.109375 -0.8125 C 4.671875 -0.8125 5.09375 -1.039062 5.375 -1.5 C 5.664062 -1.957031 5.8125 -2.640625 5.8125 -3.546875 Z M 5.8125 -3.546875 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph1-3">
|
|
||||||
<path style="stroke:none;" d="M 4.0625 -2.578125 C 4.0625 -2.054688 4.15625 -1.660156 4.34375 -1.390625 C 4.539062 -1.117188 4.828125 -0.984375 5.203125 -0.984375 L 6.5625 -0.984375 L 6.5625 0 L 5.078125 0 C 4.378906 0 3.835938 -0.222656 3.453125 -0.671875 C 3.078125 -1.117188 2.890625 -1.753906 2.890625 -2.578125 L 2.890625 -9.03125 L 1.015625 -9.03125 L 1.015625 -9.953125 L 4.0625 -9.953125 Z M 4.0625 -2.578125 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph1-4">
|
|
||||||
<path style="stroke:none;" d="M 1.625 -7.109375 L 4.609375 -7.109375 L 4.609375 -0.90625 L 6.9375 -0.90625 L 6.9375 0 L 1.125 0 L 1.125 -0.90625 L 3.453125 -0.90625 L 3.453125 -6.203125 L 1.625 -6.203125 Z M 3.453125 -9.875 L 4.609375 -9.875 L 4.609375 -8.390625 L 3.453125 -8.390625 Z M 3.453125 -9.875 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph1-5">
|
|
||||||
<path style="stroke:none;" d="M 7.0625 -3.84375 L 7.0625 -3.28125 L 2 -3.28125 L 2 -3.234375 C 2 -2.460938 2.203125 -1.863281 2.609375 -1.4375 C 3.015625 -1.019531 3.582031 -0.8125 4.3125 -0.8125 C 4.6875 -0.8125 5.078125 -0.867188 5.484375 -0.984375 C 5.890625 -1.097656 6.320312 -1.28125 6.78125 -1.53125 L 6.78125 -0.359375 C 6.34375 -0.179688 5.914062 -0.046875 5.5 0.046875 C 5.082031 0.140625 4.679688 0.1875 4.296875 0.1875 C 3.191406 0.1875 2.328125 -0.140625 1.703125 -0.796875 C 1.085938 -1.460938 0.78125 -2.378906 0.78125 -3.546875 C 0.78125 -4.679688 1.082031 -5.585938 1.6875 -6.265625 C 2.300781 -6.941406 3.113281 -7.28125 4.125 -7.28125 C 5.03125 -7.28125 5.742188 -6.972656 6.265625 -6.359375 C 6.796875 -5.742188 7.0625 -4.90625 7.0625 -3.84375 Z M 5.890625 -4.1875 C 5.867188 -4.875 5.703125 -5.394531 5.390625 -5.75 C 5.085938 -6.113281 4.648438 -6.296875 4.078125 -6.296875 C 3.515625 -6.296875 3.050781 -6.109375 2.6875 -5.734375 C 2.320312 -5.359375 2.109375 -4.84375 2.046875 -4.1875 Z M 5.890625 -4.1875 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph1-6">
|
|
||||||
<path style="stroke:none;" d="M 6.171875 -6.859375 L 6.171875 -5.71875 C 5.835938 -5.914062 5.5 -6.0625 5.15625 -6.15625 C 4.820312 -6.25 4.476562 -6.296875 4.125 -6.296875 C 3.601562 -6.296875 3.210938 -6.210938 2.953125 -6.046875 C 2.691406 -5.878906 2.5625 -5.617188 2.5625 -5.265625 C 2.5625 -4.941406 2.65625 -4.703125 2.84375 -4.546875 C 3.039062 -4.390625 3.523438 -4.238281 4.296875 -4.09375 L 4.78125 -4 C 5.351562 -3.894531 5.785156 -3.675781 6.078125 -3.34375 C 6.378906 -3.007812 6.53125 -2.582031 6.53125 -2.0625 C 6.53125 -1.351562 6.28125 -0.800781 5.78125 -0.40625 C 5.289062 -0.0078125 4.597656 0.1875 3.703125 0.1875 C 3.359375 0.1875 2.992188 0.148438 2.609375 0.078125 C 2.222656 0.00390625 1.804688 -0.109375 1.359375 -0.265625 L 1.359375 -1.46875 C 1.785156 -1.238281 2.195312 -1.066406 2.59375 -0.953125 C 3 -0.847656 3.378906 -0.796875 3.734375 -0.796875 C 4.242188 -0.796875 4.640625 -0.898438 4.921875 -1.109375 C 5.210938 -1.316406 5.359375 -1.609375 5.359375 -1.984375 C 5.359375 -2.523438 4.835938 -2.898438 3.796875 -3.109375 L 3.75 -3.125 L 3.3125 -3.21875 C 2.632812 -3.34375 2.140625 -3.5625 1.828125 -3.875 C 1.523438 -4.1875 1.375 -4.609375 1.375 -5.140625 C 1.375 -5.828125 1.601562 -6.351562 2.0625 -6.71875 C 2.53125 -7.09375 3.191406 -7.28125 4.046875 -7.28125 C 4.421875 -7.28125 4.785156 -7.242188 5.140625 -7.171875 C 5.492188 -7.109375 5.835938 -7.003906 6.171875 -6.859375 Z M 6.171875 -6.859375 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph1-7">
|
|
||||||
<path style="stroke:none;" d=""/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph1-8">
|
|
||||||
<path style="stroke:none;" d="M 3.890625 -9.125 L 3.890625 -7.109375 L 6.546875 -7.109375 L 6.546875 -6.203125 L 3.890625 -6.203125 L 3.890625 -2.34375 C 3.890625 -1.820312 3.988281 -1.457031 4.1875 -1.25 C 4.394531 -1.039062 4.742188 -0.9375 5.234375 -0.9375 L 6.546875 -0.9375 L 6.546875 0 L 5.125 0 C 4.25 0 3.628906 -0.171875 3.265625 -0.515625 C 2.910156 -0.867188 2.734375 -1.476562 2.734375 -2.34375 L 2.734375 -6.203125 L 0.828125 -6.203125 L 0.828125 -7.109375 L 2.734375 -7.109375 L 2.734375 -9.125 Z M 3.890625 -9.125 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph1-9">
|
|
||||||
<path style="stroke:none;" d="M 3.90625 -6.296875 C 3.3125 -6.296875 2.863281 -6.0625 2.5625 -5.59375 C 2.257812 -5.132812 2.109375 -4.453125 2.109375 -3.546875 C 2.109375 -2.648438 2.257812 -1.96875 2.5625 -1.5 C 2.863281 -1.039062 3.3125 -0.8125 3.90625 -0.8125 C 4.507812 -0.8125 4.960938 -1.039062 5.265625 -1.5 C 5.566406 -1.96875 5.71875 -2.648438 5.71875 -3.546875 C 5.71875 -4.453125 5.566406 -5.132812 5.265625 -5.59375 C 4.960938 -6.0625 4.507812 -6.296875 3.90625 -6.296875 Z M 3.90625 -7.28125 C 4.894531 -7.28125 5.648438 -6.957031 6.171875 -6.3125 C 6.691406 -5.675781 6.953125 -4.753906 6.953125 -3.546875 C 6.953125 -2.335938 6.691406 -1.410156 6.171875 -0.765625 C 5.648438 -0.128906 4.894531 0.1875 3.90625 0.1875 C 2.925781 0.1875 2.175781 -0.128906 1.65625 -0.765625 C 1.132812 -1.410156 0.875 -2.335938 0.875 -3.546875 C 0.875 -4.753906 1.132812 -5.675781 1.65625 -6.3125 C 2.175781 -6.957031 2.925781 -7.28125 3.90625 -7.28125 Z M 3.90625 -7.28125 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph1-10">
|
|
||||||
<path style="stroke:none;" d="M 5.453125 -3.609375 C 5.453125 -4.484375 5.304688 -5.148438 5.015625 -5.609375 C 4.734375 -6.066406 4.316406 -6.296875 3.765625 -6.296875 C 3.191406 -6.296875 2.753906 -6.066406 2.453125 -5.609375 C 2.160156 -5.148438 2.015625 -4.484375 2.015625 -3.609375 C 2.015625 -2.734375 2.164062 -2.066406 2.46875 -1.609375 C 2.769531 -1.148438 3.207031 -0.921875 3.78125 -0.921875 C 4.320312 -0.921875 4.734375 -1.148438 5.015625 -1.609375 C 5.304688 -2.066406 5.453125 -2.734375 5.453125 -3.609375 Z M 6.609375 -0.453125 C 6.609375 0.609375 6.359375 1.414062 5.859375 1.96875 C 5.359375 2.519531 4.617188 2.796875 3.640625 2.796875 C 3.316406 2.796875 2.976562 2.765625 2.625 2.703125 C 2.269531 2.640625 1.921875 2.550781 1.578125 2.4375 L 1.578125 1.28125 C 1.992188 1.476562 2.367188 1.625 2.703125 1.71875 C 3.046875 1.8125 3.359375 1.859375 3.640625 1.859375 C 4.265625 1.859375 4.722656 1.6875 5.015625 1.34375 C 5.304688 1 5.453125 0.457031 5.453125 -0.28125 L 5.453125 -1.125 C 5.265625 -0.726562 5.007812 -0.429688 4.6875 -0.234375 C 4.363281 -0.046875 3.972656 0.046875 3.515625 0.046875 C 2.679688 0.046875 2.015625 -0.28125 1.515625 -0.9375 C 1.023438 -1.601562 0.78125 -2.492188 0.78125 -3.609375 C 0.78125 -4.722656 1.023438 -5.613281 1.515625 -6.28125 C 2.015625 -6.945312 2.679688 -7.28125 3.515625 -7.28125 C 3.972656 -7.28125 4.359375 -7.1875 4.671875 -7 C 4.984375 -6.820312 5.242188 -6.539062 5.453125 -6.15625 L 5.453125 -7.078125 L 6.609375 -7.078125 Z M 6.609375 -0.453125 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph1-11">
|
|
||||||
<path style="stroke:none;" d="M 6.734375 -0.359375 C 6.421875 -0.179688 6.097656 -0.046875 5.765625 0.046875 C 5.429688 0.140625 5.09375 0.1875 4.75 0.1875 C 3.644531 0.1875 2.78125 -0.140625 2.15625 -0.796875 C 1.539062 -1.460938 1.234375 -2.378906 1.234375 -3.546875 C 1.234375 -4.710938 1.539062 -5.625 2.15625 -6.28125 C 2.78125 -6.945312 3.644531 -7.28125 4.75 -7.28125 C 5.09375 -7.28125 5.425781 -7.234375 5.75 -7.140625 C 6.070312 -7.054688 6.398438 -6.921875 6.734375 -6.734375 L 6.734375 -5.515625 C 6.421875 -5.785156 6.109375 -5.984375 5.796875 -6.109375 C 5.492188 -6.234375 5.144531 -6.296875 4.75 -6.296875 C 4.019531 -6.296875 3.457031 -6.054688 3.0625 -5.578125 C 2.664062 -5.109375 2.46875 -4.429688 2.46875 -3.546875 C 2.46875 -2.671875 2.664062 -1.992188 3.0625 -1.515625 C 3.457031 -1.046875 4.019531 -0.8125 4.75 -0.8125 C 5.15625 -0.8125 5.519531 -0.875 5.84375 -1 C 6.164062 -1.125 6.460938 -1.316406 6.734375 -1.578125 Z M 6.734375 -0.359375 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph1-12">
|
|
||||||
<path style="stroke:none;" d="M 6.671875 -4.40625 L 6.671875 0 L 5.5 0 L 5.5 -4.40625 C 5.5 -5.039062 5.382812 -5.507812 5.15625 -5.8125 C 4.9375 -6.113281 4.585938 -6.265625 4.109375 -6.265625 C 3.554688 -6.265625 3.132812 -6.070312 2.84375 -5.6875 C 2.550781 -5.300781 2.40625 -4.742188 2.40625 -4.015625 L 2.40625 0 L 1.234375 0 L 1.234375 -7.109375 L 2.40625 -7.109375 L 2.40625 -6.046875 C 2.613281 -6.453125 2.894531 -6.757812 3.25 -6.96875 C 3.601562 -7.175781 4.023438 -7.28125 4.515625 -7.28125 C 5.234375 -7.28125 5.769531 -7.039062 6.125 -6.5625 C 6.488281 -6.09375 6.671875 -5.375 6.671875 -4.40625 Z M 6.671875 -4.40625 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph1-13">
|
|
||||||
<path style="stroke:none;" d="M 6.75 -9.875 L 6.75 -8.90625 L 5.421875 -8.90625 C 5.003906 -8.90625 4.710938 -8.816406 4.546875 -8.640625 C 4.378906 -8.472656 4.296875 -8.171875 4.296875 -7.734375 L 4.296875 -7.109375 L 6.75 -7.109375 L 6.75 -6.203125 L 4.296875 -6.203125 L 4.296875 0 L 3.140625 0 L 3.140625 -6.203125 L 1.234375 -6.203125 L 1.234375 -7.109375 L 3.140625 -7.109375 L 3.140625 -7.609375 C 3.140625 -8.378906 3.316406 -8.945312 3.671875 -9.3125 C 4.023438 -9.6875 4.582031 -9.875 5.34375 -9.875 Z M 6.75 -9.875 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph1-14">
|
|
||||||
<path style="stroke:none;" d="M 1.234375 -2.6875 L 1.234375 -7.09375 L 2.40625 -7.09375 L 2.40625 -2.6875 C 2.40625 -2.050781 2.515625 -1.582031 2.734375 -1.28125 C 2.960938 -0.976562 3.316406 -0.828125 3.796875 -0.828125 C 4.347656 -0.828125 4.769531 -1.019531 5.0625 -1.40625 C 5.351562 -1.800781 5.5 -2.359375 5.5 -3.078125 L 5.5 -7.09375 L 6.671875 -7.09375 L 6.671875 0 L 5.5 0 L 5.5 -1.0625 C 5.289062 -0.65625 5.003906 -0.34375 4.640625 -0.125 C 4.285156 0.0820312 3.867188 0.1875 3.390625 0.1875 C 2.660156 0.1875 2.117188 -0.0507812 1.765625 -0.53125 C 1.410156 -1.007812 1.234375 -1.726562 1.234375 -2.6875 Z M 1.234375 -2.6875 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph1-15">
|
|
||||||
<path style="stroke:none;" d="M 7.328125 -5.640625 C 7.078125 -5.835938 6.820312 -5.976562 6.5625 -6.0625 C 6.3125 -6.15625 6.03125 -6.203125 5.71875 -6.203125 C 4.988281 -6.203125 4.429688 -5.972656 4.046875 -5.515625 C 3.660156 -5.054688 3.46875 -4.394531 3.46875 -3.53125 L 3.46875 0 L 2.296875 0 L 2.296875 -7.109375 L 3.46875 -7.109375 L 3.46875 -5.71875 C 3.664062 -6.21875 3.96875 -6.601562 4.375 -6.875 C 4.78125 -7.144531 5.257812 -7.28125 5.8125 -7.28125 C 6.09375 -7.28125 6.359375 -7.242188 6.609375 -7.171875 C 6.859375 -7.097656 7.097656 -6.988281 7.328125 -6.84375 Z M 7.328125 -5.640625 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph1-16">
|
|
||||||
<path style="stroke:none;" d="M 4.453125 -3.578125 L 4.0625 -3.578125 C 3.382812 -3.578125 2.875 -3.457031 2.53125 -3.21875 C 2.1875 -2.976562 2.015625 -2.617188 2.015625 -2.140625 C 2.015625 -1.710938 2.140625 -1.378906 2.390625 -1.140625 C 2.648438 -0.910156 3.007812 -0.796875 3.46875 -0.796875 C 4.113281 -0.796875 4.617188 -1.019531 4.984375 -1.46875 C 5.359375 -1.914062 5.546875 -2.53125 5.546875 -3.3125 L 5.546875 -3.578125 Z M 6.71875 -4.0625 L 6.71875 0 L 5.546875 0 L 5.546875 -1.046875 C 5.296875 -0.628906 4.976562 -0.316406 4.59375 -0.109375 C 4.21875 0.0859375 3.757812 0.1875 3.21875 0.1875 C 2.5 0.1875 1.921875 -0.015625 1.484375 -0.421875 C 1.054688 -0.835938 0.84375 -1.382812 0.84375 -2.0625 C 0.84375 -2.851562 1.109375 -3.453125 1.640625 -3.859375 C 2.171875 -4.273438 2.953125 -4.484375 3.984375 -4.484375 L 5.546875 -4.484375 L 5.546875 -4.671875 C 5.546875 -5.234375 5.398438 -5.644531 5.109375 -5.90625 C 4.828125 -6.164062 4.378906 -6.296875 3.765625 -6.296875 C 3.359375 -6.296875 2.953125 -6.238281 2.546875 -6.125 C 2.140625 -6.007812 1.742188 -5.84375 1.359375 -5.625 L 1.359375 -6.78125 C 1.796875 -6.945312 2.210938 -7.070312 2.609375 -7.15625 C 3.003906 -7.238281 3.390625 -7.28125 3.765625 -7.28125 C 4.347656 -7.28125 4.847656 -7.191406 5.265625 -7.015625 C 5.679688 -6.847656 6.019531 -6.585938 6.28125 -6.234375 C 6.4375 -6.023438 6.546875 -5.765625 6.609375 -5.453125 C 6.679688 -5.140625 6.71875 -4.675781 6.71875 -4.0625 Z M 6.71875 -4.0625 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph1-17">
|
|
||||||
<path style="stroke:none;" d="M 4.296875 -6.390625 C 4.429688 -6.691406 4.609375 -6.914062 4.828125 -7.0625 C 5.054688 -7.207031 5.328125 -7.28125 5.640625 -7.28125 C 6.210938 -7.28125 6.613281 -7.054688 6.84375 -6.609375 C 7.082031 -6.171875 7.203125 -5.34375 7.203125 -4.125 L 7.203125 0 L 6.140625 0 L 6.140625 -4.0625 C 6.140625 -5.070312 6.082031 -5.695312 5.96875 -5.9375 C 5.851562 -6.175781 5.648438 -6.296875 5.359375 -6.296875 C 5.015625 -6.296875 4.78125 -6.164062 4.65625 -5.90625 C 4.53125 -5.644531 4.46875 -5.03125 4.46875 -4.0625 L 4.46875 0 L 3.40625 0 L 3.40625 -4.0625 C 3.40625 -5.082031 3.34375 -5.707031 3.21875 -5.9375 C 3.101562 -6.175781 2.890625 -6.296875 2.578125 -6.296875 C 2.265625 -6.296875 2.046875 -6.164062 1.921875 -5.90625 C 1.804688 -5.644531 1.75 -5.03125 1.75 -4.0625 L 1.75 0 L 0.6875 0 L 0.6875 -7.109375 L 1.75 -7.109375 L 1.75 -6.5 C 1.894531 -6.75 2.070312 -6.941406 2.28125 -7.078125 C 2.488281 -7.210938 2.722656 -7.28125 2.984375 -7.28125 C 3.304688 -7.28125 3.570312 -7.207031 3.78125 -7.0625 C 4 -6.914062 4.171875 -6.691406 4.296875 -6.390625 Z M 4.296875 -6.390625 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph1-18">
|
|
||||||
<path style="stroke:none;" d="M 6.671875 -4.40625 L 6.671875 0 L 5.5 0 L 5.5 -4.40625 C 5.5 -5.039062 5.382812 -5.507812 5.15625 -5.8125 C 4.9375 -6.113281 4.585938 -6.265625 4.109375 -6.265625 C 3.554688 -6.265625 3.132812 -6.070312 2.84375 -5.6875 C 2.550781 -5.300781 2.40625 -4.742188 2.40625 -4.015625 L 2.40625 0 L 1.234375 0 L 1.234375 -9.875 L 2.40625 -9.875 L 2.40625 -6.046875 C 2.613281 -6.453125 2.894531 -6.757812 3.25 -6.96875 C 3.601562 -7.175781 4.023438 -7.28125 4.515625 -7.28125 C 5.234375 -7.28125 5.769531 -7.039062 6.125 -6.5625 C 6.488281 -6.09375 6.671875 -5.375 6.671875 -4.40625 Z M 6.671875 -4.40625 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph1-19">
|
|
||||||
<path style="stroke:none;" d="M 0.640625 -7.109375 L 1.84375 -7.109375 L 3.90625 -1.140625 L 5.984375 -7.109375 L 7.1875 -7.109375 L 4.671875 0 L 3.15625 0 Z M 0.640625 -7.109375 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph1-20">
|
|
||||||
<path style="stroke:none;" d="M 7.015625 -0.78125 C 6.671875 -0.46875 6.28125 -0.226562 5.84375 -0.0625 C 5.414062 0.101562 4.953125 0.1875 4.453125 0.1875 C 3.253906 0.1875 2.316406 -0.242188 1.640625 -1.109375 C 0.972656 -1.972656 0.640625 -3.179688 0.640625 -4.734375 C 0.640625 -6.273438 0.976562 -7.476562 1.65625 -8.34375 C 2.332031 -9.21875 3.273438 -9.65625 4.484375 -9.65625 C 4.878906 -9.65625 5.257812 -9.597656 5.625 -9.484375 C 5.988281 -9.367188 6.34375 -9.195312 6.6875 -8.96875 L 6.6875 -7.65625 C 6.34375 -7.976562 5.988281 -8.21875 5.625 -8.375 C 5.269531 -8.53125 4.890625 -8.609375 4.484375 -8.609375 C 3.648438 -8.609375 3.023438 -8.285156 2.609375 -7.640625 C 2.191406 -6.992188 1.984375 -6.023438 1.984375 -4.734375 C 1.984375 -3.410156 2.1875 -2.429688 2.59375 -1.796875 C 3 -1.171875 3.617188 -0.859375 4.453125 -0.859375 C 4.734375 -0.859375 4.976562 -0.890625 5.1875 -0.953125 C 5.40625 -1.015625 5.601562 -1.117188 5.78125 -1.265625 L 5.78125 -3.8125 L 4.40625 -3.8125 L 4.40625 -4.859375 L 7.015625 -4.859375 Z M 7.015625 -0.78125 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph1-21">
|
|
||||||
<path style="stroke:none;" d="M 5.453125 -6.203125 L 5.453125 -9.875 L 6.609375 -9.875 L 6.609375 0 L 5.453125 0 L 5.453125 -0.890625 C 5.253906 -0.546875 4.992188 -0.28125 4.671875 -0.09375 C 4.347656 0.09375 3.972656 0.1875 3.546875 0.1875 C 2.691406 0.1875 2.015625 -0.144531 1.515625 -0.8125 C 1.023438 -1.476562 0.78125 -2.398438 0.78125 -3.578125 C 0.78125 -4.734375 1.023438 -5.640625 1.515625 -6.296875 C 2.015625 -6.953125 2.691406 -7.28125 3.546875 -7.28125 C 3.972656 -7.28125 4.347656 -7.1875 4.671875 -7 C 5.003906 -6.820312 5.265625 -6.554688 5.453125 -6.203125 Z M 2.015625 -3.546875 C 2.015625 -2.640625 2.15625 -1.957031 2.4375 -1.5 C 2.726562 -1.039062 3.15625 -0.8125 3.71875 -0.8125 C 4.28125 -0.8125 4.707031 -1.039062 5 -1.5 C 5.300781 -1.96875 5.453125 -2.648438 5.453125 -3.546875 C 5.453125 -4.453125 5.300781 -5.132812 5 -5.59375 C 4.707031 -6.0625 4.28125 -6.296875 3.71875 -6.296875 C 3.15625 -6.296875 2.726562 -6.0625 2.4375 -5.59375 C 2.15625 -5.132812 2.015625 -4.453125 2.015625 -3.546875 Z M 2.015625 -3.546875 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph1-22">
|
|
||||||
<path style="stroke:none;" d="M 0.875 -9.484375 L 2.5 -9.484375 L 5.703125 -1.671875 L 5.703125 -9.484375 L 6.9375 -9.484375 L 6.9375 0 L 5.3125 0 L 2.125 -7.796875 L 2.125 0 L 0.875 0 Z M 0.875 -9.484375 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph1-23">
|
|
||||||
<path style="stroke:none;" d="M 7.09375 -7.109375 L 4.546875 -3.703125 L 7.34375 0 L 6 0 L 3.90625 -2.84375 L 1.828125 0 L 0.484375 0 L 3.28125 -3.703125 L 0.734375 -7.109375 L 2.03125 -7.109375 L 3.90625 -4.53125 L 5.78125 -7.109375 Z M 7.09375 -7.109375 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph1-24">
|
|
||||||
<path style="stroke:none;" d="M 0.296875 -9.484375 L 7.53125 -9.484375 L 7.53125 -8.390625 L 4.5625 -8.390625 L 4.5625 0 L 3.28125 0 L 3.28125 -8.390625 L 0.296875 -8.390625 Z M 0.296875 -9.484375 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph1-25">
|
|
||||||
<path style="stroke:none;" d="M 2.765625 -1.046875 C 3.847656 -1.046875 4.601562 -1.3125 5.03125 -1.84375 C 5.457031 -2.375 5.671875 -3.335938 5.671875 -4.734375 C 5.671875 -6.128906 5.457031 -7.09375 5.03125 -7.625 C 4.601562 -8.15625 3.847656 -8.421875 2.765625 -8.421875 L 2.15625 -8.421875 L 2.15625 -1.046875 Z M 2.796875 -9.484375 C 4.242188 -9.484375 5.304688 -9.097656 5.984375 -8.328125 C 6.671875 -7.554688 7.015625 -6.359375 7.015625 -4.734375 C 7.015625 -3.109375 6.671875 -1.910156 5.984375 -1.140625 C 5.304688 -0.378906 4.242188 0 2.796875 0 L 0.875 0 L 0.875 -9.484375 Z M 2.796875 -9.484375 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph1-26">
|
|
||||||
<path style="stroke:none;" d="M 6.8125 -0.34375 C 6.488281 -0.164062 6.15625 -0.0351562 5.8125 0.046875 C 5.46875 0.140625 5.101562 0.1875 4.71875 0.1875 C 3.5 0.1875 2.550781 -0.238281 1.875 -1.09375 C 1.207031 -1.957031 0.875 -3.171875 0.875 -4.734375 C 0.875 -6.273438 1.210938 -7.476562 1.890625 -8.34375 C 2.566406 -9.21875 3.507812 -9.65625 4.71875 -9.65625 C 5.101562 -9.65625 5.46875 -9.609375 5.8125 -9.515625 C 6.15625 -9.429688 6.488281 -9.300781 6.8125 -9.125 L 6.8125 -7.8125 C 6.5 -8.070312 6.160156 -8.269531 5.796875 -8.40625 C 5.441406 -8.539062 5.082031 -8.609375 4.71875 -8.609375 C 3.882812 -8.609375 3.257812 -8.285156 2.84375 -7.640625 C 2.425781 -6.992188 2.21875 -6.023438 2.21875 -4.734375 C 2.21875 -3.429688 2.425781 -2.457031 2.84375 -1.8125 C 3.257812 -1.175781 3.882812 -0.859375 4.71875 -0.859375 C 5.09375 -0.859375 5.457031 -0.925781 5.8125 -1.0625 C 6.164062 -1.195312 6.5 -1.394531 6.8125 -1.65625 Z M 6.8125 -0.34375 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph1-27">
|
|
||||||
<path style="stroke:none;" d="M 0.546875 -9.484375 L 2.265625 -9.484375 L 3.890625 -4.65625 L 5.546875 -9.484375 L 7.265625 -9.484375 L 7.265625 0 L 6.078125 0 L 6.078125 -8.375 L 4.390625 -3.375 L 3.421875 -3.375 L 1.734375 -8.375 L 1.734375 0 L 0.546875 0 Z M 0.546875 -9.484375 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph1-28">
|
|
||||||
<path style="stroke:none;" d="M 1.359375 -9.484375 L 2.65625 -9.484375 L 2.65625 -1.078125 L 7.234375 -1.078125 L 7.234375 0 L 1.359375 0 Z M 1.359375 -9.484375 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph2-0">
|
|
||||||
<path style="stroke:none;" d="M 0.640625 2.296875 L 0.640625 -9.171875 L 7.140625 -9.171875 L 7.140625 2.296875 Z M 1.375 1.578125 L 6.421875 1.578125 L 6.421875 -8.4375 L 1.375 -8.4375 Z M 1.375 1.578125 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph2-1">
|
|
||||||
<path style="stroke:none;" d="M 6.9375 -1.734375 L 3.125 -1.734375 L 2.515625 0 L 0.0625 0 L 3.578125 -9.484375 L 6.484375 -9.484375 L 10 0 L 7.546875 0 Z M 3.734375 -3.484375 L 6.328125 -3.484375 L 5.03125 -7.25 Z M 3.734375 -3.484375 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph2-2">
|
|
||||||
<path style="stroke:none;" d="M 5.921875 -6.0625 L 5.921875 -9.875 L 8.21875 -9.875 L 8.21875 0 L 5.921875 0 L 5.921875 -1.03125 C 5.609375 -0.613281 5.265625 -0.304688 4.890625 -0.109375 C 4.515625 0.0859375 4.082031 0.1875 3.59375 0.1875 C 2.707031 0.1875 1.984375 -0.160156 1.421875 -0.859375 C 0.859375 -1.554688 0.578125 -2.453125 0.578125 -3.546875 C 0.578125 -4.640625 0.859375 -5.535156 1.421875 -6.234375 C 1.984375 -6.929688 2.707031 -7.28125 3.59375 -7.28125 C 4.082031 -7.28125 4.515625 -7.179688 4.890625 -6.984375 C 5.265625 -6.785156 5.609375 -6.476562 5.921875 -6.0625 Z M 4.4375 -1.46875 C 4.914062 -1.46875 5.28125 -1.644531 5.53125 -2 C 5.789062 -2.351562 5.921875 -2.867188 5.921875 -3.546875 C 5.921875 -4.222656 5.789062 -4.738281 5.53125 -5.09375 C 5.28125 -5.445312 4.914062 -5.625 4.4375 -5.625 C 3.945312 -5.625 3.570312 -5.445312 3.3125 -5.09375 C 3.0625 -4.738281 2.9375 -4.222656 2.9375 -3.546875 C 2.9375 -2.867188 3.0625 -2.351562 3.3125 -2 C 3.570312 -1.644531 3.945312 -1.46875 4.4375 -1.46875 Z M 4.4375 -1.46875 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph2-3">
|
|
||||||
<path style="stroke:none;" d="M 7.6875 -5.921875 C 7.96875 -6.367188 8.304688 -6.707031 8.703125 -6.9375 C 9.097656 -7.164062 9.535156 -7.28125 10.015625 -7.28125 C 10.828125 -7.28125 11.445312 -7.023438 11.875 -6.515625 C 12.300781 -6.015625 12.515625 -5.285156 12.515625 -4.328125 L 12.515625 0 L 10.234375 0 L 10.234375 -3.703125 C 10.234375 -3.765625 10.234375 -3.820312 10.234375 -3.875 C 10.242188 -3.9375 10.25 -4.019531 10.25 -4.125 C 10.25 -4.632812 10.171875 -5 10.015625 -5.21875 C 9.867188 -5.445312 9.632812 -5.5625 9.3125 -5.5625 C 8.875 -5.5625 8.535156 -5.382812 8.296875 -5.03125 C 8.066406 -4.675781 7.945312 -4.160156 7.9375 -3.484375 L 7.9375 0 L 5.65625 0 L 5.65625 -3.703125 C 5.65625 -4.492188 5.585938 -5 5.453125 -5.21875 C 5.316406 -5.445312 5.078125 -5.5625 4.734375 -5.5625 C 4.296875 -5.5625 3.957031 -5.382812 3.71875 -5.03125 C 3.476562 -4.675781 3.359375 -4.164062 3.359375 -3.5 L 3.359375 0 L 1.078125 0 L 1.078125 -7.109375 L 3.359375 -7.109375 L 3.359375 -6.0625 C 3.640625 -6.46875 3.960938 -6.769531 4.328125 -6.96875 C 4.691406 -7.175781 5.085938 -7.28125 5.515625 -7.28125 C 6.015625 -7.28125 6.453125 -7.160156 6.828125 -6.921875 C 7.203125 -6.679688 7.488281 -6.347656 7.6875 -5.921875 Z M 7.6875 -5.921875 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph2-4">
|
|
||||||
<path style="stroke:none;" d="M 1.09375 -7.109375 L 3.359375 -7.109375 L 3.359375 0 L 1.09375 0 Z M 1.09375 -9.875 L 3.359375 -9.875 L 3.359375 -8.03125 L 1.09375 -8.03125 Z M 1.09375 -9.875 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph2-5">
|
|
||||||
<path style="stroke:none;" d="M 8.234375 -4.328125 L 8.234375 0 L 5.953125 0 L 5.953125 -3.3125 C 5.953125 -3.925781 5.9375 -4.347656 5.90625 -4.578125 C 5.882812 -4.816406 5.835938 -4.988281 5.765625 -5.09375 C 5.679688 -5.238281 5.5625 -5.351562 5.40625 -5.4375 C 5.257812 -5.519531 5.085938 -5.5625 4.890625 -5.5625 C 4.410156 -5.5625 4.035156 -5.378906 3.765625 -5.015625 C 3.492188 -4.648438 3.359375 -4.144531 3.359375 -3.5 L 3.359375 0 L 1.09375 0 L 1.09375 -7.109375 L 3.359375 -7.109375 L 3.359375 -6.0625 C 3.703125 -6.476562 4.066406 -6.785156 4.453125 -6.984375 C 4.835938 -7.179688 5.265625 -7.28125 5.734375 -7.28125 C 6.554688 -7.28125 7.175781 -7.023438 7.59375 -6.515625 C 8.019531 -6.015625 8.234375 -5.285156 8.234375 -4.328125 Z M 8.234375 -4.328125 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph2-6">
|
|
||||||
<path style="stroke:none;" d="M 6.640625 -6.890625 L 6.640625 -5.15625 C 6.160156 -5.363281 5.691406 -5.515625 5.234375 -5.609375 C 4.785156 -5.710938 4.359375 -5.765625 3.953125 -5.765625 C 3.523438 -5.765625 3.203125 -5.710938 2.984375 -5.609375 C 2.773438 -5.503906 2.671875 -5.335938 2.671875 -5.109375 C 2.671875 -4.929688 2.75 -4.789062 2.90625 -4.6875 C 3.070312 -4.59375 3.359375 -4.519531 3.765625 -4.46875 L 4.171875 -4.421875 C 5.335938 -4.273438 6.117188 -4.03125 6.515625 -3.6875 C 6.921875 -3.351562 7.125 -2.820312 7.125 -2.09375 C 7.125 -1.332031 6.84375 -0.757812 6.28125 -0.375 C 5.726562 0 4.894531 0.1875 3.78125 0.1875 C 3.3125 0.1875 2.828125 0.148438 2.328125 0.078125 C 1.828125 0.00390625 1.3125 -0.109375 0.78125 -0.265625 L 0.78125 -1.984375 C 1.226562 -1.765625 1.691406 -1.597656 2.171875 -1.484375 C 2.648438 -1.378906 3.132812 -1.328125 3.625 -1.328125 C 4.070312 -1.328125 4.40625 -1.382812 4.625 -1.5 C 4.851562 -1.625 4.96875 -1.8125 4.96875 -2.0625 C 4.96875 -2.257812 4.890625 -2.40625 4.734375 -2.5 C 4.578125 -2.601562 4.269531 -2.6875 3.8125 -2.75 L 3.40625 -2.796875 C 2.394531 -2.921875 1.6875 -3.15625 1.28125 -3.5 C 0.875 -3.84375 0.671875 -4.363281 0.671875 -5.0625 C 0.671875 -5.8125 0.925781 -6.367188 1.4375 -6.734375 C 1.957031 -7.097656 2.753906 -7.28125 3.828125 -7.28125 C 4.242188 -7.28125 4.679688 -7.25 5.140625 -7.1875 C 5.597656 -7.125 6.097656 -7.023438 6.640625 -6.890625 Z M 6.640625 -6.890625 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph2-7">
|
|
||||||
<path style="stroke:none;" d="M 3.578125 -9.125 L 3.578125 -7.109375 L 5.921875 -7.109375 L 5.921875 -5.484375 L 3.578125 -5.484375 L 3.578125 -2.46875 C 3.578125 -2.132812 3.640625 -1.910156 3.765625 -1.796875 C 3.898438 -1.679688 4.160156 -1.625 4.546875 -1.625 L 5.71875 -1.625 L 5.71875 0 L 3.765625 0 C 2.867188 0 2.234375 -0.1875 1.859375 -0.5625 C 1.484375 -0.9375 1.296875 -1.570312 1.296875 -2.46875 L 1.296875 -5.484375 L 0.171875 -5.484375 L 0.171875 -7.109375 L 1.296875 -7.109375 L 1.296875 -9.125 Z M 3.578125 -9.125 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph2-8">
|
|
||||||
<path style="stroke:none;" d="M 6.375 -5.171875 C 6.175781 -5.265625 5.976562 -5.332031 5.78125 -5.375 C 5.582031 -5.425781 5.382812 -5.453125 5.1875 -5.453125 C 4.601562 -5.453125 4.148438 -5.265625 3.828125 -4.890625 C 3.515625 -4.515625 3.359375 -3.976562 3.359375 -3.28125 L 3.359375 0 L 1.09375 0 L 1.09375 -7.109375 L 3.359375 -7.109375 L 3.359375 -5.9375 C 3.648438 -6.40625 3.984375 -6.742188 4.359375 -6.953125 C 4.742188 -7.171875 5.203125 -7.28125 5.734375 -7.28125 C 5.804688 -7.28125 5.882812 -7.273438 5.96875 -7.265625 C 6.0625 -7.265625 6.191406 -7.253906 6.359375 -7.234375 Z M 6.375 -5.171875 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph2-9">
|
|
||||||
<path style="stroke:none;" d="M 4.28125 -3.203125 C 3.800781 -3.203125 3.441406 -3.117188 3.203125 -2.953125 C 2.960938 -2.796875 2.84375 -2.5625 2.84375 -2.25 C 2.84375 -1.957031 2.9375 -1.726562 3.125 -1.5625 C 3.320312 -1.40625 3.59375 -1.328125 3.9375 -1.328125 C 4.363281 -1.328125 4.722656 -1.476562 5.015625 -1.78125 C 5.304688 -2.09375 5.453125 -2.476562 5.453125 -2.9375 L 5.453125 -3.203125 Z M 7.75 -4.0625 L 7.75 0 L 5.453125 0 L 5.453125 -1.046875 C 5.148438 -0.617188 4.804688 -0.304688 4.421875 -0.109375 C 4.046875 0.0859375 3.585938 0.1875 3.046875 0.1875 C 2.304688 0.1875 1.707031 -0.0234375 1.25 -0.453125 C 0.789062 -0.890625 0.5625 -1.453125 0.5625 -2.140625 C 0.5625 -2.972656 0.847656 -3.582031 1.421875 -3.96875 C 1.992188 -4.351562 2.894531 -4.546875 4.125 -4.546875 L 5.453125 -4.546875 L 5.453125 -4.734375 C 5.453125 -5.085938 5.3125 -5.347656 5.03125 -5.515625 C 4.75 -5.679688 4.304688 -5.765625 3.703125 -5.765625 C 3.222656 -5.765625 2.769531 -5.71875 2.34375 -5.625 C 1.925781 -5.53125 1.539062 -5.382812 1.1875 -5.1875 L 1.1875 -6.921875 C 1.664062 -7.035156 2.148438 -7.125 2.640625 -7.1875 C 3.140625 -7.25 3.632812 -7.28125 4.125 -7.28125 C 5.40625 -7.28125 6.328125 -7.023438 6.890625 -6.515625 C 7.460938 -6.015625 7.75 -5.195312 7.75 -4.0625 Z M 7.75 -4.0625 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph2-10">
|
|
||||||
<path style="stroke:none;" d="M 4.46875 -5.65625 C 3.96875 -5.65625 3.582031 -5.472656 3.3125 -5.109375 C 3.050781 -4.753906 2.921875 -4.234375 2.921875 -3.546875 C 2.921875 -2.867188 3.050781 -2.347656 3.3125 -1.984375 C 3.582031 -1.617188 3.96875 -1.4375 4.46875 -1.4375 C 4.96875 -1.4375 5.347656 -1.617188 5.609375 -1.984375 C 5.867188 -2.347656 6 -2.867188 6 -3.546875 C 6 -4.234375 5.867188 -4.753906 5.609375 -5.109375 C 5.347656 -5.472656 4.96875 -5.65625 4.46875 -5.65625 Z M 4.46875 -7.28125 C 5.695312 -7.28125 6.65625 -6.945312 7.34375 -6.28125 C 8.03125 -5.625 8.375 -4.710938 8.375 -3.546875 C 8.375 -2.378906 8.03125 -1.460938 7.34375 -0.796875 C 6.65625 -0.140625 5.695312 0.1875 4.46875 0.1875 C 3.25 0.1875 2.289062 -0.140625 1.59375 -0.796875 C 0.90625 -1.460938 0.5625 -2.378906 0.5625 -3.546875 C 0.5625 -4.710938 0.90625 -5.625 1.59375 -6.28125 C 2.289062 -6.945312 3.25 -7.28125 4.46875 -7.28125 Z M 4.46875 -7.28125 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph2-11">
|
|
||||||
<path style="stroke:none;" d="M 8.703125 -0.515625 C 8.253906 -0.285156 7.785156 -0.113281 7.296875 0 C 6.816406 0.125 6.3125 0.1875 5.78125 0.1875 C 4.207031 0.1875 2.957031 -0.253906 2.03125 -1.140625 C 1.101562 -2.023438 0.640625 -3.222656 0.640625 -4.734375 C 0.640625 -6.242188 1.101562 -7.441406 2.03125 -8.328125 C 2.957031 -9.210938 4.207031 -9.65625 5.78125 -9.65625 C 6.3125 -9.65625 6.816406 -9.59375 7.296875 -9.46875 C 7.785156 -9.351562 8.253906 -9.175781 8.703125 -8.9375 L 8.703125 -6.984375 C 8.253906 -7.296875 7.804688 -7.519531 7.359375 -7.65625 C 6.921875 -7.800781 6.460938 -7.875 5.984375 -7.875 C 5.109375 -7.875 4.421875 -7.59375 3.921875 -7.03125 C 3.421875 -6.476562 3.171875 -5.710938 3.171875 -4.734375 C 3.171875 -3.753906 3.421875 -2.984375 3.921875 -2.421875 C 4.421875 -1.867188 5.109375 -1.59375 5.984375 -1.59375 C 6.460938 -1.59375 6.921875 -1.660156 7.359375 -1.796875 C 7.804688 -1.941406 8.253906 -2.171875 8.703125 -2.484375 Z M 8.703125 -0.515625 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph2-12">
|
|
||||||
<path style="stroke:none;" d="M 1.015625 -2.765625 L 1.015625 -7.109375 L 3.296875 -7.109375 L 3.296875 -6.40625 C 3.296875 -6.019531 3.289062 -5.535156 3.28125 -4.953125 C 3.28125 -4.367188 3.28125 -3.976562 3.28125 -3.78125 C 3.28125 -3.207031 3.296875 -2.796875 3.328125 -2.546875 C 3.359375 -2.296875 3.410156 -2.113281 3.484375 -2 C 3.578125 -1.851562 3.695312 -1.738281 3.84375 -1.65625 C 4 -1.570312 4.175781 -1.53125 4.375 -1.53125 C 4.84375 -1.53125 5.210938 -1.710938 5.484375 -2.078125 C 5.753906 -2.441406 5.890625 -2.945312 5.890625 -3.59375 L 5.890625 -7.109375 L 8.15625 -7.109375 L 8.15625 0 L 5.890625 0 L 5.890625 -1.03125 C 5.546875 -0.613281 5.179688 -0.304688 4.796875 -0.109375 C 4.421875 0.0859375 4 0.1875 3.53125 0.1875 C 2.707031 0.1875 2.082031 -0.0625 1.65625 -0.5625 C 1.226562 -1.070312 1.015625 -1.804688 1.015625 -2.765625 Z M 1.015625 -2.765625 "/>
|
|
||||||
</symbol>
|
|
||||||
<symbol overflow="visible" id="glyph2-13">
|
|
||||||
<path style="stroke:none;" d="M 8.1875 -3.578125 L 8.1875 -2.921875 L 2.875 -2.921875 C 2.925781 -2.390625 3.117188 -1.988281 3.453125 -1.71875 C 3.785156 -1.457031 4.25 -1.328125 4.84375 -1.328125 C 5.3125 -1.328125 5.796875 -1.394531 6.296875 -1.53125 C 6.804688 -1.675781 7.328125 -1.894531 7.859375 -2.1875 L 7.859375 -0.4375 C 7.316406 -0.226562 6.773438 -0.0703125 6.234375 0.03125 C 5.703125 0.132812 5.164062 0.1875 4.625 0.1875 C 3.34375 0.1875 2.34375 -0.140625 1.625 -0.796875 C 0.914062 -1.453125 0.5625 -2.367188 0.5625 -3.546875 C 0.5625 -4.703125 0.910156 -5.613281 1.609375 -6.28125 C 2.304688 -6.945312 3.269531 -7.28125 4.5 -7.28125 C 5.613281 -7.28125 6.503906 -6.941406 7.171875 -6.265625 C 7.847656 -5.597656 8.1875 -4.703125 8.1875 -3.578125 Z M 5.859375 -4.328125 C 5.859375 -4.765625 5.726562 -5.113281 5.46875 -5.375 C 5.21875 -5.632812 4.890625 -5.765625 4.484375 -5.765625 C 4.046875 -5.765625 3.6875 -5.640625 3.40625 -5.390625 C 3.132812 -5.148438 2.96875 -4.796875 2.90625 -4.328125 Z M 5.859375 -4.328125 "/>
|
|
||||||
</symbol>
|
|
||||||
</g>
|
|
||||||
</defs>
|
|
||||||
<g id="surface25169">
|
|
||||||
<rect x="0" y="0" width="1146" height="548" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/>
|
|
||||||
<path style="fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 28.5 4.95 L 35.825 4.95 L 35.825 6.35 L 28.5 6.35 Z M 28.5 4.95 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
|
||||||
<use xlink:href="#glyph0-1" x="537.601562" y="110"/>
|
|
||||||
<use xlink:href="#glyph0-2" x="549.984375" y="110"/>
|
|
||||||
<use xlink:href="#glyph0-3" x="561.371094" y="110"/>
|
|
||||||
<use xlink:href="#glyph0-4" x="572.816406" y="110"/>
|
|
||||||
<use xlink:href="#glyph0-5" x="578.304688" y="110"/>
|
|
||||||
<use xlink:href="#glyph0-6" x="585.960938" y="110"/>
|
|
||||||
<use xlink:href="#glyph0-7" x="623.109375" y="110"/>
|
|
||||||
<use xlink:href="#glyph0-8" x="623.109375" y="110"/>
|
|
||||||
<use xlink:href="#glyph0-9" x="633.96875" y="110"/>
|
|
||||||
<use xlink:href="#glyph0-10" x="650.648438" y="110"/>
|
|
||||||
<use xlink:href="#glyph0-11" x="662.09375" y="110"/>
|
|
||||||
<use xlink:href="#glyph0-12" x="667.582031" y="110"/>
|
|
||||||
<use xlink:href="#glyph0-5" x="678.382812" y="110"/>
|
|
||||||
<use xlink:href="#glyph0-8" x="686.039062" y="110"/>
|
|
||||||
</g>
|
|
||||||
<path style="fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 10.6 7 L 19.475 7 L 19.475 8.4 L 10.6 8.4 Z M 10.6 7 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
|
||||||
<use xlink:href="#glyph0-13" x="191" y="151"/>
|
|
||||||
<use xlink:href="#glyph0-10" x="204.59375" y="151"/>
|
|
||||||
<use xlink:href="#glyph0-8" x="216.039063" y="151"/>
|
|
||||||
<use xlink:href="#glyph0-14" x="226.898438" y="151"/>
|
|
||||||
<use xlink:href="#glyph0-15" x="238.285156" y="151"/>
|
|
||||||
<use xlink:href="#glyph0-5" x="249.808594" y="151"/>
|
|
||||||
<use xlink:href="#glyph0-12" x="257.464844" y="151"/>
|
|
||||||
<use xlink:href="#glyph0-16" x="268.265625" y="151"/>
|
|
||||||
<use xlink:href="#glyph0-17" x="277.757812" y="151"/>
|
|
||||||
<use xlink:href="#glyph0-6" x="288.402344" y="151"/>
|
|
||||||
<use xlink:href="#glyph0-18" x="293.96875" y="151"/>
|
|
||||||
<use xlink:href="#glyph0-11" x="305.707031" y="151"/>
|
|
||||||
<use xlink:href="#glyph0-2" x="311.195312" y="151"/>
|
|
||||||
<use xlink:href="#glyph0-19" x="322.582031" y="151"/>
|
|
||||||
<use xlink:href="#glyph0-5" x="332.113281" y="151"/>
|
|
||||||
<use xlink:href="#glyph0-8" x="339.769531" y="151"/>
|
|
||||||
<use xlink:href="#glyph0-20" x="350.628906" y="151"/>
|
|
||||||
</g>
|
|
||||||
<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.4,0.4;stroke-miterlimit:10;" d="M 28.451953 5.65 L 22.3 5.65 L 22.3 7.7 L 19.85957 7.7 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 20.491797 7.45 L 19.691797 7.7 L 20.491797 7.95 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
|
||||||
<use xlink:href="#glyph1-1" x="422" y="121.5"/>
|
|
||||||
<use xlink:href="#glyph1-2" x="429.695313" y="121.5"/>
|
|
||||||
<use xlink:href="#glyph1-2" x="437.390625" y="121.5"/>
|
|
||||||
<use xlink:href="#glyph1-3" x="445.085938" y="121.5"/>
|
|
||||||
<use xlink:href="#glyph1-4" x="452.78125" y="121.5"/>
|
|
||||||
<use xlink:href="#glyph1-5" x="460.476563" y="121.5"/>
|
|
||||||
<use xlink:href="#glyph1-6" x="468.171875" y="121.5"/>
|
|
||||||
<use xlink:href="#glyph1-7" x="475.867188" y="121.5"/>
|
|
||||||
<use xlink:href="#glyph1-8" x="483.5625" y="121.5"/>
|
|
||||||
<use xlink:href="#glyph1-9" x="491.257812" y="121.5"/>
|
|
||||||
</g>
|
|
||||||
<path style="fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 30.75 11.35 L 33.669922 11.35 L 33.669922 12.75 L 30.75 12.75 Z M 30.75 11.35 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
|
||||||
<use xlink:href="#glyph0-1" x="594.019531" y="238"/>
|
|
||||||
<use xlink:href="#glyph0-2" x="606.402344" y="238"/>
|
|
||||||
<use xlink:href="#glyph0-3" x="617.789062" y="238"/>
|
|
||||||
<use xlink:href="#glyph0-4" x="629.234375" y="238"/>
|
|
||||||
<use xlink:href="#glyph0-5" x="634.722656" y="238"/>
|
|
||||||
</g>
|
|
||||||
<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.4,0.4;stroke-miterlimit:10;" d="M 32.209961 11.299805 L 32.209961 9.424805 L 32.215039 9.424805 L 32.215039 6.685352 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 32.465039 7.317578 L 32.215039 6.517578 L 31.965039 7.317578 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
|
||||||
<use xlink:href="#glyph1-10" x="529.753906" y="176.496094"/>
|
|
||||||
<use xlink:href="#glyph1-5" x="537.449219" y="176.496094"/>
|
|
||||||
<use xlink:href="#glyph1-8" x="545.144531" y="176.496094"/>
|
|
||||||
<use xlink:href="#glyph1-6" x="552.839844" y="176.496094"/>
|
|
||||||
<use xlink:href="#glyph1-7" x="560.535156" y="176.496094"/>
|
|
||||||
<use xlink:href="#glyph1-11" x="568.230469" y="176.496094"/>
|
|
||||||
<use xlink:href="#glyph1-9" x="575.925781" y="176.496094"/>
|
|
||||||
<use xlink:href="#glyph1-12" x="583.621094" y="176.496094"/>
|
|
||||||
<use xlink:href="#glyph1-13" x="591.316406" y="176.496094"/>
|
|
||||||
<use xlink:href="#glyph1-4" x="599.011719" y="176.496094"/>
|
|
||||||
<use xlink:href="#glyph1-10" x="606.707031" y="176.496094"/>
|
|
||||||
<use xlink:href="#glyph1-14" x="614.402344" y="176.496094"/>
|
|
||||||
<use xlink:href="#glyph1-15" x="622.097656" y="176.496094"/>
|
|
||||||
<use xlink:href="#glyph1-16" x="629.792969" y="176.496094"/>
|
|
||||||
<use xlink:href="#glyph1-8" x="637.488281" y="176.496094"/>
|
|
||||||
<use xlink:href="#glyph1-4" x="645.183594" y="176.496094"/>
|
|
||||||
<use xlink:href="#glyph1-9" x="652.878906" y="176.496094"/>
|
|
||||||
<use xlink:href="#glyph1-12" x="660.574219" y="176.496094"/>
|
|
||||||
<use xlink:href="#glyph1-7" x="668.269531" y="176.496094"/>
|
|
||||||
<use xlink:href="#glyph1-13" x="675.964844" y="176.496094"/>
|
|
||||||
<use xlink:href="#glyph1-15" x="683.660156" y="176.496094"/>
|
|
||||||
<use xlink:href="#glyph1-9" x="691.355469" y="176.496094"/>
|
|
||||||
<use xlink:href="#glyph1-17" x="699.050781" y="176.496094"/>
|
|
||||||
</g>
|
|
||||||
<path style="fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 45.8 0.45 L 48.322461 0.45 L 48.322461 1.85 L 45.8 1.85 Z M 45.8 0.45 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
|
||||||
<use xlink:href="#glyph0-21" x="895.03125" y="20"/>
|
|
||||||
<use xlink:href="#glyph0-22" x="908.15625" y="20"/>
|
|
||||||
<use xlink:href="#glyph0-12" x="919.152344" y="20"/>
|
|
||||||
<use xlink:href="#glyph0-11" x="929.953125" y="20"/>
|
|
||||||
</g>
|
|
||||||
<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.4,0.4;stroke-miterlimit:10;" d="M 32.1625 4.899609 L 32.1625 3.6 L 47.061328 3.6 L 47.061328 2.235547 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 47.311328 2.867969 L 47.061328 2.067969 L 46.811328 2.867969 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
|
||||||
<use xlink:href="#glyph1-1" x="735.457031" y="60"/>
|
|
||||||
<use xlink:href="#glyph1-11" x="743.152344" y="60"/>
|
|
||||||
<use xlink:href="#glyph1-18" x="750.847656" y="60"/>
|
|
||||||
<use xlink:href="#glyph1-4" x="758.542969" y="60"/>
|
|
||||||
<use xlink:href="#glyph1-5" x="766.238281" y="60"/>
|
|
||||||
<use xlink:href="#glyph1-19" x="773.933594" y="60"/>
|
|
||||||
<use xlink:href="#glyph1-5" x="781.628906" y="60"/>
|
|
||||||
<use xlink:href="#glyph1-6" x="789.324219" y="60"/>
|
|
||||||
</g>
|
|
||||||
<path style="fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 24.75 18.35 L 30.372461 18.35 L 30.372461 19.75 L 24.75 19.75 Z M 24.75 18.35 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
|
||||||
<use xlink:href="#glyph0-1" x="474.054688" y="378"/>
|
|
||||||
<use xlink:href="#glyph0-16" x="486.4375" y="378"/>
|
|
||||||
<use xlink:href="#glyph0-5" x="495.929688" y="378"/>
|
|
||||||
<use xlink:href="#glyph0-4" x="503.585938" y="378"/>
|
|
||||||
<use xlink:href="#glyph0-22" x="509.074219" y="378"/>
|
|
||||||
<use xlink:href="#glyph0-14" x="520.070312" y="378"/>
|
|
||||||
<use xlink:href="#glyph0-6" x="531.457031" y="378"/>
|
|
||||||
<use xlink:href="#glyph0-23" x="537.023438" y="378"/>
|
|
||||||
<use xlink:href="#glyph0-11" x="548.742188" y="378"/>
|
|
||||||
<use xlink:href="#glyph0-12" x="554.230469" y="378"/>
|
|
||||||
<use xlink:href="#glyph0-14" x="565.03125" y="378"/>
|
|
||||||
</g>
|
|
||||||
<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.4,0.4;stroke-miterlimit:10;" d="M 32.209961 12.8 L 32.209961 14.925 L 26.15 14.925 L 26.15 17.814648 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 25.9 17.182422 L 26.15 17.982422 L 26.4 17.182422 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
|
||||||
<use xlink:href="#glyph1-20" x="522.972656" y="286.5"/>
|
|
||||||
<use xlink:href="#glyph1-5" x="530.667969" y="286.5"/>
|
|
||||||
<use xlink:href="#glyph1-12" x="538.363281" y="286.5"/>
|
|
||||||
<use xlink:href="#glyph1-5" x="546.058594" y="286.5"/>
|
|
||||||
<use xlink:href="#glyph1-15" x="553.753906" y="286.5"/>
|
|
||||||
<use xlink:href="#glyph1-16" x="561.449219" y="286.5"/>
|
|
||||||
<use xlink:href="#glyph1-8" x="569.144531" y="286.5"/>
|
|
||||||
<use xlink:href="#glyph1-5" x="576.839844" y="286.5"/>
|
|
||||||
<use xlink:href="#glyph1-6" x="584.535156" y="286.5"/>
|
|
||||||
</g>
|
|
||||||
<path style="fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 34.1 23.55 L 37.472461 23.55 L 37.472461 24.95 L 34.1 24.95 Z M 34.1 23.55 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
|
||||||
<use xlink:href="#glyph0-1" x="661.035156" y="482"/>
|
|
||||||
<use xlink:href="#glyph0-16" x="673.417969" y="482"/>
|
|
||||||
<use xlink:href="#glyph0-5" x="682.910156" y="482"/>
|
|
||||||
<use xlink:href="#glyph0-4" x="690.566406" y="482"/>
|
|
||||||
<use xlink:href="#glyph0-22" x="696.054688" y="482"/>
|
|
||||||
<use xlink:href="#glyph0-14" x="707.050781" y="482"/>
|
|
||||||
</g>
|
|
||||||
<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 27.561328 21.047266 L 27.561328 22.15 L 35.786328 22.15 L 35.786328 23.501562 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<path style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 27.561328 19.788672 L 27.801172 20.488672 L 27.561328 21.188672 L 27.321289 20.488672 Z M 27.561328 19.788672 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
|
||||||
<use xlink:href="#glyph1-4" x="553.609375" y="431"/>
|
|
||||||
<use xlink:href="#glyph1-6" x="561.304688" y="431"/>
|
|
||||||
<use xlink:href="#glyph1-7" x="569" y="431"/>
|
|
||||||
<use xlink:href="#glyph1-11" x="576.695313" y="431"/>
|
|
||||||
<use xlink:href="#glyph1-9" x="584.390625" y="431"/>
|
|
||||||
<use xlink:href="#glyph1-17" x="592.085938" y="431"/>
|
|
||||||
<use xlink:href="#glyph1-2" x="599.78125" y="431"/>
|
|
||||||
<use xlink:href="#glyph1-9" x="607.476563" y="431"/>
|
|
||||||
<use xlink:href="#glyph1-6" x="615.171875" y="431"/>
|
|
||||||
<use xlink:href="#glyph1-5" x="622.867188" y="431"/>
|
|
||||||
<use xlink:href="#glyph1-21" x="630.5625" y="431"/>
|
|
||||||
<use xlink:href="#glyph1-7" x="638.257812" y="431"/>
|
|
||||||
<use xlink:href="#glyph1-9" x="645.953125" y="431"/>
|
|
||||||
<use xlink:href="#glyph1-13" x="653.648438" y="431"/>
|
|
||||||
</g>
|
|
||||||
<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 37.472461 24.95 L 37.472461 25.85 L 43.1 25.85 L 43.1 24.25 L 37.472461 24.25 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
|
||||||
<use xlink:href="#glyph1-22" x="737.402344" y="505"/>
|
|
||||||
<use xlink:href="#glyph1-5" x="745.097656" y="505"/>
|
|
||||||
<use xlink:href="#glyph1-23" x="752.792969" y="505"/>
|
|
||||||
<use xlink:href="#glyph1-8" x="760.488281" y="505"/>
|
|
||||||
<use xlink:href="#glyph1-7" x="768.183594" y="505"/>
|
|
||||||
<use xlink:href="#glyph1-16" x="775.878906" y="505"/>
|
|
||||||
<use xlink:href="#glyph1-11" x="783.574219" y="505"/>
|
|
||||||
<use xlink:href="#glyph1-8" x="791.269531" y="505"/>
|
|
||||||
<use xlink:href="#glyph1-4" x="798.964844" y="505"/>
|
|
||||||
<use xlink:href="#glyph1-9" x="806.660156" y="505"/>
|
|
||||||
<use xlink:href="#glyph1-12" x="814.355469" y="505"/>
|
|
||||||
</g>
|
|
||||||
<path style=" stroke:none;fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 824.074219 505 L 824.074219 497 L 832.074219 501 Z M 824.074219 505 "/>
|
|
||||||
<path style="fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(100%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 52.1 10.95 C 52.1 11.115625 51.965625 11.25 51.8 11.25 C 51.634375 11.25 51.5 11.115625 51.5 10.95 C 51.5 10.784375 51.634375 10.65 51.8 10.65 C 51.965625 10.65 52.1 10.784375 52.1 10.95 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(100%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 50.6 11.55 L 53 11.55 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(100%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 51.8 11.25 L 51.8 12.75 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(100%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 51.8 12.75 L 50.6 14.05 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(100%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 51.8 12.75 L 53 14.05 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<g style="fill:rgb(100%,0%,0%);fill-opacity:1;">
|
|
||||||
<use xlink:href="#glyph2-1" x="959.921875" y="296.898438"/>
|
|
||||||
<use xlink:href="#glyph2-2" x="969.824219" y="296.898438"/>
|
|
||||||
<use xlink:href="#glyph2-3" x="978.984375" y="296.898438"/>
|
|
||||||
<use xlink:href="#glyph2-4" x="992.324219" y="296.898438"/>
|
|
||||||
<use xlink:href="#glyph2-5" x="996.71875" y="296.898438"/>
|
|
||||||
<use xlink:href="#glyph2-4" x="1005.820312" y="296.898438"/>
|
|
||||||
<use xlink:href="#glyph2-6" x="1010.214844" y="296.898438"/>
|
|
||||||
<use xlink:href="#glyph2-7" x="1017.832031" y="296.898438"/>
|
|
||||||
<use xlink:href="#glyph2-8" x="1023.945312" y="296.898438"/>
|
|
||||||
<use xlink:href="#glyph2-9" x="1030.253906" y="296.898438"/>
|
|
||||||
<use xlink:href="#glyph2-7" x="1038.886719" y="296.898438"/>
|
|
||||||
<use xlink:href="#glyph2-10" x="1045" y="296.898438"/>
|
|
||||||
<use xlink:href="#glyph2-8" x="1053.789062" y="296.898438"/>
|
|
||||||
</g>
|
|
||||||
<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.4,0.4;stroke-miterlimit:10;" d="M 49.295898 12.75 L 41.708203 12.75 L 41.708203 12.05 L 34.055664 12.05 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 34.688086 11.8 L 33.888086 12.05 L 34.688086 12.3 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
|
||||||
<use xlink:href="#glyph1-24" x="810.164062" y="236"/>
|
|
||||||
<use xlink:href="#glyph1-15" x="817.859375" y="236"/>
|
|
||||||
<use xlink:href="#glyph1-4" x="825.554688" y="236"/>
|
|
||||||
<use xlink:href="#glyph1-10" x="833.25" y="236"/>
|
|
||||||
<use xlink:href="#glyph1-10" x="840.945312" y="236"/>
|
|
||||||
<use xlink:href="#glyph1-5" x="848.640625" y="236"/>
|
|
||||||
<use xlink:href="#glyph1-15" x="856.335938" y="236"/>
|
|
||||||
<use xlink:href="#glyph1-6" x="864.03125" y="236"/>
|
|
||||||
</g>
|
|
||||||
<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.4,0.4;stroke-miterlimit:10;" d="M 51.9 9.649609 L 44.0625 9.649609 L 44.0625 5.65 L 36.160352 5.65 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 36.792578 5.4 L 35.992578 5.65 L 36.792578 5.9 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
|
||||||
<use xlink:href="#glyph1-25" x="857.25" y="140.996094"/>
|
|
||||||
<use xlink:href="#glyph1-5" x="864.945312" y="140.996094"/>
|
|
||||||
<use xlink:href="#glyph1-13" x="872.640625" y="140.996094"/>
|
|
||||||
<use xlink:href="#glyph1-4" x="880.335938" y="140.996094"/>
|
|
||||||
<use xlink:href="#glyph1-12" x="888.03125" y="140.996094"/>
|
|
||||||
<use xlink:href="#glyph1-5" x="895.726562" y="140.996094"/>
|
|
||||||
<use xlink:href="#glyph1-6" x="903.421875" y="140.996094"/>
|
|
||||||
<use xlink:href="#glyph1-7" x="911.117188" y="140.996094"/>
|
|
||||||
<use xlink:href="#glyph1-1" x="918.8125" y="140.996094"/>
|
|
||||||
<use xlink:href="#glyph1-14" x="926.507812" y="140.996094"/>
|
|
||||||
<use xlink:href="#glyph1-21" x="934.203125" y="140.996094"/>
|
|
||||||
<use xlink:href="#glyph1-4" x="941.898438" y="140.996094"/>
|
|
||||||
<use xlink:href="#glyph1-8" x="949.59375" y="140.996094"/>
|
|
||||||
<use xlink:href="#glyph1-7" x="957.289062" y="140.996094"/>
|
|
||||||
<use xlink:href="#glyph1-11" x="964.984375" y="140.996094"/>
|
|
||||||
<use xlink:href="#glyph1-9" x="972.679688" y="140.996094"/>
|
|
||||||
<use xlink:href="#glyph1-12" x="980.375" y="140.996094"/>
|
|
||||||
<use xlink:href="#glyph1-13" x="988.070312" y="140.996094"/>
|
|
||||||
<use xlink:href="#glyph1-4" x="995.765625" y="140.996094"/>
|
|
||||||
<use xlink:href="#glyph1-10" x="1003.460938" y="140.996094"/>
|
|
||||||
<use xlink:href="#glyph1-14" x="1011.15625" y="140.996094"/>
|
|
||||||
<use xlink:href="#glyph1-15" x="1018.851562" y="140.996094"/>
|
|
||||||
<use xlink:href="#glyph1-16" x="1026.546875" y="140.996094"/>
|
|
||||||
<use xlink:href="#glyph1-8" x="1034.242188" y="140.996094"/>
|
|
||||||
<use xlink:href="#glyph1-4" x="1041.9375" y="140.996094"/>
|
|
||||||
<use xlink:href="#glyph1-9" x="1049.632812" y="140.996094"/>
|
|
||||||
<use xlink:href="#glyph1-12" x="1057.328125" y="140.996094"/>
|
|
||||||
<use xlink:href="#glyph1-7" x="1065.023438" y="140.996094"/>
|
|
||||||
<use xlink:href="#glyph1-4" x="1072.71875" y="140.996094"/>
|
|
||||||
<use xlink:href="#glyph1-12" x="1080.414062" y="140.996094"/>
|
|
||||||
</g>
|
|
||||||
<path style="fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(100%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 5.45 1.4 C 5.45 1.565625 5.315625 1.7 5.15 1.7 C 4.984375 1.7 4.85 1.565625 4.85 1.4 C 4.85 1.234375 4.984375 1.1 5.15 1.1 C 5.315625 1.1 5.45 1.234375 5.45 1.4 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(100%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 3.95 2 L 6.35 2 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(100%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 5.15 1.7 L 5.15 3.2 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(100%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 5.15 3.2 L 3.95 4.5 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(100%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 5.15 3.2 L 6.35 4.5 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<g style="fill:rgb(100%,0%,0%);fill-opacity:1;">
|
|
||||||
<use xlink:href="#glyph2-11" x="42.332031" y="105.898438"/>
|
|
||||||
<use xlink:href="#glyph2-12" x="51.726562" y="105.898438"/>
|
|
||||||
<use xlink:href="#glyph2-6" x="60.828125" y="105.898438"/>
|
|
||||||
<use xlink:href="#glyph2-7" x="68.445312" y="105.898438"/>
|
|
||||||
<use xlink:href="#glyph2-10" x="74.558594" y="105.898438"/>
|
|
||||||
<use xlink:href="#glyph2-3" x="83.347656" y="105.898438"/>
|
|
||||||
<use xlink:href="#glyph2-13" x="96.6875" y="105.898438"/>
|
|
||||||
<use xlink:href="#glyph2-8" x="105.359375" y="105.898438"/>
|
|
||||||
</g>
|
|
||||||
<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.4,0.4;stroke-miterlimit:10;" d="M 6.88418 3.2 L 15.0375 3.2 L 15.0375 6.664648 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 14.7875 6.032422 L 15.0375 6.832422 L 15.2875 6.032422 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
|
||||||
<use xlink:href="#glyph1-26" x="123.957031" y="52"/>
|
|
||||||
<use xlink:href="#glyph1-9" x="131.652344" y="52"/>
|
|
||||||
<use xlink:href="#glyph1-12" x="139.347656" y="52"/>
|
|
||||||
<use xlink:href="#glyph1-6" x="147.042969" y="52"/>
|
|
||||||
<use xlink:href="#glyph1-14" x="154.738281" y="52"/>
|
|
||||||
<use xlink:href="#glyph1-17" x="162.433594" y="52"/>
|
|
||||||
<use xlink:href="#glyph1-5" x="170.128906" y="52"/>
|
|
||||||
<use xlink:href="#glyph1-6" x="177.824219" y="52"/>
|
|
||||||
<use xlink:href="#glyph1-7" x="185.519531" y="52"/>
|
|
||||||
<use xlink:href="#glyph1-15" x="193.214844" y="52"/>
|
|
||||||
<use xlink:href="#glyph1-5" x="200.910156" y="52"/>
|
|
||||||
<use xlink:href="#glyph1-6" x="208.605469" y="52"/>
|
|
||||||
<use xlink:href="#glyph1-9" x="216.300781" y="52"/>
|
|
||||||
<use xlink:href="#glyph1-14" x="223.996094" y="52"/>
|
|
||||||
<use xlink:href="#glyph1-15" x="231.691406" y="52"/>
|
|
||||||
<use xlink:href="#glyph1-11" x="239.386719" y="52"/>
|
|
||||||
<use xlink:href="#glyph1-5" x="247.082031" y="52"/>
|
|
||||||
<use xlink:href="#glyph1-6" x="254.777344" y="52"/>
|
|
||||||
</g>
|
|
||||||
<path style="fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 1.35 12.9 L 6.490039 12.9 L 6.490039 14.3 L 1.35 14.3 Z M 1.35 12.9 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
|
||||||
<use xlink:href="#glyph0-24" x="5.972656" y="269"/>
|
|
||||||
<use xlink:href="#glyph0-8" x="18.296875" y="269"/>
|
|
||||||
<use xlink:href="#glyph0-19" x="29.15625" y="269"/>
|
|
||||||
<use xlink:href="#glyph0-22" x="38.6875" y="269"/>
|
|
||||||
<use xlink:href="#glyph0-2" x="49.683594" y="269"/>
|
|
||||||
<use xlink:href="#glyph0-20" x="61.070312" y="269"/>
|
|
||||||
<use xlink:href="#glyph0-16" x="68.960938" y="269"/>
|
|
||||||
<use xlink:href="#glyph0-8" x="78.453125" y="269"/>
|
|
||||||
<use xlink:href="#glyph0-19" x="89.3125" y="269"/>
|
|
||||||
</g>
|
|
||||||
<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 9.341406 7.7 L 3.919922 7.7 L 3.919922 12.9 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<path style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 10.6 7.7 L 9.9 7.940039 L 9.2 7.7 L 9.9 7.459961 Z M 10.6 7.7 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.4,0.4;stroke-miterlimit:10;" d="M 35.786133 24.95 L 35.786133 27 L 3.919922 27 L 3.919922 14.635352 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 4.169922 15.267578 L 3.919922 14.467578 L 3.669922 15.267578 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
|
||||||
<use xlink:href="#glyph1-27" x="340.28125" y="528"/>
|
|
||||||
<use xlink:href="#glyph1-9" x="347.976563" y="528"/>
|
|
||||||
<use xlink:href="#glyph1-21" x="355.671875" y="528"/>
|
|
||||||
<use xlink:href="#glyph1-4" x="363.367188" y="528"/>
|
|
||||||
<use xlink:href="#glyph1-13" x="371.0625" y="528"/>
|
|
||||||
<use xlink:href="#glyph1-4" x="378.757813" y="528"/>
|
|
||||||
<use xlink:href="#glyph1-5" x="386.453125" y="528"/>
|
|
||||||
<use xlink:href="#glyph1-6" x="394.148438" y="528"/>
|
|
||||||
</g>
|
|
||||||
<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.4,0.4;stroke-miterlimit:10;" d="M 51.8 15.49707 L 51.8 19.05 L 30.707813 19.05 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 31.340039 18.8 L 30.540039 19.05 L 31.340039 19.3 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
|
||||||
<use xlink:href="#glyph1-28" x="764.945312" y="369"/>
|
|
||||||
<use xlink:href="#glyph1-16" x="772.640625" y="369"/>
|
|
||||||
<use xlink:href="#glyph1-14" x="780.335938" y="369"/>
|
|
||||||
<use xlink:href="#glyph1-12" x="788.03125" y="369"/>
|
|
||||||
<use xlink:href="#glyph1-11" x="795.726562" y="369"/>
|
|
||||||
<use xlink:href="#glyph1-18" x="803.421875" y="369"/>
|
|
||||||
<use xlink:href="#glyph1-5" x="811.117188" y="369"/>
|
|
||||||
<use xlink:href="#glyph1-6" x="818.8125" y="369"/>
|
|
||||||
</g>
|
|
||||||
<path style="fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.144922 2.155078 L 58.557422 2.155078 L 58.557422 3.555078 L 54.144922 3.555078 Z M 54.144922 2.155078 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
|
||||||
<use xlink:href="#glyph0-15" x="1061.902344" y="54.101562"/>
|
|
||||||
<use xlink:href="#glyph0-5" x="1073.425781" y="54.101562"/>
|
|
||||||
<use xlink:href="#glyph0-20" x="1081.082031" y="54.101562"/>
|
|
||||||
<use xlink:href="#glyph0-12" x="1088.972656" y="54.101562"/>
|
|
||||||
<use xlink:href="#glyph0-5" x="1099.773438" y="54.101562"/>
|
|
||||||
<use xlink:href="#glyph0-8" x="1107.429688" y="54.101562"/>
|
|
||||||
<use xlink:href="#glyph0-25" x="1118.289062" y="54.101562"/>
|
|
||||||
<use xlink:href="#glyph0-26" x="1129.734375" y="54.101562"/>
|
|
||||||
</g>
|
|
||||||
<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.4,0.4;stroke-miterlimit:10;" d="M 48.322461 1.15 L 51.008594 1.15 L 51.008594 2.855078 L 53.760742 2.855078 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 53.12832 3.105078 L 53.92832 2.855078 L 53.12832 2.605078 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
|
||||||
<use xlink:href="#glyph1-14" x="996.171875" y="28.050781"/>
|
|
||||||
<use xlink:href="#glyph1-6" x="1003.867188" y="28.050781"/>
|
|
||||||
<use xlink:href="#glyph1-5" x="1011.5625" y="28.050781"/>
|
|
||||||
<use xlink:href="#glyph1-6" x="1019.257812" y="28.050781"/>
|
|
||||||
</g>
|
|
||||||
<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 27.561328 21.058594 L 27.561328 22.15 L 19.345703 22.15 L 19.345703 23.652734 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<path style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 27.561328 19.8 L 27.801172 20.5 L 27.561328 21.2 L 27.321289 20.5 Z M 27.561328 19.8 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
|
||||||
<use xlink:href="#glyph1-4" x="389.203125" y="431"/>
|
|
||||||
<use xlink:href="#glyph1-6" x="396.898438" y="431"/>
|
|
||||||
<use xlink:href="#glyph1-7" x="404.59375" y="431"/>
|
|
||||||
<use xlink:href="#glyph1-11" x="412.289062" y="431"/>
|
|
||||||
<use xlink:href="#glyph1-9" x="419.984375" y="431"/>
|
|
||||||
<use xlink:href="#glyph1-17" x="427.679688" y="431"/>
|
|
||||||
<use xlink:href="#glyph1-2" x="435.375" y="431"/>
|
|
||||||
<use xlink:href="#glyph1-9" x="443.070312" y="431"/>
|
|
||||||
<use xlink:href="#glyph1-6" x="450.765625" y="431"/>
|
|
||||||
<use xlink:href="#glyph1-5" x="458.460938" y="431"/>
|
|
||||||
<use xlink:href="#glyph1-21" x="466.15625" y="431"/>
|
|
||||||
<use xlink:href="#glyph1-7" x="473.851562" y="431"/>
|
|
||||||
<use xlink:href="#glyph1-9" x="481.546875" y="431"/>
|
|
||||||
<use xlink:href="#glyph1-13" x="489.242188" y="431"/>
|
|
||||||
</g>
|
|
||||||
<path style="fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 15.201953 23.652734 L 23.489453 23.652734 L 23.489453 25.052734 L 15.201953 25.052734 Z M 15.201953 23.652734 " transform="matrix(20,0,0,20,-26,-8)"/>
|
|
||||||
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
|
|
||||||
<use xlink:href="#glyph0-27" x="283.082031" y="484.054688"/>
|
|
||||||
<use xlink:href="#glyph0-28" x="294.019531" y="484.054688"/>
|
|
||||||
<use xlink:href="#glyph0-16" x="311.871094" y="484.054688"/>
|
|
||||||
<use xlink:href="#glyph0-12" x="321.363281" y="484.054688"/>
|
|
||||||
<use xlink:href="#glyph0-16" x="332.164062" y="484.054688"/>
|
|
||||||
<use xlink:href="#glyph0-26" x="341.65625" y="484.054688"/>
|
|
||||||
<use xlink:href="#glyph0-6" x="352.085938" y="484.054688"/>
|
|
||||||
<use xlink:href="#glyph0-29" x="357.652344" y="484.054688"/>
|
|
||||||
<use xlink:href="#glyph0-14" x="363.609375" y="484.054688"/>
|
|
||||||
<use xlink:href="#glyph0-3" x="374.996094" y="484.054688"/>
|
|
||||||
<use xlink:href="#glyph0-4" x="386.441406" y="484.054688"/>
|
|
||||||
<use xlink:href="#glyph0-16" x="391.929688" y="484.054688"/>
|
|
||||||
<use xlink:href="#glyph0-12" x="401.421875" y="484.054688"/>
|
|
||||||
<use xlink:href="#glyph0-5" x="412.222656" y="484.054688"/>
|
|
||||||
<use xlink:href="#glyph0-22" x="419.878906" y="484.054688"/>
|
|
||||||
<use xlink:href="#glyph0-20" x="430.875" y="484.054688"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 86 KiB |
Before Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 72 KiB |
Before Width: | Height: | Size: 72 KiB |
@ -1,120 +0,0 @@
|
|||||||
..
|
|
||||||
Except where otherwise noted, this document is licensed under Creative
|
|
||||||
Commons Attribution 3.0 License. You can view the license at:
|
|
||||||
|
|
||||||
https://creativecommons.org/licenses/by/3.0/
|
|
||||||
|
|
||||||
================================
|
|
||||||
Welcome to Watcher documentation
|
|
||||||
================================
|
|
||||||
|
|
||||||
OpenStack Watcher provides a flexible and scalable resource optimization
|
|
||||||
service for multi-tenant OpenStack-based clouds.
|
|
||||||
Watcher provides a complete optimization loop—including everything from a
|
|
||||||
metrics receiver, complex event processor and profiler, optimization processor
|
|
||||||
and an action plan applier. This provides a robust framework to realize a wide
|
|
||||||
range of cloud optimization goals, including the reduction of data center
|
|
||||||
operating costs, increased system performance via intelligent virtual machine
|
|
||||||
migration, increased energy efficiency—and more!
|
|
||||||
|
|
||||||
Watcher project consists of several source code repositories:
|
|
||||||
|
|
||||||
* `watcher`_ - is the main repository. It contains code for Watcher API server,
|
|
||||||
Watcher Decision Engine and Watcher Applier.
|
|
||||||
* `python-watcherclient`_ - Client library and CLI client for Watcher.
|
|
||||||
* `watcher-dashboard`_ - Watcher Horizon plugin.
|
|
||||||
|
|
||||||
The documentation provided here is continually kept up-to-date based
|
|
||||||
on the latest code, and may not represent the state of the project at any
|
|
||||||
specific prior release.
|
|
||||||
|
|
||||||
.. _watcher: https://git.openstack.org/cgit/openstack/watcher/
|
|
||||||
.. _python-watcherclient: https://git.openstack.org/cgit/openstack/python-watcherclient/
|
|
||||||
.. _watcher-dashboard: https://git.openstack.org/cgit/openstack/watcher-dashboard/
|
|
||||||
|
|
||||||
Developer Guide
|
|
||||||
===============
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
------------
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 1
|
|
||||||
|
|
||||||
glossary
|
|
||||||
architecture
|
|
||||||
contributor/contributing
|
|
||||||
|
|
||||||
|
|
||||||
Getting Started
|
|
||||||
---------------
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 1
|
|
||||||
|
|
||||||
contributor/index
|
|
||||||
|
|
||||||
API References
|
|
||||||
--------------
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 1
|
|
||||||
|
|
||||||
api/index
|
|
||||||
|
|
||||||
Plugins
|
|
||||||
-------
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 1
|
|
||||||
|
|
||||||
contributor/plugin/index
|
|
||||||
|
|
||||||
Installation
|
|
||||||
============
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 2
|
|
||||||
|
|
||||||
install/index
|
|
||||||
|
|
||||||
Admin Guide
|
|
||||||
===========
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 1
|
|
||||||
|
|
||||||
admin/index
|
|
||||||
|
|
||||||
User Guide
|
|
||||||
==========
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 2
|
|
||||||
|
|
||||||
user/index
|
|
||||||
|
|
||||||
Watcher Manual Pages
|
|
||||||
====================
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:glob:
|
|
||||||
:maxdepth: 1
|
|
||||||
|
|
||||||
man/index
|
|
||||||
|
|
||||||
.. # 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
|
|
||||||
# they aren't in the toctree somewhere. For example, we hide api/autoindex
|
|
||||||
# since that's already covered with modindex below.
|
|
||||||
.. toctree::
|
|
||||||
:hidden:
|
|
||||||
|
|
||||||
api/autoindex
|
|
||||||
|
|
||||||
|
|
||||||
Indices and tables
|
|
||||||
==================
|
|
||||||
|
|
||||||
* :ref:`genindex`
|
|
||||||
* :ref:`modindex`
|
|
||||||
* :ref:`search`
|
|