Compare commits

..

171 Commits

Author SHA1 Message Date
aditi
d7a44739a6 Cancel Action Plan
This patch adds feature to cancel action plan in watcher.
A General flow from watcher-api to watcher-applier is implemented.

action plan cancel can cancel any [ongoing, pending, recommended]
action plan, it will update the action states also to "cancelled".
For ongoing actions in action plan, actions needs to be aborted.
Seperate patches will be added to support abort operation
in each action.

Notification part is addressed by a seperate blueprint.
https://blueprints.launchpad.net/watcher/+spec/notifications-actionplan-cancel

Change-Id: I895a5eaca5239d5657702c8d1875b9ece21682dc
Partially-Implements: blueprint cancel-action-plan
2017-06-07 05:36:18 +00:00
OpenStack Proposal Bot
58d86de064 Updated from global requirements
Change-Id: I65ae1ac5170cf675d8c396ef3b7166bafc19190e
2017-06-06 06:14:58 +00:00
Yumeng Bao
8d84da307b Add rm to whitelist_externals in tox.ini
Fix the following WARNING:

WARNING:test command found but not installed in testenv
  cmd: /bin/rm
  env: /home/jenkins/workspace/gate-watcher-python27-ubuntu-xenial/.tox/py27
Maybe you forgot to specify a dependency? See also the whitelist_externals envconfig setting.

Change-Id: Ie091bd64b6a87c30535ada34daf9d594aa3fdd41
2017-06-05 19:10:28 +08:00
Jenkins
01e865edbf Merge "Replace default cinder endpoint type" 2017-06-05 08:37:45 +00:00
Jenkins
b4b3856f14 Merge "Add action description" 2017-06-02 08:31:21 +00:00
Jenkins
67d065e02a Merge "Remove usage of parameter enforce_type" 2017-06-02 01:26:10 +00:00
Jenkins
891a351a04 Merge "Watcher official install-guide" 2017-06-01 04:38:16 +00:00
Feng Shengqin
f47fd9ac5e Remove usage of parameter enforce_type
Oslo.config deprecated parameter enforce_type and change
its default value to True. Remove the usage of it to avoid
DeprecationWarning: "Using the 'enforce_type' argument is
deprecated in version '4.0' and will be removed in version
'5.0': The argument enforce_type has changed its default
value to True and then will be removed completely."

Change-Id: I59621664773ee5ad264e6da9b15231f30dbb9c40
Closes-Bug: #1694616
2017-06-01 10:13:20 +08:00
Hidekazu Nakamura
7b766680b0 Replace default cinder endpoint type
The default cinder endpoint type is publicURL in cinderclient.
This patch replaces default cinder endpoint type from
internalURL to publicURL.

Change-Id: Ie6951086e4656bd83195dab151dbaaf948113a7c
Related-Bug: #1686298
2017-06-01 01:20:00 +00:00
licanwei
75a025d2d2 Add action description
Add action get_description in class BaseAction.
This information will be sent to the API side via notification.

Partially Implements: blueprint dynamic-action-description

Change-Id: I9ce1b18ad8c5eb7db62ec926d1859d0f508074b0
2017-05-31 18:03:19 +08:00
Jenkins
590bd43a1d Merge "Trivial fix typos" 2017-05-31 08:54:56 +00:00
Jenkins
d2e42a835b Merge "Deleted audit record still get by 'audit list'cmd" 2017-05-31 08:54:15 +00:00
Jenkins
a34e55e47a Merge "Replace oslo_utils.timeutils.isotime" 2017-05-31 08:49:41 +00:00
aditi
a62acbf2ab Watcher official install-guide
Currently watcher project does not have an official
install guide at [1]

This patch adds watcher install guide for rdo and debian.

install-guide is written following the document [2].

[1] https://docs.openstack.org/project-install-guide/ocata/
[2] https://docs.openstack.org/contributor-guide/project-install-guide.html

Change-Id: Idfae7286003f81222dadf91ddcaf95a42c7eb07f
2017-05-31 08:40:27 +00:00
Vu Cong Tuan
35074edaf7 Trivial fix typos
Change-Id: I4c7d3a0d815a616d1ba2c0d26135db5f2aea0c2f
2017-05-30 15:55:33 +07:00
Luong Anh Tuan
dd4aac4092 Replace oslo_utils.timeutils.isotime
Function 'oslo_utils.timeutils.isotime()' is deprecated in version '1.6'
and will be removed in a future version. We use
datetime.datetime.isoformat() instead. For more informations:
http://docs.openstack.org/developer/oslo.utils/api/timeutils.html#oslo_utils.timeutils.isotime

Change-Id: I17384c369fdc7f86b37fd62370d800ed2463adbe
Closes-Bug: #1514331
2017-05-29 23:34:03 +07:00
Jenkins
bd8151e581 Merge "Reduced the code complexity" 2017-05-29 09:15:26 +00:00
Jenkins
8585e49359 Merge "Updated from global requirements" 2017-05-27 12:23:06 +00:00
Jenkins
5d3af47b7d Merge "Versioned Notifications for service object" 2017-05-27 12:20:45 +00:00
OpenStack Proposal Bot
1001525664 Updated from global requirements
Change-Id: I1baa46eba0e7dbae816dbbeb0914f4e1efc8fa0a
2017-05-26 17:31:36 +00:00
licanwei
a33f40ec21 Deleted audit record still get by 'audit list'cmd
Audit record was deleted but the field 'state' maybe not set DELETED.
get_audit_list's filter used field 'state' will get
wrong result.
filter rule should use field 'deleted_at' instead of field 'state'.
get_action_list and get_action_plan_list have the same filter rule.

Change-Id: I08b2a005ca5fb7c2741ac5ed97c6e6b4279758ed
Closes-Bug: #1693666
2017-05-26 14:53:32 +08:00
Vladimir Ostroverkhov
d2a8454043 Versioned Notifications for service object
Implements: blueprint service-versioned-notifications-api

Change-Id: I9d601edb265ee230104f6c63a5f044869aeb3a02
2017-05-25 12:52:01 +03:00
Jenkins
9bb1e653d8 Merge "Change cinder api_version to '3' in default" 2017-05-25 06:51:58 +00:00
Akihito INOH
bb536ee40d Change cinder api_version to '3' in default
Block Storage API v2 is deprecated now. Instead of it, we should use v3
in default (api_version).

This patch replace cinder default api_version from '2' to '3' in
conf/cinder_client.py

Change-Id: I53ffa74cdac7ac31c74937bf18da8ed2fec92223
Closes-Bug: #1691104
2017-05-25 09:26:33 +09:00
OpenStack Proposal Bot
a0bf1b7d70 Updated from global requirements
Change-Id: Id71f841aa19c8cc07205a59450ea376d4a7ffce4
2017-05-24 03:47:55 +00:00
Jenkins
40f6eea637 Merge "Remove the deprecated tempest.test.attr" 2017-05-22 09:38:12 +00:00
suzhengwei
6c5a3910a7 doc error for WeightPlanner
Change-Id: I6c51a919baa32e9b46bfadfcf8e6afac27890b17
2017-05-22 16:08:53 +08:00
Ngo Quoc Cuong
a4fac69d85 Remove the deprecated tempest.test.attr
[1] moves the attr decorator from test.py to tempest/lib. So, all the
references to tempest.test has to be moved to tempest.lib.decorator.

[2] https://review.openstack.org/#/c/456236/

Change-Id: If977e559d9f3b982baf2974efef3c5b375f263b9
2017-05-22 10:11:18 +07:00
Luong Anh Tuan
21994297cf Replace assertRaisesRegexp with assertRaisesRegex
This replaces the deprecated (in python 3.2) unittest.TestCase
method assertRaisesRegexp() with assertRaisesRegex().

Change-Id: I38c3055288034aba51c11bb1bccd3655f760cecc
Closes-Bug: #1436957
2017-05-19 18:06:00 +07:00
OpenStack Proposal Bot
8a818c9071 Updated from global requirements
Change-Id: Id3b644be5dccdf4abf60c6a49400f61582f0d244
2017-05-17 04:00:56 +00:00
Jenkins
041fcb4ca0 Merge "Added tempest test for workload_stabilization" 2017-05-17 01:32:13 +00:00
Jenkins
a8d765bb28 Merge "Fix a typo" 2017-05-10 18:22:08 +00:00
zhangjianfeng
2b152bf17c [bugfix]for division use accurate division
for now / just get int value ,this will lead method
filter_destination_hosts return 0 host
because self.threshold / 100 * host.vcpus is 0
so we need use accurate division to change this

close-bug: 1689269

Change-Id: I5663951ce750d6c4580a507ccfc0268baea0685f
2017-05-08 18:27:24 +08:00
chenaidong1
08e585d405 Fix a typo
'specfication' should be 'specification'

Change-Id: I845e6199c4e2152295fb02ac44a1b090a3d7561d
2017-05-08 15:43:57 +08:00
OpenStack Proposal Bot
38e4255ec0 Updated from global requirements
Change-Id: I5ab36d982f5ef09548303f1233116a7ad74e00f2
2017-05-04 13:33:41 +00:00
Jenkins
a167044cde Merge "[bugfix]retry is reached but action still success" 2017-05-04 09:17:36 +00:00
Jenkins
1366f79b63 Merge "Add Watcher JobStore for background jobs" 2017-05-03 14:50:35 +00:00
Jenkins
f55b9b127e Merge "Add 'rm -f .testrepository/times.dbm' command in testenv" 2017-05-03 12:01:49 +00:00
Jenkins
1b7b467151 Merge "replace nova endpoint" 2017-05-03 12:01:32 +00:00
Alexander Chadin
f40fcdc573 Add Watcher JobStore for background jobs
This patch set adds WatcherJobStore class that allows to link
jobs and services.

Partially-Implements: blueprint background-jobs-ha
Change-Id: I575887ca6dae60b3b7709e6d2e2b256e09a3d824
2017-05-03 12:07:01 +03:00
Jenkins
2d98d5e743 Merge "Fix devstack plugin" 2017-05-02 18:36:27 +00:00
OpenStack Proposal Bot
877230569a Updated from global requirements
Change-Id: I685b9a86764c24fb638c6a684a7b82818d8a6aac
2017-04-27 11:50:22 +00:00
Jenkins
f842c5f601 Merge "Add host_aggregates in exclude rule of audit scope" 2017-04-27 11:01:22 +00:00
Pradeep Kumar Singh
0a899a2dc2 Add host_aggregates in exclude rule of audit scope
Currently if user wants to skip some host_aggregates from audit,
it is not possible. This patch adds host_aggregates into the exclude
rule of audit scope. This patch also implements audit-tag-vm-metadata
using scopes.

TODOs:
1. Add tests
2. Remove old implementation of audit-tag-vm-metadata

Change-Id: Ie86378cb02145a660bbf446eedb29dc311fa29d7
Implements: BP audit-tag-vm-metadata
2017-04-27 08:37:16 +00:00
licanwei
426232e288 replace nova endpoint
The default is publicURL in novaclient.
This also caused the failure of
gate-watcher-dsvm-multinode-ubuntu-xenial-nv.

Change-Id: I485dd62fb7199ffeca29a9b573a624bf144484d1
Closes-Bug: #1686298
Closes-Bug: #1686281
2017-04-27 02:08:04 +00:00
Jenkins
778d4c6fe4 Merge "Set access_policy for messaging's dispatcher" 2017-04-25 14:11:17 +00:00
Jenkins
f852467d6a Merge "Add ironicclient" 2017-04-25 13:43:14 +00:00
M V P Nitesh
dcf64ed1f4 Add 'rm -f .testrepository/times.dbm' command in testenv
Running py2* post py3* tests results in error. Add
'rm -f .testrepository/times.dbm' command in testenv to
resolve this.

Change-Id: Ia43f8d10f157d988c4d2c89f16cac0ea729cabe6
2017-04-25 12:52:13 +05:30
Jenkins
03f75202c8 Merge "[Doc] fix local.conf.compute" 2017-04-25 07:01:57 +00:00
Jenkins
0173a713c1 Merge "use instance data replace exception.NoDataFound" 2017-04-25 00:14:07 +00:00
Hidekazu Nakamura
216f3bab29 [Doc] fix local.conf.compute
Compute node needs placement-client service from Ocata.

Change-Id: Ibd02a126bb4808625cede8fe04255ac014268adb
2017-04-24 20:58:37 +09:00
zhangjianfeng
077b806bf6 [bugfix]retry is reached but action still success
now when action like live-migration retry is reached
result is False but action still success
we can add check in do execute method can fix this problem.
close-bug: 1685757

Change-Id: I8390566ec8dcfa3a71b931d5be1b305802ac0b2a
2017-04-24 18:17:22 +08:00
licanwei
d892153b58 use instance data replace exception.NoDataFound
If instance_ram_util and instance_disk_util can not get data
from datasource. we can use instance data,
just like total_cpu_utilization

Change-Id: I4170b96946b07435411ada5ff4a14c978c0435b4
2017-04-24 15:35:04 +08:00
shubhendu
2efe211f36 Set access_policy for messaging's dispatcher
oslo.messaging allow dispatcher to restrict endpoint
methods with DefaultRPCAccessPolicy to fix FutureWarning

Closes-Bug:1663543

Change-Id: I0288320193b0153ee223664696abca21cbdb0349
2017-04-24 06:32:33 +00:00
Hidekazu Nakamura
f55ea7824e Fix devstack plugin
Stack.sh after unstack.sh results in error.
This patch fix it.

Change-Id: I35d74896611e56d916a9846b2f854bd060a606e4
2017-04-21 16:49:04 +09:00
Hidekazu Nakamura
e5eb4f51be [Doc] messaging -> messagingv2
Nova sends notifications using 2.0 messging format.

Change-Id: Ib0202ba5291f1666bdbf9b6830521b1a2aa20a80
2017-04-18 11:54:16 +09:00
licanwei
f637a368d7 Add ironicclient
This patch set adds ironicclient.

Change-Id: I122a26465d339ee6e36c0f234d3fd6c57cee2afa
Partially-Implements: blueprint build-baremetal-data-model-in-watcher
2017-04-17 06:48:05 +00:00
Jenkins
2e8fb5a821 Merge "exception when running 'watcher actionplan start XXX'" 2017-04-13 11:59:45 +00:00
OpenStack Proposal Bot
dbff4326e3 Updated from global requirements
Change-Id: I3df338013a22ba11e83929660e1c63d87fb30d01
2017-04-12 13:29:03 +00:00
Jenkins
13a99b4c09 Merge "Prevent the migration of VM with 'optimize' False in VM metadata" 2017-04-12 12:00:05 +00:00
Jenkins
a8994bc227 Merge "Added suspended audit state" 2017-04-12 05:24:01 +00:00
Hidekazu Nakamura
c6845c0136 Added suspended audit state
New audit state SUSPENDED is added in this patch set. If audit
state with continuous mode is changed from ONGOING to SUSPENDED,
audit's job is removed and the audit is not executed.
If audit state changed from SUSPENDED to ONGOING in reverse,
audit is executed again periodically.

Change-Id: I32257f56a40c0352a7c24f3fb80ad95ec28dc614
Implements: blueprint suspended-audit-state
2017-04-11 20:50:24 +09:00
Jenkins
02c8e7d89c Merge "Add gnocchi support in uniform_airflow strategy" 2017-04-11 10:52:30 +00:00
Jenkins
0db41f1862 Merge "Updated from global requirements" 2017-04-11 01:30:46 +00:00
Santhosh Fernandes
b02cf3bea5 Add gnocchi support in uniform_airflow strategy
This patch adds gnocchi support in uniform_airflow strategy
and adds unit tests corresponding to that change.

Change-Id: I347d0129da94a2fc88229d09297765795c5eeb1a
Partiallly-Implements: bp gnocchi-watcher
2017-04-10 19:14:37 +05:30
XieYingYun
4eeaa0ab6b Add Apache License Content in index.rst
Add Apache License 2.0 Content which is necessary
for ./releasenotes/source/index.rst.

