Compare commits
125 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dbff4326e3 | ||
|
|
13a99b4c09 | ||
|
|
a8994bc227 | ||
|
|
c6845c0136 | ||
|
|
02c8e7d89c | ||
|
|
0db41f1862 | ||
|
|
b02cf3bea5 | ||
|
|
4eeaa0ab6b | ||
|
|
84d6d4aadd | ||
|
|
4511b36496 | ||
|
|
9a5c017a9a | ||
|
|
4690e402ce | ||
|
|
442e569686 | ||
|
|
5d948e8aa1 | ||
|
|
f83a92fc70 | ||
|
|
a06c462050 | ||
|
|
74e9349c1f | ||
|
|
7c048c761e | ||
|
|
4006b4af7a | ||
|
|
1d05444f67 | ||
|
|
6de94cca2d | ||
|
|
9b5d17b412 | ||
|
|
719b96f2a8 | ||
|
|
e9f83417eb | ||
|
|
a139cca260 | ||
|
|
c04d3cc5e0 | ||
|
|
e549e43e9e | ||
|
|
c1a2c79514 | ||
|
|
f79cad99cb | ||
|
|
8663c3a5c5 | ||
|
|
19d9b83665 | ||
|
|
af22899ebe | ||
|
|
fc33e181fc | ||
|
|
a3ee163480 | ||
|
|
4642a92e78 | ||
|
|
69c53da298 | ||
|
|
49924e1915 | ||
|
|
d53abb7af5 | ||
|
|
4d3727eafb | ||
|
|
4a3c15185c | ||
|
|
2c6ab9a926 | ||
|
|
0750b93827 | ||
|
|
a2cb02a861 | ||
|
|
377889859d | ||
|
|
54f0758fc3 | ||
|
|
a644600a18 | ||
|
|
ca3d367ac7 | ||
|
|
cde60d2ead | ||
|
|
f106076d70 | ||
|
|
e75dbfd776 | ||
|
|
18aa50c58e | ||
|
|
2c2120526c | ||
|
|
9e505d3d36 | ||
|
|
54ce5f796f | ||
|
|
f605888e32 | ||
|
|
0b213a8734 | ||
|
|
38a3cbc84a | ||
|
|
eb038e4af0 | ||
|
|
b5eccceaed | ||
|
|
f7b655b712 | ||
|
|
1386ce690f | ||
|
|
38e4b48d70 | ||
|
|
56ca542bef | ||
|
|
dafe2ad04b | ||
|
|
6044b04d33 | ||
|
|
6d81ac15b8 | ||
|
|
db077e872e | ||
|
|
51bf7fedb6 | ||
|
|
bf0fd48659 | ||
|
|
ba98c88303 | ||
|
|
77b406748c | ||
|
|
d21198da8f | ||
|
|
12a7b7171b | ||
|
|
d45ab13619 | ||
|
|
e2d2fc6227 | ||
|
|
3c564ee3d8 | ||
|
|
f9ce21a9a9 | ||
|
|
03a2c0142a | ||
|
|
5afcf7a7f4 | ||
|
|
63faf4695e | ||
|
|
97800d1553 | ||
|
|
8f85169c15 | ||
|
|
68e4bc4d87 | ||
|
|
9e7f7f54f3 | ||
|
|
fceab5299b | ||
|
|
dddbb63633 | ||
|
|
b788dfab71 | ||
|
|
7824b41e12 | ||
|
|
86ded4d952 | ||
|
|
5d6e731c42 | ||
|
|
cba6713bdc | ||
|
|
24ab0469ec | ||
|
|
4d71bb112c | ||
|
|
fd374d1d30 | ||
|
|
25789c9c5a | ||
|
|
a9b3534e97 | ||
|
|
f80c0c732a | ||
|
|
0d83354c57 | ||
|
|
67d44eb118 | ||
|
|
8c1757f86d | ||
|
|
e55c73be0e | ||
|
|
04c9e0362e | ||
|
|
8ceb710b59 | ||
|
|
58711aaaec | ||
|
|
3ad5261d2a | ||
|
|
26c7726c00 | ||
|
|
5b2cdb53a8 | ||
|
|
4b5dce51dc | ||
|
|
b6a96e04aa | ||
|
|
62cb8a8d29 | ||
|
|
50e5e86c75 | ||
|
|
e3dd5c2a7e | ||
|
|
630c2cbb79 | ||
|
|
d49c6c16a6 | ||
|
|
e51e7e4317 | ||
|
|
244d28afa6 | ||
|
|
7ac1d0d048 | ||
|
|
65f9646eae | ||
|
|
52d701a56e | ||
|
|
ea1fd5967a | ||
|
|
547bf0529f | ||
|
|
659cbf3207 | ||
|
|
eb5a362287 | ||
|
|
198d827645 | ||
|
|
59c5adc8ad |
@@ -1,13 +1,13 @@
|
|||||||
If you would like to contribute to the development of OpenStack,
|
If you would like to contribute to the development of OpenStack,
|
||||||
you must follow the steps in this page:
|
you must follow the steps in this page:
|
||||||
|
|
||||||
http://docs.openstack.org/infra/manual/developers.html
|
https://docs.openstack.org/infra/manual/developers.html
|
||||||
|
|
||||||
Once those steps have been completed, changes to OpenStack
|
Once those steps have been completed, changes to OpenStack
|
||||||
should be submitted for review via the Gerrit tool, following
|
should be submitted for review via the Gerrit tool, following
|
||||||
the workflow documented at:
|
the workflow documented at:
|
||||||
|
|
||||||
http://docs.openstack.org/infra/manual/developers.html#development-workflow
|
https://docs.openstack.org/infra/manual/developers.html#development-workflow
|
||||||
|
|
||||||
Pull requests submitted through GitHub will be ignored.
|
Pull requests submitted through GitHub will be ignored.
|
||||||
|
|
||||||
|
|||||||
@@ -8,4 +8,4 @@
|
|||||||
watcher Style Commandments
|
watcher Style Commandments
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
Read the OpenStack Style Commandments http://docs.openstack.org/developer/hacking/
|
Read the OpenStack Style Commandments https://docs.openstack.org/developer/hacking/
|
||||||
|
|||||||
10
README.rst
10
README.rst
@@ -2,8 +2,8 @@
|
|||||||
Team and repository tags
|
Team and repository tags
|
||||||
========================
|
========================
|
||||||
|
|
||||||
.. image:: http://governance.openstack.org/badges/watcher.svg
|
.. image:: https://governance.openstack.org/badges/watcher.svg
|
||||||
:target: http://governance.openstack.org/reference/tags/index.html
|
:target: https://governance.openstack.org/reference/tags/index.html
|
||||||
|
|
||||||
.. Change things from this point on
|
.. Change things from this point on
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ operating costs, increased system performance via intelligent virtual machine
|
|||||||
migration, increased energy efficiency-and more!
|
migration, increased energy efficiency-and more!
|
||||||
|
|
||||||
* Free software: Apache license
|
* Free software: Apache license
|
||||||
* Wiki: http://wiki.openstack.org/wiki/Watcher
|
* Wiki: https://wiki.openstack.org/wiki/Watcher
|
||||||
* Source: https://github.com/openstack/watcher
|
* Source: https://github.com/openstack/watcher
|
||||||
* Bugs: http://bugs.launchpad.net/watcher
|
* Bugs: https://bugs.launchpad.net/watcher
|
||||||
* Documentation: http://docs.openstack.org/developer/watcher/
|
* Documentation: https://docs.openstack.org/developer/watcher/
|
||||||
|
|||||||
42
devstack/files/apache-watcher-api.template
Normal file
42
devstack/files/apache-watcher-api.template
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
# 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>
|
||||||
@@ -44,6 +44,9 @@ WATCHER_CONF_DIR=/etc/watcher
|
|||||||
WATCHER_CONF=$WATCHER_CONF_DIR/watcher.conf
|
WATCHER_CONF=$WATCHER_CONF_DIR/watcher.conf
|
||||||
WATCHER_POLICY_JSON=$WATCHER_CONF_DIR/policy.json
|
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_DIR=/etc/nova
|
||||||
NOVA_CONF=$NOVA_CONF_DIR/nova.conf
|
NOVA_CONF=$NOVA_CONF_DIR/nova.conf
|
||||||
|
|
||||||
@@ -51,6 +54,13 @@ if is_ssl_enabled_service "watcher" || is_service_enabled tls-proxy; then
|
|||||||
WATCHER_SERVICE_PROTOCOL="https"
|
WATCHER_SERVICE_PROTOCOL="https"
|
||||||
fi
|
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
|
# Public facing bits
|
||||||
WATCHER_SERVICE_HOST=${WATCHER_SERVICE_HOST:-$HOST_IP}
|
WATCHER_SERVICE_HOST=${WATCHER_SERVICE_HOST:-$HOST_IP}
|
||||||
WATCHER_SERVICE_PORT=${WATCHER_SERVICE_PORT:-9322}
|
WATCHER_SERVICE_PORT=${WATCHER_SERVICE_PORT:-9322}
|
||||||
@@ -74,10 +84,21 @@ function is_watcher_enabled {
|
|||||||
return 1
|
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
|
# cleanup_watcher() - Remove residual data files, anything left over from previous
|
||||||
# runs that a clean run would need to clean up
|
# runs that a clean run would need to clean up
|
||||||
function cleanup_watcher {
|
function cleanup_watcher {
|
||||||
sudo rm -rf $WATCHER_STATE_PATH $WATCHER_AUTH_CACHE_DIR
|
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
|
# configure_watcher() - Set config files, create data dirs, etc
|
||||||
@@ -108,6 +129,28 @@ function create_watcher_accounts {
|
|||||||
"$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
|
# create_watcher_conf() - Create a new watcher.conf file
|
||||||
function create_watcher_conf {
|
function create_watcher_conf {
|
||||||
# (Re)create ``watcher.conf``
|
# (Re)create ``watcher.conf``
|
||||||
@@ -126,7 +169,7 @@ function create_watcher_conf {
|
|||||||
iniset $WATCHER_CONF oslo_messaging_rabbit rabbit_password $RABBIT_PASSWORD
|
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_rabbit rabbit_host $RABBIT_HOST
|
||||||
|
|
||||||
iniset $WATCHER_CONF oslo_messaging_notifications driver "messaging"
|
iniset $WATCHER_CONF oslo_messaging_notifications driver "messagingv2"
|
||||||
|
|
||||||
iniset $NOVA_CONF oslo_messaging_notifications topics "notifications,watcher_notifications"
|
iniset $NOVA_CONF oslo_messaging_notifications topics "notifications,watcher_notifications"
|
||||||
iniset $NOVA_CONF notifications notify_on_state_change "vm_and_task_state"
|
iniset $NOVA_CONF notifications notify_on_state_change "vm_and_task_state"
|
||||||
@@ -154,9 +197,13 @@ function create_watcher_conf {
|
|||||||
setup_colorized_logging $WATCHER_CONF DEFAULT
|
setup_colorized_logging $WATCHER_CONF DEFAULT
|
||||||
else
|
else
|
||||||
# Show user_name and project_name instead of user_id and project_id
|
# 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 %(user_name)s %(project_name)s] %(instance)s%(message)s"
|
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
|
fi
|
||||||
|
|
||||||
|
#config apache files
|
||||||
|
if [[ "$WATCHER_USE_MOD_WSGI" == "True" ]]; then
|
||||||
|
_config_watcher_apache_wsgi
|
||||||
|
fi
|
||||||
# Register SSL certificates if provided
|
# Register SSL certificates if provided
|
||||||
if is_ssl_enabled_service watcher; then
|
if is_ssl_enabled_service watcher; then
|
||||||
ensure_certificates WATCHER
|
ensure_certificates WATCHER
|
||||||
@@ -188,7 +235,7 @@ function init_watcher {
|
|||||||
recreate_database watcher
|
recreate_database watcher
|
||||||
|
|
||||||
# Create watcher schema
|
# Create watcher schema
|
||||||
$WATCHER_BIN_DIR/watcher-db-manage --config-file $WATCHER_CONF create_schema
|
$WATCHER_BIN_DIR/watcher-db-manage --config-file $WATCHER_CONF upgrade head
|
||||||
fi
|
fi
|
||||||
create_watcher_cache_dir
|
create_watcher_cache_dir
|
||||||
}
|
}
|
||||||
@@ -205,19 +252,26 @@ function install_watcherclient {
|
|||||||
function install_watcher {
|
function install_watcher {
|
||||||
git_clone $WATCHER_REPO $WATCHER_DIR $WATCHER_BRANCH
|
git_clone $WATCHER_REPO $WATCHER_DIR $WATCHER_BRANCH
|
||||||
setup_develop $WATCHER_DIR
|
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
|
# start_watcher_api() - Start the API process ahead of other things
|
||||||
function start_watcher_api {
|
function start_watcher_api {
|
||||||
# Get right service port for testing
|
# Get right service port for testing
|
||||||
|
|
||||||
local service_port=$WATCHER_SERVICE_PORT
|
local service_port=$WATCHER_SERVICE_PORT
|
||||||
local service_protocol=$WATCHER_SERVICE_PROTOCOL
|
local service_protocol=$WATCHER_SERVICE_PROTOCOL
|
||||||
if is_service_enabled tls-proxy; then
|
if is_service_enabled tls-proxy; then
|
||||||
service_port=$WATCHER_SERVICE_PORT_INT
|
service_port=$WATCHER_SERVICE_PORT_INT
|
||||||
service_protocol="http"
|
service_protocol="http"
|
||||||
fi
|
fi
|
||||||
|
if [[ "$WATCHER_USE_MOD_WSGI" == "True" ]]; then
|
||||||
run_process watcher-api "$WATCHER_BIN_DIR/watcher-api --config-file $WATCHER_CONF"
|
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..."
|
echo "Waiting for watcher-api to start..."
|
||||||
if ! wait_for_service $SERVICE_TIMEOUT $service_protocol://$WATCHER_SERVICE_HOST:$service_port; then
|
if ! wait_for_service $SERVICE_TIMEOUT $service_protocol://$WATCHER_SERVICE_HOST:$service_port; then
|
||||||
die $LINENO "watcher-api did not start"
|
die $LINENO "watcher-api did not start"
|
||||||
@@ -240,7 +294,12 @@ function start_watcher {
|
|||||||
|
|
||||||
# stop_watcher() - Stop running processes (non-screen)
|
# stop_watcher() - Stop running processes (non-screen)
|
||||||
function stop_watcher {
|
function stop_watcher {
|
||||||
for serv in watcher-api watcher-decision-engine watcher-applier; do
|
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
|
stop_process $serv
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ NETWORK_GATEWAY=10.254.1.1 # Change this for your network
|
|||||||
|
|
||||||
MULTI_HOST=1
|
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
|
# This is the controller node, so disable nova-compute
|
||||||
disable_service n-cpu
|
disable_service n-cpu
|
||||||
|
|
||||||
@@ -28,7 +32,7 @@ ENABLED_SERVICES+=,q-svc,q-dhcp,q-meta,q-agt,q-l3,neutron
|
|||||||
enable_service n-cauth
|
enable_service n-cauth
|
||||||
|
|
||||||
# Enable the Watcher Dashboard plugin
|
# Enable the Watcher Dashboard plugin
|
||||||
# enable_plugin watcher-dashboard git://git.openstack.org/openstack/watcher-dashboard
|
enable_plugin watcher-dashboard git://git.openstack.org/openstack/watcher-dashboard
|
||||||
|
|
||||||
# Enable the Watcher plugin
|
# Enable the Watcher plugin
|
||||||
enable_plugin watcher git://git.openstack.org/openstack/watcher
|
enable_plugin watcher git://git.openstack.org/openstack/watcher
|
||||||
@@ -38,6 +42,11 @@ enable_plugin ceilometer git://git.openstack.org/openstack/ceilometer
|
|||||||
|
|
||||||
# This is the controller node, so disable the ceilometer compute agent
|
# This is the controller node, so disable the ceilometer compute agent
|
||||||
disable_service ceilometer-acompute
|
disable_service ceilometer-acompute
|
||||||
|
# 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
|
LOGFILE=$DEST/logs/stack.sh.log
|
||||||
LOGDAYS=2
|
LOGDAYS=2
|
||||||
|
|||||||
40
doc/notification_samples/action-create.json
Normal file
40
doc/notification_samples/action-create.json
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
40
doc/notification_samples/action-delete.json
Normal file
40
doc/notification_samples/action-delete.json
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
41
doc/notification_samples/action-execution-end.json
Normal file
41
doc/notification_samples/action-execution-end.json
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
51
doc/notification_samples/action-execution-error.json
Normal file
51
doc/notification_samples/action-execution-error.json
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
41
doc/notification_samples/action-execution-start.json
Normal file
41
doc/notification_samples/action-execution-start.json
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
49
doc/notification_samples/action-update.json
Normal file
49
doc/notification_samples/action-update.json
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
54
doc/notification_samples/action_plan-create.json
Normal file
54
doc/notification_samples/action_plan-create.json
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
54
doc/notification_samples/action_plan-delete.json
Normal file
54
doc/notification_samples/action_plan-delete.json
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
55
doc/notification_samples/action_plan-execution-end.json
Normal file
55
doc/notification_samples/action_plan-execution-end.json
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
65
doc/notification_samples/action_plan-execution-error.json
Normal file
65
doc/notification_samples/action_plan-execution-error.json
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
55
doc/notification_samples/action_plan-execution-start.json
Normal file
55
doc/notification_samples/action_plan-execution-start.json
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
63
doc/notification_samples/action_plan-update.json
Normal file
63
doc/notification_samples/action_plan-update.json
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@
|
|||||||
"state": "PENDING",
|
"state": "PENDING",
|
||||||
"updated_at": null,
|
"updated_at": null,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
|
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||||
"goal": {
|
"goal": {
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
"uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
"uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||||
@@ -26,6 +27,7 @@
|
|||||||
},
|
},
|
||||||
"interval": null,
|
"interval": null,
|
||||||
"scope": [],
|
"scope": [],
|
||||||
|
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
||||||
"strategy": {
|
"strategy": {
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
"parameters_spec": {
|
"parameters_spec": {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
"state": "DELETED",
|
"state": "DELETED",
|
||||||
"updated_at": null,
|
"updated_at": null,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
|
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||||
"goal": {
|
"goal": {
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
"uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
"uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||||
@@ -26,6 +27,7 @@
|
|||||||
},
|
},
|
||||||
"interval": null,
|
"interval": null,
|
||||||
"scope": [],
|
"scope": [],
|
||||||
|
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
||||||
"strategy": {
|
"strategy": {
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
"parameters_spec": {
|
"parameters_spec": {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
"updated_at": null,
|
"updated_at": null,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"fault": null,
|
"fault": null,
|
||||||
|
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||||
"goal": {
|
"goal": {
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
"uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
"uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||||
@@ -27,6 +28,7 @@
|
|||||||
},
|
},
|
||||||
"interval": null,
|
"interval": null,
|
||||||
"scope": [],
|
"scope": [],
|
||||||
|
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
||||||
"strategy": {
|
"strategy": {
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
"parameters_spec": {
|
"parameters_spec": {
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
"watcher_object.namespace": "watcher",
|
"watcher_object.namespace": "watcher",
|
||||||
"watcher_object.version": "1.0"
|
"watcher_object.version": "1.0"
|
||||||
},
|
},
|
||||||
|
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||||
"goal": {
|
"goal": {
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
"uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
"uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||||
@@ -37,6 +38,7 @@
|
|||||||
},
|
},
|
||||||
"interval": null,
|
"interval": null,
|
||||||
"scope": [],
|
"scope": [],
|
||||||
|
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
||||||
"strategy": {
|
"strategy": {
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
"parameters_spec": {
|
"parameters_spec": {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
"updated_at": null,
|
"updated_at": null,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"fault": null,
|
"fault": null,
|
||||||
|
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||||
"goal": {
|
"goal": {
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
"uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
"uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||||
@@ -27,6 +28,7 @@
|
|||||||
},
|
},
|
||||||
"interval": null,
|
"interval": null,
|
||||||
"scope": [],
|
"scope": [],
|
||||||
|
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
||||||
"strategy": {
|
"strategy": {
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
"parameters_spec": {
|
"parameters_spec": {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
"updated_at": null,
|
"updated_at": null,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"fault": null,
|
"fault": null,
|
||||||
|
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||||
"goal": {
|
"goal": {
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
"uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
"uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||||
@@ -27,6 +28,7 @@
|
|||||||
},
|
},
|
||||||
"interval": null,
|
"interval": null,
|
||||||
"scope": [],
|
"scope": [],
|
||||||
|
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
||||||
"strategy": {
|
"strategy": {
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
"parameters_spec": {
|
"parameters_spec": {
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
"watcher_object.namespace": "watcher",
|
"watcher_object.namespace": "watcher",
|
||||||
"watcher_object.version": "1.0"
|
"watcher_object.version": "1.0"
|
||||||
},
|
},
|
||||||
|
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||||
"goal": {
|
"goal": {
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
"uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
"uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||||
@@ -37,6 +38,7 @@
|
|||||||
},
|
},
|
||||||
"interval": null,
|
"interval": null,
|
||||||
"scope": [],
|
"scope": [],
|
||||||
|
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
||||||
"strategy": {
|
"strategy": {
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
"parameters_spec": {
|
"parameters_spec": {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
"updated_at": null,
|
"updated_at": null,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"fault": null,
|
"fault": null,
|
||||||
|
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||||
"goal": {
|
"goal": {
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
"uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
"uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||||
@@ -27,6 +28,7 @@
|
|||||||
},
|
},
|
||||||
"interval": null,
|
"interval": null,
|
||||||
"scope": [],
|
"scope": [],
|
||||||
|
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
||||||
"strategy": {
|
"strategy": {
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
"parameters_spec": {
|
"parameters_spec": {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
"payload": {
|
"payload": {
|
||||||
"watcher_object.name": "AuditUpdatePayload",
|
"watcher_object.name": "AuditUpdatePayload",
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
|
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
||||||
"strategy": {
|
"strategy": {
|
||||||
"watcher_object.name": "StrategyPayload",
|
"watcher_object.name": "StrategyPayload",
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
@@ -36,6 +37,7 @@
|
|||||||
"scope": [],
|
"scope": [],
|
||||||
"created_at": "2016-11-04T16:51:21Z",
|
"created_at": "2016-11-04T16:51:21Z",
|
||||||
"uuid": "f1e0d912-afd9-4bf2-91ef-c99cd08cc1ef",
|
"uuid": "f1e0d912-afd9-4bf2-91ef-c99cd08cc1ef",
|
||||||
|
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||||
"goal": {
|
"goal": {
|
||||||
"watcher_object.name": "GoalPayload",
|
"watcher_object.name": "GoalPayload",
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ Overview
|
|||||||
Below you will find a diagram, showing the main components of Watcher:
|
Below you will find a diagram, showing the main components of Watcher:
|
||||||
|
|
||||||
.. image:: ./images/architecture.svg
|
.. image:: ./images/architecture.svg
|
||||||
:width: 100%
|
:width: 110%
|
||||||
|
|
||||||
|
|
||||||
.. _components_definition:
|
.. _components_definition:
|
||||||
@@ -37,13 +37,12 @@ AMQP Bus
|
|||||||
The AMQP message bus handles internal asynchronous communications between the
|
The AMQP message bus handles internal asynchronous communications between the
|
||||||
different Watcher components.
|
different Watcher components.
|
||||||
|
|
||||||
.. _cluster_history_db_definition:
|
.. _cluster_datasource_definition:
|
||||||
|
|
||||||
Cluster History Database
|
Datasource
|
||||||
------------------------
|
----------
|
||||||
|
|
||||||
This component stores the data related to the
|
This component stores the metrics related to the cluster.
|
||||||
:ref:`Cluster History <cluster_history_definition>`.
|
|
||||||
|
|
||||||
It can potentially rely on any appropriate storage system (InfluxDB, OpenTSDB,
|
It can potentially rely on any appropriate storage system (InfluxDB, OpenTSDB,
|
||||||
MongoDB,...) but will probably be more performant when using
|
MongoDB,...) but will probably be more performant when using
|
||||||
@@ -51,14 +50,6 @@ MongoDB,...) but will probably be more performant when using
|
|||||||
which are optimized for handling time series data, which are arrays of numbers
|
which are optimized for handling time series data, which are arrays of numbers
|
||||||
indexed by time (a datetime or a datetime range).
|
indexed by time (a datetime or a datetime range).
|
||||||
|
|
||||||
.. _cluster_model_db_definition:
|
|
||||||
|
|
||||||
Cluster Model Database
|
|
||||||
------------------------
|
|
||||||
|
|
||||||
This component stores the data related to the
|
|
||||||
:ref:`Cluster Data Model <cluster_data_model_definition>`.
|
|
||||||
|
|
||||||
.. _archi_watcher_api_definition:
|
.. _archi_watcher_api_definition:
|
||||||
|
|
||||||
Watcher API
|
Watcher API
|
||||||
@@ -193,8 +184,8 @@ data:
|
|||||||
:ref:`Managed resources <managed_resource_definition>` (e.g., the data stored
|
: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
|
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 current state of a given :ref:`cluster <cluster_definition>`.
|
||||||
- The data stored in the :ref:`Cluster History Database
|
- The data stored in the :ref:`Cluster Datasource
|
||||||
<cluster_history_db_definition>` which provides information about the past of
|
<cluster_datasource_definition>` which provides information about the past of
|
||||||
the :ref:`Cluster <cluster_definition>`.
|
the :ref:`Cluster <cluster_definition>`.
|
||||||
|
|
||||||
Here below is a sequence diagram showing how the Decision Engine builds and
|
Here below is a sequence diagram showing how the Decision Engine builds and
|
||||||
@@ -416,6 +407,9 @@ be one of the following:
|
|||||||
- **CANCELLED** : the :ref:`Audit <audit_definition>` was in **PENDING** or
|
- **CANCELLED** : the :ref:`Audit <audit_definition>` was in **PENDING** or
|
||||||
**ONGOING** state and was cancelled by the
|
**ONGOING** state and was cancelled by the
|
||||||
:ref:`Administrator <administrator_definition>`
|
: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
|
The following diagram shows the different possible states of an
|
||||||
:ref:`Audit <audit_definition>` and what event makes the state change to a new
|
:ref:`Audit <audit_definition>` and what event makes the state change to a new
|
||||||
@@ -452,6 +446,10 @@ state may be one of the following:
|
|||||||
- **CANCELLED** : the :ref:`Action Plan <action_plan_definition>` was in
|
- **CANCELLED** : the :ref:`Action Plan <action_plan_definition>` was in
|
||||||
**RECOMMENDED**, **PENDING** or **ONGOING** state and was cancelled by the
|
**RECOMMENDED**, **PENDING** or **ONGOING** state and was cancelled by the
|
||||||
:ref:`Administrator <administrator_definition>`
|
: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
|
The following diagram shows the different possible states of an
|
||||||
|
|||||||
49
doc/source/deploy/apache-mod-wsgi.rst
Normal file
49
doc/source/deploy/apache-mod-wsgi.rst
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
..
|
||||||
|
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
|
||||||
@@ -18,14 +18,14 @@ The source install instructions specifically avoid using platform specific
|
|||||||
packages, instead using the source for the code and the Python Package Index
|
packages, instead using the source for the code and the Python Package Index
|
||||||
(PyPi_).
|
(PyPi_).
|
||||||
|
|
||||||
.. _PyPi: http://pypi.python.org/pypi
|
.. _PyPi: https://pypi.python.org/pypi
|
||||||
|
|
||||||
It's expected that your system already has python2.7_, latest version of pip_,
|
It's expected that your system already has python2.7_, latest version of pip_,
|
||||||
and git_ available.
|
and git_ available.
|
||||||
|
|
||||||
.. _python2.7: http://www.python.org
|
.. _python2.7: https://www.python.org
|
||||||
.. _pip: http://www.pip-installer.org/en/latest/installing.html
|
.. _pip: https://pip.pypa.io/en/latest/installing/
|
||||||
.. _git: http://git-scm.com/
|
.. _git: https://git-scm.com/
|
||||||
|
|
||||||
Your system shall also have some additional system libraries:
|
Your system shall also have some additional system libraries:
|
||||||
|
|
||||||
|
|||||||
@@ -92,6 +92,12 @@ Detailed DevStack Instructions
|
|||||||
Note: if you want to use a specific branch, specify WATCHER_BRANCH in the
|
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.
|
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::
|
#. Start stacking from the controller node::
|
||||||
|
|
||||||
./devstack/stack.sh
|
./devstack/stack.sh
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ for development purposes.
|
|||||||
To install Watcher from packaging, refer instead to Watcher `User
|
To install Watcher from packaging, refer instead to Watcher `User
|
||||||
Documentation`_.
|
Documentation`_.
|
||||||
|
|
||||||
.. _`Git Repository`: http://git.openstack.org/cgit/openstack/watcher
|
.. _`Git Repository`: https://git.openstack.org/cgit/openstack/watcher
|
||||||
.. _`User Documentation`: http://docs.openstack.org/developer/watcher/
|
.. _`User Documentation`: https://docs.openstack.org/developer/watcher/
|
||||||
|
|
||||||
Prerequisites
|
Prerequisites
|
||||||
=============
|
=============
|
||||||
@@ -35,10 +35,10 @@ following tools available on your system:
|
|||||||
**Reminder**: If you're successfully using a different platform, or a
|
**Reminder**: If you're successfully using a different platform, or a
|
||||||
different version of the above, please document your configuration here!
|
different version of the above, please document your configuration here!
|
||||||
|
|
||||||
.. _Python: http://www.python.org/
|
.. _Python: https://www.python.org/
|
||||||
.. _git: http://git-scm.com/
|
.. _git: https://git-scm.com/
|
||||||
.. _setuptools: http://pypi.python.org/pypi/setuptools
|
.. _setuptools: https://pypi.python.org/pypi/setuptools
|
||||||
.. _virtualenvwrapper: https://virtualenvwrapper.readthedocs.org/en/latest/install.html
|
.. _virtualenvwrapper: https://virtualenvwrapper.readthedocs.io/en/latest/install.html
|
||||||
|
|
||||||
Getting the latest code
|
Getting the latest code
|
||||||
=======================
|
=======================
|
||||||
@@ -175,11 +175,12 @@ The HTML files are available into ``doc/build`` directory.
|
|||||||
Configure the Watcher services
|
Configure the Watcher services
|
||||||
==============================
|
==============================
|
||||||
|
|
||||||
Watcher services require a configuration file. There is a sample configuration
|
Watcher services require a configuration file. Use tox to generate
|
||||||
file that can be used to get started:
|
a sample configuration file that can be used to get started:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ tox -e genconfig
|
||||||
$ cp etc/watcher.conf.sample etc/watcher.conf
|
$ cp etc/watcher.conf.sample etc/watcher.conf
|
||||||
|
|
||||||
Most of the default configuration should be enough to get you going, but you
|
Most of the default configuration should be enough to get you going, but you
|
||||||
|
|||||||
@@ -271,57 +271,44 @@ requires new metrics not covered by Ceilometer, you can add them through a
|
|||||||
.. _`Ceilometer plugin`: http://docs.openstack.org/developer/ceilometer/plugins.html
|
.. _`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
|
.. _`Ceilosca`: https://github.com/openstack/monasca-ceilometer/blob/master/ceilosca/ceilometer/storage/impl_monasca.py
|
||||||
|
|
||||||
|
Read usage metrics using the Watcher Datasource Helper
|
||||||
|
------------------------------------------------------
|
||||||
|
|
||||||
Read usage metrics using the Python binding
|
The following code snippet shows how to invoke a Datasource Helper class:
|
||||||
-------------------------------------------
|
|
||||||
|
|
||||||
You can find the information about the Ceilometer Python binding on the
|
|
||||||
OpenStack `ceilometer client python API documentation
|
|
||||||
<http://docs.openstack.org/developer/python-ceilometerclient/api.html>`_
|
|
||||||
|
|
||||||
To facilitate the process, Watcher provides the ``osc`` attribute to every
|
|
||||||
strategy which includes clients to major OpenStack services, including
|
|
||||||
Ceilometer. So to access it within your strategy, you can do the following:
|
|
||||||
|
|
||||||
.. code-block:: py
|
.. code-block:: py
|
||||||
|
|
||||||
# Within your strategy "execute()"
|
from watcher.datasource import ceilometer as ceil
|
||||||
cclient = self.osc.ceilometer
|
from watcher.datasource import monasca as mon
|
||||||
# TODO: Do something here
|
|
||||||
|
@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:
|
Using that you can now query the values for that specific metric:
|
||||||
|
|
||||||
.. code-block:: py
|
.. code-block:: py
|
||||||
|
|
||||||
query = None # e.g. [{'field': 'foo', 'op': 'le', 'value': 34},]
|
if self.config.datasource == "ceilometer":
|
||||||
value_cpu = cclient.samples.list(
|
resource_id = "%s_%s" % (node.uuid, node.hostname)
|
||||||
meter_name='cpu_util',
|
return self.ceilometer.statistic_aggregation(
|
||||||
limit=10, q=query)
|
resource_id=resource_id,
|
||||||
|
meter_name='compute.node.cpu.percent',
|
||||||
|
period="7200",
|
||||||
Read usage metrics using the Watcher Cluster History Helper
|
aggregate='avg',
|
||||||
-----------------------------------------------------------
|
)
|
||||||
|
elif self.config.datasource == "monasca":
|
||||||
Here below is the abstract ``BaseClusterHistory`` class of the Helper.
|
statistics = self.monasca.statistic_aggregation(
|
||||||
|
meter_name='compute.node.cpu.percent',
|
||||||
.. autoclass:: watcher.decision_engine.cluster.history.base.BaseClusterHistory
|
dimensions=dict(hostname=node.uuid),
|
||||||
:members:
|
period=7200,
|
||||||
:noindex:
|
aggregate='avg'
|
||||||
|
)
|
||||||
The following code snippet shows how to create a Cluster History class:
|
|
||||||
|
|
||||||
.. code-block:: py
|
|
||||||
|
|
||||||
from watcher.decision_engine.cluster.history import ceilometer as ceil
|
|
||||||
|
|
||||||
query_history = ceil.CeilometerClusterHistory()
|
|
||||||
|
|
||||||
Using that you can now query the values for that specific metric:
|
|
||||||
|
|
||||||
.. code-block:: py
|
|
||||||
|
|
||||||
query_history.statistic_aggregation(resource_id=compute_node.uuid,
|
|
||||||
meter_name='compute.node.cpu.percent',
|
|
||||||
period="7200",
|
|
||||||
aggregate='avg'
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ Unit tests
|
|||||||
==========
|
==========
|
||||||
|
|
||||||
All unit tests should be run using `tox`_. To run the same unit tests that are
|
All unit tests should be run using `tox`_. To run the same unit tests that are
|
||||||
executing onto `Gerrit`_ which includes ``py34``, ``py27`` and ``pep8``, you
|
executing onto `Gerrit`_ which includes ``py35``, ``py27`` and ``pep8``, you
|
||||||
can issue the following command::
|
can issue the following command::
|
||||||
|
|
||||||
$ workon watcher
|
$ workon watcher
|
||||||
@@ -26,7 +26,7 @@ If you want to only run one of the aforementioned, you can then issue one of
|
|||||||
the following::
|
the following::
|
||||||
|
|
||||||
$ workon watcher
|
$ workon watcher
|
||||||
(watcher) $ tox -e py34
|
(watcher) $ tox -e py35
|
||||||
(watcher) $ tox -e py27
|
(watcher) $ tox -e py27
|
||||||
(watcher) $ tox -e pep8
|
(watcher) $ tox -e pep8
|
||||||
|
|
||||||
|
|||||||
@@ -101,12 +101,6 @@ Cluster Data Model (CDM)
|
|||||||
|
|
||||||
.. watcher-term:: watcher.decision_engine.model.collector.base
|
.. watcher-term:: watcher.decision_engine.model.collector.base
|
||||||
|
|
||||||
.. _cluster_history_definition:
|
|
||||||
|
|
||||||
Cluster History
|
|
||||||
===============
|
|
||||||
|
|
||||||
.. watcher-term:: watcher.decision_engine.cluster.history.base
|
|
||||||
|
|
||||||
.. _controller_node_definition:
|
.. _controller_node_definition:
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,10 @@ FAILED --> DELETED : Administrator removes\nAction Plan
|
|||||||
SUCCEEDED --> DELETED : Administrator removes\nAction Plan
|
SUCCEEDED --> DELETED : Administrator removes\nAction Plan
|
||||||
ONGOING --> CANCELLED : Administrator cancels\nAction Plan
|
ONGOING --> CANCELLED : Administrator cancels\nAction Plan
|
||||||
RECOMMENDED --> 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
|
PENDING --> CANCELLED : Administrator cancels\nAction Plan
|
||||||
CANCELLED --> DELETED
|
CANCELLED --> DELETED
|
||||||
|
SUPERSEDED --> DELETED
|
||||||
DELETED --> [*]
|
DELETED --> [*]
|
||||||
|
|
||||||
@enduml
|
@enduml
|
||||||
|
|||||||
@@ -4,11 +4,14 @@
|
|||||||
PENDING --> ONGOING: Audit request is received\nby the Watcher Decision Engine
|
PENDING --> ONGOING: Audit request is received\nby the Watcher Decision Engine
|
||||||
ONGOING --> FAILED: Audit fails\n(no solution found, technical error, ...)
|
ONGOING --> FAILED: Audit fails\n(no solution found, technical error, ...)
|
||||||
ONGOING --> SUCCEEDED: The Watcher Decision Engine\ncould find at least one Solution
|
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
|
FAILED --> DELETED : Administrator wants to\narchive/delete the Audit
|
||||||
SUCCEEDED --> DELETED : Administrator wants to\narchive/delete the Audit
|
SUCCEEDED --> DELETED : Administrator wants to\narchive/delete the Audit
|
||||||
PENDING --> CANCELLED : Administrator cancels\nthe Audit
|
PENDING --> CANCELLED : Administrator cancels\nthe Audit
|
||||||
ONGOING --> CANCELLED : Administrator cancels\nthe Audit
|
ONGOING --> CANCELLED : Administrator cancels\nthe Audit
|
||||||
CANCELLED --> DELETED : Administrator wants to\narchive/delete the Audit
|
CANCELLED --> DELETED : Administrator wants to\narchive/delete the Audit
|
||||||
|
SUSPENDED --> DELETED: Administrator wants to\narchive/delete the Audit
|
||||||
DELETED --> [*]
|
DELETED --> [*]
|
||||||
|
|
||||||
@enduml
|
@enduml
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ table(audits) {
|
|||||||
interval : Integer, nullable
|
interval : Integer, nullable
|
||||||
parameters : JSONEncodedDict, nullable
|
parameters : JSONEncodedDict, nullable
|
||||||
scope : JSONEncodedList, nullable
|
scope : JSONEncodedList, nullable
|
||||||
|
auto_trigger: Boolean
|
||||||
|
|
||||||
created_at : DateTime
|
created_at : DateTime
|
||||||
updated_at : DateTime
|
updated_at : DateTime
|
||||||
@@ -73,7 +74,6 @@ table(action_plans) {
|
|||||||
foreign_key("audit_id : Integer, nullable")
|
foreign_key("audit_id : Integer, nullable")
|
||||||
foreign_key("strategy_id : Integer")
|
foreign_key("strategy_id : Integer")
|
||||||
uuid : String[36]
|
uuid : String[36]
|
||||||
first_action_id : Integer
|
|
||||||
state : String[20], nullable
|
state : String[20], nullable
|
||||||
global_efficacy : JSONEncodedDict, nullable
|
global_efficacy : JSONEncodedDict, nullable
|
||||||
|
|
||||||
@@ -91,7 +91,7 @@ table(actions) {
|
|||||||
action_type : String[255]
|
action_type : String[255]
|
||||||
input_parameters : JSONEncodedDict, nullable
|
input_parameters : JSONEncodedDict, nullable
|
||||||
state : String[20], nullable
|
state : String[20], nullable
|
||||||
next : String[36], nullable
|
parents : JSONEncodedList, nullable
|
||||||
|
|
||||||
created_at : DateTime
|
created_at : DateTime
|
||||||
updated_at : DateTime
|
updated_at : DateTime
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 58 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 47 KiB |
@@ -56,6 +56,7 @@ Getting Started
|
|||||||
dev/devstack
|
dev/devstack
|
||||||
deploy/configuration
|
deploy/configuration
|
||||||
deploy/conf-files
|
deploy/conf-files
|
||||||
|
deploy/apache-mod-wsgi
|
||||||
dev/notifications
|
dev/notifications
|
||||||
dev/testing
|
dev/testing
|
||||||
dev/rally_link
|
dev/rally_link
|
||||||
|
|||||||
@@ -72,6 +72,9 @@ Strategy parameter is:
|
|||||||
parameter type default Value description
|
parameter type default Value description
|
||||||
============== ====== ============= ====================================
|
============== ====== ============= ====================================
|
||||||
``threshold`` Number 35.0 Temperature threshold for migration
|
``threshold`` Number 35.0 Temperature threshold for migration
|
||||||
|
``period`` Number 30 The time interval in seconds for
|
||||||
|
getting statistic aggregation from
|
||||||
|
metric data source
|
||||||
============== ====== ============= ====================================
|
============== ====== ============= ====================================
|
||||||
|
|
||||||
Efficacy Indicator
|
Efficacy Indicator
|
||||||
|
|||||||
@@ -70,6 +70,20 @@ Default Watcher's planner:
|
|||||||
.. watcher-term:: watcher.decision_engine.planner.default.DefaultPlanner
|
.. watcher-term:: watcher.decision_engine.planner.default.DefaultPlanner
|
||||||
|
|
||||||
|
|
||||||
|
Configuration
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Strategy parameter is:
|
||||||
|
|
||||||
|
====================== ====== ============= ===================================
|
||||||
|
parameter type default Value description
|
||||||
|
====================== ====== ============= ===================================
|
||||||
|
``period`` Number 3600 The time interval in seconds
|
||||||
|
for getting statistic aggregation
|
||||||
|
from metric data source
|
||||||
|
====================== ====== ============= ===================================
|
||||||
|
|
||||||
|
|
||||||
Efficacy Indicator
|
Efficacy Indicator
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
|||||||
33
etc/apache2/watcher
Normal file
33
etc/apache2/watcher
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# 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
|
||||||
|
# Watcher API through mod_wsgi
|
||||||
|
Listen 9322
|
||||||
|
|
||||||
|
<VirtualHost *:9322>
|
||||||
|
WSGIDaemonProcess watcher-api user=stack group=stack processes=2 threads=2 display-name=%{GROUP}
|
||||||
|
WSGIScriptAlias / /opt/stack/watcher/watcher/api/app.wsgi
|
||||||
|
WSGIProcessGroup watcher-api
|
||||||
|
|
||||||
|
ErrorLog /var/log/httpd/watcher_error.log
|
||||||
|
LogLevel info
|
||||||
|
CustomLog /var/log/httpd/watcher_access.log combined
|
||||||
|
|
||||||
|
<Directory /opt/stack/watcher/watcher/api>
|
||||||
|
WSGIProcessGroup watcher-api
|
||||||
|
WSGIApplicationGroup %{GLOBAL}
|
||||||
|
AllowOverride All
|
||||||
|
Require all granted
|
||||||
|
</Directory>
|
||||||
|
</VirtualHost>
|
||||||
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Add notifications related to Action plan object.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
---
|
---
|
||||||
features:
|
features:
|
||||||
- Add superseded state for an action plan if the cluster data model has
|
- Check the creation time of the action plan,
|
||||||
changed after it has been created.
|
and set its state to SUPERSEDED if it has expired.
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Added SUSPENDED audit state
|
||||||
@@ -1,3 +1,16 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
# watcher documentation build configuration file, created by
|
# watcher documentation build configuration file, created by
|
||||||
# sphinx-quickstart on Fri Jun 3 11:37:52 2016.
|
# sphinx-quickstart on Fri Jun 3 11:37:52 2016.
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -1,3 +1,17 @@
|
|||||||
|
..
|
||||||
|
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.
|
||||||
|
|
||||||
|
=================================================
|
||||||
Welcome to watcher's Release Notes documentation!
|
Welcome to watcher's Release Notes documentation!
|
||||||
=================================================
|
=================================================
|
||||||
|
|
||||||
@@ -7,5 +21,6 @@ Contents:
|
|||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
|
||||||
unreleased
|
unreleased
|
||||||
|
ocata
|
||||||
newton
|
newton
|
||||||
|
|
||||||
|
|||||||
33
releasenotes/source/locale/fr/LC_MESSAGES/releasenotes.po
Normal file
33
releasenotes/source/locale/fr/LC_MESSAGES/releasenotes.po
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# Gérald LONLAS <g.lonlas@gmail.com>, 2016. #zanata
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: watcher 1.0.1.dev51\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2017-03-21 11:57+0000\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"PO-Revision-Date: 2016-10-22 06:44+0000\n"
|
||||||
|
"Last-Translator: Gérald LONLAS <g.lonlas@gmail.com>\n"
|
||||||
|
"Language-Team: French\n"
|
||||||
|
"Language: fr\n"
|
||||||
|
"X-Generator: Zanata 3.9.6\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n > 1)\n"
|
||||||
|
|
||||||
|
msgid "0.29.0"
|
||||||
|
msgstr "0.29.0"
|
||||||
|
|
||||||
|
msgid "Contents:"
|
||||||
|
msgstr "Contenu :"
|
||||||
|
|
||||||
|
msgid "Current Series Release Notes"
|
||||||
|
msgstr "Note de la release actuelle"
|
||||||
|
|
||||||
|
msgid "New Features"
|
||||||
|
msgstr "Nouvelles fonctionnalités"
|
||||||
|
|
||||||
|
msgid "Newton Series Release Notes"
|
||||||
|
msgstr "Note de release pour Newton"
|
||||||
|
|
||||||
|
msgid "Welcome to watcher's Release Notes documentation!"
|
||||||
|
msgstr "Bienvenue dans la documentation de la note de Release de Watcher"
|
||||||
6
releasenotes/source/ocata.rst
Normal file
6
releasenotes/source/ocata.rst
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
===================================
|
||||||
|
Ocata Series Release Notes
|
||||||
|
===================================
|
||||||
|
|
||||||
|
.. release-notes::
|
||||||
|
:branch: origin/stable/ocata
|
||||||
@@ -10,36 +10,37 @@ keystonemiddleware>=4.12.0 # Apache-2.0
|
|||||||
lxml!=3.7.0,>=2.3 # BSD
|
lxml!=3.7.0,>=2.3 # BSD
|
||||||
oslo.concurrency>=3.8.0 # Apache-2.0
|
oslo.concurrency>=3.8.0 # Apache-2.0
|
||||||
oslo.cache>=1.5.0 # Apache-2.0
|
oslo.cache>=1.5.0 # Apache-2.0
|
||||||
oslo.config!=3.18.0,>=3.14.0 # Apache-2.0
|
oslo.config>=3.22.0 # Apache-2.0
|
||||||
oslo.context>=2.9.0 # Apache-2.0
|
oslo.context>=2.12.0 # Apache-2.0
|
||||||
oslo.db>=4.15.0 # Apache-2.0
|
oslo.db>=4.19.0 # Apache-2.0
|
||||||
oslo.i18n>=2.1.0 # Apache-2.0
|
oslo.i18n>=2.1.0 # Apache-2.0
|
||||||
oslo.log>=3.11.0 # Apache-2.0
|
oslo.log>=3.22.0 # Apache-2.0
|
||||||
oslo.messaging>=5.14.0 # Apache-2.0
|
oslo.messaging>=5.19.0 # Apache-2.0
|
||||||
oslo.policy>=1.17.0 # Apache-2.0
|
oslo.policy>=1.17.0 # Apache-2.0
|
||||||
oslo.reports>=0.6.0 # Apache-2.0
|
oslo.reports>=0.6.0 # Apache-2.0
|
||||||
oslo.serialization>=1.10.0 # Apache-2.0
|
oslo.serialization>=1.10.0 # Apache-2.0
|
||||||
oslo.service>=1.10.0 # Apache-2.0
|
oslo.service>=1.10.0 # Apache-2.0
|
||||||
oslo.utils>=3.18.0 # Apache-2.0
|
oslo.utils>=3.20.0 # Apache-2.0
|
||||||
oslo.versionedobjects>=1.17.0 # Apache-2.0
|
oslo.versionedobjects>=1.17.0 # Apache-2.0
|
||||||
PasteDeploy>=1.5.0 # MIT
|
PasteDeploy>=1.5.0 # MIT
|
||||||
pbr>=1.8 # Apache-2.0
|
pbr!=2.1.0,>=2.0.0 # Apache-2.0
|
||||||
pecan!=1.0.2,!=1.0.3,!=1.0.4,!=1.2,>=1.0.0 # BSD
|
pecan!=1.0.2,!=1.0.3,!=1.0.4,!=1.2,>=1.0.0 # BSD
|
||||||
PrettyTable<0.8,>=0.7.1 # BSD
|
PrettyTable<0.8,>=0.7.1 # BSD
|
||||||
voluptuous>=0.8.9 # BSD License
|
voluptuous>=0.8.9 # BSD License
|
||||||
|
gnocchiclient>=2.7.0 # Apache-2.0
|
||||||
python-ceilometerclient>=2.5.0 # Apache-2.0
|
python-ceilometerclient>=2.5.0 # Apache-2.0
|
||||||
python-cinderclient!=1.7.0,!=1.7.1,>=1.6.0 # Apache-2.0
|
python-cinderclient>=2.0.1 # Apache-2.0
|
||||||
python-glanceclient>=2.5.0 # Apache-2.0
|
python-glanceclient>=2.5.0 # Apache-2.0
|
||||||
python-keystoneclient>=3.8.0 # Apache-2.0
|
python-keystoneclient>=3.8.0 # Apache-2.0
|
||||||
python-monascaclient>=1.1.0 # Apache-2.0
|
python-monascaclient>=1.1.0 # Apache-2.0
|
||||||
python-neutronclient>=5.1.0 # Apache-2.0
|
python-neutronclient>=5.1.0 # Apache-2.0
|
||||||
python-novaclient!=7.0.0,>=6.0.0 # Apache-2.0
|
python-novaclient>=7.1.0 # Apache-2.0
|
||||||
python-openstackclient>=3.3.0 # Apache-2.0
|
python-openstackclient>=3.3.0 # Apache-2.0
|
||||||
six>=1.9.0 # MIT
|
six>=1.9.0 # MIT
|
||||||
SQLAlchemy<1.1.0,>=1.0.10 # MIT
|
SQLAlchemy!=1.1.5,!=1.1.6,!=1.1.7,!=1.1.8,>=1.0.10 # MIT
|
||||||
stevedore>=1.17.1 # Apache-2.0
|
stevedore>=1.20.0 # Apache-2.0
|
||||||
taskflow>=2.7.0 # Apache-2.0
|
taskflow>=2.7.0 # Apache-2.0
|
||||||
WebOb>=1.6.0 # MIT
|
WebOb>=1.7.1 # MIT
|
||||||
WSME>=0.8 # MIT
|
WSME>=0.8 # MIT
|
||||||
networkx>=1.10 # BSD
|
networkx>=1.10 # BSD
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ classifier =
|
|||||||
Programming Language :: Python :: 2
|
Programming Language :: Python :: 2
|
||||||
Programming Language :: Python :: 2.7
|
Programming Language :: Python :: 2.7
|
||||||
Programming Language :: Python :: 3
|
Programming Language :: Python :: 3
|
||||||
Programming Language :: Python :: 3.4
|
|
||||||
Programming Language :: Python :: 3.5
|
Programming Language :: Python :: 3.5
|
||||||
|
|
||||||
[files]
|
[files]
|
||||||
|
|||||||
2
setup.py
2
setup.py
@@ -25,5 +25,5 @@ except ImportError:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
setuptools.setup(
|
setuptools.setup(
|
||||||
setup_requires=['pbr>=1.8'],
|
setup_requires=['pbr>=2.0.0'],
|
||||||
pbr=True)
|
pbr=True)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
coverage>=4.0 # Apache-2.0
|
coverage>=4.0 # Apache-2.0
|
||||||
doc8 # Apache-2.0
|
doc8 # Apache-2.0
|
||||||
freezegun>=0.3.6 # Apache-2.0
|
freezegun>=0.3.6 # Apache-2.0
|
||||||
hacking<0.11,>=0.10.2
|
hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0
|
||||||
mock>=2.0 # BSD
|
mock>=2.0 # BSD
|
||||||
oslotest>=1.10.0 # Apache-2.0
|
oslotest>=1.10.0 # Apache-2.0
|
||||||
os-testr>=0.8.0 # Apache-2.0
|
os-testr>=0.8.0 # Apache-2.0
|
||||||
@@ -16,7 +16,7 @@ testtools>=1.4.0 # MIT
|
|||||||
|
|
||||||
# Doc requirements
|
# Doc requirements
|
||||||
oslosphinx>=4.7.0 # Apache-2.0
|
oslosphinx>=4.7.0 # Apache-2.0
|
||||||
sphinx!=1.3b1,<1.4,>=1.2.1 # BSD
|
sphinx>=1.5.1 # BSD
|
||||||
sphinxcontrib-pecanwsme>=0.8 # Apache-2.0
|
sphinxcontrib-pecanwsme>=0.8 # Apache-2.0
|
||||||
|
|
||||||
# releasenotes
|
# releasenotes
|
||||||
|
|||||||
4
tox.ini
4
tox.ini
@@ -1,6 +1,6 @@
|
|||||||
[tox]
|
[tox]
|
||||||
minversion = 1.8
|
minversion = 1.8
|
||||||
envlist = py35,py34,py27,pep8
|
envlist = py35,py27,pep8
|
||||||
skipsdist = True
|
skipsdist = True
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
@@ -45,7 +45,7 @@ commands =
|
|||||||
|
|
||||||
[flake8]
|
[flake8]
|
||||||
show-source=True
|
show-source=True
|
||||||
ignore=
|
ignore= H105,E123,E226,N320
|
||||||
builtins= _
|
builtins= _
|
||||||
exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build,*sqlalchemy/alembic/versions/*,demo/,releasenotes
|
exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build,*sqlalchemy/alembic/versions/*,demo/,releasenotes
|
||||||
|
|
||||||
|
|||||||
40
watcher/api/app.wsgi
Normal file
40
watcher/api/app.wsgi
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
# -*- mode: python -*-
|
||||||
|
# -*- encoding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
"""
|
||||||
|
Use this file for deploying the API service under Apache2 mod_wsgi.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from oslo_config import cfg
|
||||||
|
import oslo_i18n as i18n
|
||||||
|
from oslo_log import log
|
||||||
|
|
||||||
|
from watcher.api import app
|
||||||
|
from watcher.common import service
|
||||||
|
|
||||||
|
|
||||||
|
CONF = cfg.CONF
|
||||||
|
|
||||||
|
i18n.install('watcher')
|
||||||
|
|
||||||
|
service.prepare_service(sys.argv)
|
||||||
|
|
||||||
|
LOG = log.getLogger(__name__)
|
||||||
|
LOG.debug("Configuration:")
|
||||||
|
CONF.log_opt_values(LOG, log.DEBUG)
|
||||||
|
|
||||||
|
application = app.VersionSelectorApplication()
|
||||||
|
|
||||||
@@ -455,7 +455,8 @@ class ActionPlansController(rest.RestController):
|
|||||||
:param action_plan_uuid: UUID of a action.
|
:param action_plan_uuid: UUID of a action.
|
||||||
"""
|
"""
|
||||||
context = pecan.request.context
|
context = pecan.request.context
|
||||||
action_plan = api_utils.get_resource('ActionPlan', action_plan_uuid)
|
action_plan = api_utils.get_resource(
|
||||||
|
'ActionPlan', action_plan_uuid, eager=True)
|
||||||
policy.enforce(context, 'action_plan:delete', action_plan,
|
policy.enforce(context, 'action_plan:delete', action_plan,
|
||||||
action='action_plan:delete')
|
action='action_plan:delete')
|
||||||
|
|
||||||
@@ -474,8 +475,8 @@ class ActionPlansController(rest.RestController):
|
|||||||
raise exception.OperationNotPermitted
|
raise exception.OperationNotPermitted
|
||||||
|
|
||||||
context = pecan.request.context
|
context = pecan.request.context
|
||||||
action_plan_to_update = api_utils.get_resource('ActionPlan',
|
action_plan_to_update = api_utils.get_resource(
|
||||||
action_plan_uuid)
|
'ActionPlan', action_plan_uuid, eager=True)
|
||||||
policy.enforce(context, 'action_plan:update', action_plan_to_update,
|
policy.enforce(context, 'action_plan:update', action_plan_to_update,
|
||||||
action='action_plan:update')
|
action='action_plan:update')
|
||||||
|
|
||||||
|
|||||||
@@ -129,8 +129,15 @@ class AuditPatchType(types.JsonPatchType):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def validate(patch):
|
def validate(patch):
|
||||||
serialized_patch = {'path': patch.path, 'op': patch.op}
|
|
||||||
if patch.path in AuditPatchType.mandatory_attrs():
|
def is_new_state_none(p):
|
||||||
|
return p.path == '/state' and p.op == 'replace' and p.value is None
|
||||||
|
|
||||||
|
serialized_patch = {'path': patch.path,
|
||||||
|
'op': patch.op,
|
||||||
|
'value': patch.value}
|
||||||
|
if (patch.path in AuditPatchType.mandatory_attrs() or
|
||||||
|
is_new_state_none(patch)):
|
||||||
msg = _("%(field)s can't be updated.")
|
msg = _("%(field)s can't be updated.")
|
||||||
raise exception.PatchError(
|
raise exception.PatchError(
|
||||||
patch=serialized_patch,
|
patch=serialized_patch,
|
||||||
@@ -294,7 +301,7 @@ class Audit(base.APIBase):
|
|||||||
audit.unset_fields_except(['uuid', 'audit_type', 'state',
|
audit.unset_fields_except(['uuid', 'audit_type', 'state',
|
||||||
'goal_uuid', 'interval', 'scope',
|
'goal_uuid', 'interval', 'scope',
|
||||||
'strategy_uuid', 'goal_name',
|
'strategy_uuid', 'goal_name',
|
||||||
'strategy_name'])
|
'strategy_name', 'auto_trigger'])
|
||||||
|
|
||||||
audit.links = [link.Link.make_link('self', url,
|
audit.links = [link.Link.make_link('self', url,
|
||||||
'audits', audit.uuid),
|
'audits', audit.uuid),
|
||||||
@@ -557,6 +564,18 @@ class AuditsController(rest.RestController):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
audit_dict = audit_to_update.as_dict()
|
audit_dict = audit_to_update.as_dict()
|
||||||
|
|
||||||
|
initial_state = audit_dict['state']
|
||||||
|
new_state = api_utils.get_patch_value(patch, 'state')
|
||||||
|
if not api_utils.check_audit_state_transition(
|
||||||
|
patch, initial_state):
|
||||||
|
error_message = _("State transition not allowed: "
|
||||||
|
"(%(initial_state)s -> %(new_state)s)")
|
||||||
|
raise exception.PatchError(
|
||||||
|
patch=patch,
|
||||||
|
reason=error_message % dict(
|
||||||
|
initial_state=initial_state, new_state=new_state))
|
||||||
|
|
||||||
audit = Audit(**api_utils.apply_jsonpatch(audit_dict, patch))
|
audit = Audit(**api_utils.apply_jsonpatch(audit_dict, patch))
|
||||||
except api_utils.JSONPATCH_EXCEPTIONS as e:
|
except api_utils.JSONPATCH_EXCEPTIONS as e:
|
||||||
raise exception.PatchError(patch=patch, reason=e)
|
raise exception.PatchError(patch=patch, reason=e)
|
||||||
|
|||||||
@@ -333,6 +333,7 @@ class AuditTemplate(base.APIBase):
|
|||||||
|
|
||||||
self.fields.append('goal_id')
|
self.fields.append('goal_id')
|
||||||
self.fields.append('strategy_id')
|
self.fields.append('strategy_id')
|
||||||
|
setattr(self, 'strategy_id', kwargs.get('strategy_id', wtypes.Unset))
|
||||||
|
|
||||||
# goal_uuid & strategy_uuid are not part of
|
# goal_uuid & strategy_uuid are not part of
|
||||||
# objects.AuditTemplate.fields because they're API-only attributes.
|
# objects.AuditTemplate.fields because they're API-only attributes.
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ import wsme
|
|||||||
from wsme import types as wtypes
|
from wsme import types as wtypes
|
||||||
import wsmeext.pecan as wsme_pecan
|
import wsmeext.pecan as wsme_pecan
|
||||||
|
|
||||||
from watcher._i18n import _LW
|
|
||||||
from watcher.api.controllers import base
|
from watcher.api.controllers import base
|
||||||
from watcher.api.controllers import link
|
from watcher.api.controllers import link
|
||||||
from watcher.api.controllers.v1 import collection
|
from watcher.api.controllers.v1 import collection
|
||||||
@@ -56,8 +55,8 @@ class Service(base.APIBase):
|
|||||||
def _get_status(self):
|
def _get_status(self):
|
||||||
return self._status
|
return self._status
|
||||||
|
|
||||||
def _set_status(self, name):
|
def _set_status(self, id):
|
||||||
service = objects.Service.get_by_name(pecan.request.context, name)
|
service = objects.Service.get(pecan.request.context, id)
|
||||||
last_heartbeat = (service.last_seen_up or service.updated_at
|
last_heartbeat = (service.last_seen_up or service.updated_at
|
||||||
or service.created_at)
|
or service.created_at)
|
||||||
if isinstance(last_heartbeat, six.string_types):
|
if isinstance(last_heartbeat, six.string_types):
|
||||||
@@ -72,9 +71,9 @@ class Service(base.APIBase):
|
|||||||
elapsed = timeutils.delta_seconds(last_heartbeat, timeutils.utcnow())
|
elapsed = timeutils.delta_seconds(last_heartbeat, timeutils.utcnow())
|
||||||
is_up = abs(elapsed) <= CONF.service_down_time
|
is_up = abs(elapsed) <= CONF.service_down_time
|
||||||
if not is_up:
|
if not is_up:
|
||||||
LOG.warning(_LW('Seems service %(name)s on host %(host)s is down. '
|
LOG.warning('Seems service %(name)s on host %(host)s is down. '
|
||||||
'Last heartbeat was %(lhb)s.'
|
'Last heartbeat was %(lhb)s.'
|
||||||
'Elapsed time is %(el)s'),
|
'Elapsed time is %(el)s',
|
||||||
{'name': service.name,
|
{'name': service.name,
|
||||||
'host': service.host,
|
'host': service.host,
|
||||||
'lhb': str(last_heartbeat), 'el': str(elapsed)})
|
'lhb': str(last_heartbeat), 'el': str(elapsed)})
|
||||||
@@ -108,7 +107,7 @@ class Service(base.APIBase):
|
|||||||
for field in fields:
|
for field in fields:
|
||||||
self.fields.append(field)
|
self.fields.append(field)
|
||||||
setattr(self, field, kwargs.get(
|
setattr(self, field, kwargs.get(
|
||||||
field if field != 'status' else 'name', wtypes.Unset))
|
field if field != 'status' else 'id', wtypes.Unset))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _convert_with_links(service, url, expand=True):
|
def _convert_with_links(service, url, expand=True):
|
||||||
|
|||||||
@@ -73,6 +73,21 @@ def apply_jsonpatch(doc, patch):
|
|||||||
return jsonpatch.apply_patch(doc, jsonpatch.JsonPatch(patch))
|
return jsonpatch.apply_patch(doc, jsonpatch.JsonPatch(patch))
|
||||||
|
|
||||||
|
|
||||||
|
def get_patch_value(patch, key):
|
||||||
|
for p in patch:
|
||||||
|
if p['op'] == 'replace' and p['path'] == '/%s' % key:
|
||||||
|
return p['value']
|
||||||
|
|
||||||
|
|
||||||
|
def check_audit_state_transition(patch, initial):
|
||||||
|
is_transition_valid = True
|
||||||
|
state_value = get_patch_value(patch, "state")
|
||||||
|
if state_value is not None:
|
||||||
|
is_transition_valid = objects.audit.AuditStateTransitionManager(
|
||||||
|
).check_transition(initial, state_value)
|
||||||
|
return is_transition_valid
|
||||||
|
|
||||||
|
|
||||||
def as_filters_dict(**filters):
|
def as_filters_dict(**filters):
|
||||||
filters_dict = {}
|
filters_dict = {}
|
||||||
for filter_name, filter_value in filters.items():
|
for filter_name, filter_value in filters.items():
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ from oslo_serialization import jsonutils
|
|||||||
import six
|
import six
|
||||||
import webob
|
import webob
|
||||||
|
|
||||||
from watcher._i18n import _, _LE
|
from watcher._i18n import _
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ class ParsableErrorMiddleware(object):
|
|||||||
et.ElementTree.Element(
|
et.ElementTree.Element(
|
||||||
'error_message', text='\n'.join(app_iter)))]
|
'error_message', text='\n'.join(app_iter)))]
|
||||||
except et.ElementTree.ParseError as err:
|
except et.ElementTree.ParseError as err:
|
||||||
LOG.error(_LE('Error parsing HTTP response: %s'), err)
|
LOG.error('Error parsing HTTP response: %s', err)
|
||||||
body = ['<error_message>%s'
|
body = ['<error_message>%s'
|
||||||
'</error_message>' % state['status_code']]
|
'</error_message>' % state['status_code']]
|
||||||
state['headers'].append(('Content-Type', 'application/xml'))
|
state['headers'].append(('Content-Type', 'application/xml'))
|
||||||
|
|||||||
@@ -20,32 +20,47 @@ from oslo_log import log
|
|||||||
|
|
||||||
from watcher.applier.action_plan import base
|
from watcher.applier.action_plan import base
|
||||||
from watcher.applier import default
|
from watcher.applier import default
|
||||||
|
from watcher import notifications
|
||||||
from watcher import objects
|
from watcher import objects
|
||||||
|
from watcher.objects import fields
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class DefaultActionPlanHandler(base.BaseActionPlanHandler):
|
class DefaultActionPlanHandler(base.BaseActionPlanHandler):
|
||||||
|
|
||||||
def __init__(self, context, service, action_plan_uuid):
|
def __init__(self, context, service, action_plan_uuid):
|
||||||
super(DefaultActionPlanHandler, self).__init__()
|
super(DefaultActionPlanHandler, self).__init__()
|
||||||
self.ctx = context
|
self.ctx = context
|
||||||
self.service = service
|
self.service = service
|
||||||
self.action_plan_uuid = action_plan_uuid
|
self.action_plan_uuid = action_plan_uuid
|
||||||
|
|
||||||
def update_action_plan(self, uuid, state):
|
|
||||||
action_plan = objects.ActionPlan.get_by_uuid(self.ctx, uuid)
|
|
||||||
action_plan.state = state
|
|
||||||
action_plan.save()
|
|
||||||
|
|
||||||
def execute(self):
|
def execute(self):
|
||||||
try:
|
try:
|
||||||
self.update_action_plan(self.action_plan_uuid,
|
action_plan = objects.ActionPlan.get_by_uuid(
|
||||||
objects.action_plan.State.ONGOING)
|
self.ctx, self.action_plan_uuid, eager=True)
|
||||||
|
action_plan.state = objects.action_plan.State.ONGOING
|
||||||
|
action_plan.save()
|
||||||
|
notifications.action_plan.send_action_notification(
|
||||||
|
self.ctx, action_plan,
|
||||||
|
action=fields.NotificationAction.EXECUTION,
|
||||||
|
phase=fields.NotificationPhase.START)
|
||||||
|
|
||||||
applier = default.DefaultApplier(self.ctx, self.service)
|
applier = default.DefaultApplier(self.ctx, self.service)
|
||||||
applier.execute(self.action_plan_uuid)
|
applier.execute(self.action_plan_uuid)
|
||||||
state = objects.action_plan.State.SUCCEEDED
|
|
||||||
|
action_plan.state = objects.action_plan.State.SUCCEEDED
|
||||||
|
notifications.action_plan.send_action_notification(
|
||||||
|
self.ctx, action_plan,
|
||||||
|
action=fields.NotificationAction.EXECUTION,
|
||||||
|
phase=fields.NotificationPhase.END)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOG.exception(e)
|
LOG.exception(e)
|
||||||
state = objects.action_plan.State.FAILED
|
action_plan.state = objects.action_plan.State.FAILED
|
||||||
|
notifications.action_plan.send_action_notification(
|
||||||
|
self.ctx, action_plan,
|
||||||
|
action=fields.NotificationAction.EXECUTION,
|
||||||
|
priority=fields.NotificationPriority.ERROR,
|
||||||
|
phase=fields.NotificationPhase.ERROR)
|
||||||
finally:
|
finally:
|
||||||
self.update_action_plan(self.action_plan_uuid, state)
|
action_plan.save()
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ from oslo_log import log
|
|||||||
import six
|
import six
|
||||||
import voluptuous
|
import voluptuous
|
||||||
|
|
||||||
from watcher._i18n import _, _LC
|
from watcher._i18n import _
|
||||||
from watcher.applier.actions import base
|
from watcher.applier.actions import base
|
||||||
from watcher.common import exception
|
from watcher.common import exception
|
||||||
from watcher.common import nova_helper
|
from watcher.common import nova_helper
|
||||||
@@ -120,9 +120,9 @@ class Migrate(base.BaseAction):
|
|||||||
"migrating instance %s.Exception: %s" %
|
"migrating instance %s.Exception: %s" %
|
||||||
(self.instance_uuid, e))
|
(self.instance_uuid, e))
|
||||||
except Exception:
|
except Exception:
|
||||||
LOG.critical(_LC("Unexpected error occurred. Migration failed for "
|
LOG.critical("Unexpected error occurred. Migration failed for "
|
||||||
"instance %s. Leaving instance on previous "
|
"instance %s. Leaving instance on previous "
|
||||||
"host."), self.instance_uuid)
|
"host.", self.instance_uuid)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@@ -134,9 +134,9 @@ class Migrate(base.BaseAction):
|
|||||||
dest_hostname=destination)
|
dest_hostname=destination)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
LOG.exception(exc)
|
LOG.exception(exc)
|
||||||
LOG.critical(_LC("Unexpected error occurred. Migration failed for "
|
LOG.critical("Unexpected error occurred. Migration failed for "
|
||||||
"instance %s. Leaving instance on previous "
|
"instance %s. Leaving instance on previous "
|
||||||
"host."), self.instance_uuid)
|
"host.", self.instance_uuid)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ from oslo_log import log
|
|||||||
import six
|
import six
|
||||||
import voluptuous
|
import voluptuous
|
||||||
|
|
||||||
from watcher._i18n import _, _LC
|
from watcher._i18n import _
|
||||||
from watcher.applier.actions import base
|
from watcher.applier.actions import base
|
||||||
from watcher.common import nova_helper
|
from watcher.common import nova_helper
|
||||||
from watcher.common import utils
|
from watcher.common import utils
|
||||||
@@ -86,8 +86,8 @@ class Resize(base.BaseAction):
|
|||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
LOG.exception(exc)
|
LOG.exception(exc)
|
||||||
LOG.critical(
|
LOG.critical(
|
||||||
_LC("Unexpected error occurred. Resizing failed for "
|
"Unexpected error occurred. Resizing failed for "
|
||||||
"instance %s."), self.instance_uuid)
|
"instance %s.", self.instance_uuid)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def execute(self):
|
def execute(self):
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ class DefaultApplier(base.BaseApplier):
|
|||||||
|
|
||||||
def execute(self, action_plan_uuid):
|
def execute(self, action_plan_uuid):
|
||||||
LOG.debug("Executing action plan %s ", action_plan_uuid)
|
LOG.debug("Executing action plan %s ", action_plan_uuid)
|
||||||
|
|
||||||
filters = {'action_plan_uuid': action_plan_uuid}
|
filters = {'action_plan_uuid': action_plan_uuid}
|
||||||
actions = objects.Action.list(self.context,
|
actions = objects.Action.list(self.context, filters=filters)
|
||||||
filters=filters)
|
|
||||||
return self.engine.execute(actions)
|
return self.engine.execute(actions)
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class ApplierAPI(service.Service):
|
|||||||
if not utils.is_uuid_like(action_plan_uuid):
|
if not utils.is_uuid_like(action_plan_uuid):
|
||||||
raise exception.InvalidUuidOrName(name=action_plan_uuid)
|
raise exception.InvalidUuidOrName(name=action_plan_uuid)
|
||||||
|
|
||||||
return self.conductor_client.call(
|
self.conductor_client.cast(
|
||||||
context, 'launch_action_plan', action_plan_uuid=action_plan_uuid)
|
context, 'launch_action_plan', action_plan_uuid=action_plan_uuid)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -18,12 +18,19 @@
|
|||||||
|
|
||||||
import abc
|
import abc
|
||||||
|
|
||||||
|
from oslo_log import log
|
||||||
import six
|
import six
|
||||||
|
from taskflow import task as flow_task
|
||||||
|
|
||||||
from watcher.applier.actions import factory
|
from watcher.applier.actions import factory
|
||||||
from watcher.common import clients
|
from watcher.common import clients
|
||||||
from watcher.common.loader import loadable
|
from watcher.common.loader import loadable
|
||||||
|
from watcher import notifications
|
||||||
from watcher import objects
|
from watcher import objects
|
||||||
|
from watcher.objects import fields
|
||||||
|
|
||||||
|
|
||||||
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@six.add_metaclass(abc.ABCMeta)
|
@six.add_metaclass(abc.ABCMeta)
|
||||||
@@ -72,11 +79,95 @@ class BaseWorkFlowEngine(loadable.Loadable):
|
|||||||
return self._action_factory
|
return self._action_factory
|
||||||
|
|
||||||
def notify(self, action, state):
|
def notify(self, action, state):
|
||||||
db_action = objects.Action.get_by_uuid(self.context, action.uuid)
|
db_action = objects.Action.get_by_uuid(self.context, action.uuid,
|
||||||
|
eager=True)
|
||||||
db_action.state = state
|
db_action.state = state
|
||||||
db_action.save()
|
db_action.save()
|
||||||
# NOTE(v-francoise): Implement notifications for action
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def execute(self, actions):
|
def execute(self, actions):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
|
class BaseTaskFlowActionContainer(flow_task.Task):
|
||||||
|
|
||||||
|
def __init__(self, name, db_action, engine, **kwargs):
|
||||||
|
super(BaseTaskFlowActionContainer, self).__init__(name=name)
|
||||||
|
self._db_action = db_action
|
||||||
|
self._engine = engine
|
||||||
|
self.loaded_action = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def engine(self):
|
||||||
|
return self._engine
|
||||||
|
|
||||||
|
@property
|
||||||
|
def action(self):
|
||||||
|
if self.loaded_action is None:
|
||||||
|
action = self.engine.action_factory.make_action(
|
||||||
|
self._db_action,
|
||||||
|
osc=self._engine.osc)
|
||||||
|
self.loaded_action = action
|
||||||
|
return self.loaded_action
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def do_pre_execute(self):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def do_execute(self, *args, **kwargs):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def do_post_execute(self):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
# NOTE(alexchadin): taskflow does 3 method calls (pre_execute, execute,
|
||||||
|
# post_execute) independently. We want to support notifications in base
|
||||||
|
# class, so child's methods should be named with `do_` prefix and wrapped.
|
||||||
|
def pre_execute(self):
|
||||||
|
try:
|
||||||
|
self.do_pre_execute()
|
||||||
|
notifications.action.send_execution_notification(
|
||||||
|
self.engine.context, self._db_action,
|
||||||
|
fields.NotificationAction.EXECUTION,
|
||||||
|
fields.NotificationPhase.START)
|
||||||
|
except Exception as e:
|
||||||
|
LOG.exception(e)
|
||||||
|
self.engine.notify(self._db_action, objects.action.State.FAILED)
|
||||||
|
notifications.action.send_execution_notification(
|
||||||
|
self.engine.context, self._db_action,
|
||||||
|
fields.NotificationAction.EXECUTION,
|
||||||
|
fields.NotificationPhase.ERROR,
|
||||||
|
priority=fields.NotificationPriority.ERROR)
|
||||||
|
|
||||||
|
def execute(self, *args, **kwargs):
|
||||||
|
try:
|
||||||
|
self.do_execute(*args, **kwargs)
|
||||||
|
notifications.action.send_execution_notification(
|
||||||
|
self.engine.context, self._db_action,
|
||||||
|
fields.NotificationAction.EXECUTION,
|
||||||
|
fields.NotificationPhase.END)
|
||||||
|
except Exception as e:
|
||||||
|
LOG.exception(e)
|
||||||
|
LOG.error('The workflow engine has failed '
|
||||||
|
'to execute the action: %s', self.name)
|
||||||
|
self.engine.notify(self._db_action, objects.action.State.FAILED)
|
||||||
|
notifications.action.send_execution_notification(
|
||||||
|
self.engine.context, self._db_action,
|
||||||
|
fields.NotificationAction.EXECUTION,
|
||||||
|
fields.NotificationPhase.ERROR,
|
||||||
|
priority=fields.NotificationPriority.ERROR)
|
||||||
|
raise
|
||||||
|
|
||||||
|
def post_execute(self):
|
||||||
|
try:
|
||||||
|
self.do_post_execute()
|
||||||
|
except Exception as e:
|
||||||
|
LOG.exception(e)
|
||||||
|
self.engine.notify(self._db_action, objects.action.State.FAILED)
|
||||||
|
notifications.action.send_execution_notification(
|
||||||
|
self.engine.context, self._db_action,
|
||||||
|
fields.NotificationAction.EXECUTION,
|
||||||
|
fields.NotificationPhase.ERROR,
|
||||||
|
priority=fields.NotificationPriority.ERROR)
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ from taskflow import engines
|
|||||||
from taskflow.patterns import graph_flow as gf
|
from taskflow.patterns import graph_flow as gf
|
||||||
from taskflow import task as flow_task
|
from taskflow import task as flow_task
|
||||||
|
|
||||||
from watcher._i18n import _LE, _LW, _LC
|
|
||||||
from watcher.applier.workflow_engine import base
|
from watcher.applier.workflow_engine import base
|
||||||
from watcher.common import exception
|
from watcher.common import exception
|
||||||
from watcher import objects
|
from watcher import objects
|
||||||
@@ -95,69 +94,35 @@ class DefaultWorkFlowEngine(base.BaseWorkFlowEngine):
|
|||||||
raise exception.WorkflowExecutionException(error=e)
|
raise exception.WorkflowExecutionException(error=e)
|
||||||
|
|
||||||
|
|
||||||
class TaskFlowActionContainer(flow_task.Task):
|
class TaskFlowActionContainer(base.BaseTaskFlowActionContainer):
|
||||||
def __init__(self, db_action, engine):
|
def __init__(self, db_action, engine):
|
||||||
name = "action_type:{0} uuid:{1}".format(db_action.action_type,
|
name = "action_type:{0} uuid:{1}".format(db_action.action_type,
|
||||||
db_action.uuid)
|
db_action.uuid)
|
||||||
super(TaskFlowActionContainer, self).__init__(name=name)
|
super(TaskFlowActionContainer, self).__init__(name, db_action, engine)
|
||||||
self._db_action = db_action
|
|
||||||
self._engine = engine
|
|
||||||
self.loaded_action = None
|
|
||||||
|
|
||||||
@property
|
def do_pre_execute(self):
|
||||||
def action(self):
|
self.engine.notify(self._db_action, objects.action.State.ONGOING)
|
||||||
if self.loaded_action is None:
|
LOG.debug("Pre-condition action: %s", self.name)
|
||||||
action = self.engine.action_factory.make_action(
|
self.action.pre_condition()
|
||||||
self._db_action,
|
|
||||||
osc=self._engine.osc)
|
|
||||||
self.loaded_action = action
|
|
||||||
return self.loaded_action
|
|
||||||
|
|
||||||
@property
|
def do_execute(self, *args, **kwargs):
|
||||||
def engine(self):
|
LOG.debug("Running action: %s", self.name)
|
||||||
return self._engine
|
|
||||||
|
|
||||||
def pre_execute(self):
|
self.action.execute()
|
||||||
try:
|
self.engine.notify(self._db_action, objects.action.State.SUCCEEDED)
|
||||||
self.engine.notify(self._db_action, objects.action.State.ONGOING)
|
|
||||||
LOG.debug("Pre-condition action: %s", self.name)
|
|
||||||
self.action.pre_condition()
|
|
||||||
except Exception as e:
|
|
||||||
LOG.exception(e)
|
|
||||||
self.engine.notify(self._db_action, objects.action.State.FAILED)
|
|
||||||
raise
|
|
||||||
|
|
||||||
def execute(self, *args, **kwargs):
|
def do_post_execute(self):
|
||||||
try:
|
LOG.debug("Post-condition action: %s", self.name)
|
||||||
LOG.debug("Running action: %s", self.name)
|
self.action.post_condition()
|
||||||
|
|
||||||
self.action.execute()
|
|
||||||
self.engine.notify(self._db_action, objects.action.State.SUCCEEDED)
|
|
||||||
except Exception as e:
|
|
||||||
LOG.exception(e)
|
|
||||||
LOG.error(_LE('The workflow engine has failed '
|
|
||||||
'to execute the action: %s'), self.name)
|
|
||||||
|
|
||||||
self.engine.notify(self._db_action, objects.action.State.FAILED)
|
|
||||||
raise
|
|
||||||
|
|
||||||
def post_execute(self):
|
|
||||||
try:
|
|
||||||
LOG.debug("Post-condition action: %s", self.name)
|
|
||||||
self.action.post_condition()
|
|
||||||
except Exception as e:
|
|
||||||
LOG.exception(e)
|
|
||||||
self.engine.notify(self._db_action, objects.action.State.FAILED)
|
|
||||||
raise
|
|
||||||
|
|
||||||
def revert(self, *args, **kwargs):
|
def revert(self, *args, **kwargs):
|
||||||
LOG.warning(_LW("Revert action: %s"), self.name)
|
LOG.warning("Revert action: %s", self.name)
|
||||||
try:
|
try:
|
||||||
# TODO(jed): do we need to update the states in case of failure?
|
# TODO(jed): do we need to update the states in case of failure?
|
||||||
self.action.revert()
|
self.action.revert()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOG.exception(e)
|
LOG.exception(e)
|
||||||
LOG.critical(_LC("Oops! We need a disaster recover plan."))
|
LOG.critical("Oops! We need a disaster recover plan.")
|
||||||
|
|
||||||
|
|
||||||
class TaskFlowNop(flow_task.Task):
|
class TaskFlowNop(flow_task.Task):
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import sys
|
|||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
|
||||||
from watcher._i18n import _LI
|
|
||||||
from watcher.common import service
|
from watcher.common import service
|
||||||
from watcher import conf
|
from watcher import conf
|
||||||
|
|
||||||
@@ -39,11 +38,11 @@ def main():
|
|||||||
server = service.WSGIService('watcher-api', CONF.api.enable_ssl_api)
|
server = service.WSGIService('watcher-api', CONF.api.enable_ssl_api)
|
||||||
|
|
||||||
if host == '127.0.0.1':
|
if host == '127.0.0.1':
|
||||||
LOG.info(_LI('serving on 127.0.0.1:%(port)s, '
|
LOG.info('serving on 127.0.0.1:%(port)s, '
|
||||||
'view at %(protocol)s://127.0.0.1:%(port)s') %
|
'view at %(protocol)s://127.0.0.1:%(port)s' %
|
||||||
dict(protocol=protocol, port=port))
|
dict(protocol=protocol, port=port))
|
||||||
else:
|
else:
|
||||||
LOG.info(_LI('serving on %(protocol)s://%(host)s:%(port)s') %
|
LOG.info('serving on %(protocol)s://%(host)s:%(port)s' %
|
||||||
dict(protocol=protocol, host=host, port=port))
|
dict(protocol=protocol, host=host, port=port))
|
||||||
|
|
||||||
launcher = service.launch(CONF, server, workers=server.workers)
|
launcher = service.launch(CONF, server, workers=server.workers)
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import sys
|
|||||||
|
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
|
||||||
from watcher._i18n import _LI
|
|
||||||
from watcher.applier import manager
|
from watcher.applier import manager
|
||||||
from watcher.common import service as watcher_service
|
from watcher.common import service as watcher_service
|
||||||
from watcher import conf
|
from watcher import conf
|
||||||
@@ -34,7 +33,7 @@ CONF = conf.CONF
|
|||||||
def main():
|
def main():
|
||||||
watcher_service.prepare_service(sys.argv, CONF)
|
watcher_service.prepare_service(sys.argv, CONF)
|
||||||
|
|
||||||
LOG.info(_LI('Starting Watcher Applier service in PID %s'), os.getpid())
|
LOG.info('Starting Watcher Applier service in PID %s', os.getpid())
|
||||||
|
|
||||||
applier_service = watcher_service.Service(manager.ApplierManager)
|
applier_service = watcher_service.Service(manager.ApplierManager)
|
||||||
|
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ def add_command_parsers(subparsers):
|
|||||||
"Optionally, use --revision to specify an alembic revision "
|
"Optionally, use --revision to specify an alembic revision "
|
||||||
"string to upgrade to.")
|
"string to upgrade to.")
|
||||||
parser.set_defaults(func=DBCommand.upgrade)
|
parser.set_defaults(func=DBCommand.upgrade)
|
||||||
parser.add_argument('--revision', nargs='?')
|
parser.add_argument('revision', nargs='?')
|
||||||
|
|
||||||
parser = subparsers.add_parser(
|
parser = subparsers.add_parser(
|
||||||
'downgrade',
|
'downgrade',
|
||||||
@@ -79,10 +79,10 @@ def add_command_parsers(subparsers):
|
|||||||
"While optional, one should generally use --revision to "
|
"While optional, one should generally use --revision to "
|
||||||
"specify the alembic revision string to downgrade to.")
|
"specify the alembic revision string to downgrade to.")
|
||||||
parser.set_defaults(func=DBCommand.downgrade)
|
parser.set_defaults(func=DBCommand.downgrade)
|
||||||
parser.add_argument('--revision', nargs='?')
|
parser.add_argument('revision', nargs='?')
|
||||||
|
|
||||||
parser = subparsers.add_parser('stamp')
|
parser = subparsers.add_parser('stamp')
|
||||||
parser.add_argument('--revision', nargs='?')
|
parser.add_argument('revision', nargs='?')
|
||||||
parser.set_defaults(func=DBCommand.stamp)
|
parser.set_defaults(func=DBCommand.stamp)
|
||||||
|
|
||||||
parser = subparsers.add_parser(
|
parser = subparsers.add_parser(
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import sys
|
|||||||
|
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
|
||||||
from watcher._i18n import _LI
|
|
||||||
from watcher.common import service as watcher_service
|
from watcher.common import service as watcher_service
|
||||||
from watcher import conf
|
from watcher import conf
|
||||||
from watcher.decision_engine import gmr
|
from watcher.decision_engine import gmr
|
||||||
@@ -38,7 +37,7 @@ def main():
|
|||||||
watcher_service.prepare_service(sys.argv, CONF)
|
watcher_service.prepare_service(sys.argv, CONF)
|
||||||
gmr.register_gmr_plugins()
|
gmr.register_gmr_plugins()
|
||||||
|
|
||||||
LOG.info(_LI('Starting Watcher Decision Engine service in PID %s'),
|
LOG.info('Starting Watcher Decision Engine service in PID %s',
|
||||||
os.getpid())
|
os.getpid())
|
||||||
|
|
||||||
syncer = sync.Syncer()
|
syncer = sync.Syncer()
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import sys
|
|||||||
|
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
|
||||||
from watcher._i18n import _LI
|
|
||||||
from watcher.common import service as service
|
from watcher.common import service as service
|
||||||
from watcher import conf
|
from watcher import conf
|
||||||
from watcher.decision_engine import sync
|
from watcher.decision_engine import sync
|
||||||
@@ -32,10 +31,10 @@ CONF = conf.CONF
|
|||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
LOG.info(_LI('Watcher sync started.'))
|
LOG.info('Watcher sync started.')
|
||||||
|
|
||||||
service.prepare_service(sys.argv, CONF)
|
service.prepare_service(sys.argv, CONF)
|
||||||
syncer = sync.Syncer()
|
syncer = sync.Syncer()
|
||||||
syncer.sync()
|
syncer.sync()
|
||||||
|
|
||||||
LOG.info(_LI('Watcher sync finished.'))
|
LOG.info('Watcher sync finished.')
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
from ceilometerclient import client as ceclient
|
from ceilometerclient import client as ceclient
|
||||||
from cinderclient import client as ciclient
|
from cinderclient import client as ciclient
|
||||||
from glanceclient import client as glclient
|
from glanceclient import client as glclient
|
||||||
|
from gnocchiclient import client as gnclient
|
||||||
from keystoneauth1 import loading as ka_loading
|
from keystoneauth1 import loading as ka_loading
|
||||||
from keystoneclient import client as keyclient
|
from keystoneclient import client as keyclient
|
||||||
from monascaclient import client as monclient
|
from monascaclient import client as monclient
|
||||||
@@ -39,6 +40,7 @@ class OpenStackClients(object):
|
|||||||
self._keystone = None
|
self._keystone = None
|
||||||
self._nova = None
|
self._nova = None
|
||||||
self._glance = None
|
self._glance = None
|
||||||
|
self._gnocchi = None
|
||||||
self._cinder = None
|
self._cinder = None
|
||||||
self._ceilometer = None
|
self._ceilometer = None
|
||||||
self._monasca = None
|
self._monasca = None
|
||||||
@@ -78,7 +80,9 @@ class OpenStackClients(object):
|
|||||||
return self._nova
|
return self._nova
|
||||||
|
|
||||||
novaclient_version = self._get_client_option('nova', 'api_version')
|
novaclient_version = self._get_client_option('nova', 'api_version')
|
||||||
|
nova_endpoint_type = self._get_client_option('nova', 'endpoint_type')
|
||||||
self._nova = nvclient.Client(novaclient_version,
|
self._nova = nvclient.Client(novaclient_version,
|
||||||
|
endpoint_type=nova_endpoint_type,
|
||||||
session=self.session)
|
session=self.session)
|
||||||
return self._nova
|
return self._nova
|
||||||
|
|
||||||
@@ -88,17 +92,37 @@ class OpenStackClients(object):
|
|||||||
return self._glance
|
return self._glance
|
||||||
|
|
||||||
glanceclient_version = self._get_client_option('glance', 'api_version')
|
glanceclient_version = self._get_client_option('glance', 'api_version')
|
||||||
|
glance_endpoint_type = self._get_client_option('glance',
|
||||||
|
'endpoint_type')
|
||||||
self._glance = glclient.Client(glanceclient_version,
|
self._glance = glclient.Client(glanceclient_version,
|
||||||
|
interface=glance_endpoint_type,
|
||||||
session=self.session)
|
session=self.session)
|
||||||
return self._glance
|
return self._glance
|
||||||
|
|
||||||
|
@exception.wrap_keystone_exception
|
||||||
|
def gnocchi(self):
|
||||||
|
if self._gnocchi:
|
||||||
|
return self._gnocchi
|
||||||
|
|
||||||
|
gnocchiclient_version = self._get_client_option('gnocchi',
|
||||||
|
'api_version')
|
||||||
|
gnocchiclient_interface = self._get_client_option('gnocchi',
|
||||||
|
'endpoint_type')
|
||||||
|
self._gnocchi = gnclient.Client(gnocchiclient_version,
|
||||||
|
interface=gnocchiclient_interface,
|
||||||
|
session=self.session)
|
||||||
|
return self._gnocchi
|
||||||
|
|
||||||
@exception.wrap_keystone_exception
|
@exception.wrap_keystone_exception
|
||||||
def cinder(self):
|
def cinder(self):
|
||||||
if self._cinder:
|
if self._cinder:
|
||||||
return self._cinder
|
return self._cinder
|
||||||
|
|
||||||
cinderclient_version = self._get_client_option('cinder', 'api_version')
|
cinderclient_version = self._get_client_option('cinder', 'api_version')
|
||||||
|
cinder_endpoint_type = self._get_client_option('cinder',
|
||||||
|
'endpoint_type')
|
||||||
self._cinder = ciclient.Client(cinderclient_version,
|
self._cinder = ciclient.Client(cinderclient_version,
|
||||||
|
endpoint_type=cinder_endpoint_type,
|
||||||
session=self.session)
|
session=self.session)
|
||||||
return self._cinder
|
return self._cinder
|
||||||
|
|
||||||
@@ -109,8 +133,12 @@ class OpenStackClients(object):
|
|||||||
|
|
||||||
ceilometerclient_version = self._get_client_option('ceilometer',
|
ceilometerclient_version = self._get_client_option('ceilometer',
|
||||||
'api_version')
|
'api_version')
|
||||||
self._ceilometer = ceclient.get_client(ceilometerclient_version,
|
ceilometer_endpoint_type = self._get_client_option('ceilometer',
|
||||||
session=self.session)
|
'endpoint_type')
|
||||||
|
self._ceilometer = ceclient.get_client(
|
||||||
|
ceilometerclient_version,
|
||||||
|
endpoint_type=ceilometer_endpoint_type,
|
||||||
|
session=self.session)
|
||||||
return self._ceilometer
|
return self._ceilometer
|
||||||
|
|
||||||
@exception.wrap_keystone_exception
|
@exception.wrap_keystone_exception
|
||||||
@@ -120,6 +148,8 @@ class OpenStackClients(object):
|
|||||||
|
|
||||||
monascaclient_version = self._get_client_option(
|
monascaclient_version = self._get_client_option(
|
||||||
'monasca', 'api_version')
|
'monasca', 'api_version')
|
||||||
|
monascaclient_interface = self._get_client_option(
|
||||||
|
'monasca', 'interface')
|
||||||
token = self.session.get_token()
|
token = self.session.get_token()
|
||||||
watcher_clients_auth_config = CONF.get(_CLIENTS_AUTH_GROUP)
|
watcher_clients_auth_config = CONF.get(_CLIENTS_AUTH_GROUP)
|
||||||
service_type = 'monitoring'
|
service_type = 'monitoring'
|
||||||
@@ -135,7 +165,8 @@ class OpenStackClients(object):
|
|||||||
'username': watcher_clients_auth_config.username,
|
'username': watcher_clients_auth_config.username,
|
||||||
'password': watcher_clients_auth_config.password,
|
'password': watcher_clients_auth_config.password,
|
||||||
}
|
}
|
||||||
endpoint = self.session.get_endpoint(service_type=service_type)
|
endpoint = self.session.get_endpoint(service_type=service_type,
|
||||||
|
interface=monascaclient_interface)
|
||||||
|
|
||||||
self._monasca = monclient.Client(
|
self._monasca = monclient.Client(
|
||||||
monascaclient_version, endpoint, **monasca_kwargs)
|
monascaclient_version, endpoint, **monasca_kwargs)
|
||||||
@@ -149,7 +180,11 @@ class OpenStackClients(object):
|
|||||||
|
|
||||||
neutronclient_version = self._get_client_option('neutron',
|
neutronclient_version = self._get_client_option('neutron',
|
||||||
'api_version')
|
'api_version')
|
||||||
|
neutron_endpoint_type = self._get_client_option('neutron',
|
||||||
|
'endpoint_type')
|
||||||
|
|
||||||
self._neutron = netclient.Client(neutronclient_version,
|
self._neutron = netclient.Client(neutronclient_version,
|
||||||
|
endpoint_type=neutron_endpoint_type,
|
||||||
session=self.session)
|
session=self.session)
|
||||||
self._neutron.format = 'json'
|
self._neutron.format = 'json'
|
||||||
return self._neutron
|
return self._neutron
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ from oslo_log import log as logging
|
|||||||
from oslo_utils import timeutils
|
from oslo_utils import timeutils
|
||||||
import six
|
import six
|
||||||
|
|
||||||
from watcher._i18n import _LW
|
|
||||||
from watcher.common import utils
|
from watcher.common import utils
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
@@ -65,7 +64,7 @@ class RequestContext(context.RequestContext):
|
|||||||
# safely ignore this as we don't use it.
|
# safely ignore this as we don't use it.
|
||||||
kwargs.pop('user_identity', None)
|
kwargs.pop('user_identity', None)
|
||||||
if kwargs:
|
if kwargs:
|
||||||
LOG.warning(_LW('Arguments dropped when creating context: %s'),
|
LOG.warning('Arguments dropped when creating context: %s',
|
||||||
str(kwargs))
|
str(kwargs))
|
||||||
|
|
||||||
# FIXME(dims): user_id and project_id duplicate information that is
|
# FIXME(dims): user_id and project_id duplicate information that is
|
||||||
@@ -75,7 +74,7 @@ class RequestContext(context.RequestContext):
|
|||||||
self.domain_name = domain_name
|
self.domain_name = domain_name
|
||||||
self.domain_id = domain_id
|
self.domain_id = domain_id
|
||||||
self.auth_token_info = auth_token_info
|
self.auth_token_info = auth_token_info
|
||||||
self.user_id = user_id
|
self.user_id = user_id or user
|
||||||
self.project_id = project_id
|
self.project_id = project_id
|
||||||
if not timestamp:
|
if not timestamp:
|
||||||
timestamp = timeutils.utcnow()
|
timestamp = timeutils.utcnow()
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ from keystoneclient import exceptions as keystone_exceptions
|
|||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
import six
|
import six
|
||||||
|
|
||||||
from watcher._i18n import _, _LE
|
from watcher._i18n import _
|
||||||
|
|
||||||
from watcher import conf
|
from watcher import conf
|
||||||
|
|
||||||
@@ -83,9 +83,9 @@ class WatcherException(Exception):
|
|||||||
except Exception:
|
except Exception:
|
||||||
# kwargs doesn't match a variable in msg_fmt
|
# kwargs doesn't match a variable in msg_fmt
|
||||||
# log the issue and the kwargs
|
# log the issue and the kwargs
|
||||||
LOG.exception(_LE('Exception in string format operation'))
|
LOG.exception('Exception in string format operation')
|
||||||
for name, value in kwargs.items():
|
for name, value in kwargs.items():
|
||||||
LOG.error(_LE("%(name)s: %(value)s"),
|
LOG.error("%(name)s: %(value)s",
|
||||||
{'name': name, 'value': value})
|
{'name': name, 'value': value})
|
||||||
|
|
||||||
if CONF.fatal_exception_format_errors:
|
if CONF.fatal_exception_format_errors:
|
||||||
@@ -130,7 +130,7 @@ class OperationNotPermitted(NotAuthorized):
|
|||||||
msg_fmt = _("Operation not permitted")
|
msg_fmt = _("Operation not permitted")
|
||||||
|
|
||||||
|
|
||||||
class Invalid(WatcherException):
|
class Invalid(WatcherException, ValueError):
|
||||||
msg_fmt = _("Unacceptable parameters")
|
msg_fmt = _("Unacceptable parameters")
|
||||||
code = 400
|
code = 400
|
||||||
|
|
||||||
@@ -149,6 +149,10 @@ class ResourceNotFound(ObjectNotFound):
|
|||||||
code = 404
|
code = 404
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidParameter(Invalid):
|
||||||
|
msg_fmt = _("%(parameter)s has to be of type %(parameter_type)s")
|
||||||
|
|
||||||
|
|
||||||
class InvalidIdentity(Invalid):
|
class InvalidIdentity(Invalid):
|
||||||
msg_fmt = _("Expected a uuid or int but received %(identity)s")
|
msg_fmt = _("Expected a uuid or int but received %(identity)s")
|
||||||
|
|
||||||
@@ -174,6 +178,18 @@ class EagerlyLoadedAuditRequired(InvalidAudit):
|
|||||||
msg_fmt = _("Audit %(audit)s was not eagerly loaded")
|
msg_fmt = _("Audit %(audit)s was not eagerly loaded")
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidActionPlan(Invalid):
|
||||||
|
msg_fmt = _("Action plan %(action_plan)s is invalid")
|
||||||
|
|
||||||
|
|
||||||
|
class EagerlyLoadedActionPlanRequired(InvalidActionPlan):
|
||||||
|
msg_fmt = _("Action plan %(action_plan)s was not eagerly loaded")
|
||||||
|
|
||||||
|
|
||||||
|
class EagerlyLoadedActionRequired(InvalidActionPlan):
|
||||||
|
msg_fmt = _("Action %(action)s was not eagerly loaded")
|
||||||
|
|
||||||
|
|
||||||
class InvalidUUID(Invalid):
|
class InvalidUUID(Invalid):
|
||||||
msg_fmt = _("Expected a uuid but received %(uuid)s")
|
msg_fmt = _("Expected a uuid but received %(uuid)s")
|
||||||
|
|
||||||
@@ -259,9 +275,7 @@ class ActionPlanReferenced(Invalid):
|
|||||||
|
|
||||||
|
|
||||||
class ActionPlanIsOngoing(Conflict):
|
class ActionPlanIsOngoing(Conflict):
|
||||||
msg_fmt = _("Action Plan %(action_plan)s is currently running. "
|
msg_fmt = _("Action Plan %(action_plan)s is currently running.")
|
||||||
"New Action Plan %(new_action_plan)s will be set as "
|
|
||||||
"SUPERSEDED")
|
|
||||||
|
|
||||||
|
|
||||||
class ActionNotFound(ResourceNotFound):
|
class ActionNotFound(ResourceNotFound):
|
||||||
@@ -402,11 +416,15 @@ class WildcardCharacterIsUsed(WatcherException):
|
|||||||
|
|
||||||
# Model
|
# Model
|
||||||
|
|
||||||
class InstanceNotFound(WatcherException):
|
class ComputeResourceNotFound(WatcherException):
|
||||||
|
msg_fmt = _("The compute resource '%(name)s' could not be found")
|
||||||
|
|
||||||
|
|
||||||
|
class InstanceNotFound(ComputeResourceNotFound):
|
||||||
msg_fmt = _("The instance '%(name)s' could not be found")
|
msg_fmt = _("The instance '%(name)s' could not be found")
|
||||||
|
|
||||||
|
|
||||||
class ComputeNodeNotFound(WatcherException):
|
class ComputeNodeNotFound(ComputeResourceNotFound):
|
||||||
msg_fmt = _("The compute node %(name)s could not be found")
|
msg_fmt = _("The compute node %(name)s could not be found")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ from oslo_config import cfg
|
|||||||
from oslo_log import log
|
from oslo_log import log
|
||||||
import oslo_messaging as messaging
|
import oslo_messaging as messaging
|
||||||
|
|
||||||
from watcher._i18n import _LE
|
|
||||||
from watcher.common import context as watcher_context
|
from watcher.common import context as watcher_context
|
||||||
from watcher.common import exception
|
from watcher.common import exception
|
||||||
|
|
||||||
@@ -32,7 +31,6 @@ __all__ = [
|
|||||||
'get_client',
|
'get_client',
|
||||||
'get_server',
|
'get_server',
|
||||||
'get_notifier',
|
'get_notifier',
|
||||||
'TRANSPORT_ALIASES',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
@@ -46,16 +44,6 @@ ALLOWED_EXMODS = [
|
|||||||
]
|
]
|
||||||
EXTRA_EXMODS = []
|
EXTRA_EXMODS = []
|
||||||
|
|
||||||
# NOTE(lucasagomes): The watcher.openstack.common.rpc entries are for
|
|
||||||
# backwards compat with IceHouse rpc_backend configuration values.
|
|
||||||
TRANSPORT_ALIASES = {
|
|
||||||
'watcher.openstack.common.rpc.impl_kombu': 'rabbit',
|
|
||||||
'watcher.openstack.common.rpc.impl_qpid': 'qpid',
|
|
||||||
'watcher.openstack.common.rpc.impl_zmq': 'zmq',
|
|
||||||
'watcher.rpc.impl_kombu': 'rabbit',
|
|
||||||
'watcher.rpc.impl_qpid': 'qpid',
|
|
||||||
'watcher.rpc.impl_zmq': 'zmq',
|
|
||||||
}
|
|
||||||
|
|
||||||
JsonPayloadSerializer = messaging.JsonPayloadSerializer
|
JsonPayloadSerializer = messaging.JsonPayloadSerializer
|
||||||
|
|
||||||
@@ -64,12 +52,10 @@ def init(conf):
|
|||||||
global TRANSPORT, NOTIFICATION_TRANSPORT, NOTIFIER
|
global TRANSPORT, NOTIFICATION_TRANSPORT, NOTIFIER
|
||||||
exmods = get_allowed_exmods()
|
exmods = get_allowed_exmods()
|
||||||
TRANSPORT = messaging.get_transport(conf,
|
TRANSPORT = messaging.get_transport(conf,
|
||||||
allowed_remote_exmods=exmods,
|
allowed_remote_exmods=exmods)
|
||||||
aliases=TRANSPORT_ALIASES)
|
|
||||||
NOTIFICATION_TRANSPORT = messaging.get_notification_transport(
|
NOTIFICATION_TRANSPORT = messaging.get_notification_transport(
|
||||||
conf,
|
conf,
|
||||||
allowed_remote_exmods=exmods,
|
allowed_remote_exmods=exmods)
|
||||||
aliases=TRANSPORT_ALIASES)
|
|
||||||
|
|
||||||
serializer = RequestContextSerializer(JsonPayloadSerializer())
|
serializer = RequestContextSerializer(JsonPayloadSerializer())
|
||||||
if not conf.notification_level:
|
if not conf.notification_level:
|
||||||
@@ -87,7 +73,7 @@ def initialized():
|
|||||||
def cleanup():
|
def cleanup():
|
||||||
global TRANSPORT, NOTIFICATION_TRANSPORT, NOTIFIER
|
global TRANSPORT, NOTIFICATION_TRANSPORT, NOTIFIER
|
||||||
if NOTIFIER is None:
|
if NOTIFIER is None:
|
||||||
LOG.exception(_LE("RPC cleanup: NOTIFIER is None"))
|
LOG.exception("RPC cleanup: NOTIFIER is None")
|
||||||
TRANSPORT.cleanup()
|
TRANSPORT.cleanup()
|
||||||
NOTIFICATION_TRANSPORT.cleanup()
|
NOTIFICATION_TRANSPORT.cleanup()
|
||||||
TRANSPORT = NOTIFICATION_TRANSPORT = NOTIFIER = None
|
TRANSPORT = NOTIFICATION_TRANSPORT = NOTIFIER = None
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ from oslo_utils import timeutils
|
|||||||
from oslo_utils import uuidutils
|
from oslo_utils import uuidutils
|
||||||
import six
|
import six
|
||||||
|
|
||||||
from watcher._i18n import _LW
|
|
||||||
from watcher.common import exception
|
from watcher.common import exception
|
||||||
|
|
||||||
from watcher import conf
|
from watcher import conf
|
||||||
@@ -73,9 +72,9 @@ def safe_rstrip(value, chars=None):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
if not isinstance(value, six.string_types):
|
if not isinstance(value, six.string_types):
|
||||||
LOG.warning(_LW(
|
LOG.warning(
|
||||||
"Failed to remove trailing character. Returning original object."
|
"Failed to remove trailing character. Returning original object."
|
||||||
"Supplied object is not a string: %s,"), value)
|
"Supplied object is not a string: %s,", value)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
return value.rstrip(chars) or value
|
return value.rstrip(chars) or value
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ from watcher.conf import db
|
|||||||
from watcher.conf import decision_engine
|
from watcher.conf import decision_engine
|
||||||
from watcher.conf import exception
|
from watcher.conf import exception
|
||||||
from watcher.conf import glance_client
|
from watcher.conf import glance_client
|
||||||
|
from watcher.conf import gnocchi_client
|
||||||
from watcher.conf import monasca_client
|
from watcher.conf import monasca_client
|
||||||
from watcher.conf import neutron_client
|
from watcher.conf import neutron_client
|
||||||
from watcher.conf import nova_client
|
from watcher.conf import nova_client
|
||||||
@@ -50,6 +51,7 @@ decision_engine.register_opts(CONF)
|
|||||||
monasca_client.register_opts(CONF)
|
monasca_client.register_opts(CONF)
|
||||||
nova_client.register_opts(CONF)
|
nova_client.register_opts(CONF)
|
||||||
glance_client.register_opts(CONF)
|
glance_client.register_opts(CONF)
|
||||||
|
gnocchi_client.register_opts(CONF)
|
||||||
cinder_client.register_opts(CONF)
|
cinder_client.register_opts(CONF)
|
||||||
ceilometer_client.register_opts(CONF)
|
ceilometer_client.register_opts(CONF)
|
||||||
neutron_client.register_opts(CONF)
|
neutron_client.register_opts(CONF)
|
||||||
|
|||||||
@@ -32,9 +32,10 @@ API_SERVICE_OPTS = [
|
|||||||
cfg.PortOpt('port',
|
cfg.PortOpt('port',
|
||||||
default=9322,
|
default=9322,
|
||||||
help='The port for the watcher API server'),
|
help='The port for the watcher API server'),
|
||||||
cfg.StrOpt('host',
|
cfg.HostAddressOpt('host',
|
||||||
default='127.0.0.1',
|
default='127.0.0.1',
|
||||||
help='The listen IP address for the watcher API server'),
|
help='The listen IP address for the watcher API server'
|
||||||
|
),
|
||||||
cfg.IntOpt('max_limit',
|
cfg.IntOpt('max_limit',
|
||||||
default=1000,
|
default=1000,
|
||||||
help='The maximum number of items returned in a single '
|
help='The maximum number of items returned in a single '
|
||||||
|
|||||||
@@ -25,7 +25,12 @@ CEILOMETER_CLIENT_OPTS = [
|
|||||||
cfg.StrOpt('api_version',
|
cfg.StrOpt('api_version',
|
||||||
default='2',
|
default='2',
|
||||||
help='Version of Ceilometer API to use in '
|
help='Version of Ceilometer API to use in '
|
||||||
'ceilometerclient.')]
|
'ceilometerclient.'),
|
||||||
|
cfg.StrOpt('endpoint_type',
|
||||||
|
default='internalURL',
|
||||||
|
help='Type of endpoint to use in ceilometerclient.'
|
||||||
|
'Supported values: internalURL, publicURL, adminURL'
|
||||||
|
'The default is internalURL.')]
|
||||||
|
|
||||||
|
|
||||||
def register_opts(conf):
|
def register_opts(conf):
|
||||||
|
|||||||
@@ -24,7 +24,12 @@ cinder_client = cfg.OptGroup(name='cinder_client',
|
|||||||
CINDER_CLIENT_OPTS = [
|
CINDER_CLIENT_OPTS = [
|
||||||
cfg.StrOpt('api_version',
|
cfg.StrOpt('api_version',
|
||||||
default='2',
|
default='2',
|
||||||
help='Version of Cinder API to use in cinderclient.')]
|
help='Version of Cinder API to use in cinderclient.'),
|
||||||
|
cfg.StrOpt('endpoint_type',
|
||||||
|
default='internalURL',
|
||||||
|
help='Type of endpoint to use in cinderclient.'
|
||||||
|
'Supported values: internalURL, publicURL, adminURL'
|
||||||
|
'The default is internalURL.')]
|
||||||
|
|
||||||
|
|
||||||
def register_opts(conf):
|
def register_opts(conf):
|
||||||
|
|||||||
@@ -42,6 +42,15 @@ WATCHER_DECISION_ENGINE_OPTS = [
|
|||||||
required=True,
|
required=True,
|
||||||
help='The maximum number of threads that can be used to '
|
help='The maximum number of threads that can be used to '
|
||||||
'execute strategies'),
|
'execute strategies'),
|
||||||
|
cfg.IntOpt('action_plan_expiry',
|
||||||
|
default=24,
|
||||||
|
help='An expiry timespan(hours). Watcher invalidates any '
|
||||||
|
'action plan for which its creation time '
|
||||||
|
'-whose number of hours has been offset by this value-'
|
||||||
|
' is older that the current time.'),
|
||||||
|
cfg.IntOpt('check_periodic_interval',
|
||||||
|
default=30*60,
|
||||||
|
help='Interval (in seconds) for checking action plan expiry.')
|
||||||
]
|
]
|
||||||
|
|
||||||
WATCHER_CONTINUOUS_OPTS = [
|
WATCHER_CONTINUOUS_OPTS = [
|
||||||
|
|||||||
@@ -24,7 +24,12 @@ glance_client = cfg.OptGroup(name='glance_client',
|
|||||||
GLANCE_CLIENT_OPTS = [
|
GLANCE_CLIENT_OPTS = [
|
||||||
cfg.StrOpt('api_version',
|
cfg.StrOpt('api_version',
|
||||||
default='2',
|
default='2',
|
||||||
help='Version of Glance API to use in glanceclient.')]
|
help='Version of Glance API to use in glanceclient.'),
|
||||||
|
cfg.StrOpt('endpoint_type',
|
||||||
|
default='internalURL',
|
||||||
|
help='Type of endpoint to use in glanceclient.'
|
||||||
|
'Supported values: internalURL, publicURL, adminURL'
|
||||||
|
'The default is internalURL.')]
|
||||||
|
|
||||||
|
|
||||||
def register_opts(conf):
|
def register_opts(conf):
|
||||||
|
|||||||
47
watcher/conf/gnocchi_client.py
Normal file
47
watcher/conf/gnocchi_client.py
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# -*- encoding: utf-8 -*-
|
||||||
|
# Copyright (c) 2017 Servionica
|
||||||
|
#
|
||||||
|
# Authors: Alexander Chadin <a.chadin@servionica.ru>
|
||||||
|
#
|
||||||
|
# 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 oslo_config import cfg
|
||||||
|
|
||||||
|
gnocchi_client = cfg.OptGroup(name='gnocchi_client',
|
||||||
|
title='Configuration Options for Gnocchi')
|
||||||
|
|
||||||
|
GNOCCHI_CLIENT_OPTS = [
|
||||||
|
cfg.StrOpt('api_version',
|
||||||
|
default='1',
|
||||||
|
help='Version of Gnocchi API to use in gnocchiclient.'),
|
||||||
|
cfg.StrOpt('endpoint_type',
|
||||||
|
default='internalURL',
|
||||||
|
help='Type of endpoint to use in gnocchi client.'
|
||||||
|
'Supported values: internalURL, publicURL, adminURL'
|
||||||
|
'The default is internalURL.'),
|
||||||
|
cfg.IntOpt('query_max_retries',
|
||||||
|
default=10,
|
||||||
|
help='How many times Watcher is trying to query again'),
|
||||||
|
cfg.IntOpt('query_timeout',
|
||||||
|
default=1,
|
||||||
|
help='How many seconds Watcher should wait to do query again')]
|
||||||
|
|
||||||
|
|
||||||
|
def register_opts(conf):
|
||||||
|
conf.register_group(gnocchi_client)
|
||||||
|
conf.register_opts(GNOCCHI_CLIENT_OPTS, group=gnocchi_client)
|
||||||
|
|
||||||
|
|
||||||
|
def list_opts():
|
||||||
|
return [('gnocchi_client', GNOCCHI_CLIENT_OPTS)]
|
||||||
@@ -24,7 +24,12 @@ monasca_client = cfg.OptGroup(name='monasca_client',
|
|||||||
MONASCA_CLIENT_OPTS = [
|
MONASCA_CLIENT_OPTS = [
|
||||||
cfg.StrOpt('api_version',
|
cfg.StrOpt('api_version',
|
||||||
default='2_0',
|
default='2_0',
|
||||||
help='Version of Monasca API to use in monascaclient.')]
|
help='Version of Monasca API to use in monascaclient.'),
|
||||||
|
cfg.StrOpt('interface',
|
||||||
|
default='internal',
|
||||||
|
help='Type of interface used for monasca endpoint.'
|
||||||
|
'Supported values: internal, public, admin'
|
||||||
|
'The default is internal.')]
|
||||||
|
|
||||||
|
|
||||||
def register_opts(conf):
|
def register_opts(conf):
|
||||||
|
|||||||
@@ -24,7 +24,12 @@ neutron_client = cfg.OptGroup(name='neutron_client',
|
|||||||
NEUTRON_CLIENT_OPTS = [
|
NEUTRON_CLIENT_OPTS = [
|
||||||
cfg.StrOpt('api_version',
|
cfg.StrOpt('api_version',
|
||||||
default='2.0',
|
default='2.0',
|
||||||
help='Version of Neutron API to use in neutronclient.')]
|
help='Version of Neutron API to use in neutronclient.'),
|
||||||
|
cfg.StrOpt('endpoint_type',
|
||||||
|
default='internalURL',
|
||||||
|
help='Type of endpoint to use in neutronclient.'
|
||||||
|
'Supported values: internalURL, publicURL, adminURL'
|
||||||
|
'The default is internalURL.')]
|
||||||
|
|
||||||
|
|
||||||
def register_opts(conf):
|
def register_opts(conf):
|
||||||
|
|||||||
@@ -24,7 +24,12 @@ nova_client = cfg.OptGroup(name='nova_client',
|
|||||||
NOVA_CLIENT_OPTS = [
|
NOVA_CLIENT_OPTS = [
|
||||||
cfg.StrOpt('api_version',
|
cfg.StrOpt('api_version',
|
||||||
default='2',
|
default='2',
|
||||||
help='Version of Nova API to use in novaclient.')]
|
help='Version of Nova API to use in novaclient.'),
|
||||||
|
cfg.StrOpt('endpoint_type',
|
||||||
|
default='internalURL',
|
||||||
|
help='Type of endpoint to use in novaclient.'
|
||||||
|
'Supported values: internalURL, publicURL, adminURL'
|
||||||
|
'The default is internalURL.')]
|
||||||
|
|
||||||
|
|
||||||
def register_opts(conf):
|
def register_opts(conf):
|
||||||
|
|||||||
@@ -26,13 +26,14 @@ SERVICE_OPTS = [
|
|||||||
cfg.IntOpt('periodic_interval',
|
cfg.IntOpt('periodic_interval',
|
||||||
default=60,
|
default=60,
|
||||||
help=_('Seconds between running periodic tasks.')),
|
help=_('Seconds between running periodic tasks.')),
|
||||||
cfg.StrOpt('host',
|
cfg.HostAddressOpt('host',
|
||||||
default=socket.gethostname(),
|
default=socket.gethostname(),
|
||||||
help=_('Name of this node. This can be an opaque identifier. '
|
help=_('Name of this node. This can be an opaque '
|
||||||
'It is not necessarily a hostname, FQDN, or IP address. '
|
'identifier. It is not necessarily a hostname, '
|
||||||
'However, the node name must be valid within '
|
'FQDN, or IP address. However, the node name '
|
||||||
'an AMQP key, and if using ZeroMQ, a valid '
|
'must be valid within an AMQP key, and if using '
|
||||||
'hostname, FQDN, or IP address.')),
|
'ZeroMQ, a valid hostname, FQDN, or IP address.')
|
||||||
|
),
|
||||||
cfg.IntOpt('service_down_time',
|
cfg.IntOpt('service_down_time',
|
||||||
default=90,
|
default=90,
|
||||||
help=_('Maximum time since last check-in for up service.'))
|
help=_('Maximum time since last check-in for up service.'))
|
||||||
|
|||||||
92
watcher/datasource/gnocchi.py
Normal file
92
watcher/datasource/gnocchi.py
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
# -*- encoding: utf-8 -*-
|
||||||
|
# Copyright (c) 2017 Servionica
|
||||||
|
#
|
||||||
|
# Authors: Alexander Chadin <a.chadin@servionica.ru>
|
||||||
|
#
|
||||||
|
# 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 datetime import datetime
|
||||||
|
import time
|
||||||
|
|
||||||
|
from oslo_config import cfg
|
||||||
|
from oslo_log import log
|
||||||
|
|
||||||
|
from watcher.common import clients
|
||||||
|
from watcher.common import exception
|
||||||
|
|
||||||
|
CONF = cfg.CONF
|
||||||
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class GnocchiHelper(object):
|
||||||
|
|
||||||
|
def __init__(self, osc=None):
|
||||||
|
""":param osc: an OpenStackClients instance"""
|
||||||
|
self.osc = osc if osc else clients.OpenStackClients()
|
||||||
|
self.gnocchi = self.osc.gnocchi()
|
||||||
|
|
||||||
|
def query_retry(self, f, *args, **kwargs):
|
||||||
|
for i in range(CONF.gnocchi_client.query_max_retries):
|
||||||
|
try:
|
||||||
|
return f(*args, **kwargs)
|
||||||
|
except Exception as e:
|
||||||
|
LOG.exception(e)
|
||||||
|
time.sleep(CONF.gnocchi_client.query_timeout)
|
||||||
|
raise
|
||||||
|
|
||||||
|
def statistic_aggregation(self,
|
||||||
|
resource_id,
|
||||||
|
metric,
|
||||||
|
granularity,
|
||||||
|
start_time=None,
|
||||||
|
stop_time=None,
|
||||||
|
aggregation='mean'):
|
||||||
|
"""Representing a statistic aggregate by operators
|
||||||
|
|
||||||
|
:param metric: metric name of which we want the statistics
|
||||||
|
:param resource_id: id of resource to list statistics for
|
||||||
|
:param start_time: Start datetime from which metrics will be used
|
||||||
|
:param stop_time: End datetime from which metrics will be used
|
||||||
|
:param granularity: frequency of marking metric point, in seconds
|
||||||
|
:param aggregation: Should be chosen in accrodance with policy
|
||||||
|
aggregations
|
||||||
|
:return: value of aggregated metric
|
||||||
|
"""
|
||||||
|
|
||||||
|
if start_time is not None and not isinstance(start_time, datetime):
|
||||||
|
raise exception.InvalidParameter(parameter='start_time',
|
||||||
|
parameter_type=datetime)
|
||||||
|
|
||||||
|
if stop_time is not None and not isinstance(stop_time, datetime):
|
||||||
|
raise exception.InvalidParameter(parameter='stop_time',
|
||||||
|
parameter_type=datetime)
|
||||||
|
|
||||||
|
raw_kwargs = dict(
|
||||||
|
metric=metric,
|
||||||
|
start=start_time,
|
||||||
|
stop=stop_time,
|
||||||
|
resource_id=resource_id,
|
||||||
|
granularity=granularity,
|
||||||
|
aggregation=aggregation,
|
||||||
|
)
|
||||||
|
|
||||||
|
kwargs = {k: v for k, v in raw_kwargs.items() if k and v}
|
||||||
|
|
||||||
|
statistics = self.query_retry(
|
||||||
|
f=self.gnocchi.metric.get_measures, **kwargs)
|
||||||
|
|
||||||
|
if statistics:
|
||||||
|
# return value of latest measure
|
||||||
|
# measure has structure [time, granularity, value]
|
||||||
|
return statistics[-1][2]
|
||||||
@@ -27,7 +27,7 @@ from oslo_utils import strutils
|
|||||||
import prettytable as ptable
|
import prettytable as ptable
|
||||||
from six.moves import input
|
from six.moves import input
|
||||||
|
|
||||||
from watcher._i18n import _, _LI
|
from watcher._i18n import _
|
||||||
from watcher._i18n import lazy_translation_enabled
|
from watcher._i18n import lazy_translation_enabled
|
||||||
from watcher.common import context
|
from watcher.common import context
|
||||||
from watcher.common import exception
|
from watcher.common import exception
|
||||||
@@ -231,7 +231,7 @@ class PurgeCommand(object):
|
|||||||
if action.action_plan_id not in action_plan_ids]
|
if action.action_plan_id not in action_plan_ids]
|
||||||
|
|
||||||
LOG.debug("Orphans found:\n%s", orphans)
|
LOG.debug("Orphans found:\n%s", orphans)
|
||||||
LOG.info(_LI("Orphans found:\n%s"), orphans.get_count_table())
|
LOG.info("Orphans found:\n%s", orphans.get_count_table())
|
||||||
|
|
||||||
return orphans
|
return orphans
|
||||||
|
|
||||||
@@ -403,13 +403,13 @@ class PurgeCommand(object):
|
|||||||
return to_be_deleted
|
return to_be_deleted
|
||||||
|
|
||||||
def do_delete(self):
|
def do_delete(self):
|
||||||
LOG.info(_LI("Deleting..."))
|
LOG.info("Deleting...")
|
||||||
# Reversed to avoid errors with foreign keys
|
# Reversed to avoid errors with foreign keys
|
||||||
for entry in reversed(list(self._objects_map)):
|
for entry in reversed(list(self._objects_map)):
|
||||||
entry.destroy()
|
entry.destroy()
|
||||||
|
|
||||||
def execute(self):
|
def execute(self):
|
||||||
LOG.info(_LI("Starting purge command"))
|
LOG.info("Starting purge command")
|
||||||
self._objects_map = self.find_objects_to_delete()
|
self._objects_map = self.find_objects_to_delete()
|
||||||
|
|
||||||
if (self.max_number is not None and
|
if (self.max_number is not None and
|
||||||
@@ -424,15 +424,15 @@ class PurgeCommand(object):
|
|||||||
if not self.dry_run and self.confirmation_prompt():
|
if not self.dry_run and self.confirmation_prompt():
|
||||||
self.do_delete()
|
self.do_delete()
|
||||||
print(_("Purge results summary%s:") % _orphans_note)
|
print(_("Purge results summary%s:") % _orphans_note)
|
||||||
LOG.info(_LI("Purge results summary%s:"), _orphans_note)
|
LOG.info("Purge results summary%s:", _orphans_note)
|
||||||
else:
|
else:
|
||||||
LOG.debug(self._objects_map)
|
LOG.debug(self._objects_map)
|
||||||
print(_("Here below is a table containing the objects "
|
print(_("Here below is a table containing the objects "
|
||||||
"that can be purged%s:") % _orphans_note)
|
"that can be purged%s:") % _orphans_note)
|
||||||
|
|
||||||
LOG.info(_LI("\n%s"), self._objects_map.get_count_table())
|
LOG.info("\n%s", self._objects_map.get_count_table())
|
||||||
print(self._objects_map.get_count_table())
|
print(self._objects_map.get_count_table())
|
||||||
LOG.info(_LI("Purge process completed"))
|
LOG.info("Purge process completed")
|
||||||
|
|
||||||
|
|
||||||
def purge(age_in_days, max_number, goal, exclude_orphans, dry_run):
|
def purge(age_in_days, max_number, goal, exclude_orphans, dry_run):
|
||||||
@@ -457,11 +457,11 @@ def purge(age_in_days, max_number, goal, exclude_orphans, dry_run):
|
|||||||
if max_number and max_number < 0:
|
if max_number and max_number < 0:
|
||||||
raise exception.NegativeLimitError
|
raise exception.NegativeLimitError
|
||||||
|
|
||||||
LOG.info(_LI("[options] age_in_days = %s"), age_in_days)
|
LOG.info("[options] age_in_days = %s", age_in_days)
|
||||||
LOG.info(_LI("[options] max_number = %s"), max_number)
|
LOG.info("[options] max_number = %s", max_number)
|
||||||
LOG.info(_LI("[options] goal = %s"), goal)
|
LOG.info("[options] goal = %s", goal)
|
||||||
LOG.info(_LI("[options] exclude_orphans = %s"), exclude_orphans)
|
LOG.info("[options] exclude_orphans = %s", exclude_orphans)
|
||||||
LOG.info(_LI("[options] dry_run = %s"), dry_run)
|
LOG.info("[options] dry_run = %s", dry_run)
|
||||||
|
|
||||||
uuid = PurgeCommand.get_goal_uuid(goal)
|
uuid = PurgeCommand.get_goal_uuid(goal)
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
Please see https://alembic.readthedocs.org/en/latest/index.html for general documentation
|
|
||||||
|
|
||||||
To create alembic migrations use:
|
|
||||||
$ watcher-db-manage revision --message "description of revision" --autogenerate
|
|
||||||
|
|
||||||
Stamp db with most recent migration version, without actually running migrations
|
|
||||||
$ watcher-db-manage stamp head
|
|
||||||
|
|
||||||
Upgrade can be performed by:
|
|
||||||
$ watcher-db-manage upgrade
|
|
||||||
$ watcher-db-manage upgrade head
|
|
||||||
|
|
||||||
Downgrading db:
|
|
||||||
$ watcher-db-manage downgrade
|
|
||||||
$ watcher-db-manage downgrade base
|
|
||||||
62
watcher/db/sqlalchemy/alembic/README.rst
Normal file
62
watcher/db/sqlalchemy/alembic/README.rst
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
The migrations in the alembic/versions contain the changes needed to migrate
|
||||||
|
from older Watcher releases to newer versions. A migration occurs by executing
|
||||||
|
a script that details the changes needed to upgrade/downgrade the database. The
|
||||||
|
migration scripts are ordered so that multiple scripts can run sequentially to
|
||||||
|
update the database. The scripts are executed by Watcher's migration wrapper
|
||||||
|
which uses the Alembic library to manage the migration. Watcher supports
|
||||||
|
migration from Ocata or later.
|
||||||
|
|
||||||
|
|
||||||
|
If you are a deployer or developer and want to migrate from Ocata to later
|
||||||
|
release you must first add version tracking to the database::
|
||||||
|
|
||||||
|
$ watcher-db-manage --config-file /path/to/watcher.conf stamp ocata
|
||||||
|
|
||||||
|
|
||||||
|
You can upgrade to the latest database version via::
|
||||||
|
|
||||||
|
$ watcher-db-manage --config-file /path/to/watcher.conf upgrade head
|
||||||
|
|
||||||
|
|
||||||
|
To check the current database version::
|
||||||
|
|
||||||
|
$ watcher-db-manage --config-file /path/to/watcher.conf current
|
||||||
|
|
||||||
|
|
||||||
|
To create a script to run the migration offline::
|
||||||
|
|
||||||
|
$ watcher-db-manage --config-file /path/to/watcher.conf upgrade head --sql
|
||||||
|
|
||||||
|
|
||||||
|
To run the offline migration between specific migration versions::
|
||||||
|
|
||||||
|
$ watcher-db-manage --config-file /path/to/watcher.conf upgrade \
|
||||||
|
<start version>:<end version> --sql
|
||||||
|
|
||||||
|
|
||||||
|
Upgrade the database incrementally::
|
||||||
|
|
||||||
|
$ watcher-db-manage --config-file /path/to/watcher.conf upgrade --delta \
|
||||||
|
<# of revs>
|
||||||
|
|
||||||
|
|
||||||
|
Downgrade the database by a certain number of revisions::
|
||||||
|
|
||||||
|
$ watcher-db-manage --config-file /path/to/watcher.conf downgrade --delta \
|
||||||
|
<# of revs>
|
||||||
|
|
||||||
|
|
||||||
|
Create new revision::
|
||||||
|
|
||||||
|
$ watcher-db-manage --config-file /path/to/watcher.conf revision \
|
||||||
|
-m "description of revision" --autogenerate
|
||||||
|
|
||||||
|
|
||||||
|
Create a blank file::
|
||||||
|
|
||||||
|
$ watcher-db-manage --config-file /path/to/watcher.conf revision \
|
||||||
|
-m "description of revision"
|
||||||
|
|
||||||
|
Please see https://alembic.readthedocs.org/en/latest/index.html for general
|
||||||
|
documentation
|
||||||
|
|
||||||
203
watcher/db/sqlalchemy/alembic/versions/001_ocata.py
Normal file
203
watcher/db/sqlalchemy/alembic/versions/001_ocata.py
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
"""ocata release
|
||||||
|
|
||||||
|
Revision ID: 9894235b4278
|
||||||
|
Revises: None
|
||||||
|
Create Date: 2017-02-01 09:40:05.065981
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import oslo_db
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from watcher.db.sqlalchemy import models
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '001'
|
||||||
|
down_revision = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
op.create_table(
|
||||||
|
'goals',
|
||||||
|
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('deleted_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('deleted', oslo_db.sqlalchemy.types.SoftDeleteInteger(),
|
||||||
|
nullable=True),
|
||||||
|
sa.Column('id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('uuid', sa.String(length=36), nullable=True),
|
||||||
|
sa.Column('name', sa.String(length=63), nullable=False),
|
||||||
|
sa.Column('display_name', sa.String(length=63), nullable=False),
|
||||||
|
sa.Column('efficacy_specification', models.JSONEncodedList(),
|
||||||
|
nullable=False),
|
||||||
|
sa.PrimaryKeyConstraint('id'),
|
||||||
|
sa.UniqueConstraint('name', 'deleted', name='uniq_goals0name'),
|
||||||
|
sa.UniqueConstraint('uuid', name='uniq_goals0uuid')
|
||||||
|
)
|
||||||
|
|
||||||
|
op.create_table(
|
||||||
|
'scoring_engines',
|
||||||
|
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('deleted_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('deleted', oslo_db.sqlalchemy.types.SoftDeleteInteger(),
|
||||||
|
nullable=True),
|
||||||
|
sa.Column('id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('uuid', sa.String(length=36), nullable=False),
|
||||||
|
sa.Column('name', sa.String(length=63), nullable=False),
|
||||||
|
sa.Column('description', sa.String(length=255), nullable=True),
|
||||||
|
sa.Column('metainfo', sa.Text(), nullable=True),
|
||||||
|
sa.PrimaryKeyConstraint('id'),
|
||||||
|
sa.UniqueConstraint('name', 'deleted',
|
||||||
|
name='uniq_scoring_engines0name'),
|
||||||
|
sa.UniqueConstraint('uuid', name='uniq_scoring_engines0uuid')
|
||||||
|
)
|
||||||
|
|
||||||
|
op.create_table(
|
||||||
|
'services',
|
||||||
|
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('deleted_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('deleted', oslo_db.sqlalchemy.types.SoftDeleteInteger(),
|
||||||
|
nullable=True),
|
||||||
|
sa.Column('id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('name', sa.String(length=255), nullable=False),
|
||||||
|
sa.Column('host', sa.String(length=255), nullable=False),
|
||||||
|
sa.Column('last_seen_up', sa.DateTime(), nullable=True),
|
||||||
|
sa.PrimaryKeyConstraint('id'),
|
||||||
|
sa.UniqueConstraint('host', 'name', 'deleted',
|
||||||
|
name='uniq_services0host0name0deleted')
|
||||||
|
)
|
||||||
|
|
||||||
|
op.create_table(
|
||||||
|
'strategies',
|
||||||
|
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('deleted_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('deleted', oslo_db.sqlalchemy.types.SoftDeleteInteger(),
|
||||||
|
nullable=True),
|
||||||
|
sa.Column('id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('uuid', sa.String(length=36), nullable=True),
|
||||||
|
sa.Column('name', sa.String(length=63), nullable=False),
|
||||||
|
sa.Column('display_name', sa.String(length=63), nullable=False),
|
||||||
|
sa.Column('goal_id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('parameters_spec', models.JSONEncodedDict(),
|
||||||
|
nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(['goal_id'], ['goals.id'], ),
|
||||||
|
sa.PrimaryKeyConstraint('id'),
|
||||||
|
sa.UniqueConstraint('name', 'deleted', name='uniq_strategies0name'),
|
||||||
|
sa.UniqueConstraint('uuid', name='uniq_strategies0uuid')
|
||||||
|
)
|
||||||
|
|
||||||
|
op.create_table(
|
||||||
|
'audit_templates',
|
||||||
|
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('deleted_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('deleted', oslo_db.sqlalchemy.types.SoftDeleteInteger(),
|
||||||
|
nullable=True),
|
||||||
|
sa.Column('id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('uuid', sa.String(length=36), nullable=True),
|
||||||
|
sa.Column('name', sa.String(length=63), nullable=True),
|
||||||
|
sa.Column('description', sa.String(length=255), nullable=True),
|
||||||
|
sa.Column('goal_id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('strategy_id', sa.Integer(), nullable=True),
|
||||||
|
sa.Column('scope', models.JSONEncodedList(),
|
||||||
|
nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(['goal_id'], ['goals.id'], ),
|
||||||
|
sa.ForeignKeyConstraint(['strategy_id'], ['strategies.id'], ),
|
||||||
|
sa.PrimaryKeyConstraint('id'),
|
||||||
|
sa.UniqueConstraint('name', 'deleted',
|
||||||
|
name='uniq_audit_templates0name'),
|
||||||
|
sa.UniqueConstraint('uuid', name='uniq_audit_templates0uuid')
|
||||||
|
)
|
||||||
|
op.create_table(
|
||||||
|
'audits',
|
||||||
|
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('deleted_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('deleted', oslo_db.sqlalchemy.types.SoftDeleteInteger(),
|
||||||
|
nullable=True),
|
||||||
|
sa.Column('id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('uuid', sa.String(length=36), nullable=True),
|
||||||
|
sa.Column('audit_type', sa.String(length=20), nullable=True),
|
||||||
|
sa.Column('state', sa.String(length=20), nullable=True),
|
||||||
|
sa.Column('parameters', models.JSONEncodedDict(), nullable=True),
|
||||||
|
sa.Column('interval', sa.Integer(), nullable=True),
|
||||||
|
sa.Column('goal_id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('strategy_id', sa.Integer(), nullable=True),
|
||||||
|
sa.Column('scope', models.JSONEncodedList(), nullable=True),
|
||||||
|
sa.Column('auto_trigger', sa.Boolean(), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(['goal_id'], ['goals.id'], ),
|
||||||
|
sa.ForeignKeyConstraint(['strategy_id'], ['strategies.id'], ),
|
||||||
|
sa.PrimaryKeyConstraint('id'),
|
||||||
|
sa.UniqueConstraint('uuid', name='uniq_audits0uuid')
|
||||||
|
)
|
||||||
|
op.create_table(
|
||||||
|
'action_plans',
|
||||||
|
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('deleted_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('deleted', oslo_db.sqlalchemy.types.SoftDeleteInteger(),
|
||||||
|
nullable=True),
|
||||||
|
sa.Column('id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('uuid', sa.String(length=36), nullable=True),
|
||||||
|
sa.Column('audit_id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('strategy_id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('state', sa.String(length=20), nullable=True),
|
||||||
|
sa.Column('global_efficacy', models.JSONEncodedDict(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(['audit_id'], ['audits.id'], ),
|
||||||
|
sa.ForeignKeyConstraint(['strategy_id'], ['strategies.id'], ),
|
||||||
|
sa.PrimaryKeyConstraint('id'),
|
||||||
|
sa.UniqueConstraint('uuid', name='uniq_action_plans0uuid')
|
||||||
|
)
|
||||||
|
|
||||||
|
op.create_table(
|
||||||
|
'actions',
|
||||||
|
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('deleted_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('deleted', oslo_db.sqlalchemy.types.SoftDeleteInteger(),
|
||||||
|
nullable=True),
|
||||||
|
sa.Column('id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('uuid', sa.String(length=36), nullable=False),
|
||||||
|
sa.Column('action_plan_id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('action_type', sa.String(length=255), nullable=False),
|
||||||
|
sa.Column('input_parameters', models.JSONEncodedDict(), nullable=True),
|
||||||
|
sa.Column('state', sa.String(length=20), nullable=True),
|
||||||
|
sa.Column('parents', models.JSONEncodedList(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(['action_plan_id'], ['action_plans.id'], ),
|
||||||
|
sa.PrimaryKeyConstraint('id'),
|
||||||
|
sa.UniqueConstraint('uuid', name='uniq_actions0uuid')
|
||||||
|
)
|
||||||
|
|
||||||
|
op.create_table(
|
||||||
|
'efficacy_indicators',
|
||||||
|
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('deleted_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('deleted', oslo_db.sqlalchemy.types.SoftDeleteInteger(),
|
||||||
|
nullable=True),
|
||||||
|
sa.Column('id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('uuid', sa.String(length=36), nullable=True),
|
||||||
|
sa.Column('name', sa.String(length=63), nullable=True),
|
||||||
|
sa.Column('description', sa.String(length=255), nullable=True),
|
||||||
|
sa.Column('unit', sa.String(length=63), nullable=True),
|
||||||
|
sa.Column('value', sa.Numeric(), nullable=True),
|
||||||
|
sa.Column('action_plan_id', sa.Integer(), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(['action_plan_id'], ['action_plans.id'], ),
|
||||||
|
sa.PrimaryKeyConstraint('id'),
|
||||||
|
sa.UniqueConstraint('uuid', name='uniq_efficacy_indicators0uuid')
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
op.drop_table('efficacy_indicators')
|
||||||
|
op.drop_table('actions')
|
||||||
|
op.drop_table('action_plans')
|
||||||
|
op.drop_table('audits')
|
||||||
|
op.drop_table('audit_templates')
|
||||||
|
op.drop_table('strategies')
|
||||||
|
op.drop_table('services')
|
||||||
|
op.drop_table('scoring_engines')
|
||||||
|
op.drop_table('goals')
|
||||||
@@ -54,7 +54,7 @@ def upgrade(revision, config=None):
|
|||||||
revision = revision or 'head'
|
revision = revision or 'head'
|
||||||
config = config or _alembic_config()
|
config = config or _alembic_config()
|
||||||
|
|
||||||
alembic.command.upgrade(config, revision or 'head')
|
alembic.command.upgrade(config, revision)
|
||||||
|
|
||||||
|
|
||||||
def create_schema(config=None, engine=None):
|
def create_schema(config=None, engine=None):
|
||||||
|
|||||||
@@ -102,23 +102,24 @@ class AuditHandler(BaseAuditHandler):
|
|||||||
audit.state = state
|
audit.state = state
|
||||||
audit.save()
|
audit.save()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def check_ongoing_action_plans(request_context):
|
||||||
|
a_plan_filters = {'state': objects.action_plan.State.ONGOING}
|
||||||
|
ongoing_action_plans = objects.ActionPlan.list(
|
||||||
|
request_context, filters=a_plan_filters)
|
||||||
|
if ongoing_action_plans:
|
||||||
|
raise exception.ActionPlanIsOngoing(
|
||||||
|
action_plan=ongoing_action_plans[0].uuid)
|
||||||
|
|
||||||
def pre_execute(self, audit, request_context):
|
def pre_execute(self, audit, request_context):
|
||||||
LOG.debug("Trigger audit %s", audit.uuid)
|
LOG.debug("Trigger audit %s", audit.uuid)
|
||||||
|
self.check_ongoing_action_plans(request_context)
|
||||||
# change state of the audit to ONGOING
|
# change state of the audit to ONGOING
|
||||||
self.update_audit_state(audit, objects.audit.State.ONGOING)
|
self.update_audit_state(audit, objects.audit.State.ONGOING)
|
||||||
|
|
||||||
def post_execute(self, audit, solution, request_context):
|
def post_execute(self, audit, solution, request_context):
|
||||||
action_plan = self.do_schedule(request_context, audit, solution)
|
action_plan = self.do_schedule(request_context, audit, solution)
|
||||||
a_plan_filters = {'state': objects.action_plan.State.ONGOING}
|
if audit.auto_trigger:
|
||||||
ongoing_action_plans = objects.ActionPlan.list(
|
|
||||||
request_context, filters=a_plan_filters)
|
|
||||||
if ongoing_action_plans:
|
|
||||||
action_plan.state = objects.action_plan.State.SUPERSEDED
|
|
||||||
action_plan.save()
|
|
||||||
raise exception.ActionPlanIsOngoing(
|
|
||||||
action_plan=ongoing_action_plans[0].uuid,
|
|
||||||
new_action_plan=action_plan.uuid)
|
|
||||||
elif audit.auto_trigger:
|
|
||||||
applier_client = rpcapi.ApplierAPI()
|
applier_client = rpcapi.ApplierAPI()
|
||||||
applier_client.launch_action_plan(request_context,
|
applier_client.launch_action_plan(request_context,
|
||||||
action_plan.uuid)
|
action_plan.uuid)
|
||||||
@@ -129,7 +130,7 @@ class AuditHandler(BaseAuditHandler):
|
|||||||
solution = self.do_execute(audit, request_context)
|
solution = self.do_execute(audit, request_context)
|
||||||
self.post_execute(audit, solution, request_context)
|
self.post_execute(audit, solution, request_context)
|
||||||
except exception.ActionPlanIsOngoing as e:
|
except exception.ActionPlanIsOngoing as e:
|
||||||
LOG.exception(e)
|
LOG.warning(e)
|
||||||
if audit.audit_type == objects.audit.AuditType.ONESHOT.value:
|
if audit.audit_type == objects.audit.AuditType.ONESHOT.value:
|
||||||
self.update_audit_state(audit, objects.audit.State.CANCELLED)
|
self.update_audit_state(audit, objects.audit.State.CANCELLED)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@@ -49,9 +49,7 @@ class ContinuousAuditHandler(base.AuditHandler):
|
|||||||
def _is_audit_inactive(self, audit):
|
def _is_audit_inactive(self, audit):
|
||||||
audit = objects.Audit.get_by_uuid(
|
audit = objects.Audit.get_by_uuid(
|
||||||
self.context_show_deleted, audit.uuid)
|
self.context_show_deleted, audit.uuid)
|
||||||
if audit.state in (objects.audit.State.CANCELLED,
|
if objects.audit.AuditStateTransitionManager().is_inactive(audit):
|
||||||
objects.audit.State.DELETED,
|
|
||||||
objects.audit.State.FAILED):
|
|
||||||
# if audit isn't in active states, audit's job must be removed to
|
# if audit isn't in active states, audit's job must be removed to
|
||||||
# prevent using of inactive audit in future.
|
# prevent using of inactive audit in future.
|
||||||
job_to_delete = [job for job in self.jobs
|
job_to_delete = [job for job in self.jobs
|
||||||
@@ -72,7 +70,7 @@ class ContinuousAuditHandler(base.AuditHandler):
|
|||||||
a_plan_filters = {'audit_uuid': audit.uuid,
|
a_plan_filters = {'audit_uuid': audit.uuid,
|
||||||
'state': objects.action_plan.State.RECOMMENDED}
|
'state': objects.action_plan.State.RECOMMENDED}
|
||||||
action_plans = objects.ActionPlan.list(
|
action_plans = objects.ActionPlan.list(
|
||||||
request_context, filters=a_plan_filters)
|
request_context, filters=a_plan_filters, eager=True)
|
||||||
for plan in action_plans:
|
for plan in action_plans:
|
||||||
plan.state = objects.action_plan.State.CANCELLED
|
plan.state = objects.action_plan.State.CANCELLED
|
||||||
plan.save()
|
plan.save()
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user