Change-Id: Ieda2bda1eadc26a1e3420aecd3bee1b64ae3e23f
2017-04-10 18:45:36 +08:00
Jenkins
84d6d4aadd Merge "Optimize the link address" 2017-04-10 08:28:17 +00:00
Jenkins
4511b36496 Merge "Optimize the link address" 2017-04-10 08:22:14 +00:00
Jenkins
9a5c017a9a Merge "correct syntax error" 2017-04-10 08:21:24 +00:00
Jenkins
4690e402ce Merge "Add gnocchi support in workload_balance strategy" 2017-04-10 08:20:21 +00:00
M V P Nitesh
442e569686 Optimize the link address
Use https instead of http to ensure the safety

Change-Id: I41035ccb7b46c3f4ffc54cedb2392bfb64e2ac4c
2017-04-10 11:59:19 +05:30
Yumeng_Bao
5d948e8aa1 correct syntax error
Change-Id: Ied06d39da39b955a90e890156f8c11e329cf864e
2017-04-10 10:57:19 +08:00
OpenStack Proposal Bot
f83a92fc70 Updated from global requirements
Change-Id: I3aee3f27ef116b4cb636b090caad1806e3447744
2017-04-07 14:34:49 +00:00
Jenkins
a06c462050 Merge "Add gnocchi support in VM-Workload-Consolidation strategy" 2017-04-07 13:37:59 +00:00
Jenkins
74e9349c1f Merge "Add gnocchi support in outlet_temp_control strategy" 2017-04-07 12:49:33 +00:00
Jenkins
7c048c761e Merge "Add gnocchi support in workload_stabilization strategy" 2017-04-07 10:12:48 +00:00
Jenkins
4006b4af7a Merge "Run Watcher-API behind mod-wsgi" 2017-04-07 08:42:30 +00:00
licanwei
527423a5fa exception when running 'watcher actionplan start XXX'
In DefaultApplier.execute(), Action.list should set eager=True.
Otherwise it will trigger an exception when the notification is sent.

This also causes the FAILURE of
gate-watcher-dsvm-multinode-ubuntu-xenial-nv.

Change-Id: I27db9691727671abb582d4f22283ebda5bd51b07
Closes-Bug: #1676308
2017-04-07 16:19:21 +08:00
XieYingYun
1d05444f67 Optimize the link address
Use https instead of http to ensure the safety without containing our
account/password information

Change-Id: I1f164848f164d9694c0cfc802cc3980459bdf12f
2017-04-07 10:55:59 +08:00
Santhosh Fernandes
6de94cca2d Add gnocchi support in outlet_temp_control strategy
This patch adds gnocchi support in outlet_temp_control strategy
and adds unit tests corresponding to that change.
Partiallly-Implements: bp gnocchi-watcher

Change-Id: I2c2e9a86c470f3402adc3dbb7eb9995c643d5b37
2017-04-05 19:26:54 +05:30
Jenkins
9b5d17b412 Merge "oslo messaging notifications driver update" 2017-04-05 12:37:56 +00:00
Jenkins
719b96f2a8 Merge "fixed syntax error in json" 2017-04-05 12:33:18 +00:00
the.bling
e9f83417eb fixed syntax error in json
Change-Id: I6dc02d53291e42fb1de6811f439f5814c49af769
2017-04-05 16:37:41 +05:30
Yumeng_Bao
a139cca260 Replace py34 with py35
Change-Id: I562e53718ed269545a425cf30c59442ec72566f8
2017-04-05 11:25:01 +08:00
Jenkins
c04d3cc5e0 Merge "Use tox to generate a sample configuration file" 2017-04-05 01:52:41 +00:00
Santhosh Fernandes
e549e43e9e Add gnocchi support in workload_balance strategy
This patch adds gnocchi support in workload_balance strategy
and adds unit tests corresponding to that change.

Change-Id: I9bc56c7b91b5c3fd0cfe97d75c3bace50ab22532
Partiallly-Implements: bp gnocchi-watcher
2017-04-03 15:52:42 +05:30
Jenkins
c1a2c79514 Merge "Updated from global requirements" 2017-04-03 07:26:01 +00:00
Jenkins
f79cad99cb Merge "Add gnocchi plugin support for devstack" 2017-04-03 07:23:33 +00:00
Santhosh Fernandes
8663c3a5c5 Add gnocchi plugin support for devstack
This patch enables gnocchi plugin for devstack.

Partiallly-Implements: bp gnocchi-watcher
Closes-Bug: 1662515
Change-Id: I6614ce6999c9681bd6fafc6c85a3755b5ce8e2dd
2017-04-03 09:52:07 +05:30
OpenStack Proposal Bot
19d9b83665 Updated from global requirements
Change-Id: I4b82c80745c1cb54b66a5cb4a7fcecd7fbf964a3
2017-04-01 15:35:28 +00:00
aditi
af22899ebe Run Watcher-API behind mod-wsgi
This patch adds support to run watcher-api
with mod-wsgi. It provides
1. wsgi app script files, to run watcher-api under apache.
2. updated devstack plugin to run watcher-api default with
   mod-wsgi.
3. Document to deploy watcher-api behind wsgi.

Change-Id: I8f1026f0b09fd774376220c2d117ee66f72421b8
Closes-Bug: #1675376
2017-04-01 19:03:17 +05:30
Yumeng_Bao
fc33e181fc oslo messaging notifications driver update
Replace "messaging" with "messagingv2".

Change-Id: Iab53b5ba8cd58a0655dc35489081fb22d5834363
2017-04-01 18:34:34 +08:00
Yumeng_Bao
a3ee163480 Use tox to generate a sample configuration file
There is no sample configuration file if we don't generate one.

Change-Id: Ibe9005db4fa24b63914fa5f24fe4b144867781cd
2017-04-01 18:26:28 +08:00
Vincent Françoise
334558f17c Added tempest test for workload_stabilization
In this changeset, I added a tempest test that is in charge of
executing the workload_stabilization strategy.

Change-Id: I61bad268fc5895ddb22312baeb21da5ae3c71de9
2017-03-30 07:20:13 +00:00
Santhosh Fernandes
4642a92e78 Add gnocchi support in VM-Workload-Consolidation strategy
This patch adds gnocchi support in VM-Workload-Consolidation strategy
and adds unit tests corresponding to that change.

Change-Id: I4aab158a6b7c92cb9fe8979bb8bd6338c4686b11
Partiallly-Implements: bp gnocchi-watcher
2017-03-29 19:33:55 +05:30
OpenStack Proposal Bot
69c53da298 Updated from global requirements
Change-Id: I07bc3672692faec1dab41e98f7cf6b8fab821a2a
2017-03-29 13:44:56 +00:00
Jenkins
49924e1915 Merge "Use HostAddressOpt for opts that accept IP and hostnames" 2017-03-29 12:05:35 +00:00
Santhosh Fernandes
d53abb7af5 Fix for remove verbose option
This commit[1] has removed verbose option due to which our ut's are failing.
This patch is fixing this issue.

[1] https://review.openstack.org/#/c/444217/

Change-Id: I784a7f855f42de462e8fc8f829f5526e1483dab4
2017-03-29 11:17:43 +05:30
jeremy.zhang
4d3727eafb Use HostAddressOpt for opts that accept IP and hostnames
Some configuration options were accepting both IP addresses
and hostnames. Since there was no specific OSLO opt type to
support this, we were using ``StrOpt``. The change [1] that
added support for ``HostAddressOpt`` type was merged in Ocata
and became available for use with oslo version 3.22.

This patch changes the opt type of configuration options to use
this more relevant opt type - HostAddressOpt.

[1] I77bdb64b7e6e56ce761d76696bc4448a9bd325eb

Change-Id: Idec43189ff8edc539027ba0b0369e54ae883cd2b
2017-03-28 15:22:25 +08:00
Jenkins
4a3c15185c Merge "stale the action plan" 2017-03-27 22:46:30 +00:00
Jenkins
2c6ab9a926 Merge "Add period input parameter to vm workload consolidation and outlet temp control strategy." 2017-03-27 22:46:07 +00:00
Santhosh Fernandes
0750b93827 Add gnocchi support in workload_stabilization strategy
This patch adds gnocchi support in workload_stabilization strategy
and adds unit tests corresponding to that change.

Change-Id: I96bd758962bbf67d60e19a99a19451fb80e447b2
Partiallly-Implements: bp gnocchi-watcher
2017-03-27 23:56:41 +05:30
Pradeep Kumar Singh
a2cb02a861 Prevent the migration of VM with 'optimize' False in VM metadata
This patch adds the functionality to filter out VMs which have
metadata field 'optimize' set to False. This patch implements the
functionality for basic_consolidation strategy.

Change-Id: Iaf7b63e09534e4a67406e7f092242558b78c0bde
Partially-Implements: BP audit-tag-vm-metadata
2017-03-27 10:17:37 +00:00
Santhosh Fernandes
377889859d Add period input parameter to vm workload consolidation and
outlet temp control strategy.

Closes-Bug: #1614021
Change-Id: Iec975e4a4a39168a65ae89ca75a5ca9445c14f9d
2017-03-27 15:06:36 +05:30
Jenkins
54f0758fc3 Merge "Remove log translations" 2017-03-27 08:36:22 +00:00
Jenkins
a644600a18 Merge "Add endpoint_type option for openstack clients." 2017-03-27 07:49:04 +00:00
Jenkins
ca3d367ac7 Merge "Updated from global requirements" 2017-03-27 00:53:08 +00:00
Margarita Shakhova
cde60d2ead Add endpoint_type option for openstack clients.
Interface type internalURL' is used as a default value.

Change-Id: Ia1acbfbfd2a1eecd85e5aa1d2e19665d411c4c58
Closes-Bug: #1671405
2017-03-24 21:12:11 +00:00
Jenkins
f106076d70 Merge "Imported Translations from Zanata" 2017-03-24 20:03:43 +00:00
OpenStack Proposal Bot
e75dbfd776 Updated from global requirements
Change-Id: I74bfd82a835c43d94be6279adbe582f2a0bfa302
2017-03-24 16:38:30 +00:00
Santhosh Fernandes
18aa50c58e Add gnocchi support in basic_consolidation strategy
This patch adds gnocchi support in basic_consolidation strategy
and adds unit tests corresponding to that change.

Change-Id: Ia1ee55fca8eadffbd244c0247577805b6856369d
Partiallly-Implements: bp gnocchi-watcher
2017-03-24 09:09:42 +00:00
Jenkins
2c2120526c Merge "Add Gnocchi datasource" 2017-03-24 09:00:33 +00:00
Jenkins
9e505d3d36 Merge "exception when running 'watcher service list'" 2017-03-24 08:17:51 +00:00
OpenStack Proposal Bot
54ce5f796f Imported Translations from Zanata
For more information about this automatic import see:
http://docs.openstack.org/developer/i18n/reviewing-translation-import.html

Change-Id: I3090e188c8506781fe7260cb99727fab02df1044
2017-03-24 07:41:20 +00:00
yanxubin
f605888e32 Remove log translations
Log messages are no longer being translated. This removes all use of
the _LE, _LI, and _LW translation markers to simplify logging and to
avoid confusion with new contributions.

See:
http://lists.openstack.org/pipermail/openstack-i18n/2016-November/002574.html
http://lists.openstack.org/pipermail/openstack-dev/2017-March/113365.html

Change-Id: I3552767976807a9851af69b1fa4f86ac25943025
2017-03-24 09:46:19 +08:00
Alexander Chadin
0b213a8734 Add Gnocchi datasource
This patch set adds Gnocchi datasource support

Implements: blueprint gnocchi-watcher

Change-Id: I41653149435fd355548071de855586004371c4fc
2017-03-23 13:54:03 +03:00
licanwei
38a3cbc84a exception when running 'watcher service list'
We have two controllers as HA in our OpenStack environment.
There are watcher-applier and watcher-decision-engine in each
controller. So there are two same name in the services table.
In this case, the objects.Service.get_by_name(context, name)
will trigger exception of MultipleResultsFound.
We should use objects.Service.get(context, id) replace of
objects.Service.get_by_name(context, name).

Change-Id: Ic3ce784590d6c2a648cb3b28299744deed281332
Closes-Bug: #1674196
2017-03-22 12:12:31 +08:00
Jenkins
eb038e4af0 Merge "set eager=True for actionplan.list" 2017-03-21 10:19:41 +00:00
Jenkins
b5eccceaed Merge "Remove old oslo.messaging transport aliases" 2017-03-21 09:24:23 +00:00
Jenkins
f7b655b712 Merge "Local copy of scenario test base class" 2017-03-20 13:10:33 +00:00
ChangBo Guo(gcb)
1386ce690f Remove old oslo.messaging transport aliases
Those are remnants from the oslo-incubator times. Also, oslo.messaging
deprecated [1] transport aliases since 5.2.0+ that is the minimal
version supported for stable/newton. The patch that bumped the minimal
version for Watcher landed 3 months+ ago, so we can proceed ripping
those aliases from the code base.

[1] I314cefa5fb1803fa7e21e3e34300e5ced31bba89

Change-Id: Ie3008cc54b0eb3d1d02f55f388bd1c3b109d126d
Closes-Bug: #1424728
2017-03-20 13:23:45 +08:00
licanwei
38e4b48d70 stale the action plan
Check the creation time of the actionplan,
and set the state to SUPERSEDED if it has expired.

Change-Id: I900e8dc5011dec4cffd58913b9c5083a6131d70d
Implements: blueprint stale-action-plan
2017-03-18 13:46:34 +08:00
Andrea Frittoli
56ca542bef Local copy of scenario test base class
The scenario tests base class from Tempest is not a stable interface
and it's going to be refactored on Tempest side, as notified in

http://lists.openstack.org/pipermail/openstack-dev/2017-February/112938.html

Maintain a local copy of the base class, taken from Tempest with head of
master at c5f1064759fe6c75a4bc5dc251ed1661845936cb.

Change-Id: Idfa5ebe18c794c51e406156fb120d128478d4f1e
2017-03-17 17:31:46 +00:00
Jenkins
dafe2ad04b Merge "Use https instead of http" 2017-03-17 09:04:48 +00:00
licanwei
6044b04d33 set eager=True for actionplan.list
actionplan.save() will send a send_update notification.
This notification need eagerly loaded,
so we should set eager=True for actionplan.list.

Change-Id: Iafe35b9782fb0cc52ba5121c155f62c61ef70e1f
Closes-Bug: #1673679
2017-03-17 16:16:26 +08:00
Yumeng_Bao
6d81ac15b8 Use https instead of http
Currently http is used to access git, however http is not safe enough
since the access information contains our account/password information.
Use https instead of http to ensure the safety.

And for others services such as pypi or python, it's still nice to use
https.

Change-Id: I706a4a1873c6bbc05385057757fc5962344f9371
2017-03-17 07:44:27 +00:00
OpenStack Proposal Bot
db077e872e Updated from global requirements
Change-Id: Id1f3bee0c6cfb5621a7c23d7865247d6ef4217d1
2017-03-16 18:24:19 +00:00
Béla Vancsics
fd55d28d42 Reduced the code complexity
I extracted some of the functionalities into helper functions
to reduce the length and complexity of build_query (in
watcher/datasource/ceilometer.py).
Additionally it became more readable as well, without
changing its functionality.

Change-Id: I9e5c524754cf0f9d718a216465ba1b7536add80e
2017-03-16 07:45:44 +01:00
OpenStack Proposal Bot
51bf7fedb6 Updated from global requirements
Change-Id: Id125d2e27aba257fb026491fc505245f4d7555ba
2017-03-15 12:54:16 +00:00
OpenStack Proposal Bot
bf0fd48659 Updated from global requirements
Change-Id: Id458895286cdaffe66676b68a4f4fd7169c24347
2017-03-15 05:21:56 +00:00
Jenkins
ba98c88303 Merge "Add Action Notification" 2017-03-08 09:58:46 +00:00
OpenStack Proposal Bot
77b406748c Updated from global requirements
Change-Id: I35c23139feb449af69470f8f9e90f82dda516585
2017-03-07 02:08:03 +00:00
Jenkins
d21198da8f Merge "[Fix gate]Update test requirement" 2017-03-06 03:30:47 +00:00
Jenkins
12a7b7171b Merge "Add Apache License content in conf.py file" 2017-03-04 23:16:39 +00:00
Jenkins
d45ab13619 Merge "Adding instance metadata into cluster data model" 2017-03-04 01:54:03 +00:00
Prudhvi Rao Shedimbi
e2d2fc6227 Adding instance metadata into cluster data model
This patch adds instance metadata in the cluster data model. This
is needed for Noisy Neighbor strategy.

Change-Id: Ia92a9f97ba1457ba844cc37a4d443ca4354069e3
2017-03-03 14:52:42 +00:00
yuhui_inspur
3c564ee3d8 Add Apache License content in conf.py file
Change-Id: I84478f02bc7f04ef57334a738fa0b1f3ca0cac45
2017-03-02 23:27:32 -08:00
ricolin
f9ce21a9a9 [Fix gate]Update test requirement
Since pbr already landed and the old version of hacking seems not
work very well with pbr>=2, we should update it to match global
requirement.
Partial-Bug: #1668848

Change-Id: I5de155e6ff255f4ae65deff991cff754f5777a8d
2017-03-03 11:43:53 +08:00
Jenkins
03a2c0142a Merge "Optimize audit process" 2017-03-02 23:25:39 +00:00
Hidekazu Nakamura
5afcf7a7f4 Remove unused PNG files in image_src directory
This patch removes unused PNG files in image_src directory.

Change-Id: Ia65ae07932d238277731a26fddb798b92d06e958
2017-03-01 10:26:14 +09:00
Jenkins
63faf4695e Merge "Fix no endpoints of ceilometer in devstack environment setup." 2017-02-28 01:55:53 +00:00
Jenkins
97800d1553 Merge "Switch to use test_utils.call_until_true" 2017-02-27 23:40:58 +00:00
OpenStack Proposal Bot
8f85169c15 Updated from global requirements
Change-Id: I693764145996f4c941de4b129a73c36e0db839d6
2017-02-27 01:21:44 +00:00
ericxiett
68e4bc4d87 Fix no endpoints of ceilometer in devstack environment setup.
There are not any endpoints for `ceilometer` with devstack/
local.conf.controller. The service `ceilometer-api` should
be enabled explicitly.

Change-Id: I2218a98182001bef65fbc17ae305cfadf341930e
Closes-Bug: #1667678
2017-02-24 21:40:19 +08:00
ericxiett
9e7f7f54f3 Fix some typos in vm_workload_consolidation.py.
Change-Id: I1da1ed89f3e278af05d227d5011c8984218c026f
2017-02-23 16:40:00 +08:00
licanwei
fceab5299b Optimize audit process
In the current audit process, after executing the strategy,
will check whether there are currently running actionplan,
and if so, will set the new actionplan SUPERSEDED.
We can optimize the process to perform this check in pre_execute(),
and if any actionplan is running, no further processing is performed.

Change-Id: I7377b53a2374b1dc177d256a0f800a86b1a2a16b
Closes-Bug: #1663150
2017-02-17 15:01:05 +08:00
Jenkins
dddbb63633 Merge "Adding additional details to notification logs" 2017-02-16 13:25:14 +00:00
Jenkins
b788dfab71 Merge "Fix spelling error in NotificationEndpoint classes." 2017-02-16 13:24:42 +00:00
Jenkins
7824b41e12 Merge "Add SUPERSEDED description" 2017-02-16 13:23:47 +00:00
Jenkins
86ded4d952 Merge "Reactivate watcher dashboard plugin in devstack/local.conf.controller" 2017-02-16 13:04:28 +00:00
Jenkins
5d6e731c42 Merge "Fix that remove 'strategy' attribute does not work." 2017-02-15 14:09:08 +00:00
Jenkins
cba6713bdc Merge "Add checking audit state" 2017-02-15 14:08:59 +00:00
Yumeng_Bao
24ab0469ec Reactivate watcher dashboard plugin in devstack/local.conf.controller
Since watcher dashboard can be sucessfully installed now by devstack,
we should enable this again. Many of us are get the local.conf from
here,so this change is necessary, we can enable watch dashboard plugin
by default.

Change-Id: Iad5081a97515b3f831d2f468dc514a942e6d3420
2017-02-15 17:32:47 +08:00
Jenkins
4d71bb112c Merge "Remove support for py34" 2017-02-14 10:28:34 +00:00
licanwei
fd374d1d30 Add SUPERSEDED description
Add SUPERSEDED description

Change-Id: I05dc12451ecde338d94f99be522a38e7fb042528
2017-02-13 12:23:32 +08:00
Alexander Chadin
25789c9c5a Add Action Notification
This patch set adds the following action notifications:

- action.create
- action.update
- action.delete
- action.execution.start
- action.execution.end
- action.execution.error

Partially Implements: blueprint action-versioned-notifications-api

Change-Id: If0bc25bfb7cb1bff3bfa2c5d5fb9ad48b0794168
2017-02-10 11:43:35 +03:00
Ken'ichi Ohmichi
a9b3534e97 Switch to use test_utils.call_until_true
test.call_until_true has been deprecated since Newton on Tempest side,
and now Tempest provides test_utils.call_until_true as the stable
library method. So this patch switches to use the stable method before
removing old test.call_until_true on Tempest side.

Change-Id: Iba2130aca93c8e6bccb4f8ed169424c791ebc127
Needed-by: Ide11a7434a4714e5d2211af1803333535f557370
2017-02-09 10:50:11 -08:00
Chris Spencer
f80c0c732a Adding additional details to notification logs
Improves tracking independent workflows.  A log adapter
was added to provide an easy means of prepending publisher
ID and event type information.

Change-Id: I5d2d8a369f99497b05c2a683989e656554d01b4f
Closes-Bug: 1642623
2017-02-09 11:26:53 -07:00
Hidekazu Nakamura
0d83354c57 Add checking audit state
This patch adds checking audit state when updating an existing audit
in accordance with audit state machine.

Closes-Bug: #1662406

Change-Id: I20610c83169b77f141974a5cebe33818a4bf0728
2017-02-09 14:23:14 +09:00
licanwei
67d44eb118 Fix the mapping between the instance and the node
The argument to the add_edge function should be instance.uuid
and node.uuid, not instance and node

Change-Id: Ida694f9158d3eb26e7f31062a18844472ea3c6fa
Closes-Bug: #1662810
2017-02-08 17:41:47 +08:00
Cao Xuan Hoang
8c1757f86d Remove support for py34
The gating on python 3.4 is restricted to <= Mitaka. This is due to
the change from Ubuntu Trusty to Xenial, where only python3.5 is
available. There is no need to continue to keep these settings.

Change-Id: I3b3f0b08f6f27322b8a9d99eb25984ccd6bfe7a6
2017-02-08 11:09:30 +07:00
ericxiett
e55c73be0e Fix that remove 'strategy' attribute does not work.
The 'strategy_id' attribute is the one that not exposes
to API. But the 'PATCH' API always update this attribute.
So this change does not work when choose 'remove' op.
This patch sets value for 'strategy_id' attribute.

Change-Id: I1597fb5d4985bb8271ad3cea7ea5f0adb7de65f4
Closes-Bug: #1662395
2017-02-08 10:57:26 +08:00
Chris Spencer
04c9e0362e Fix spelling error in NotificationEndpoint classes.
Change-Id: I47dc2d73b8e7c4adaa9622de932c0d8abcd17d87
2017-02-07 15:36:50 -07:00
Jenkins
8ceb710b59 Merge "Fix incorrect auto trigger flag" 2017-02-07 16:04:33 +00:00
Hidekazu Nakamura
58711aaaec Fix log level error to warning
When action plan is currently running, new action plan is set as
SUPERSEDED and error log reported. This patch changes log level
from error to warning.

Change-Id: I931218843d8f09340bd5363256164807d514446b
Closes-Bug: #1662450
2017-02-07 17:48:56 +09:00
licanwei
3ad5261d2a Fix incorrect auto trigger flag
'watcher audit list' returns a incorrect auto trigger flag
auto_trigger field is incorrectly unset to False

Change-Id: Iba4a0bda1acf18cbfde6f1dcdb0985a4c3f7b5bb
Closes-Bug: #1662051
2017-02-06 14:42:44 +08:00
Jenkins
26c7726c00 Merge "Using items() instead of six.iteritems()" 2017-02-03 09:33:24 +00:00
zhuzeyu
5b2cdb53a8 Using items() instead of six.iteritems()
We'd better not use six.iteritems(), read follow doc
http://lists.openstack.org/pipermail/openstack-dev/2015-June/066391.html

Change-Id: I32aff3ad0cc936c6b623db313b6f6a0790cbc7fb
2017-02-03 17:01:40 +08:00
Jenkins
4b5dce51dc Merge "Use RPC cast() to be asynchronous" 2017-02-03 08:48:56 +00:00
OpenStack Release Bot
b6a96e04aa Update reno for stable/ocata
Change-Id: I6c75072180fcbd449d9049ae1f2258a53a236ebd
2017-02-02 18:23:37 +00:00
Vincent Françoise
65f9646eae Use RPC cast() to be asynchronous
Change-Id: I54814dc37a79eb06386923f946d85a67894c7646
2017-02-01 14:40:10 +01:00
215 changed files with 6492 additions and 1688 deletions

View File

@@ -2,4 +2,3 @@
host=review.openstack.org
port=29418
project=openstack/watcher.git
defaultbranch=stable/ocata

View File

@@ -1,13 +1,13 @@
If you would like to contribute to the development of OpenStack,
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
should be submitted for review via the Gerrit tool, following
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.

View File

@@ -8,4 +8,4 @@
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/

View File

@@ -2,8 +2,8 @@
Team and repository tags
========================
.. image:: http://governance.openstack.org/badges/watcher.svg
:target: http://governance.openstack.org/reference/tags/index.html
.. image:: https://governance.openstack.org/badges/watcher.svg
:target: https://governance.openstack.org/reference/tags/index.html
.. 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!
* Free software: Apache license
* Wiki: http://wiki.openstack.org/wiki/Watcher
* Wiki: https://wiki.openstack.org/wiki/Watcher
* Source: https://github.com/openstack/watcher
* Bugs: http://bugs.launchpad.net/watcher
* Documentation: http://docs.openstack.org/developer/watcher/
* Bugs: https://bugs.launchpad.net/watcher
* Documentation: https://docs.openstack.org/developer/watcher/

View 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>

View File

@@ -44,6 +44,9 @@ WATCHER_CONF_DIR=/etc/watcher
WATCHER_CONF=$WATCHER_CONF_DIR/watcher.conf
WATCHER_POLICY_JSON=$WATCHER_CONF_DIR/policy.json
WATCHER_DEVSTACK_DIR=$WATCHER_DIR/devstack
WATCHER_DEVSTACK_FILES_DIR=$WATCHER_DEVSTACK_DIR/files
NOVA_CONF_DIR=/etc/nova
NOVA_CONF=$NOVA_CONF_DIR/nova.conf
@@ -51,6 +54,13 @@ if is_ssl_enabled_service "watcher" || is_service_enabled tls-proxy; then
WATCHER_SERVICE_PROTOCOL="https"
fi
WATCHER_USE_MOD_WSGI=$(trueorfalse True WATCHER_USE_MOD_WSGI)
if is_suse; then
WATCHER_WSGI_DIR=${WATCHER_WSGI_DIR:-/srv/www/htdocs/watcher}
else
WATCHER_WSGI_DIR=${WATCHER_WSGI_DIR:-/var/www/watcher}
fi
# Public facing bits
WATCHER_SERVICE_HOST=${WATCHER_SERVICE_HOST:-$HOST_IP}
WATCHER_SERVICE_PORT=${WATCHER_SERVICE_PORT:-9322}
@@ -74,10 +84,21 @@ function is_watcher_enabled {
return 1
}
#_cleanup_watcher_apache_wsgi - Remove wsgi files,
#disable and remove apache vhost file
function _cleanup_watcher_apache_wsgi {
sudo rm -rf $WATCHER_WSGI_DIR
sudo rm -f $(apache_site_config_for watcher-api)
restart_apache_server
}
# cleanup_watcher() - Remove residual data files, anything left over from previous
# runs that a clean run would need to clean up
function cleanup_watcher {
sudo rm -rf $WATCHER_STATE_PATH $WATCHER_AUTH_CACHE_DIR
if [[ "$WATCHER_USE_MOD_WSGI" == "True" ]]; then
_cleanup_watcher_apache_wsgi
fi
}
# configure_watcher() - Set config files, create data dirs, etc
@@ -108,6 +129,28 @@ function create_watcher_accounts {
"$WATCHER_SERVICE_PROTOCOL://$WATCHER_SERVICE_HOST:$WATCHER_SERVICE_PORT"
}
# _config_watcher_apache_wsgi() - Set WSGI config files of watcher
function _config_watcher_apache_wsgi {
local watcher_apache_conf
if [[ "$WATCHER_USE_MOD_WSGI" == "True" ]]; then
sudo mkdir -p $WATCHER_WSGI_DIR
sudo cp $WATCHER_DIR/watcher/api/app.wsgi $WATCHER_WSGI_DIR/app.wsgi
watcher_apache_conf=$(apache_site_config_for watcher-api)
sudo cp $WATCHER_DEVSTACK_FILES_DIR/apache-watcher-api.template $watcher_apache_conf
sudo sed -e "
s|%WATCHER_SERVICE_PORT%|$WATCHER_SERVICE_PORT|g;
s|%WATCHER_WSGI_DIR%|$WATCHER_WSGI_DIR|g;
s|%USER%|$STACK_USER|g;
s|%APIWORKERS%|$API_WORKERS|g;
s|%APACHE_NAME%|$APACHE_NAME|g;
" -i $watcher_apache_conf
enable_apache_site watcher-api
tail_log watcher-access /var/log/$APACHE_NAME/watcher-api-access.log
tail_log watcher-api /var/log/$APACHE_NAME/watcher-api.log
fi
}
# create_watcher_conf() - Create a new watcher.conf file
function create_watcher_conf {
# (Re)create ``watcher.conf``
@@ -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_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 notifications notify_on_state_change "vm_and_task_state"
@@ -154,9 +197,13 @@ function create_watcher_conf {
setup_colorized_logging $WATCHER_CONF DEFAULT
else
# Show user_name and project_name instead of user_id and project_id
iniset $WATCHER_CONF DEFAULT logging_context_format_string "%(asctime)s.%(msecs)03d %(levelname)s %(name)s [%(request_id)s %(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
#config apache files
if [[ "$WATCHER_USE_MOD_WSGI" == "True" ]]; then
_config_watcher_apache_wsgi
fi
# Register SSL certificates if provided
if is_ssl_enabled_service watcher; then
ensure_certificates WATCHER
@@ -205,19 +252,26 @@ function install_watcherclient {
function install_watcher {
git_clone $WATCHER_REPO $WATCHER_DIR $WATCHER_BRANCH
setup_develop $WATCHER_DIR
if [[ "$WATCHER_USE_MOD_WSGI" == "True" ]]; then
install_apache_wsgi
fi
}
# start_watcher_api() - Start the API process ahead of other things
function start_watcher_api {
# Get right service port for testing
local service_port=$WATCHER_SERVICE_PORT
local service_protocol=$WATCHER_SERVICE_PROTOCOL
if is_service_enabled tls-proxy; then
service_port=$WATCHER_SERVICE_PORT_INT
service_protocol="http"
fi
run_process watcher-api "$WATCHER_BIN_DIR/watcher-api --config-file $WATCHER_CONF"
if [[ "$WATCHER_USE_MOD_WSGI" == "True" ]]; then
restart_apache_server
else
run_process watcher-api "$WATCHER_BIN_DIR/watcher-api --config-file $WATCHER_CONF"
fi
echo "Waiting for watcher-api to start..."
if ! wait_for_service $SERVICE_TIMEOUT $service_protocol://$WATCHER_SERVICE_HOST:$service_port; then
die $LINENO "watcher-api did not start"
@@ -240,7 +294,12 @@ function start_watcher {
# stop_watcher() - Stop running processes (non-screen)
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
done
}

View File

@@ -25,7 +25,7 @@ GLANCE_HOSTPORT=${SERVICE_HOST}:9292
DATABASE_TYPE=mysql
# Enable services (including neutron)
ENABLED_SERVICES=n-cpu,n-api-meta,c-vol,q-agt
ENABLED_SERVICES=n-cpu,n-api-meta,c-vol,q-agt,placement-client
NOVA_VNC_ENABLED=True
NOVNCPROXY_URL="http://$SERVICE_HOST:6080/vnc_auto.html"

View File

@@ -17,6 +17,10 @@ NETWORK_GATEWAY=10.254.1.1 # Change this for your network
MULTI_HOST=1
#Set this to FALSE if do not want to run watcher-api behind mod-wsgi
#WATCHER_USE_MOD_WSGI=TRUE
# This is the controller node, so disable nova-compute
disable_service n-cpu
@@ -28,7 +32,7 @@ ENABLED_SERVICES+=,q-svc,q-dhcp,q-meta,q-agt,q-l3,neutron
enable_service n-cauth
# 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_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
disable_service ceilometer-acompute
# Enable the ceilometer api explicitly(bug:1667678)
enable_service ceilometer-api
# Enable the Gnocchi plugin
enable_plugin gnocchi https://git.openstack.org/openstack/gnocchi
LOGFILE=$DEST/logs/stack.sh.log
LOGDAYS=2

View 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"
}

View 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"
}

View 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"
}

View 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"
}

View 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"
}

View 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"
}

View File

@@ -0,0 +1,26 @@
{
"payload": {
"watcher_object.name": "ServiceUpdatePayload",
"watcher_object.namespace": "watcher",
"watcher_object.data": {
"status_update": {
"watcher_object.name": "ServiceStatusUpdatePayload",
"watcher_object.namespace": "watcher",
"watcher_object.data": {
"old_state": "ACTIVE",
"state": "FAILED"
},
"watcher_object.version": "1.0"
},
"last_seen_up": "2016-09-22T08:32:06Z",
"name": "watcher-service",
"sevice_host": "controller"
},
"watcher_object.version": "1.0"
},
"event_type": "service.update",
"priority": "INFO",
"message_id": "3984dc2b-8aef-462b-a220-8ae04237a56e",
"timestamp": "2016-10-18 09:52:05.219414",
"publisher_id": "infra-optim:node0"
}

View File

@@ -407,6 +407,9 @@ be one of the following:
- **CANCELLED** : the :ref:`Audit <audit_definition>` was in **PENDING** or
**ONGOING** state and was cancelled by the
:ref:`Administrator <administrator_definition>`
- **SUSPENDED** : the :ref:`Audit <audit_definition>` was in **ONGOING**
state and was suspended by the
:ref:`Administrator <administrator_definition>`
The following diagram shows the different possible states of an
:ref:`Audit <audit_definition>` and what event makes the state change to a new

View 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

View File

@@ -424,7 +424,7 @@ to Watcher receives Nova notifications in ``watcher_notifications`` as well.
into which Nova services will publish events ::
[oslo_messaging_notifications]
driver = messaging
driver = messagingv2
topics = notifications,watcher_notifications
* Restart the Nova services.

View File

@@ -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
(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_,
and git_ available.
.. _python2.7: http://www.python.org
.. _pip: http://www.pip-installer.org/en/latest/installing.html
.. _git: http://git-scm.com/
.. _python2.7: https://www.python.org
.. _pip: https://pip.pypa.io/en/latest/installing/
.. _git: https://git-scm.com/
Your system shall also have some additional system libraries:

View File

@@ -92,6 +92,12 @@ Detailed DevStack Instructions
Note: if you want to use a specific branch, specify WATCHER_BRANCH in the
local.conf file. By default it will use the master branch.
Note: watcher-api will default run under apache/httpd, set the variable
WATCHER_USE_MOD_WSGI=FALSE if you do not wish to run under apache/httpd.
For development environment it is suggested to set WATHCER_USE_MOD_WSGI
to FALSE. For Production environment it is suggested to keep it at the
default TRUE value.
#. Start stacking from the controller node::
./devstack/stack.sh

View File

@@ -16,8 +16,8 @@ for development purposes.
To install Watcher from packaging, refer instead to Watcher `User
Documentation`_.
.. _`Git Repository`: http://git.openstack.org/cgit/openstack/watcher
.. _`User Documentation`: http://docs.openstack.org/developer/watcher/
.. _`Git Repository`: https://git.openstack.org/cgit/openstack/watcher
.. _`User Documentation`: https://docs.openstack.org/developer/watcher/
Prerequisites
=============
@@ -35,10 +35,10 @@ following tools available on your system:
**Reminder**: If you're successfully using a different platform, or a
different version of the above, please document your configuration here!
.. _Python: http://www.python.org/
.. _git: http://git-scm.com/
.. _setuptools: http://pypi.python.org/pypi/setuptools
.. _virtualenvwrapper: https://virtualenvwrapper.readthedocs.org/en/latest/install.html
.. _Python: https://www.python.org/
.. _git: https://git-scm.com/
.. _setuptools: https://pypi.python.org/pypi/setuptools
.. _virtualenvwrapper: https://virtualenvwrapper.readthedocs.io/en/latest/install.html
Getting the latest code
=======================
@@ -175,11 +175,12 @@ The HTML files are available into ``doc/build`` directory.
Configure the Watcher services
==============================
Watcher services require a configuration file. There is a sample configuration
file that can be used to get started:
Watcher services require a configuration file. Use tox to generate
a sample configuration file that can be used to get started:
.. code-block:: bash
$ tox -e genconfig
$ cp etc/watcher.conf.sample etc/watcher.conf
Most of the default configuration should be enough to get you going, but you

View File

@@ -14,7 +14,7 @@ Unit tests
==========
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::
$ workon watcher
@@ -26,7 +26,7 @@ If you want to only run one of the aforementioned, you can then issue one of
the following::
$ workon watcher
(watcher) $ tox -e py34
(watcher) $ tox -e py35
(watcher) $ tox -e py27
(watcher) $ tox -e pep8

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

View File

@@ -4,11 +4,14 @@
PENDING --> ONGOING: Audit request is received\nby the Watcher Decision Engine
ONGOING --> FAILED: Audit fails\n(no solution found, technical error, ...)
ONGOING --> SUCCEEDED: The Watcher Decision Engine\ncould find at least one Solution
ONGOING --> SUSPENDED: Administrator wants to\nsuspend the Audit
SUSPENDED --> ONGOING: Administrator wants to\nresume the Audit
FAILED --> DELETED : Administrator wants to\narchive/delete the Audit
SUCCEEDED --> DELETED : Administrator wants to\narchive/delete the Audit
PENDING --> CANCELLED : Administrator cancels\nthe Audit
ONGOING --> CANCELLED : Administrator cancels\nthe Audit
CANCELLED --> DELETED : Administrator wants to\narchive/delete the Audit
SUSPENDED --> DELETED: Administrator wants to\narchive/delete the Audit
DELETED --> [*]
@enduml

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 47 KiB

View File

@@ -56,6 +56,7 @@ Getting Started
dev/devstack
deploy/configuration
deploy/conf-files
deploy/apache-mod-wsgi
dev/notifications
dev/testing
dev/rally_link

View File

@@ -72,6 +72,9 @@ Strategy parameter is:
parameter type default Value description
============== ====== ============= ====================================
``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

View File

@@ -70,6 +70,20 @@ Default Watcher's planner:
.. 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
------------------

33
etc/apache2/watcher Normal file
View 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>

View File

@@ -0,0 +1,71 @@
2. Edit the ``/etc/watcher/watcher.conf`` file and complete the following
actions:
* In the ``[database]`` section, configure database access:
.. code-block:: ini
[database]
...
connection = mysql+pymysql://watcher:WATCHER_DBPASS@controller/watcher?charset=utf8
* In the `[DEFAULT]` section, configure the transport url for RabbitMQ message broker.
.. code-block:: ini
[DEFAULT]
...
control_exchange = watcher
transport_url = rabbit://openstack:RABBIT_PASS@controller
Replace the RABBIT_PASS with the password you chose for OpenStack user in RabbitMQ.
* In the `[keystone_authtoken]` section, configure Identity service access.
.. code-block:: ini
[keystone_authtoken]
...
auth_uri = http://controller:5000
auth_url = http://controller:35357
memcached_servers = controller:11211
auth_type = password
project_domain_name = default
user_domain_name = default
project_name = service
username = watcher
password = WATCHER_PASS
Replace WATCHER_PASS with the password you chose for the watcher user in the Identity service.
* Watcher interacts with other OpenStack projects via project clients, in order to instantiate these
clients, Watcher requests new session from Identity service. In the `[watcher_client_auth]` section,
configure the identity service access to interact with other OpenStack project clients.
.. code-block:: ini
[watcher_client_auth]
...
auth_type = password
auth_url = http://controller:35357
username = watcher
password = WATCHER_PASS
project_domain_name = default
user_domain_name = default
project_name = service
Replace WATCHER_PASS with the password you chose for the watcher user in the Identity service.
* In the `[oslo_messaging_notifications]` section, configure the messaging driver.
.. code-block:: ini
[oslo_messaging_notifications]
...
driver = messagingv2
3. Populate watcher database:
.. code-block:: ini
su -s /bin/sh -c "watcher-db-manage" watcher

View File

@@ -0,0 +1,139 @@
Prerequisites
-------------
Before you install and configure the Infrastructure Optimization service,
you must create a database, service credentials, and API endpoints.
1. Create the database, complete these steps:
* Use the database access client to connect to the database
server as the ``root`` user:
.. code-block:: console
$ mysql -u root -p
* Create the ``watcher`` database:
.. code-block:: none
CREATE DATABASE watcher CHARACTER SET utf8;
* Grant proper access to the ``watcher`` database:
.. code-block:: none
GRANT ALL PRIVILEGES ON watcher.* TO 'watcher'@'localhost' \
IDENTIFIED BY 'WATCHER_DBPASS';
GRANT ALL PRIVILEGES ON watcher.* TO 'watcher'@'%' \
IDENTIFIED BY 'WATCHER_DBPASS';
Replace ``WATCHER_DBPASS`` with a suitable password.
* Exit the database access client.
.. code-block:: none
exit;
2. Source the ``admin`` credentials to gain access to
admin-only CLI commands:
.. code-block:: console
$ . admin-openrc
3. To create the service credentials, complete these steps:
* Create the ``watcher`` user:
.. code-block:: console
$ openstack user create --domain default --password-prompt watcher
User Password:
Repeat User Password:
+---------------------+----------------------------------+
| Field | Value |
+---------------------+----------------------------------+
| domain_id | default |
| enabled | True |
| id | b18ee38e06034b748141beda8fc8bfad |
| name | watcher |
| options | {} |
| password_expires_at | None |
+---------------------+----------------------------------+
* Add the ``admin`` role to the ``watcher`` user:
.. code-block:: console
$ openstack role add --project service --user watcher admin
.. note::
This command produces no output.
* Create the watcher service entities:
.. code-block:: console
$ openstack service create --name watcher --description "Infrastructure Optimization" infra-optim
+-------------+----------------------------------+
| Field | Value |
+-------------+----------------------------------+
| description | Infrastructure Optimization |
| enabled | True |
| id | d854f6fff0a64f77bda8003c8dedfada |
| name | watcher |
| type | infra-optim |
+-------------+----------------------------------+
4. Create the Infrastructure Optimization service API endpoints:
.. code-block:: console
$ openstack endpoint create --region RegionOne \
infra-optim public http://controller:9322
+-------------+----------------------------------+
| Field | Value |
+-------------+----------------------------------+
| description | Infrastructure Optimization |
| enabled | True |
| id | d854f6fff0a64f77bda8003c8dedfada |
| name | watcher |
| type | infra-optim |
+-------------+----------------------------------+
$ openstack endpoint create --region RegionOne \
infra-optim internal http://controller:9322
+--------------+----------------------------------+
| Field | Value |
+--------------+----------------------------------+
| enabled | True |
| id | 225aef8465ef4df48a341aaaf2b0a390 |
| interface | internal |
| region | RegionOne |
| region_id | RegionOne |
| service_id | d854f6fff0a64f77bda8003c8dedfada |
| service_name | watcher |
| service_type | infra-optim |
| url | http://controller:9322 |
+--------------+----------------------------------+
$ openstack endpoint create --region RegionOne \
infra-optim admin http://controller:9322
+--------------+----------------------------------+
| Field | Value |
+--------------+----------------------------------+
| enabled | True |
| id | 375eb5057fb546edbdf3ee4866179672 |
| interface | admin |
| region | RegionOne |
| region_id | RegionOne |
| service_id | d854f6fff0a64f77bda8003c8dedfada |
| service_name | watcher |
| service_type | infra-optim |
| url | http://controller:9322 |
+--------------+----------------------------------+

View File

@@ -0,0 +1,301 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import os
# import sys
import openstackdocstheme
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
# sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
# TODO(ajaeger): enable PDF building, for example add 'rst2pdf.pdfbuilder'
# extensions =
# Add any paths that contain templates here, relative to this directory.
# templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
# source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'Installation Guide for Infrastructure Optimization Service'
bug_tag = u'install-guide'
copyright = u'2016, OpenStack contributors'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '0.1'
# The full version, including alpha/beta/rc tags.
release = '0.1'
# A few variables have to be set for the log-a-bug feature.
# giturl: The location of conf.py on Git. Must be set manually.
# gitsha: The SHA checksum of the bug description. Automatically extracted
# from git log.
# bug_tag: Tag for categorizing the bug. Must be set manually.
# These variables are passed to the logabug code via html_context.
giturl = u'http://git.openstack.org/cgit/openstack/watcher/tree/install-guide/source' # noqa
git_cmd = "/usr/bin/git log | head -n1 | cut -f2 -d' '"
gitsha = os.popen(git_cmd).read().strip('\n')
html_context = {"gitsha": gitsha, "bug_tag": bug_tag,
"giturl": giturl,
"bug_project": "watcher"}
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
# language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
# today = ''
# Else, today_fmt is used as the format for a strftime call.
# today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ["common_prerequisites.rst", "common_configure.rst"]
# The reST default role (used for this markup: `text`) to use for all
# documents.
# default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
# add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
# add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
# show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
# modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
# keep_warnings = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'openstackdocs'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
# html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
html_theme_path = [openstackdocstheme.get_html_theme_path()]
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
# html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
# html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
# html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
# html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
# html_static_path = []
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
# html_extra_path = []
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
# So that we can enable "log-a-bug" links from each output HTML page, this
# variable must be set to a format that includes year, month, day, hours and
# minutes.
html_last_updated_fmt = '%Y-%m-%d %H:%M'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
# html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
# html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
# html_additional_pages = {}
# If false, no module index is generated.
# html_domain_indices = True
# If false, no index is generated.
html_use_index = False
# If true, the index is split into individual pages for each letter.
# html_split_index = False
# If true, links to the reST sources are added to the pages.
html_show_sourcelink = False
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
# html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
# html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
# html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
# html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'install-guide'
# If true, publish source files
html_copy_source = False
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
# 'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
('index', 'InstallGuide.tex', u'Install Guide',
u'OpenStack contributors', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
# latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
# latex_use_parts = False
# If true, show page references after internal links.
# latex_show_pagerefs = False
# If true, show URL addresses after external links.
# latex_show_urls = False
# Documents to append as an appendix to all manuals.
# latex_appendices = []
# If false, no module index is generated.
# latex_domain_indices = True
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'installguide', u'Install Guide',
[u'OpenStack contributors'], 1)
]
# If true, show URL addresses after external links.
# man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'InstallGuide', u'Install Guide',
u'OpenStack contributors', 'InstallGuide',
'This guide shows OpenStack end users how to install '
'an OpenStack cloud.', 'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
# texinfo_appendices = []
# If false, no module index is generated.
# texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
# texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
# texinfo_no_detailmenu = False
# -- Options for Internationalization output ------------------------------
locale_dirs = ['locale/']
# -- Options for PDF output --------------------------------------------------
pdf_documents = [
('index', u'InstallGuide', u'Install Guide',
u'OpenStack contributors')
]

View File

@@ -0,0 +1,27 @@
============================================
Infrastructure Optimization service overview
============================================
The Infrastructure Optimization service provides flexible and scalable
optimization service for multi-tenant OpenStack based clouds.
The Infrastructure Optimization service consists of the following components:
``watcher`` command-line client
A CLI to communicate with ``watcher-api`` to optimize the cloud.
``watcher-api`` service
An OpenStack-native REST API that accepts and responds to end-user calls
by processing them and forwarding to appropriate underlying watcher
services via AMQP.
``watcher-decision-engine`` service
It runs audit and return an action plan to achieve optimization goal
specified by the end-user in audit.
``watcher-applier`` service
It executes action plan built by watcher-decision-engine. It interacts with
other OpenStack components like nova to execute the given action
plan.
``watcher-dashboard``
Watcher UI implemented as a plugin for the OpenStack Dashboard.

View File

@@ -0,0 +1,39 @@
===================================
Infrastructure Optimization service
===================================
.. toctree::
:maxdepth: 2
get_started.rst
install.rst
verify.rst
next-steps.rst
The Infrastructure Optimization service (watcher) provides
flexible and scalable resource optimization service for
multi-tenant OpenStack-based clouds.
Watcher provides a complete optimization loop including
everything from a metrics receiver, complex event processor
and profiler, optimization processor and an action plan
applier. This provides a robust framework to realize a wide
range of cloud optimization goals, including the reduction
of data center operating costs, increased system performance
via intelligent virtual machine migration, increased energy
efficiency—and more!
watcher also supports a pluggable architecture by which custom
optimization algorithms, data metrics and data profilers can be
developed and inserted into the Watcher framework.
check the documentation for watcher optimization strategies at
https://docs.openstack.org/developer/watcher/strategies
check watcher glossary at
https://docs.openstack.org/developer/watcher/glossary.html
This chapter assumes a working setup of OpenStack following the
`OpenStack Installation Tutorial
<https://docs.openstack.org/project-install-guide/ocata/>`_.

View File

@@ -0,0 +1,34 @@
.. _install-obs:
Install and configure for openSUSE and SUSE Linux Enterprise
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This section describes how to install and configure the Infrastructure Optimization service
for openSUSE Leap 42.1 and SUSE Linux Enterprise Server 12 SP1.
.. include:: common_prerequisites.rst
Install and configure components
--------------------------------
#. Install the packages:
.. code-block:: console
# zypper --quiet --non-interactive install
.. include:: common_configure.rst
Finalize installation
---------------------
Start the Infrastructure Optimization services and configure them to start when
the system boots:
.. code-block:: console
# systemctl enable openstack-watcher-api.service
# systemctl start openstack-watcher-api.service

View File

@@ -0,0 +1,38 @@
.. _install-rdo:
Install and configure for Red Hat Enterprise Linux and CentOS
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This section describes how to install and configure the Infrastructure Optimization service
for Red Hat Enterprise Linux 7 and CentOS 7.
.. include:: common_prerequisites.rst
Install and configure components
--------------------------------
1. Install the packages:
.. code-block:: console
# sudo yum install openstack-watcher-api openstack-watcher-applier \
openstack-watcher-decision-engine
.. include:: common_configure.rst
Finalize installation
---------------------
Start the Infrastructure Optimization services and configure them to start when
the system boots:
.. code-block:: console
# systemctl enable openstack-watcher-api.service \
openstack-watcher-decision-engine.service \
openstack-watcher-applier.service
# systemctl start openstack-watcher-api.service \
openstack-watcher-decision-engine.service \
openstack-watcher-applier.service

View File

@@ -0,0 +1,34 @@
.. _install-ubuntu:
Install and configure for Ubuntu
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This section describes how to install and configure the Infrastructure Optimization
service for Ubuntu 14.04 (LTS).
.. include:: common_prerequisites.rst
Install and configure components
--------------------------------
1. Install the packages:
.. code-block:: console
# apt install watcher-api watcher-decision-engine \
watcher-applier
# apt install python-watcherclient
.. include:: common_configure.rst
Finalize installation
---------------------
Restart the Infrastructure Optimization services:
.. code-block:: console
# service watcher-api restart
# service watcher-decision-engine restart
# service watcher-applier restart

View File

@@ -0,0 +1,20 @@
.. _install:
Install and configure
~~~~~~~~~~~~~~~~~~~~~
This section describes how to install and configure the
Infrastructure Optimization service, code-named watcher, on the controller node.
This section assumes that you already have a working OpenStack
environment with at least the following components installed:
Identity Service, Compute Service, Telemetry data collection service.
Note that installation and configuration vary by distribution.
.. toctree::
:maxdepth: 2
install-obs.rst
install-rdo.rst
install-ubuntu.rst

View File

@@ -0,0 +1,9 @@
.. _next-steps:
Next steps
~~~~~~~~~~
Your OpenStack environment now includes the watcher service.
To add additional services, see
https://docs.openstack.org/project-install-guide/ocata/.

View File

@@ -0,0 +1,119 @@
.. _verify:
Verify operation
~~~~~~~~~~~~~~~~
Verify operation of the Infrastructure Optimization service.
.. note::
Perform these commands on the controller node.
1. Source the ``admin`` project credentials to gain access to
admin-only CLI commands:
.. code-block:: console
$ . admin-openrc
2. List service components to verify successful launch and registration
of each process:
.. code-block:: console
$ openstack optimize service list
+----+-------------------------+------------+--------+
| ID | Name | Host | Status |
+----+-------------------------+------------+--------+
| 1 | watcher-decision-engine | controller | ACTIVE |
| 2 | watcher-applier | controller | ACTIVE |
+----+-------------------------+------------+--------+
3. List goals and strategies:
.. code-block:: console
$ openstack optimize goal list
+--------------------------------------+----------------------+----------------------+
| UUID | Name | Display name |
+--------------------------------------+----------------------+----------------------+
| a8cd6d1a-008b-4ff0-8dbc-b30493fcc5b9 | dummy | Dummy goal |
| 03953f2f-02d0-42b5-9a12-7ba500a54395 | workload_balancing | Workload Balancing |
| de0f8714-984b-4d6b-add1-9cad8120fbce | server_consolidation | Server Consolidation |
| f056bc80-c6d1-40dc-b002-938ccade9385 | thermal_optimization | Thermal Optimization |
| e7062856-892e-4f0f-b84d-b828464b3fd0 | airflow_optimization | Airflow Optimization |
| 1f038da9-b36c-449f-9f04-c225bf3eb478 | unclassified | Unclassified |
+--------------------------------------+----------------------+----------------------+
$ openstack optimize strategy list
+--------------------------------------+---------------------------+---------------------------------------------+----------------------+
| UUID | Name | Display name | Goal |
+--------------------------------------+---------------------------+---------------------------------------------+----------------------+
| 98ae84c8-7c9b-4cbd-8d9c-4bd7c6b106eb | dummy | Dummy strategy | dummy |
| 02a170b6-c72e-479d-95c0-8a4fdd4cc1ef | dummy_with_scorer | Dummy Strategy using sample Scoring Engines | dummy |
| 8bf591b8-57e5-4a9e-8c7d-c37bda735a45 | outlet_temperature | Outlet temperature based strategy | thermal_optimization |
| 8a0810fb-9d9a-47b9-ab25-e442878abc54 | vm_workload_consolidation | VM Workload Consolidation Strategy | server_consolidation |
| 1718859c-3eb5-45cb-9220-9cb79fe42fa5 | basic | Basic offline consolidation | server_consolidation |
| b5e7f5f1-4824-42c7-bb52-cf50724f67bf | workload_stabilization | Workload stabilization | workload_balancing |
| f853d71e-9286-4df3-9d3e-8eaf0f598e07 | workload_balance | Workload Balance Migration Strategy | workload_balancing |
| 58bdfa89-95b5-4630-adf6-fd3af5ff1f75 | uniform_airflow | Uniform airflow migration strategy | airflow_optimization |
| 66fde55d-a612-4be9-8cb0-ea63472b420b | dummy_with_resize | Dummy strategy with resize | dummy |
+--------------------------------------+---------------------------+---------------------------------------------+----------------------+
4. Run an action plan by creating an audit with dummy goal:
.. code-block:: console
$ openstack optimize audit create --goal dummy
+--------------+--------------------------------------+
| Field | Value |
+--------------+--------------------------------------+
| UUID | e94d4826-ad4e-44df-ad93-dff489fde457 |
| Created At | 2017-05-23T11:46:58.763394+00:00 |
| Updated At | None |
| Deleted At | None |
| State | PENDING |
| Audit Type | ONESHOT |
| Parameters | {} |
| Interval | None |
| Goal | dummy |
| Strategy | auto |
| Audit Scope | [] |
| Auto Trigger | False |
+--------------+--------------------------------------+
$ openstack optimize audit list
+--------------------------------------+------------+-----------+-------+----------+--------------+
| UUID | Audit Type | State | Goal | Strategy | Auto Trigger |
+--------------------------------------+------------+-----------+-------+----------+--------------+
| e94d4826-ad4e-44df-ad93-dff489fde457 | ONESHOT | SUCCEEDED | dummy | auto | False |
+--------------------------------------+------------+-----------+-------+----------+--------------+
$ openstack optimize actionplan list
+--------------------------------------+--------------------------------------+-------------+------------+-----------------+
| UUID | Audit | State | Updated At | Global efficacy |
+--------------------------------------+--------------------------------------+-------------+------------+-----------------+
| ba9ce6b3-969c-4b8e-bb61-ae24e8630f81 | e94d4826-ad4e-44df-ad93-dff489fde457 | RECOMMENDED | None | None |
+--------------------------------------+--------------------------------------+-------------+------------+-----------------+
$ openstack optimize actionplan start ba9ce6b3-969c-4b8e-bb61-ae24e8630f81
+---------------------+--------------------------------------+
| Field | Value |
+---------------------+--------------------------------------+
| UUID | ba9ce6b3-969c-4b8e-bb61-ae24e8630f81 |
| Created At | 2017-05-23T11:46:58+00:00 |
| Updated At | 2017-05-23T11:53:12+00:00 |
| Deleted At | None |
| Audit | e94d4826-ad4e-44df-ad93-dff489fde457 |
| Strategy | dummy |
| State | ONGOING |
| Efficacy indicators | [] |
| Global efficacy | {} |
+---------------------+--------------------------------------+
$ openstack optimize actionplan list
+--------------------------------------+--------------------------------------+-----------+---------------------------+-----------------+
| UUID | Audit | State | Updated At | Global efficacy |
+--------------------------------------+--------------------------------------+-----------+---------------------------+-----------------+
| ba9ce6b3-969c-4b8e-bb61-ae24e8630f81 | e94d4826-ad4e-44df-ad93-dff489fde457 | SUCCEEDED | 2017-05-23T11:53:16+00:00 | None |
+--------------------------------------+--------------------------------------+-----------+---------------------------+-----------------+

View File

@@ -0,0 +1,4 @@
---
features:
- |
Adds feature to cancel an action-plan.

View File

@@ -1,4 +1,4 @@
---
features:
- Add superseded state for an action plan if the cluster data model has
changed after it has been created.
- Check the creation time of the action plan,
and set its state to SUPERSEDED if it has expired.

View File

@@ -0,0 +1,4 @@
---
features:
- |
Added SUSPENDED audit state

View File

@@ -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
# sphinx-quickstart on Fri Jun 3 11:37:52 2016.
#

View File

@@ -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!
=================================================
@@ -7,5 +21,6 @@ Contents:
:maxdepth: 1
unreleased
ocata
newton

View 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"

View File

@@ -0,0 +1,6 @@
===================================
Ocata Series Release Notes
===================================
.. release-notes::
:branch: origin/stable/ocata

View File

@@ -5,41 +5,43 @@
apscheduler # MIT License
enum34;python_version=='2.7' or python_version=='2.6' or python_version=='3.3' # BSD
jsonpatch>=1.1 # BSD
keystoneauth1>=2.18.0 # Apache-2.0
keystoneauth1>=2.20.0 # Apache-2.0
keystonemiddleware>=4.12.0 # Apache-2.0
lxml!=3.7.0,>=2.3 # BSD
oslo.concurrency>=3.8.0 # Apache-2.0
oslo.cache>=1.5.0 # Apache-2.0
oslo.config!=3.18.0,>=3.14.0 # Apache-2.0
oslo.context>=2.9.0 # Apache-2.0
oslo.db>=4.15.0 # Apache-2.0
oslo.i18n>=2.1.0 # Apache-2.0
oslo.log>=3.11.0 # Apache-2.0
oslo.messaging>=5.14.0 # Apache-2.0
oslo.config>=4.0.0 # Apache-2.0
oslo.context>=2.14.0 # Apache-2.0
oslo.db>=4.21.1 # Apache-2.0
oslo.i18n!=3.15.2,>=2.1.0 # Apache-2.0
oslo.log>=3.22.0 # Apache-2.0
oslo.messaging!=5.25.0,>=5.24.2 # Apache-2.0
oslo.policy>=1.17.0 # Apache-2.0
oslo.reports>=0.6.0 # Apache-2.0
oslo.serialization>=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
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
PrettyTable<0.8,>=0.7.1 # BSD
voluptuous>=0.8.9 # BSD License
gnocchiclient>=2.7.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-glanceclient>=2.5.0 # Apache-2.0
python-cinderclient>=2.1.0 # Apache-2.0
python-glanceclient>=2.7.0 # Apache-2.0
python-keystoneclient>=3.8.0 # Apache-2.0
python-monascaclient>=1.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-openstackclient>=3.3.0 # Apache-2.0
python-neutronclient>=6.3.0 # Apache-2.0
python-novaclient>=7.1.0 # Apache-2.0
python-openstackclient!=3.10.0,>=3.3.0 # Apache-2.0
python-ironicclient>=1.11.0 # Apache-2.0
six>=1.9.0 # MIT
SQLAlchemy<1.1.0,>=1.0.10 # MIT
stevedore>=1.17.1 # Apache-2.0
SQLAlchemy!=1.1.5,!=1.1.6,!=1.1.7,!=1.1.8,>=1.0.10 # MIT
stevedore>=1.20.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
networkx>=1.10 # BSD

View File

@@ -16,7 +16,6 @@ classifier =
Programming Language :: Python :: 2
Programming Language :: Python :: 2.7
Programming Language :: Python :: 3
Programming Language :: Python :: 3.4
Programming Language :: Python :: 3.5
[files]

View File

@@ -25,5 +25,5 @@ except ImportError:
pass
setuptools.setup(
setup_requires=['pbr>=1.8'],
setup_requires=['pbr>=2.0.0'],
pbr=True)

View File

@@ -2,10 +2,10 @@
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
coverage>=4.0 # Apache-2.0
coverage!=4.4,>=4.0 # Apache-2.0
doc8 # 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
oslotest>=1.10.0 # Apache-2.0
os-testr>=0.8.0 # Apache-2.0
@@ -15,12 +15,14 @@ testscenarios>=0.4 # Apache-2.0/BSD
testtools>=1.4.0 # MIT
# Doc requirements
openstackdocstheme>=1.5.0 # Apache-2.0
oslosphinx>=4.7.0 # Apache-2.0
sphinx!=1.3b1,<1.4,>=1.2.1 # BSD
sphinx!=1.6.1,>=1.5.1 # BSD
sphinxcontrib-pecanwsme>=0.8 # Apache-2.0
# releasenotes
reno>=1.8.0 # Apache-2.0
reno!=2.3.1,>=1.8.0 # Apache-2.0
# bandit
bandit>=1.1.0 # Apache-2.0

11
tox.ini
View File

@@ -1,16 +1,18 @@
[tox]
minversion = 1.8
envlist = py35,py34,py27,pep8
envlist = py35,py27,pep8
skipsdist = True
[testenv]
usedevelop = True
whitelist_externals = find
install_command = pip install -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt?h=stable/ocata} {opts} {packages}
rm
install_command = pip install -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} {opts} {packages}
setenv =
VIRTUAL_ENV={envdir}
deps = -r{toxinidir}/test-requirements.txt
commands =
rm -f .testrepository/times.dbm
find . -type f -name "*.py[c|o]" -delete
ostestr --concurrency=6 {posargs}
@@ -45,7 +47,7 @@ commands =
[flake8]
show-source=True
ignore=
ignore= H105,E123,E226,N320
builtins= _
exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build,*sqlalchemy/alembic/versions/*,demo/,releasenotes
@@ -67,3 +69,6 @@ commands = sphinx-build -a -W -E -d releasenotes/build/doctrees -b html releasen
[testenv:bandit]
deps = -r{toxinidir}/test-requirements.txt
commands = bandit -r watcher -x tests -n5 -ll -s B320
[testenv:install-guide]
commands = sphinx-build -a -E -W -d install-guide/build/doctrees -b html install-guide/source install-guide/build/html

40
watcher/api/app.wsgi Normal file
View 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()

View File

@@ -488,6 +488,7 @@ class ActionPlansController(rest.RestController):
raise exception.PatchError(patch=patch, reason=e)
launch_action_plan = False
cancel_action_plan = False
# transitions that are allowed via PATCH
allowed_patch_transitions = [
@@ -496,7 +497,7 @@ class ActionPlansController(rest.RestController):
(ap_objects.State.RECOMMENDED,
ap_objects.State.CANCELLED),
(ap_objects.State.ONGOING,
ap_objects.State.CANCELLED),
ap_objects.State.CANCELLING),
(ap_objects.State.PENDING,
ap_objects.State.CANCELLED),
]
@@ -515,6 +516,8 @@ class ActionPlansController(rest.RestController):
if action_plan.state == ap_objects.State.PENDING:
launch_action_plan = True
if action_plan.state == ap_objects.State.CANCELLED:
cancel_action_plan = True
# Update only the fields that have changed
for field in objects.ActionPlan.fields:
@@ -534,6 +537,16 @@ class ActionPlansController(rest.RestController):
action_plan_to_update.save()
# NOTE: if action plan is cancelled from pending or recommended
# state update action state here only
if cancel_action_plan:
filters = {'action_plan_uuid': action_plan.uuid}
actions = objects.Action.list(pecan.request.context,
filters=filters, eager=True)
for a in actions:
a.state = objects.action.State.CANCELLED
a.save()
if launch_action_plan:
applier_client = rpcapi.ApplierAPI()
applier_client.launch_action_plan(pecan.request.context,

View File

@@ -50,21 +50,6 @@ from watcher.decision_engine import rpcapi
from watcher import objects
ALLOWED_AUDIT_TRANSITIONS = {
objects.audit.State.PENDING:
[objects.audit.State.ONGOING, objects.audit.State.CANCELLED],
objects.audit.State.ONGOING:
[objects.audit.State.FAILED, objects.audit.State.SUCCEEDED,
objects.audit.State.CANCELLED],
objects.audit.State.FAILED:
[objects.audit.State.DELETED],
objects.audit.State.SUCCEEDED:
[objects.audit.State.DELETED],
objects.audit.State.CANCELLED:
[objects.audit.State.DELETED]
}
class AuditPostType(wtypes.Base):
audit_template_uuid = wtypes.wsattr(types.uuid, mandatory=False)
@@ -144,8 +129,15 @@ class AuditPatchType(types.JsonPatchType):
@staticmethod
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.")
raise exception.PatchError(
patch=serialized_patch,
@@ -309,7 +301,7 @@ class Audit(base.APIBase):
audit.unset_fields_except(['uuid', 'audit_type', 'state',
'goal_uuid', 'interval', 'scope',
'strategy_uuid', 'goal_name',
'strategy_name'])
'strategy_name', 'auto_trigger'])
audit.links = [link.Link.make_link('self', url,
'audits', audit.uuid),
@@ -572,21 +564,22 @@ class AuditsController(rest.RestController):
try:
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))
except api_utils.JSONPATCH_EXCEPTIONS as e:
raise exception.PatchError(patch=patch, reason=e)
initial_state = audit_dict['state']
new_state = api_utils.get_patch_value(patch, 'state')
allowed_states = ALLOWED_AUDIT_TRANSITIONS.get(initial_state, [])
if new_state is not None and new_state not in allowed_states:
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))
# Update only the fields that have changed
for field in objects.Audit.fields:
try:

View File

@@ -109,6 +109,21 @@ class AuditTemplatePostType(wtypes.Base):
common_utils.Draft4Validator(
default.DefaultScope.DEFAULT_SCHEMA).validate(audit_template.scope)
include_host_aggregates = False
exclude_host_aggregates = False
for rule in audit_template.scope:
if 'host_aggregates' in rule:
include_host_aggregates = True
elif 'exclude' in rule:
for resource in rule['exclude']:
if 'host_aggregates' in resource:
exclude_host_aggregates = True
if include_host_aggregates and exclude_host_aggregates:
raise exception.Invalid(
message=_(
"host_aggregates can't be "
"included and excluded together"))
if audit_template.strategy:
available_strategies = objects.Strategy.list(
AuditTemplatePostType._ctx)

View File

@@ -30,11 +30,11 @@ import wsme
from wsme import types as wtypes
import wsmeext.pecan as wsme_pecan
from watcher._i18n import _LW
from watcher.api.controllers import base
from watcher.api.controllers import link
from watcher.api.controllers.v1 import collection
from watcher.api.controllers.v1 import utils as api_utils
from watcher.common import context
from watcher.common import exception
from watcher.common import policy
from watcher import objects
@@ -52,12 +52,13 @@ class Service(base.APIBase):
"""
_status = None
_context = context.RequestContext(is_admin=True)
def _get_status(self):
return self._status
def _set_status(self, name):
service = objects.Service.get_by_name(pecan.request.context, name)
def _set_status(self, id):
service = objects.Service.get(pecan.request.context, id)
last_heartbeat = (service.last_seen_up or service.updated_at
or service.created_at)
if isinstance(last_heartbeat, six.string_types):
@@ -72,9 +73,9 @@ class Service(base.APIBase):
elapsed = timeutils.delta_seconds(last_heartbeat, timeutils.utcnow())
is_up = abs(elapsed) <= CONF.service_down_time
if not is_up:
LOG.warning(_LW('Seems service %(name)s on host %(host)s is down. '
'Last heartbeat was %(lhb)s.'
'Elapsed time is %(el)s'),
LOG.warning('Seems service %(name)s on host %(host)s is down. '
'Last heartbeat was %(lhb)s.'
'Elapsed time is %(el)s',
{'name': service.name,
'host': service.host,
'lhb': str(last_heartbeat), 'el': str(elapsed)})
@@ -108,7 +109,7 @@ class Service(base.APIBase):
for field in fields:
self.fields.append(field)
setattr(self, field, kwargs.get(
field if field != 'status' else 'name', wtypes.Unset))
field if field != 'status' else 'id', wtypes.Unset))
@staticmethod
def _convert_with_links(service, url, expand=True):

View File

@@ -181,7 +181,7 @@ class JsonPatchType(wtypes.Base):
@staticmethod
def mandatory_attrs():
"""Retruns a list of mandatory attributes.
"""Returns a list of mandatory attributes.
Mandatory attributes can't be removed from the document. This
method should be overwritten by derived class.

View File

@@ -55,7 +55,7 @@ def validate_sort_dir(sort_dir):
def validate_search_filters(filters, allowed_fields):
# Very leightweight validation for now
# Very lightweight validation for now
# todo: improve this (e.g. https://www.parse.com/docs/rest/guide/#queries)
for filter_name in filters.keys():
if filter_name not in allowed_fields:
@@ -79,6 +79,15 @@ def get_patch_value(patch, 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):
filters_dict = {}
for filter_name, filter_value in filters.items():

View File

@@ -27,7 +27,7 @@ from oslo_serialization import jsonutils
import six
import webob
from watcher._i18n import _, _LE
from watcher._i18n import _
LOG = log.getLogger(__name__)
@@ -79,7 +79,7 @@ class ParsableErrorMiddleware(object):
et.ElementTree.Element(
'error_message', text='\n'.join(app_iter)))]
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'
'</error_message>' % state['status_code']]
state['headers'].append(('Content-Type', 'application/xml'))

99
watcher/api/scheduling.py Normal file
View File

@@ -0,0 +1,99 @@
# -*- encoding: utf-8 -*-
# Copyright (c) 2017 Servionica
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import datetime
from oslo_config import cfg
from oslo_log import log
from oslo_utils import timeutils
import six
from watcher._i18n import _LW
from watcher.common import context as watcher_context
from watcher.common import scheduling
from watcher import notifications
from watcher import objects
CONF = cfg.CONF
LOG = log.getLogger(__name__)
class APISchedulingService(scheduling.BackgroundSchedulerService):
def __init__(self, gconfig=None, **options):
self.services_status = {}
gconfig = None or {}
super(APISchedulingService, self).__init__(gconfig, **options)
def get_services_status(self, context):
services = objects.service.Service.list(context)
for service in services:
result = self.get_service_status(context, service.id)
if service.id not in self.services_status.keys():
self.services_status[service.id] = result
continue
if self.services_status[service.id] != result:
self.services_status[service.id] = result
notifications.service.send_service_update(context, service,
state=result)
def get_service_status(self, context, service_id):
service = objects.Service.get(context, service_id)
last_heartbeat = (service.last_seen_up or service.updated_at
or service.created_at)
if isinstance(last_heartbeat, six.string_types):
# NOTE(russellb) If this service came in over rpc via
# conductor, then the timestamp will be a string and needs to be
# converted back to a datetime.
last_heartbeat = timeutils.parse_strtime(last_heartbeat)
else:
# Objects have proper UTC timezones, but the timeutils comparison
# below does not (and will fail)
last_heartbeat = last_heartbeat.replace(tzinfo=None)
elapsed = timeutils.delta_seconds(last_heartbeat, timeutils.utcnow())
is_up = abs(elapsed) <= CONF.service_down_time
if not is_up:
LOG.warning(_LW('Seems service %(name)s on host %(host)s is down. '
'Last heartbeat was %(lhb)s.'
'Elapsed time is %(el)s'),
{'name': service.name,
'host': service.host,
'lhb': str(last_heartbeat), 'el': str(elapsed)})
return objects.service.ServiceStatus.FAILED
return objects.service.ServiceStatus.ACTIVE
def start(self):
"""Start service."""
context = watcher_context.make_context(is_admin=True)
self.add_job(self.get_services_status, name='service_status',
trigger='interval', jobstore='default', args=[context],
next_run_time=datetime.datetime.now(), seconds=60)
super(APISchedulingService, self).start()
def stop(self):
"""Stop service."""
self.shutdown()
def wait(self):
"""Wait for service to complete."""
def reset(self):
"""Reset service.
Called in case service running in daemon mode receives SIGHUP.
"""

View File

@@ -20,6 +20,7 @@ from oslo_log import log
from watcher.applier.action_plan import base
from watcher.applier import default
from watcher.common import exception
from watcher import notifications
from watcher import objects
from watcher.objects import fields
@@ -39,6 +40,9 @@ class DefaultActionPlanHandler(base.BaseActionPlanHandler):
try:
action_plan = objects.ActionPlan.get_by_uuid(
self.ctx, self.action_plan_uuid, eager=True)
if action_plan.state == objects.action_plan.State.CANCELLED:
self._update_action_from_pending_to_cancelled()
return
action_plan.state = objects.action_plan.State.ONGOING
action_plan.save()
notifications.action_plan.send_action_notification(
@@ -54,6 +58,12 @@ class DefaultActionPlanHandler(base.BaseActionPlanHandler):
self.ctx, action_plan,
action=fields.NotificationAction.EXECUTION,
phase=fields.NotificationPhase.END)
except exception.ActionPlanCancelled as e:
LOG.exception(e)
action_plan.state = objects.action_plan.State.CANCELLED
self._update_action_from_pending_to_cancelled()
except Exception as e:
LOG.exception(e)
action_plan.state = objects.action_plan.State.FAILED
@@ -64,3 +74,12 @@ class DefaultActionPlanHandler(base.BaseActionPlanHandler):
phase=fields.NotificationPhase.ERROR)
finally:
action_plan.save()
def _update_action_from_pending_to_cancelled(self):
filters = {'action_plan_uuid': self.action_plan_uuid,
'state': objects.action.State.PENDING}
actions = objects.Action.list(self.ctx, filters=filters, eager=True)
if actions:
for a in actions:
a.state = objects.action.State.CANCELLED
a.save()

View File

@@ -32,6 +32,9 @@ class BaseAction(loadable.Loadable):
# watcher dashboard and will be nested in input_parameters
RESOURCE_ID = 'resource_id'
# Add action class name to the list, if implementing abort.
ABORT_TRUE = ['Sleep', 'Nop']
def __init__(self, config, osc=None):
"""Constructor
@@ -111,7 +114,7 @@ class BaseAction(loadable.Loadable):
def post_condition(self):
"""Hook: called after the execution of an action
This function is called regardless of whether an action succeded or
This function is called regardless of whether an action succeeded or
not. So you can use it to perform cleanup operations.
"""
raise NotImplementedError()
@@ -129,3 +132,11 @@ class BaseAction(loadable.Loadable):
def validate_parameters(self):
self.schema(self.input_parameters)
return True
@abc.abstractmethod
def get_description(self):
"""Description of the action"""
raise NotImplementedError()
def check_abort(self):
return bool(self.__class__.__name__ in self.ABORT_TRUE)

View File

@@ -101,3 +101,9 @@ class ChangeNovaServiceState(base.BaseAction):
def post_condition(self):
pass
def get_description(self):
"""Description of the action"""
return ("Disables or enables the nova-compute service."
"A disabled nova-compute service can not be selected "
"by the nova for future deployment of new server.")

View File

@@ -21,7 +21,7 @@ from oslo_log import log
import six
import voluptuous
from watcher._i18n import _, _LC
from watcher._i18n import _
from watcher.applier.actions import base
from watcher.common import exception
from watcher.common import nova_helper
@@ -120,9 +120,9 @@ class Migrate(base.BaseAction):
"migrating instance %s.Exception: %s" %
(self.instance_uuid, e))
except Exception:
LOG.critical(_LC("Unexpected error occurred. Migration failed for "
"instance %s. Leaving instance on previous "
"host."), self.instance_uuid)
LOG.critical("Unexpected error occurred. Migration failed for "
"instance %s. Leaving instance on previous "
"host.", self.instance_uuid)
return result
@@ -134,9 +134,9 @@ class Migrate(base.BaseAction):
dest_hostname=destination)
except Exception as exc:
LOG.exception(exc)
LOG.critical(_LC("Unexpected error occurred. Migration failed for "
"instance %s. Leaving instance on previous "
"host."), self.instance_uuid)
LOG.critical("Unexpected error occurred. Migration failed for "
"instance %s. Leaving instance on previous "
"host.", self.instance_uuid)
return result
@@ -164,6 +164,10 @@ class Migrate(base.BaseAction):
def revert(self):
return self.migrate(destination=self.source_node)
def abort(self):
# TODO(adisky): implement abort for migration
LOG.warning("Abort for migration not implemented")
def pre_condition(self):
# TODO(jed): check if the instance exists / check if the instance is on
# the source_node
@@ -172,3 +176,7 @@ class Migrate(base.BaseAction):
def post_condition(self):
# TODO(jed): check extra parameters (network response, etc.)
pass
def get_description(self):
"""Description of the action"""
return "Moving a VM instance from source_node to destination_node"

View File

@@ -23,7 +23,6 @@ import voluptuous
from watcher.applier.actions import base
LOG = log.getLogger(__name__)
@@ -65,3 +64,10 @@ class Nop(base.BaseAction):
def post_condition(self):
pass
def get_description(self):
"""Description of the action"""
return "Logging a NOP message"
def abort(self):
LOG.debug("Abort action NOP")

View File

@@ -21,7 +21,7 @@ from oslo_log import log
import six
import voluptuous
from watcher._i18n import _, _LC
from watcher._i18n import _
from watcher.applier.actions import base
from watcher.common import nova_helper
from watcher.common import utils
@@ -86,8 +86,8 @@ class Resize(base.BaseAction):
except Exception as exc:
LOG.exception(exc)
LOG.critical(
_LC("Unexpected error occurred. Resizing failed for "
"instance %s."), self.instance_uuid)
"Unexpected error occurred. Resizing failed for "
"instance %s.", self.instance_uuid)
return result
def execute(self):
@@ -104,3 +104,7 @@ class Resize(base.BaseAction):
def post_condition(self):
# TODO(jed): check extra parameters (network response, etc.)
pass
def get_description(self):
"""Description of the action"""
return "Resize a server with specified flavor."

View File

@@ -66,3 +66,10 @@ class Sleep(base.BaseAction):
def post_condition(self):
pass
def get_description(self):
"""Description of the action"""
return "Wait for a given interval in seconds."
def abort(self):
LOG.debug("Abort action sleep")

3
watcher/applier/default.py Normal file → Executable file
View File

@@ -58,5 +58,6 @@ class DefaultApplier(base.BaseApplier):
LOG.debug("Executing action plan %s ", action_plan_uuid)
filters = {'action_plan_uuid': action_plan_uuid}
actions = objects.Action.list(self.context, filters=filters)
actions = objects.Action.list(self.context, filters=filters,
eager=True)
return self.engine.execute(actions)

View File

@@ -36,7 +36,7 @@ class ApplierAPI(service.Service):
if not utils.is_uuid_like(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)

View File

@@ -17,13 +17,27 @@
#
import abc
import six
import time
import eventlet
from oslo_log import log
from taskflow import task as flow_task
from watcher.applier.actions import factory
from watcher.common import clients
from watcher.common import exception
from watcher.common.loader import loadable
from watcher import notifications
from watcher import objects
from watcher.objects import fields
LOG = log.getLogger(__name__)
CANCEL_STATE = [objects.action_plan.State.CANCELLING,
objects.action_plan.State.CANCELLED]
@six.add_metaclass(abc.ABCMeta)
@@ -72,11 +86,175 @@ class BaseWorkFlowEngine(loadable.Loadable):
return self._action_factory
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)
if (db_action.state in [objects.action.State.CANCELLING,
objects.action.State.CANCELLED] and
state == objects.action.State.SUCCEEDED):
return
db_action.state = state
db_action.save()
# NOTE(v-francoise): Implement notifications for action
@abc.abstractmethod
def execute(self, actions):
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()
@abc.abstractmethod
def do_revert(self):
raise NotImplementedError()
@abc.abstractmethod
def do_abort(self, *args, **kwargs):
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:
# NOTE(adisky): check the state of action plan before starting
# next action, if action plan is cancelled raise the exceptions
# so that taskflow does not schedule further actions.
action_plan = objects.ActionPlan.get_by_id(
self.engine.context, self._db_action.action_plan_id)
if action_plan.state in CANCEL_STATE:
raise exception.ActionPlanCancelled(uuid=action_plan.uuid)
self.do_pre_execute()
notifications.action.send_execution_notification(
self.engine.context, self._db_action,
fields.NotificationAction.EXECUTION,
fields.NotificationPhase.START)
except exception.ActionPlanCancelled as e:
LOG.exception(e)
raise
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):
def _do_execute_action(*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
# NOTE: spawn a new thread for action execution, so that if action plan
# is cancelled workflow engine will not wait to finish action execution
et = eventlet.spawn(_do_execute_action, *args, **kwargs)
# NOTE: check for the state of action plan periodically,so that if
# action is finished or action plan is cancelled we can exit from here.
while True:
action_object = objects.Action.get_by_uuid(
self.engine.context, self._db_action.uuid, eager=True)
action_plan_object = objects.ActionPlan.get_by_id(
self.engine.context, action_object.action_plan_id)
if (action_object.state in [objects.action.State.SUCCEEDED,
objects.action.State.FAILED] or
action_plan_object.state in CANCEL_STATE):
break
time.sleep(2)
try:
# NOTE: kill the action execution thread, if action plan is
# cancelled for all other cases wait for the result from action
# execution thread.
# Not all actions support abort operations, kill only those action
# which support abort operations
abort = self.action.check_abort()
if (action_plan_object.state in CANCEL_STATE and abort):
et.kill()
et.wait()
# NOTE: catch the greenlet exit exception due to thread kill,
# taskflow will call revert for the action,
# we will redirect it to abort.
except eventlet.greenlet.GreenletExit:
raise exception.ActionPlanCancelled(uuid=action_plan_object.uuid)
except Exception as e:
LOG.exception(e)
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)
def revert(self, *args, **kwargs):
action_plan = objects.ActionPlan.get_by_id(
self.engine.context, self._db_action.action_plan_id, eager=True)
# NOTE: check if revert cause by cancel action plan or
# some other exception occured during action plan execution
# if due to some other exception keep the flow intact.
if action_plan.state not in CANCEL_STATE:
self.do_revert()
action_object = objects.Action.get_by_uuid(
self.engine.context, self._db_action.uuid, eager=True)
if action_object.state == objects.action.State.ONGOING:
action_object.state = objects.action.State.CANCELLING
action_object.save()
self.abort()
if action_object.state == objects.action.State.PENDING:
action_object.state = objects.action.State.CANCELLED
action_object.save()
def abort(self, *args, **kwargs):
self.do_abort(*args, **kwargs)

View File

@@ -19,10 +19,10 @@ from oslo_concurrency import processutils
from oslo_config import cfg
from oslo_log import log
from taskflow import engines
from taskflow import exceptions as tf_exception
from taskflow.patterns import graph_flow as gf
from taskflow import task as flow_task
from watcher._i18n import _LE, _LW, _LC
from watcher.applier.workflow_engine import base
from watcher.common import exception
from watcher import objects
@@ -91,73 +91,63 @@ class DefaultWorkFlowEngine(base.BaseWorkFlowEngine):
return flow
except exception.ActionPlanCancelled as e:
raise
except tf_exception.WrappedFailure as e:
if e.check("watcher.common.exception.ActionPlanCancelled"):
raise exception.ActionPlanCancelled
else:
raise exception.WorkflowExecutionException(error=e)
except Exception as e:
raise exception.WorkflowExecutionException(error=e)
class TaskFlowActionContainer(flow_task.Task):
class TaskFlowActionContainer(base.BaseTaskFlowActionContainer):
def __init__(self, db_action, engine):
name = "action_type:{0} uuid:{1}".format(db_action.action_type,
db_action.uuid)
super(TaskFlowActionContainer, self).__init__(name=name)
self._db_action = db_action
self._engine = engine
self.loaded_action = None
super(TaskFlowActionContainer, self).__init__(name, db_action, 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
def do_pre_execute(self):
self.engine.notify(self._db_action, objects.action.State.ONGOING)
LOG.debug("Pre-condition action: %s", self.name)
self.action.pre_condition()
@property
def engine(self):
return self._engine
def do_execute(self, *args, **kwargs):
LOG.debug("Running action: %s", self.name)
def pre_execute(self):
try:
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
# NOTE: For result is False, set action state fail
result = self.action.execute()
if result is False:
self.engine.notify(self._db_action,
objects.action.State.FAILED)
else:
self.engine.notify(self._db_action,
objects.action.State.SUCCEEDED)
def execute(self, *args, **kwargs):
try:
LOG.debug("Running action: %s", self.name)
def do_post_execute(self):
LOG.debug("Post-condition 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):
LOG.warning(_LW("Revert action: %s"), self.name)
def do_revert(self, *args, **kwargs):
LOG.warning("Revert action: %s", self.name)
try:
# TODO(jed): do we need to update the states in case of failure?
self.action.revert()
except Exception as e:
LOG.exception(e)
LOG.critical(_LC("Oops! We need a disaster recover plan."))
LOG.critical("Oops! We need a disaster recover plan.")
def do_abort(self, *args, **kwargs):
LOG.warning("Aborting action: %s", self.name)
try:
self.action.abort()
self.engine.notify(self._db_action, objects.action.State.CANCELLED)
except Exception as e:
self.engine.notify(self._db_action, objects.action.State.FAILED)
LOG.exception(e)
class TaskFlowNop(flow_task.Task):

View File

@@ -22,7 +22,7 @@ import sys
from oslo_config import cfg
from oslo_log import log as logging
from watcher._i18n import _LI
from watcher.api import scheduling
from watcher.common import service
from watcher import conf
@@ -39,12 +39,15 @@ def main():
server = service.WSGIService('watcher-api', CONF.api.enable_ssl_api)
if host == '127.0.0.1':
LOG.info(_LI('serving on 127.0.0.1:%(port)s, '
'view at %(protocol)s://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' %
dict(protocol=protocol, port=port))
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))
api_schedule = scheduling.APISchedulingService()
api_schedule.start()
launcher = service.launch(CONF, server, workers=server.workers)
launcher.wait()

View File

@@ -22,7 +22,6 @@ import sys
from oslo_log import log as logging
from watcher._i18n import _LI
from watcher.applier import manager
from watcher.common import service as watcher_service
from watcher import conf
@@ -34,7 +33,7 @@ CONF = conf.CONF
def main():
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)

View File

@@ -22,7 +22,6 @@ import sys
from oslo_log import log as logging
from watcher._i18n import _LI
from watcher.common import service as watcher_service
from watcher import conf
from watcher.decision_engine import gmr
@@ -38,17 +37,17 @@ def main():
watcher_service.prepare_service(sys.argv, CONF)
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())
syncer = sync.Syncer()
syncer.sync()
de_service = watcher_service.Service(manager.DecisionEngineManager)
bg_schedulder_service = scheduling.DecisionEngineSchedulingService()
bg_scheduler_service = scheduling.DecisionEngineSchedulingService()
# Only 1 process
launcher = watcher_service.launch(CONF, de_service)
launcher.launch_service(bg_schedulder_service)
launcher.launch_service(bg_scheduler_service)
launcher.wait()

View File

@@ -22,7 +22,6 @@ import sys
from oslo_log import log as logging
from watcher._i18n import _LI
from watcher.common import service as service
from watcher import conf
from watcher.decision_engine import sync
@@ -32,10 +31,10 @@ CONF = conf.CONF
def main():
LOG.info(_LI('Watcher sync started.'))
LOG.info('Watcher sync started.')
service.prepare_service(sys.argv, CONF)
syncer = sync.Syncer()
syncer.sync()
LOG.info(_LI('Watcher sync finished.'))
LOG.info('Watcher sync finished.')

55
watcher/common/clients.py Normal file → Executable file
View File

@@ -13,6 +13,8 @@
from ceilometerclient import client as ceclient
from cinderclient import client as ciclient
from glanceclient import client as glclient
from gnocchiclient import client as gnclient
from ironicclient import client as irclient
from keystoneauth1 import loading as ka_loading
from keystoneclient import client as keyclient
from monascaclient import client as monclient
@@ -39,10 +41,12 @@ class OpenStackClients(object):
self._keystone = None
self._nova = None
self._glance = None
self._gnocchi = None
self._cinder = None
self._ceilometer = None
self._monasca = None
self._neutron = None
self._ironic = None
def _get_keystone_session(self):
auth = ka_loading.load_auth_from_conf_options(CONF,
@@ -78,7 +82,9 @@ class OpenStackClients(object):
return self._nova
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,
endpoint_type=nova_endpoint_type,
session=self.session)
return self._nova
@@ -88,17 +94,37 @@ class OpenStackClients(object):
return self._glance
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,
interface=glance_endpoint_type,
session=self.session)
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
def cinder(self):
if self._cinder:
return self._cinder
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,
endpoint_type=cinder_endpoint_type,
session=self.session)
return self._cinder
@@ -109,8 +135,12 @@ class OpenStackClients(object):
ceilometerclient_version = self._get_client_option('ceilometer',
'api_version')
self._ceilometer = ceclient.get_client(ceilometerclient_version,
session=self.session)
ceilometer_endpoint_type = self._get_client_option('ceilometer',
'endpoint_type')
self._ceilometer = ceclient.get_client(
ceilometerclient_version,
endpoint_type=ceilometer_endpoint_type,
session=self.session)
return self._ceilometer
@exception.wrap_keystone_exception
@@ -120,6 +150,8 @@ class OpenStackClients(object):
monascaclient_version = self._get_client_option(
'monasca', 'api_version')
monascaclient_interface = self._get_client_option(
'monasca', 'interface')
token = self.session.get_token()
watcher_clients_auth_config = CONF.get(_CLIENTS_AUTH_GROUP)
service_type = 'monitoring'
@@ -135,7 +167,8 @@ class OpenStackClients(object):
'username': watcher_clients_auth_config.username,
'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(
monascaclient_version, endpoint, **monasca_kwargs)
@@ -149,7 +182,23 @@ class OpenStackClients(object):
neutronclient_version = self._get_client_option('neutron',
'api_version')
neutron_endpoint_type = self._get_client_option('neutron',
'endpoint_type')
self._neutron = netclient.Client(neutronclient_version,
endpoint_type=neutron_endpoint_type,
session=self.session)
self._neutron.format = 'json'
return self._neutron
@exception.wrap_keystone_exception
def ironic(self):
if self._ironic:
return self._ironic
ironicclient_version = self._get_client_option('ironic', 'api_version')
endpoint_type = self._get_client_option('ironic', 'endpoint_type')
self._ironic = irclient.get_client(ironicclient_version,
ironic_url=endpoint_type,
session=self.session)
return self._ironic

View File

@@ -15,7 +15,6 @@ from oslo_log import log as logging
from oslo_utils import timeutils
import six
from watcher._i18n import _LW
from watcher.common import utils
LOG = logging.getLogger(__name__)
@@ -65,7 +64,7 @@ class RequestContext(context.RequestContext):
# safely ignore this as we don't use it.
kwargs.pop('user_identity', None)
if kwargs:
LOG.warning(_LW('Arguments dropped when creating context: %s'),
LOG.warning('Arguments dropped when creating context: %s',
str(kwargs))
# FIXME(dims): user_id and project_id duplicate information that is

View File

@@ -29,7 +29,7 @@ from keystoneclient import exceptions as keystone_exceptions
from oslo_log import log as logging
import six
from watcher._i18n import _, _LE
from watcher._i18n import _
from watcher import conf
@@ -83,9 +83,9 @@ class WatcherException(Exception):
except Exception:
# kwargs doesn't match a variable in msg_fmt
# 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():
LOG.error(_LE("%(name)s: %(value)s"),
LOG.error("%(name)s: %(value)s",
{'name': name, 'value': value})
if CONF.fatal_exception_format_errors:
@@ -130,7 +130,7 @@ class OperationNotPermitted(NotAuthorized):
msg_fmt = _("Operation not permitted")
class Invalid(WatcherException):
class Invalid(WatcherException, ValueError):
msg_fmt = _("Unacceptable parameters")
code = 400
@@ -149,6 +149,10 @@ class ResourceNotFound(ObjectNotFound):
code = 404
class InvalidParameter(Invalid):
msg_fmt = _("%(parameter)s has to be of type %(parameter_type)s")
class InvalidIdentity(Invalid):
msg_fmt = _("Expected a uuid or int but received %(identity)s")
@@ -182,6 +186,10 @@ 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):
msg_fmt = _("Expected a uuid but received %(uuid)s")
@@ -266,10 +274,12 @@ class ActionPlanReferenced(Invalid):
"multiple actions")
class ActionPlanCancelled(WatcherException):
msg_fmt = _("Action Plan with UUID %(uuid)s is cancelled by user")
class ActionPlanIsOngoing(Conflict):
msg_fmt = _("Action Plan %(action_plan)s is currently running. "
"New Action Plan %(new_action_plan)s will be set as "
"SUPERSEDED")
msg_fmt = _("Action Plan %(action_plan)s is currently running.")
class ActionNotFound(ResourceNotFound):

View File

@@ -17,7 +17,8 @@ from oslo_config import cfg
from oslo_log import log
import oslo_messaging as messaging
from watcher._i18n import _LE
from oslo_messaging.rpc import dispatcher
from watcher.common import context as watcher_context
from watcher.common import exception
@@ -32,7 +33,6 @@ __all__ = [
'get_client',
'get_server',
'get_notifier',
'TRANSPORT_ALIASES',
]
CONF = cfg.CONF
@@ -46,16 +46,6 @@ ALLOWED_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
@@ -64,12 +54,10 @@ def init(conf):
global TRANSPORT, NOTIFICATION_TRANSPORT, NOTIFIER
exmods = get_allowed_exmods()
TRANSPORT = messaging.get_transport(conf,
allowed_remote_exmods=exmods,
aliases=TRANSPORT_ALIASES)
allowed_remote_exmods=exmods)
NOTIFICATION_TRANSPORT = messaging.get_notification_transport(
conf,
allowed_remote_exmods=exmods,
aliases=TRANSPORT_ALIASES)
allowed_remote_exmods=exmods)
serializer = RequestContextSerializer(JsonPayloadSerializer())
if not conf.notification_level:
@@ -87,7 +75,7 @@ def initialized():
def cleanup():
global TRANSPORT, NOTIFICATION_TRANSPORT, NOTIFIER
if NOTIFIER is None:
LOG.exception(_LE("RPC cleanup: NOTIFIER is None"))
LOG.exception("RPC cleanup: NOTIFIER is None")
TRANSPORT.cleanup()
NOTIFICATION_TRANSPORT.cleanup()
TRANSPORT = NOTIFICATION_TRANSPORT = NOTIFIER = None
@@ -142,12 +130,14 @@ def get_client(target, version_cap=None, serializer=None):
def get_server(target, endpoints, serializer=None):
assert TRANSPORT is not None
access_policy = dispatcher.DefaultRPCAccessPolicy
serializer = RequestContextSerializer(serializer)
return messaging.get_rpc_server(TRANSPORT,
target,
endpoints,
executor='eventlet',
serializer=serializer)
serializer=serializer,
access_policy=access_policy)
def get_notifier(publisher_id):

View File

@@ -28,6 +28,8 @@ from oslo_reports import opts as gmr_opts
from oslo_service import service
from oslo_service import wsgi
from oslo_messaging.rpc import dispatcher
from watcher._i18n import _
from watcher.api import app
from watcher.common import config
@@ -110,16 +112,19 @@ class WSGIService(service.ServiceBase):
class ServiceHeartbeat(scheduling.BackgroundSchedulerService):
service_name = None
def __init__(self, gconfig=None, service_name=None, **kwargs):
gconfig = None or {}
super(ServiceHeartbeat, self).__init__(gconfig, **kwargs)
self.service_name = service_name
ServiceHeartbeat.service_name = service_name
self.context = context.make_context()
self.send_beat()
def send_beat(self):
host = CONF.host
watcher_list = objects.Service.list(
self.context, filters={'name': self.service_name,
self.context, filters={'name': ServiceHeartbeat.service_name,
'host': host})
if watcher_list:
watcher_service = watcher_list[0]
@@ -127,7 +132,7 @@ class ServiceHeartbeat(scheduling.BackgroundSchedulerService):
watcher_service.save()
else:
watcher_service = objects.Service(self.context)
watcher_service.name = self.service_name
watcher_service.name = ServiceHeartbeat.service_name
watcher_service.host = host
watcher_service.create()
@@ -135,6 +140,10 @@ class ServiceHeartbeat(scheduling.BackgroundSchedulerService):
self.add_job(self.send_beat, 'interval', seconds=60,
next_run_time=datetime.datetime.now())
@classmethod
def get_service_name(cls):
return CONF.host, cls.service_name
def start(self):
"""Start service."""
self.add_heartbeat_job()
@@ -168,6 +177,13 @@ class Service(service.ServiceBase):
self.conductor_topic = self.manager.conductor_topic
self.notification_topics = self.manager.notification_topics
self.heartbeat = None
self.service_name = self.manager.service_name
if self.service_name:
self.heartbeat = ServiceHeartbeat(
service_name=self.manager.service_name)
self.conductor_endpoints = [
ep(self) for ep in self.manager.conductor_endpoints
]
@@ -183,8 +199,6 @@ class Service(service.ServiceBase):
self.conductor_topic_handler = None
self.notification_handler = None
self.heartbeat = None
if self.conductor_topic and self.conductor_endpoints:
self.conductor_topic_handler = self.build_topic_handler(
self.conductor_topic, self.conductor_endpoints)
@@ -192,10 +206,6 @@ class Service(service.ServiceBase):
self.notification_handler = self.build_notification_handler(
self.notification_topics, self.notification_endpoints
)
self.service_name = self.manager.service_name
if self.service_name:
self.heartbeat = ServiceHeartbeat(
service_name=self.manager.service_name)
@property
def transport(self):
@@ -225,6 +235,7 @@ class Service(service.ServiceBase):
self.conductor_client = c
def build_topic_handler(self, topic_name, endpoints=()):
access_policy = dispatcher.DefaultRPCAccessPolicy
serializer = rpc.RequestContextSerializer(rpc.JsonPayloadSerializer())
target = om.Target(
topic=topic_name,
@@ -234,7 +245,8 @@ class Service(service.ServiceBase):
)
return om.get_rpc_server(
self.transport, target, endpoints,
executor='eventlet', serializer=serializer)
executor='eventlet', serializer=serializer,
access_policy=access_policy)
def build_notification_handler(self, topic_names, endpoints=()):
serializer = rpc.RequestContextSerializer(rpc.JsonPayloadSerializer())

View File

@@ -25,7 +25,6 @@ from oslo_utils import timeutils
from oslo_utils import uuidutils
import six
from watcher._i18n import _LW
from watcher.common import exception
from watcher import conf
@@ -73,9 +72,9 @@ def safe_rstrip(value, chars=None):
"""
if not isinstance(value, six.string_types):
LOG.warning(_LW(
LOG.warning(
"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.rstrip(chars) or value

4
watcher/conf/__init__.py Normal file → Executable file
View File

@@ -28,6 +28,8 @@ from watcher.conf import db
from watcher.conf import decision_engine
from watcher.conf import exception
from watcher.conf import glance_client
from watcher.conf import gnocchi_client
from watcher.conf import ironic_client
from watcher.conf import monasca_client
from watcher.conf import neutron_client
from watcher.conf import nova_client
@@ -50,7 +52,9 @@ decision_engine.register_opts(CONF)
monasca_client.register_opts(CONF)
nova_client.register_opts(CONF)
glance_client.register_opts(CONF)
gnocchi_client.register_opts(CONF)
cinder_client.register_opts(CONF)
ceilometer_client.register_opts(CONF)
neutron_client.register_opts(CONF)
clients_auth.register_opts(CONF)
ironic_client.register_opts(CONF)

View File

@@ -32,9 +32,10 @@ API_SERVICE_OPTS = [
cfg.PortOpt('port',
default=9322,
help='The port for the watcher API server'),
cfg.StrOpt('host',
default='127.0.0.1',
help='The listen IP address for the watcher API server'),
cfg.HostAddressOpt('host',
default='127.0.0.1',
help='The listen IP address for the watcher API server'
),
cfg.IntOpt('max_limit',
default=1000,
help='The maximum number of items returned in a single '

View File

@@ -25,7 +25,12 @@ CEILOMETER_CLIENT_OPTS = [
cfg.StrOpt('api_version',
default='2',
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):

View File

@@ -23,8 +23,13 @@ cinder_client = cfg.OptGroup(name='cinder_client',
CINDER_CLIENT_OPTS = [
cfg.StrOpt('api_version',
default='2',
help='Version of Cinder API to use in cinderclient.')]
default='3',
help='Version of Cinder API to use in cinderclient.'),
cfg.StrOpt('endpoint_type',
default='publicURL',
help='Type of endpoint to use in cinderclient.'
'Supported values: internalURL, publicURL, adminURL'
'The default is publicURL.')]
def register_opts(conf):

View File

@@ -42,6 +42,15 @@ WATCHER_DECISION_ENGINE_OPTS = [
required=True,
help='The maximum number of threads that can be used to '
'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 = [

View File

@@ -24,7 +24,12 @@ glance_client = cfg.OptGroup(name='glance_client',
GLANCE_CLIENT_OPTS = [
cfg.StrOpt('api_version',
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):

View 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)]

41
watcher/conf/ironic_client.py Executable file
View File

@@ -0,0 +1,41 @@
# -*- encoding: utf-8 -*-
# Copyright (c) 2017 ZTE Corp
#
# Authors: Prudhvi Rao Shedimbi <prudhvi.rao.shedimbi@intel.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from oslo_config import cfg
ironic_client = cfg.OptGroup(name='ironic_client',
title='Configuration Options for Ironic')
IRONIC_CLIENT_OPTS = [
cfg.StrOpt('api_version',
default=1,
help='Version of Ironic API to use in ironicclient.'),
cfg.StrOpt('endpoint_type',
default='internalURL',
help='Type of endpoint to use in ironicclient.'
'Supported values: internalURL, publicURL, adminURL'
'The default is internalURL.')]
def register_opts(conf):
conf.register_group(ironic_client)
conf.register_opts(IRONIC_CLIENT_OPTS, group=ironic_client)
def list_opts():
return [('ironic_client', IRONIC_CLIENT_OPTS)]

View File

@@ -24,7 +24,12 @@ monasca_client = cfg.OptGroup(name='monasca_client',
MONASCA_CLIENT_OPTS = [
cfg.StrOpt('api_version',
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):

View File

@@ -24,7 +24,12 @@ neutron_client = cfg.OptGroup(name='neutron_client',
NEUTRON_CLIENT_OPTS = [
cfg.StrOpt('api_version',
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):

7
watcher/conf/nova_client.py Normal file → Executable file
View File

@@ -24,7 +24,12 @@ nova_client = cfg.OptGroup(name='nova_client',
NOVA_CLIENT_OPTS = [
cfg.StrOpt('api_version',
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='publicURL',
help='Type of endpoint to use in novaclient.'
'Supported values: internalURL, publicURL, adminURL'
'The default is publicURL.')]
def register_opts(conf):

View File

@@ -26,13 +26,14 @@ SERVICE_OPTS = [
cfg.IntOpt('periodic_interval',
default=60,
help=_('Seconds between running periodic tasks.')),
cfg.StrOpt('host',
default=socket.gethostname(),
help=_('Name of this node. This can be an opaque identifier. '
'It is not necessarily a hostname, FQDN, or IP address. '
'However, the node name must be valid within '
'an AMQP key, and if using ZeroMQ, a valid '
'hostname, FQDN, or IP address.')),
cfg.HostAddressOpt('host',
default=socket.gethostname(),
help=_('Name of this node. This can be an opaque '
'identifier. It is not necessarily a hostname, '
'FQDN, or IP address. However, the node name '
'must be valid within an AMQP key, and if using '
'ZeroMQ, a valid hostname, FQDN, or IP address.')
),
cfg.IntOpt('service_down_time',
default=90,
help=_('Maximum time since last check-in for up service.'))

View File

@@ -32,6 +32,43 @@ class CeilometerHelper(object):
self.osc = osc if osc else clients.OpenStackClients()
self.ceilometer = self.osc.ceilometer()
@staticmethod
def format_query(user_id, tenant_id, resource_id,
user_ids, tenant_ids, resource_ids):
query = []
def query_append(query, _id, _ids, field):
if _id:
_ids = [_id]
for x_id in _ids:
query.append({"field": field, "op": "eq", "value": x_id})
query_append(query, user_id, (user_ids or []), "user_id")
query_append(query, tenant_id, (tenant_ids or []), "project_id")
query_append(query, resource_id, (resource_ids or []), "resource_id")
return query
def _timestamps(self, start_time, end_time):
def _format_timestamp(_time):
if _time:
if isinstance(_time, datetime.datetime):
return _time.isoformat()
return _time
return None
start_timestamp = _format_timestamp(start_time)
end_timestamp = _format_timestamp(end_time)
if ((start_timestamp is not None) and (end_timestamp is not None) and
(timeutils.parse_isotime(start_timestamp) >
timeutils.parse_isotime(end_timestamp))):
raise exception.Invalid(
_("Invalid query: %(start_time)s > %(end_time)s") % dict(
start_time=start_timestamp, end_time=end_timestamp))
return start_timestamp, end_timestamp
def build_query(self, user_id=None, tenant_id=None, resource_id=None,
user_ids=None, tenant_ids=None, resource_ids=None,
start_time=None, end_time=None):
@@ -49,45 +86,11 @@ class CeilometerHelper(object):
:param end_time: datetime until which measurements should be collected
"""
user_ids = user_ids or []
tenant_ids = tenant_ids or []
resource_ids = resource_ids or []
query = self.format_query(user_id, tenant_id, resource_id,
user_ids, tenant_ids, resource_ids)
query = []
if user_id:
user_ids = [user_id]
for u_id in user_ids:
query.append({"field": "user_id", "op": "eq", "value": u_id})
if tenant_id:
tenant_ids = [tenant_id]
for t_id in tenant_ids:
query.append({"field": "project_id", "op": "eq", "value": t_id})
if resource_id:
resource_ids = [resource_id]
for r_id in resource_ids:
query.append({"field": "resource_id", "op": "eq", "value": r_id})
start_timestamp = None
end_timestamp = None
if start_time:
start_timestamp = start_time
if isinstance(start_time, datetime.datetime):
start_timestamp = start_time.isoformat()
if end_time:
end_timestamp = end_time
if isinstance(end_time, datetime.datetime):
end_timestamp = end_time.isoformat()
if (start_timestamp and end_timestamp and
timeutils.parse_isotime(start_timestamp) >
timeutils.parse_isotime(end_timestamp)):
raise exception.Invalid(
_("Invalid query: %(start_time)s > %(end_time)s") % dict(
start_time=start_timestamp, end_time=end_timestamp))
start_timestamp, end_timestamp = self._timestamps(start_time,
end_time)
if start_timestamp:
query.append({"field": "timestamp", "op": "ge",

View 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 accordance 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]

View File

@@ -688,7 +688,7 @@ class BaseConnection(object):
def update_efficacy_indicator(self, efficacy_indicator_id, values):
"""Update properties of an efficacy indicator.
:param efficacy_indicator_uuid: The UUID of an efficacy indicator
:param efficacy_indicator_id: The ID of an efficacy indicator
:returns: An efficacy indicator
:raises: :py:class:`~.EfficacyIndicatorNotFound`
:raises: :py:class:`~.Invalid`

View File

@@ -27,7 +27,7 @@ from oslo_utils import strutils
import prettytable as ptable
from six.moves import input
from watcher._i18n import _, _LI
from watcher._i18n import _
from watcher._i18n import lazy_translation_enabled
from watcher.common import context
from watcher.common import exception
@@ -231,7 +231,7 @@ class PurgeCommand(object):
if action.action_plan_id not in action_plan_ids]
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
@@ -403,13 +403,13 @@ class PurgeCommand(object):
return to_be_deleted
def do_delete(self):
LOG.info(_LI("Deleting..."))
LOG.info("Deleting...")
# Reversed to avoid errors with foreign keys
for entry in reversed(list(self._objects_map)):
entry.destroy()
def execute(self):
LOG.info(_LI("Starting purge command"))
LOG.info("Starting purge command")
self._objects_map = self.find_objects_to_delete()
if (self.max_number is not None and
@@ -424,15 +424,15 @@ class PurgeCommand(object):
if not self.dry_run and self.confirmation_prompt():
self.do_delete()
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:
LOG.debug(self._objects_map)
print(_("Here below is a table containing the objects "
"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())
LOG.info(_LI("Purge process completed"))
LOG.info("Purge process completed")
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:
raise exception.NegativeLimitError
LOG.info(_LI("[options] age_in_days = %s"), age_in_days)
LOG.info(_LI("[options] max_number = %s"), max_number)
LOG.info(_LI("[options] goal = %s"), goal)
LOG.info(_LI("[options] exclude_orphans = %s"), exclude_orphans)
LOG.info(_LI("[options] dry_run = %s"), dry_run)
LOG.info("[options] age_in_days = %s", age_in_days)
LOG.info("[options] max_number = %s", max_number)
LOG.info("[options] goal = %s", goal)
LOG.info("[options] exclude_orphans = %s", exclude_orphans)
LOG.info("[options] dry_run = %s", dry_run)
uuid = PurgeCommand.get_goal_uuid(goal)

View File

@@ -0,0 +1,33 @@
"""Add apscheduler_jobs table to store background jobs
Revision ID: 0f6042416884
Revises: 001
Create Date: 2017-03-24 11:21:29.036532
"""
from alembic import op
import sqlalchemy as sa
from watcher.db.sqlalchemy import models
# revision identifiers, used by Alembic.
revision = '0f6042416884'
down_revision = '001'
def upgrade():
op.create_table(
'apscheduler_jobs',
sa.Column('id', sa.Unicode(191, _warn_on_bytestring=False),
nullable=False),
sa.Column('next_run_time', sa.Float(25), index=True),
sa.Column('job_state', sa.LargeBinary, nullable=False),
sa.Column('service_id', sa.Integer(), nullable=False),
sa.Column('tag', models.JSONEncodedDict(), nullable=True),
sa.PrimaryKeyConstraint('id'),
sa.ForeignKeyConstraint(['service_id'], ['services.id'])
)
def downgrade():
op.drop_table('apscheduler_jobs')

Some files were not shown because too many files have changed in this diff Show More