Compare commits

...

114 Commits
1.4.2 ... 1.5.0

Author SHA1 Message Date
caoyuan
84fb7423f1 Update the nova api_version default value to 2.53
the api_version has been update, so the doc should change the default
value

refer to https://github.com/openstack/watcher/blob/master/watcher/conf/nova_client.py#L26

Change-Id: I9717294d43203315d0593a4fee8c2ff2caf6f0d0
2017-10-17 14:40:59 +08:00
caoyuan
ee5b01d33b Correct the instance migration link
1. Update the instance migration link
2. remove the unnecessary install-guide link

configure and install Ceilometer by
https://docs.openstack.org/ceilometer/latest is enough
remove the other link.

Change-Id: I2bf408de1023750a3d1f2c9e25293649d99ac428
2017-10-17 10:07:55 +08:00
Zuul
b35feb5432 Merge "optimize update_audit_state" 2017-10-17 01:19:31 +00:00
Jenkins
8343f4bf46 Merge "Add documentation about saving energy strategy" 2017-10-13 06:51:13 +00:00
Jenkins
cd3f792eef Merge "Invoke version_string in watcher/version.py directly" 2017-10-13 04:51:43 +00:00
Jenkins
7f7f7a9fd2 Merge "Add saving energy strategy description" 2017-10-13 04:50:00 +00:00
Jenkins
d5b778b730 Merge "Fix _build_instance_node for building Compute CDM" 2017-10-13 04:05:56 +00:00
Jenkins
62a902df7c Merge "Fix the telemetry-measurements hyperlink for strategies" 2017-10-13 02:52:06 +00:00
Jenkins
5b6f65630d Merge "Update OpenStack Installation Tutorial to pike" 2017-10-13 02:23:52 +00:00
OpenStack Proposal Bot
e5031ef04a Updated from global requirements
Change-Id: I973ef2867d95fe4f70a43c9015f7571188dc13cd
2017-10-12 22:07:21 +00:00
Jenkins
ab2408ea67 Merge "writing convention: do not use “-y” for package install" 2017-10-12 07:04:58 +00:00
Yumeng_Bao
4c0d2ab4b2 Add saving energy strategy description
Change-Id: Id99d48bd2ca2a2539366d8dc1f7627d7eb472a10
2017-10-12 11:39:02 +08:00
Yumeng_Bao
cf8d7bb2f4 Add documentation about saving energy strategy
Change-Id: I9746239c83ea7bff364ad6939e4174748be2d299
Closes-Bug: #1713402
2017-10-11 14:24:30 +08:00
Jenkins
b3d60cb13d Merge "Optimize the import format by pep8" 2017-10-10 14:33:45 +00:00
Jenkins
ffdc3b554d Merge "Remove explicitly enable neutron" 2017-10-10 13:21:35 +00:00
Jenkins
9933d61065 Merge "Fix Action 'change_node_power_state' FAILED" 2017-10-10 13:19:15 +00:00
Jenkins
b4bc1599e6 Merge "Fix TypeError in function chunkify" 2017-10-10 13:17:26 +00:00
Jenkins
280188a762 Merge "Remove installation guide for openSUSE and SLES" 2017-10-10 13:14:41 +00:00
Jenkins
3942f44e56 Merge "Notification Cancel Action Plan" 2017-10-10 13:12:02 +00:00
Jenkins
6208caba0c Merge "Fix action plan state change when action failed" 2017-10-10 12:06:07 +00:00
Jenkins
f3b3e82313 Merge "Remove the unnecessary word" 2017-10-10 11:02:37 +00:00
zhuzeyu
be69ebd8bd Invoke version_string in watcher/version.py directly
There is already define version_string in version.py
So we don't need generate version in other files, just call it.

Change-Id: I7d8294860523eedad92e213ad00569829e120c39
2017-10-10 11:00:26 +00:00
Hidekazu Nakamura
7d33bf8813 Fix _build_instance_node for building Compute CDM
As of Nova API microversion 2.47, response of GET /servers/detail has flavor
which contains a subset of the actual flavor information used to create the
server instance, represented as a nested dictionary.

Since current watcher nova default api version is 2.53(Pike), This patch
follows the API response change.

Change-Id: Ia575950f0702afa1d093f03ca8ddedd3c410b7de
Closes-Bug: #1722462
2017-10-10 17:21:05 +09:00
zhengwei6082
b3fa8a0f86 writing convention: do not use “-y” for package install
Adhering to coding conventions. Refer to ``Code conventions`` at
https://docs.openstack.org/contributor-guide/ for details.

Change-Id: Ic8b166e17ab0d1cbbf2bb6b831f5e53cae6797ba
2017-10-10 06:13:52 +00:00
caoyuan
9d3cc28d2d Update OpenStack Installation Tutorial to pike
Since the pike is release, OpenStack Installation Tutorial should
update to pike

Change-Id: I565f721cb2acbc692c790707ef6b0d167d6a7b09
2017-10-10 10:37:45 +08:00
aditi
eed2e128b0 Remove explicitly enable neutron
This patch removes, explicitly enabled neutron from local.conf
as devstack now default uses neutron

Change-Id: Icf6bd944dd2262ff23cbcceb762a9ba80f471dbb
2017-10-10 01:59:46 +00:00
caoyuan
7091fe435f Fix the telemetry-measurements hyperlink for strategies
Change-Id: Ie38950967665bdc81eb75f54bc1b3b0a4630fe65
2017-10-09 10:41:54 +08:00
licanwei
7f9b562bbd optimize update_audit_state
save state only if the state is different with audit.state

Change-Id: Ida5156f2e63be55e8dd7de452965270c007ab4ab
2017-10-07 00:59:42 -07:00
caoyuan
f445fc451e Optimize the import format by pep8
Change-Id: Ic96759df51f5572fb6047df4b38bb411ecba8e20
2017-10-05 22:34:13 +08:00
Jenkins
fa7749ac8f Merge "Use Property setters" 2017-10-05 04:21:05 +00:00
Zuul
e6c06c1bdf Merge "Add exception log when migrate action failed" 2017-10-03 17:06:20 +00:00
caoyuan
f461b8c567 Remove the unnecessary word
Change-Id: I7f76f89ae17ffdacde421509dda29b7b7d3f5a4a
2017-10-03 21:06:27 +08:00
LiXiangyu
c717be12a6 Fix TypeError in function chunkify
This patch fixes TypeError of range() in function chunkify, as
range() integer step argument expected, but got str.

Change-Id: I2acde859e014baa4c4c59caa6f4ea938c7c4c3bf
2017-10-02 12:25:20 +00:00
Hidekazu Nakamura
5814914aef Fix action plan state change when action failed
Since default workflow engine action container do_execute method
does not raise exception when action failed, workflow engine action
container execute method never raise exception and
action plan state becomes always SUCCEEDED.

This patch fixes default workflow engine action container do_execute
method to raise exception when action does not return True.

Change-Id: I7eeef69dbdfb5d40e3cf0b1004cbfe199a16bf7b
Closes-Bug: #1719793
2017-10-02 07:09:17 +00:00
Hidekazu Nakamura
fb3c2355a6 Remove installation guide for openSUSE and SLES
Since packages for openSUSE and SLES are not provided,
this patch removes installation guide for openSUSE and SLES.

Change-Id: Ic15d8c4b262e935c7acaef41e18960d0b259d5c9
Closes-Bug: #1715032
2017-10-02 13:52:29 +09:00
aditi
d4e6e82dd2 Notification Cancel Action Plan
This patch adds Notifications for cancel action plan
operation.

Change-Id: I5a89a80729349e3db43ca35ff9fbe8579e86b3b1
Implements: blueprint notifications-actionplan-cancel
2017-09-29 14:44:30 +09:00
Hidekazu Nakamura
816765374d Fix migrate action failure
disk_over_commit flag was removed in Nova API microversion 2.25(Mitaka).

Since current watcher nova default api version is 2.53(Pike),
this patch removes disk_over_commit flag.

Change-Id: Ib141505b9e8cb41997b29c1762e387b1f84f5143
Closes-Bug: #1720054
2017-09-28 14:06:07 +09:00
Hidekazu Nakamura
35e502f666 Add exception log when migrate action failed
As of now we can not know what was happend when migrate action
failed critically.
This patch adds exception log when migrate action failed critically.

Change-Id: I54d0bc54ee1df6f13754771775c58255f53f5008
2017-09-28 11:56:29 +09:00
Jenkins
ee36bb8180 Merge "[Doc] Fix host option" 2017-09-28 02:06:09 +00:00
Jenkins
0213bee63b Merge "Fix Watcher DB schema creation" 2017-09-27 08:36:31 +00:00
Alexander Chadin
f516a9c3b9 [Doc] Fix host option
Change-Id: I599856d2d02396f02f91ac4a607520ff60d7b033
2017-09-27 08:10:44 +00:00
aditi
8e89d5489c Use Property setters
At various places in watcher code, we are using property getters
to set property, in this way the property setters defined are
never used, this patch fixes to use property setters to set
property.

Change-Id: Idb274887f383523cea39277b166ec9b46ebcda85
2017-09-27 10:43:43 +09:00
Jenkins
773b20a05f Merge "cleanup test-requirements" 2017-09-26 00:09:48 +00:00
Jenkins
03d6580819 Merge "Update the description for controller node" 2017-09-25 11:08:48 +00:00
Jenkins
afa73238c4 Merge "Update the "IAAS" to "IaaS"" 2017-09-25 10:54:50 +00:00
caoyuan
2467780f9d Update the description for controller node
1. change the controller node description to link
2. correct the link for compute node

Change-Id: Idfdde7f01c38a26dc4962e94431a760a0ed51f82
2017-09-25 03:21:44 +00:00
OpenStack Proposal Bot
25854aabd8 Updated from global requirements
Change-Id: I86b2ed25f98f022597d58335461efc9e0ff61b26
2017-09-24 12:31:19 +00:00
melissaml
e4f4588e69 cleanup test-requirements
python-subunit is not used directly anywhere
and it is dependency of both testrepository
and os-testr
(probably was used by some tox wrapper script before)

Change-Id: I89279430554bc522817c4e2685afef0d95c641dd
2017-09-24 04:40:32 +08:00
caoyuan
1465aa0c5f Update the "IAAS" to "IaaS"
Infrastructure-as-a-Service should short for IaaS

Change-Id: I845fed0c4a1f073dbdea1e8f0e9cdc1655aa3622
2017-09-21 16:38:30 +08:00
caoyuan
e6e0b3dbaa Correct the link for watcher cli
Change-Id: Ic844804278af3abdf5bbb05ea5ef9a1c630da628
2017-09-20 22:17:18 +08:00
Jenkins
d8274e062e Merge "Update the documentation link for doc migration" 2017-09-19 00:06:20 +00:00
lingyongxu
28b9766693 Update the documentation link for doc migration
This patch is proposed according to the Direction 10 of doc
migration(https://etherpad.openstack.org/p/doc-migration-tracking).

Change-Id: I4eb594115e350e28f9136f7003692a1ec0abfcf6
2017-09-18 09:19:33 +00:00
OpenStack Proposal Bot
998e86f6c7 Updated from global requirements
Change-Id: I464b3573c2dbab3d97efbec0280298b0331a3cef
2017-09-16 23:26:49 +00:00
Alexander Chadin
a5e7fd90c2 Fix Watcher DB schema creation
This patch set replaces create_schema with upgrade to fix
apscheduler creation issue. It also fixes pep8 warnings to
d09a5945e4a0_add_action_description_table.py

Change-Id: Ica842d585ee3a9cd67e45eb1d7bb1916573d7c9c
2017-09-15 15:30:38 +03:00
Jenkins
a99a9ae69e Merge "Utils: fix usage of strtime" 2017-09-14 07:28:24 +00:00
licanwei
6e6e5907ee Fix Action 'change_node_power_state' FAILED
The return value of ironic_client.node.set_power_state is None, so it's
useless to return the result.
We should check the node state until it's changed or timeout.

Change-Id: I31f75a2c4a721ce4481e6ae7fb83d154a443dad9
Closes-Bug: #1713655
2017-09-13 23:59:35 -07:00
Jenkins
c887499b4d Merge "Fix incorrect config section name of configure doc" 2017-09-14 02:47:17 +00:00
Jenkins
58e4bf2727 Merge "Remove redundant right parenthesis" 2017-09-14 02:44:43 +00:00
OpenStack Proposal Bot
1df395d31d Updated from global requirements
Change-Id: I52665af336d0a0c765d034368a554005505cf30a
2017-09-14 00:11:17 +00:00
Jenkins
f811c8af48 Merge "Remove the unused rootwrap config" 2017-09-13 15:50:59 +00:00
Jenkins
e447393f18 Merge "iso8601.is8601.Utc No Longer Exists" 2017-09-13 13:13:59 +00:00
gaozx
a25be6498c Fix incorrect config section name of configure doc
Change-Id: I3d1e602f3a4beace516c56979b3b21b5683c1b0a
2017-09-13 16:38:50 +08:00
Jenkins
8e372ee153 Merge "Update the documentation link for doc migration" 2017-09-13 07:41:06 +00:00
aditi
7bc984b84a Fix Gate Failure
This Patch fixes gate failure, encountered in recent version
of oslo_messaging.

Change-Id: I6d8ab882a7c157dcf4f78c805a4ce2d9b1fa3f14
Closes-Bug: #1716476
2017-09-12 16:30:22 +09:00
gaozx
eeee32ad36 Remove redundant right parenthesis
Change-Id: Ibdb295d8d5ff8e49b0bebdb71c9c856f49c3881e
2017-09-11 09:48:42 +08:00
chenghuiyu
3a7fc7a8e5 Utils: fix usage of strtime
As oslo_utils.timeutils.strtime() is deprecated in
version '1.6', and will be removed in a future version.

For more informations:
https://docs.openstack.org/oslo.utils/latest/reference/timeutils.html

Change-Id: I1aca257fbe8b08c3478c5da9639835033b19144a
Partial-Bug: #1715325
2017-09-07 16:56:01 +08:00
zhengwei6082
63697d5a6e Update the documentation link for doc migration
This patch is proposed according to the direction 10 of doc
migration(https://etherpad.openstack.org/p/doc-migration-tracking).

Change-Id: Idf2f369fb68c19efa54a06731bb33dc6fa949790
2017-09-07 09:56:40 +08:00
Sampath Priyankara
887fa746ae iso8601.is8601.Utc No Longer Exists
iso8601.UTC is correct datetime UTC field object.
iso8601 >= 0.1.12 includes only iso8601.UTC for python3
while both UTC and Utc() for python2. Less then 0.1.12
included both UTC and Utc() for both python2/3.

Change-Id: I0f8796fba6725eea013b3f8d9ad33c10a402c524
Closes-Bug: #1715486
2017-09-07 10:42:05 +09:00
Jenkins
e74095da1f Merge "Remove unused efficacy indicators" 2017-09-06 09:50:55 +00:00
zhurong
65c7cd0e02 Remove the unused rootwrap config
Watcher doesn't use rootwrap, but have the rootwrap config.
So remove the unused rootwrap config.

Change-Id: Icc32fc958ca8deb08d7b0e5404cbbe19b3ae98c7
2017-09-06 14:46:09 +08:00
Hidekazu Nakamura
5df54ea3fb Remove unused efficacy indicators
AverageCpuLoad and MigrationEfficacy efficacy indicators are not used.
This patch removes unused indicators.

Change-Id: I2b21defd442c135d26f8fd45f6faf9f67c770bde
2017-09-06 12:05:25 +09:00
Yaguo Zhou
51dba60e01 Replace DbMigrationError with DBMigrationError
because DbMigrationError is deprecated

Change-Id: I75ef338d2e22924997804632d26ae3588c4f719b
2017-09-05 23:31:05 +08:00
Jenkins
a9f33467fb Merge "Replace default gnocchi endpoint type" 2017-09-05 10:48:43 +00:00
Jenkins
4640d88adf Merge "Fix DEFAULT_SCHEMA to validate host_aggreates" 2017-09-05 08:45:35 +00:00
zhengwei6082
154aca3948 Replace default gnocchi endpoint type
The default gnocchi endpoint type is publicURL in gnocchiclient.
This patch replaces default gnocchi endpoint type from
internalURL to publicURL
see https://github.com/openstack/keystoneauth/blob/master/keystoneauth1/adapter.py#L347-L351

Change-Id: I0ba2bde46de3025964affe23ef16cce9e5b4670f
2017-09-05 02:11:42 +00:00
Jenkins
fa7afc89ab Merge "Updated from global requirements" 2017-09-04 08:30:54 +00:00
Jenkins
790548fff0 Merge "Modify display_name in strategy documentation" 2017-09-04 08:28:21 +00:00
Hidekazu Nakamura
a2fa13c8ff Fix gnocchiclient creation
Gnocchiclient uses keystoneauth1.adapter so that adapter_options
need to be given.
This patch fixes gnocchiclient creation.

Change-Id: I6b5d8ee775929f4b3fd30be3321b378d19085547
Closes-Bug: #1714871
2017-09-04 14:52:11 +09:00
Hidekazu Nakamura
4c3c84dee9 Fix DEFAULT_SCHEMA to validate host_aggreates
Audit scope JSON schema should restrict key of host_aggregates
to "id" or "name", but that is not working now.
This patch fixes DEFAULT_SCHEMA to validate host_aggregates.

Change-Id: Iea42da41d61435780e247736599a56c026f47914
Closes-Bug: #1714448
2017-09-04 09:50:49 +09:00
OpenStack Proposal Bot
8f585c3def Updated from global requirements
Change-Id: If2d709b80f1783a5b14c9eda4d15da13c9ba5234
2017-09-02 12:15:38 +00:00
Jenkins
c9a43d8da4 Merge "Update default Nova API version to 2.53(Pike)" 2017-09-02 09:00:07 +00:00
Jenkins
2ea7d61ac8 Merge "Restrict existing strategies to their default scope" 2017-09-02 09:00:02 +00:00
Yumeng_Bao
bbfd6711fc Modify display_name in strategy documentation
Display_name in documentation of each strategy should be like[1].
[1]:https://github.com/openstack/watcher/blob/master/watcher/decision_engine/strategy/strategies/workload_balance.py#L143

Change-Id: I31b16dbb81d824e0189fcf96ea7f6e57a289e59a
2017-09-01 14:48:23 +08:00
shangxiaobj
162aaa75ee [Trivialfix]Fix typos in watcher
Fix the typos in watcher.

Change-Id: I3ab77e2a1f862d3790065de4a6ff6c3ef42f226d
2017-08-31 20:47:57 -07:00
suzhengwei
4cb2b45e3a Restrict existing strategies to their default scope
Diffrent stratege has diffrent default scope, restrict them to their
default scope will avoid usage problems.
1)workload_balancing/thermal_optimization/airflow_optimization goals
  react on enabled nodes, so restrict default scope to compute nodes
  with up state and enabled status.
2)server_consolidation goal react on enabled or disabled nodes, So
  restrict default scope to compute nodes with up state and
  enabled/disabled status.

Change-Id: I7437dee699ee2d3dd227a047196d4d8db811b81e
Closes-Bug: #1714002
2017-09-01 11:21:35 +08:00
Jenkins
50935af15f Merge "Fix to use . to source script files" 2017-09-01 01:31:39 +00:00
Hidekazu Nakamura
cf92ece936 Update default Nova API version to 2.53(Pike)
Services are now identified by uuid instead of database id to ensure
uniqueness across cells.
GET /os-services returns a uuid in the id field of the response
from API microversion 2.53(maximum in Pike)

This patch set updates default Nova API version to 2.53.

Change-Id: Ib9fefb794eda3c9e75c6a2f5cfdb0e682b8955f3
Closes-Bug: #1709544
2017-08-30 14:39:31 +09:00
zhengwei6082
b7c4a0467c Fix to use . to source script files
Adhering to coding conventions. Refer to ``Code conventions`` at
https://docs.openstack.org/contributor-guide/ for details.

Change-Id: I54b93214c0e718465a0ea4ebe063061ef7d6e4b2
2017-08-29 18:01:09 +08:00
Jenkins
c12f132699 Merge "Remove unnecessary dict.keys() method calls (api)" 2017-08-29 06:30:49 +00:00
melissaml
0329dafec9 Fix to use "." to source script files
Adhering to coding conventions. Refer to ``Code conventions`` at
https://docs.openstack.org/contributor-guide/ for details.

Change-Id: I23ff70c9caefc870b3cc9d61cd8c18b534f2ffaf
2017-08-29 02:32:28 +08:00
zhengwei6082
e73ead4807 Update the documentation link for doc migration
Change-Id: If429e5023a252d9b86b227488f73cac863b3c658
2017-08-25 16:58:31 +08:00
Jenkins
cb90f60cc1 Merge "Updated from global requirements" 2017-08-25 06:23:39 +00:00
Jenkins
d7994a2466 Merge "Fix KeyError exception" 2017-08-24 12:40:32 +00:00
OpenStack Proposal Bot
62822fa933 Updated from global requirements
Change-Id: I31aaf37bf1ea73c26d9578abe167b43a24bb6c96
2017-08-24 11:51:24 +00:00
Jenkins
3f0ff1ed7e Merge "Updated from global requirements" 2017-08-24 10:09:43 +00:00
Jenkins
8e3b5c90a6 Merge "Remove watcher_tempest_plugin" 2017-08-24 10:09:24 +00:00
OpenStack Proposal Bot
1c5e254124 Updated from global requirements
Change-Id: I48a42877f8157873f4ea376c72d170d978d5e090
2017-08-24 06:03:14 +00:00
Viktor Varga
39e200e5eb Remove unnecessary dict.keys() method calls (api)
Since iter(dict) is equivalent to iter(dict.keys()), it is unnecessary
to call the keys() method of a dict, the dictionary itself is enough
to be referenced. The shorter form is also considered to be more
Pythonic.

This patch removes the unnecessary dict.keys() method calls in api.
This is a part of a larger patch series that removes dict.keys()
method calls.

TrivialFix

Change-Id: I29000f1f05b90d70109fa01393e97e1ebf450c63
2017-08-23 12:51:54 +02:00
Jenkins
2650b89fe5 Merge "Update the documention for doc migration" 2017-08-22 10:10:33 +00:00
zhengwei6082
d5bcd37478 Update the documention for doc migration
Change-Id: I22dc18e6f2f7471f5c804d4d19c631f81a6e196b
2017-08-22 09:06:06 +00:00
Alexander Chadin
0c4b439c5e Remove watcher_tempest_plugin
In accordance with Queens global goal[1], this patch set
removes watcher tempest plugin from watcher repository since
it is stored as independent repository[2]. Jenkins job
gate-watcher-dsvm-multinode-ubuntu-xenial-nv has been modified,
it uses watcher-tempest-plugin repo now.

[1]: https://governance.openstack.org/tc/goals/queens/split-tempest-plugins.html
[2]: http://git.openstack.org/cgit/openstack/watcher-tempest-plugin/

Change-Id: I4d1207fbd73ee2519a6d40342f5fd3c5d3ee8bc7
2017-08-21 17:41:56 +03:00
OpenStack Proposal Bot
0e43504e44 Updated from global requirements
Change-Id: Idd00808c17ecbca5925f91ea2f1257d097af7892
2017-08-18 11:45:04 +00:00
licanwei
322843b21c Fix KeyError exception
During the strategy sync process,
if goal_id can't be found in the goals table,
will throw a KeyError exception.

Change-Id: I62800ac5c69f4f5c7820908f2e777094a51a5541
Closes-Bug: #1711086
2017-08-17 04:25:53 -07:00
Jenkins
1b413f5536 Merge "Remove pbr warnerrors" 2017-08-17 03:07:46 +00:00
Alexander Chadin
f76a628d1f Remove pbr warnerrors
This change removes the now unused "warnerrors" setting,
which is replaced by "warning-is-error" in sphinx
releases >= 1.5 [1].

[1] http://lists.openstack.org/pipermail/openstack-dev/2017-March/113085.html

Change-Id: I32f078169668be08737e47cd15edbdfba42904dc
2017-08-16 11:54:24 +03:00
Jenkins
3e6ea71cbc Merge "Adjust the action state judgment logic" 2017-08-15 09:10:53 +00:00
Jenkins
e5c3df0c2f Merge "workload balance base on cpu or ram util" 2017-08-15 08:37:58 +00:00
Jenkins
6005d6ebdd Merge "Fix gnocchi repository URL in local.conf.controller" 2017-08-14 09:14:54 +00:00
licanwei
965af1b6fd Adjust the action state judgment logic
Only when True is returned, the action state is set to SUCCEEDED
some actions(such as migrate) will return None if exception raised

Change-Id: I52e7a1ffb68f54594f2b00d9843e8e0a4c985667
2017-08-14 02:12:35 -07:00
Jenkins
daf428ad69 Merge "Removed unnecessary setUp calls in tests" 2017-08-11 09:15:01 +00:00
OpenStack Release Bot
ab64dab646 Update reno for stable/pike
Change-Id: I1c1c855b80ad10e343d1c34e17ed11d8255e9fea
2017-08-11 01:09:58 +00:00
suzhengwei
5c86a54d20 workload balance base on cpu or ram util
By the input parameter "metrics", it makes decision to migrate a VM
base on cpu or memory utilization.

Change-Id: I35cce3495c8dacad64ea6c6ee71082a85e9e0a83
2017-08-09 07:04:10 +00:00
Hidekazu Nakamura
5cc4716a95 Fix gnocchi repository URL in local.conf.controller
This patch set updates gnocchi repository URL in local.conf.controller
bacause it moved from under openstack to their own repository.

Change-Id: I53c6efcb40b26f83bc1867564b9067ae5f50938d
2017-08-04 09:23:02 +09:00
Gábor Antal
b532355232 Removed unnecessary setUp calls in tests
TrivialFix

Change-Id: I057d03466b058a42be8ec57dbc42cbd67b75cc3c
2017-08-01 10:50:34 +02:00
158 changed files with 1556 additions and 3781 deletions

View File

@@ -24,13 +24,6 @@ MULTI_HOST=1
# This is the controller node, so disable nova-compute
disable_service n-cpu
# Disable nova-network and use neutron instead
disable_service n-net
ENABLED_SERVICES+=,q-svc,q-dhcp,q-meta,q-agt,q-l3,neutron
# Enable remote console access
enable_service n-cauth
# Enable the Watcher Dashboard plugin
enable_plugin watcher-dashboard git://git.openstack.org/openstack/watcher-dashboard
@@ -42,11 +35,12 @@ 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
enable_plugin gnocchi https://github.com/gnocchixyz/gnocchi
LOGFILE=$DEST/logs/stack.sh.log
LOGDAYS=2

View File

@@ -7,7 +7,7 @@ _XTRACE_WATCHER_PLUGIN=$(set +o | grep xtrace)
set -o xtrace
echo_summary "watcher's plugin.sh was called..."
source $DEST/watcher/devstack/lib/watcher
. $DEST/watcher/devstack/lib/watcher
# Show all of defined environment variables
(set -o posix; set)

View File

@@ -22,7 +22,7 @@ from docutils import nodes
from docutils.parsers import rst
from docutils import statemachine
from watcher.version import version_info
from watcher.version import version_string
class BaseWatcherDirective(rst.Directive):
@@ -169,4 +169,4 @@ class WatcherFunc(BaseWatcherDirective):
def setup(app):
app.add_directive('watcher-term', WatcherTerm)
app.add_directive('watcher-func', WatcherFunc)
return {'version': version_info.version_string()}
return {'version': version_string}

View File

@@ -0,0 +1,41 @@
{
"priority": "INFO",
"payload": {
"watcher_object.namespace": "watcher",
"watcher_object.version": "1.0",
"watcher_object.name": "ActionCancelPayload",
"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": "CANCELLED",
"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": "CANCELLING",
"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.cancel.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": "ActionCancelPayload",
"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_cancel_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": "CANCELLING",
"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.cancel.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": "ActionCancelPayload",
"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": "CANCELLING",
"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": "CANCELLING",
"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.cancel.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,55 @@
{
"event_type": "action_plan.cancel.end",
"payload": {
"watcher_object.namespace": "watcher",
"watcher_object.name": "ActionPlanCancelPayload",
"watcher_object.version": "1.0",
"watcher_object.data": {
"created_at": "2016-10-18T09:52:05Z",
"deleted_at": null,
"audit_uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
"audit": {
"watcher_object.namespace": "watcher",
"watcher_object.name": "TerseAuditPayload",
"watcher_object.version": "1.0",
"watcher_object.data": {
"created_at": "2016-10-18T09:52:05Z",
"deleted_at": null,
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
"scope": [],
"audit_type": "ONESHOT",
"state": "SUCCEEDED",
"parameters": {},
"interval": null,
"updated_at": null
}
},
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
"fault": null,
"state": "CANCELLED",
"global_efficacy": {},
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
"strategy": {
"watcher_object.namespace": "watcher",
"watcher_object.name": "StrategyPayload",
"watcher_object.version": "1.0",
"watcher_object.data": {
"created_at": "2016-10-18T09:52:05Z",
"deleted_at": null,
"name": "TEST",
"uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
"parameters_spec": {},
"display_name": "test strategy",
"updated_at": null
}
},
"updated_at": null
}
},
"priority": "INFO",
"message_id": "3984dc2b-8aef-462b-a220-8ae04237a56e",
"timestamp": "2016-10-18 09:52:05.219414",
"publisher_id": "infra-optim:node0"
}

View File

@@ -0,0 +1,65 @@
{
"event_type": "action_plan.cancel.error",
"publisher_id": "infra-optim:node0",
"priority": "ERROR",
"message_id": "9a45c5ae-0e21-4300-8fa0-5555d52a66d9",
"payload": {
"watcher_object.version": "1.0",
"watcher_object.namespace": "watcher",
"watcher_object.name": "ActionPlanCancelPayload",
"watcher_object.data": {
"fault": {
"watcher_object.version": "1.0",
"watcher_object.namespace": "watcher",
"watcher_object.name": "ExceptionPayload",
"watcher_object.data": {
"exception_message": "TEST",
"module_name": "watcher.tests.notifications.test_action_plan_notification",
"function_name": "test_send_action_plan_cancel_with_error",
"exception": "WatcherException"
}
},
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
"created_at": "2016-10-18T09:52:05Z",
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
"strategy": {
"watcher_object.version": "1.0",
"watcher_object.namespace": "watcher",
"watcher_object.name": "StrategyPayload",
"watcher_object.data": {
"uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
"created_at": "2016-10-18T09:52:05Z",
"name": "TEST",
"updated_at": null,
"display_name": "test strategy",
"parameters_spec": {},
"deleted_at": null
}
},
"updated_at": null,
"deleted_at": null,
"audit_uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
"audit": {
"watcher_object.version": "1.0",
"watcher_object.namespace": "watcher",
"watcher_object.name": "TerseAuditPayload",
"watcher_object.data": {
"parameters": {},
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
"created_at": "2016-10-18T09:52:05Z",
"scope": [],
"updated_at": null,
"audit_type": "ONESHOT",
"interval": null,
"deleted_at": null,
"state": "SUCCEEDED"
}
},
"global_efficacy": {},
"state": "CANCELLING"
}
},
"timestamp": "2016-10-18 09:52:05.219414"
}

View File

@@ -0,0 +1,55 @@
{
"event_type": "action_plan.cancel.start",
"payload": {
"watcher_object.namespace": "watcher",
"watcher_object.name": "ActionPlanCancelPayload",
"watcher_object.version": "1.0",
"watcher_object.data": {
"created_at": "2016-10-18T09:52:05Z",
"deleted_at": null,
"audit_uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
"audit": {
"watcher_object.namespace": "watcher",
"watcher_object.name": "TerseAuditPayload",
"watcher_object.version": "1.0",
"watcher_object.data": {
"created_at": "2016-10-18T09:52:05Z",
"deleted_at": null,
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
"scope": [],
"audit_type": "ONESHOT",
"state": "SUCCEEDED",
"parameters": {},
"interval": null,
"updated_at": null
}
},
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
"fault": null,
"state": "CANCELLING",
"global_efficacy": {},
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
"strategy": {
"watcher_object.namespace": "watcher",
"watcher_object.name": "StrategyPayload",
"watcher_object.version": "1.0",
"watcher_object.data": {
"created_at": "2016-10-18T09:52:05Z",
"deleted_at": null,
"name": "TEST",
"uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
"parameters_spec": {},
"display_name": "test strategy",
"updated_at": null
}
},
"updated_at": null
}
},
"priority": "INFO",
"message_id": "3984dc2b-8aef-462b-a220-8ae04237a56e",
"timestamp": "2016-10-18 09:52:05.219414",
"publisher_id": "infra-optim:node0"
}

View File

@@ -127,8 +127,8 @@ Here is single Dockerfile snippet you can use to run your Docker container:
RUN apt-get update
RUN apt-get dist-upgrade -y
RUN apt-get install -y vim net-tools
RUN apt-get install -yt experimental watcher-api
RUN apt-get install vim net-tools
RUN apt-get install experimental watcher-api
CMD ["/usr/bin/watcher-api"]

View File

@@ -119,7 +119,7 @@ The watcher command-line interface (CLI) can be used to interact with the
Watcher system in order to control it or to know its current status.
Please, read `the detailed documentation about Watcher CLI
<https://factory.b-com.com/www/watcher/doc/python-watcherclient/>`_.
<https://docs.openstack.org/python-watcherclient/latest/cli/>`_.
.. _archi_watcher_dashboard_definition:
@@ -130,7 +130,7 @@ The Watcher Dashboard can be used to interact with the Watcher system through
Horizon in order to control it or to know its current status.
Please, read `the detailed documentation about Watcher Dashboard
<http://docs.openstack.org/developer/watcher-dashboard/>`_.
<https://docs.openstack.org/watcher-dashboard/latest>`_.
.. _archi_watcher_database_definition:
@@ -170,7 +170,7 @@ Unless specified, it then selects the most appropriate :ref:`strategy
goal.
The :ref:`Strategy <strategy_definition>` is then dynamically loaded (via
`stevedore <http://docs.openstack.org/developer/stevedore/>`_). The
`stevedore <https://docs.openstack.org/stevedore/latest>`_). The
:ref:`Watcher Decision Engine <watcher_decision_engine_definition>` executes
the strategy.

View File

@@ -72,7 +72,7 @@ copyright = u'OpenStack Foundation'
# The full version, including alpha/beta/rc tags.
release = watcher_version.version_info.release_string()
# The short X.Y version.
version = watcher_version.version_info.version_string()
version = watcher_version.version_string
# A list of ignored prefixes for module index sorting.
modindex_common_prefix = ['watcher.']

View File

@@ -15,7 +15,7 @@ Service overview
================
The Watcher system is a collection of services that provides support to
optimize your IAAS platform. The Watcher service may, depending upon
optimize your IaaS platform. The Watcher service may, depending upon
configuration, interact with several other OpenStack services. This includes:
- the OpenStack Identity service (`keystone`_) for request authentication and
@@ -27,7 +27,7 @@ configuration, interact with several other OpenStack services. This includes:
The Watcher service includes the following components:
- ``watcher-decision-engine``: runs audit on part of your IAAS and return an
- ``watcher-decision-engine``: runs audit on part of your IaaS and return an
action plan in order to optimize resource placement.
- ``watcher-api``: A RESTful API that processes application requests by sending
them to the watcher-decision-engine over RPC.
@@ -349,7 +349,7 @@ so that the watcher service is configured for your needs.
[nova_client]
# Version of Nova API to use in novaclient. (string value)
#api_version = 2
#api_version = 2.53
api_version = 2.1
#. Create the Watcher Service database tables::
@@ -366,15 +366,14 @@ Configure Nova compute
Please check your hypervisor configuration to correctly handle
`instance migration`_.
.. _`instance migration`: http://docs.openstack.org/admin-guide/compute-live-migration-usage.html
.. _`instance migration`: https://docs.openstack.org/nova/latest/admin/migration.html
Configure Measurements
======================
You can configure and install Ceilometer by following the documentation below :
#. http://docs.openstack.org/developer/ceilometer
#. http://docs.openstack.org/kilo/install-guide/install/apt/content/ceilometer-nova.html
#. https://docs.openstack.org/ceilometer/latest
The built-in strategy 'basic_consolidation' provided by watcher requires
"**compute.node.cpu.percent**" and "**cpu_util**" measurements to be collected
@@ -386,13 +385,13 @@ the OpenStack site.
You can use 'ceilometer meter-list' to list the available meters.
For more information:
http://docs.openstack.org/developer/ceilometer/measurements.html
https://docs.openstack.org/ceilometer/latest/admin/telemetry-measurements.html
Ceilometer is designed to collect measurements from OpenStack services and from
other external components. If you would like to add new meters to the currently
existing ones, you need to follow the documentation below:
#. http://docs.openstack.org/developer/ceilometer/new_meters.html
#. https://docs.openstack.org/ceilometer/latest/contributor/new_meters.html#meters
The Ceilometer collector uses a pluggable storage system, meaning that you can
pick any database system you prefer.

View File

@@ -24,8 +24,8 @@ Watcher plugin::
For more detailed instructions, see `Detailed DevStack Instructions`_. Check
out the `DevStack documentation`_ for more information regarding DevStack.
.. _PluginModelDocs: http://docs.openstack.org/developer/devstack/plugins.html
.. _DevStack documentation: http://docs.openstack.org/developer/devstack/
.. _PluginModelDocs: https://docs.openstack.org/devstack/latest/plugins.html
.. _DevStack documentation: https://docs.openstack.org/devstack/latest
Detailed DevStack Instructions
==============================

View File

@@ -4,7 +4,7 @@
https://creativecommons.org/licenses/by/3.0/
.. _watcher_developement_environment:
.. _watcher_development_environment:
=========================================
Set up a development environment manually

View File

@@ -178,7 +178,7 @@ Here below is how you would proceed to register ``DummyAction`` using pbr_:
watcher_actions =
dummy = thirdparty.dummy:DummyAction
.. _pbr: http://docs.openstack.org/developer/pbr/
.. _pbr: https://docs.openstack.org/pbr/latest
Using action plugins

View File

@@ -22,7 +22,7 @@ Pre-requisites
We assume that you have set up a working Watcher development environment. So if
this not already the case, you can check out our documentation which explains
how to set up a :ref:`development environment
<watcher_developement_environment>`.
<watcher_development_environment>`.
.. _development environment:
@@ -34,7 +34,7 @@ First off, we need to create the project structure. To do so, we can use
generate the skeleton of our project::
$ virtualenv thirdparty
$ source thirdparty/bin/activate
$ . thirdparty/bin/activate
$ pip install cookiecutter
$ cookiecutter https://github.com/openstack-dev/cookiecutter

View File

@@ -127,7 +127,7 @@ To get a better understanding on how to implement a more advanced goal, have
a look at the
:py:class:`watcher.decision_engine.goal.goals.ServerConsolidation` class.
.. _pbr: http://docs.openstack.org/developer/pbr/
.. _pbr: https://docs.openstack.org/pbr/latest
.. _implement_efficacy_specification:

View File

@@ -145,7 +145,7 @@ Here below is how you would proceed to register ``DummyPlanner`` using pbr_:
watcher_planners =
dummy = third_party.dummy:DummyPlanner
.. _pbr: http://docs.openstack.org/developer/pbr/
.. _pbr: https://docs.openstack.org/pbr/latest
Using planner plugins

View File

@@ -190,7 +190,7 @@ the :py:class:`~.DummyScoringContainer` and the way it is configured in
watcher_scoring_engine_containers =
new_scoring_container = thirdparty.new:NewContainer
.. _pbr: http://docs.openstack.org/developer/pbr/
.. _pbr: https://docs.openstack.org/pbr/latest/
Using scoring engine plugins

View File

@@ -219,7 +219,7 @@ Here below is how you would proceed to register ``NewStrategy`` using pbr_:
To get a better understanding on how to implement a more advanced strategy,
have a look at the :py:class:`~.BasicConsolidation` class.
.. _pbr: http://docs.openstack.org/developer/pbr/
.. _pbr: https://docs.openstack.org/pbr/latest
Using strategy plugins
======================
@@ -264,11 +264,11 @@ requires new metrics not covered by Ceilometer, you can add them through a
.. _`Helper`: https://github.com/openstack/watcher/blob/master/watcher/decision_engine/cluster/history/ceilometer.py
.. _`Ceilometer developer guide`: http://docs.openstack.org/developer/ceilometer/architecture.html#storing-the-data
.. _`Ceilometer`: http://docs.openstack.org/developer/ceilometer/
.. _`Ceilometer developer guide`: https://docs.openstack.org/ceilometer/latest/contributor/architecture.html#storing-accessing-the-data
.. _`Ceilometer`: https://docs.openstack.org/ceilometer/latest
.. _`Monasca`: https://github.com/openstack/monasca-api/blob/master/docs/monasca-api-spec.md
.. _`here`: http://docs.openstack.org/developer/ceilometer/install/dbreco.html#choosing-a-database-backend
.. _`Ceilometer plugin`: http://docs.openstack.org/developer/ceilometer/plugins.html
.. _`here`: https://docs.openstack.org/ceilometer/latest/contributor/install/dbreco.html#choosing-a-database-backend
.. _`Ceilometer plugin`: https://docs.openstack.org/ceilometer/latest/contributor/plugins.html
.. _`Ceilosca`: https://github.com/openstack/monasca-ceilometer/blob/master/ceilosca/ceilometer/storage/impl_monasca.py
Read usage metrics using the Watcher Datasource Helper

View File

@@ -41,10 +41,18 @@ you can run the desired test::
$ workon watcher
(watcher) $ tox -e py27 -- -r watcher.tests.api
.. _os-testr: http://docs.openstack.org/developer/os-testr/
.. _os-testr: https://docs.openstack.org/os-testr/latest
When you're done, deactivate the virtualenv::
$ deactivate
.. include:: ../../../watcher_tempest_plugin/README.rst
.. _tempest_tests:
Tempest tests
=============
Tempest tests for Watcher has been migrated to the external repo
`watcher-tempest-plugin`_.
.. _watcher-tempest-plugin: https://github.com/openstack/watcher-tempest-plugin

View File

@@ -83,7 +83,7 @@ Audit Template
Availability Zone
=================
Please, read `the official OpenStack definition of an Availability Zone <http://docs.openstack.org/developer/nova/aggregates.html#availability-zones-azs>`_.
Please, read `the official OpenStack definition of an Availability Zone <https://docs.openstack.org/nova/latest/user/aggregates.html#availability-zones-azs>`_.
.. _cluster_definition:
@@ -115,15 +115,8 @@ Cluster Data Model (CDM)
Controller Node
===============
A controller node is a machine that typically runs the following core OpenStack
services:
- Keystone: for identity and service management
- Cinder scheduler: for volumes management
- Glance controller: for image management
- Neutron controller: for network management
- Nova controller: for global compute resources management with services
such as nova-scheduler, nova-conductor and nova-network.
Please, read `the official OpenStack definition of a Controller Node
<https://docs.openstack.org/nova/latest/install/overview.html#controller>`_.
In many configurations, Watcher will reside on a controller node even if it
can potentially be hosted on a dedicated machine.
@@ -134,7 +127,7 @@ Compute node
============
Please, read `the official OpenStack definition of a Compute Node
<http://docs.openstack.org/ops-guide/arch-compute-nodes.html>`_.
<https://docs.openstack.org/nova/latest/install/overview.html#compute>`_.
.. _customer_definition:
@@ -167,7 +160,7 @@ Host Aggregate
==============
Please, read `the official OpenStack definition of a Host Aggregate
<http://docs.openstack.org/developer/nova/aggregates.html>`_.
<https://docs.openstack.org/nova/latest/user/aggregates.html>`_.
.. _instance_definition:
@@ -206,18 +199,18 @@ the Watcher system can act on.
Here are some examples of
:ref:`Managed resource types <managed_resource_definition>`:
- `Nova Host Aggregates <http://docs.openstack.org/developer/heat/template_guide/openstack.html#OS::Nova::HostAggregate>`_
- `Nova Servers <http://docs.openstack.org/developer/heat/template_guide/openstack.html#OS::Nova::Server>`_
- `Cinder Volumes <http://docs.openstack.org/developer/heat/template_guide/openstack.html#OS::Cinder::Volume>`_
- `Neutron Routers <http://docs.openstack.org/developer/heat/template_guide/openstack.html#OS::Neutron::Router>`_
- `Neutron Networks <http://docs.openstack.org/developer/heat/template_guide/openstack.html#OS::Neutron::Net>`_
- `Neutron load-balancers <http://docs.openstack.org/developer/heat/template_guide/openstack.html#OS::Neutron::LoadBalancer>`_
- `Sahara Hadoop Cluster <http://docs.openstack.org/developer/heat/template_guide/openstack.html#OS::Sahara::Cluster>`_
- `Nova Host Aggregates <https://docs.openstack.org/heat/latest/template_guide/openstack.html#OS::Nova::HostAggregate>`_
- `Nova Servers <https://docs.openstack.org/heat/latest/template_guide/openstack.html#OS::Nova::Server>`_
- `Cinder Volumes <https://docs.openstack.org/heat/latest/template_guide/openstack.html#OS::Cinder::Volume>`_
- `Neutron Routers <https://docs.openstack.org/heat/latest/template_guide/openstack.html#OS::Neutron::Router>`_
- `Neutron Networks <https://docs.openstack.org/heat/latest/template_guide/openstack.html#OS::Neutron::Net>`_
- `Neutron load-balancers <https://docs.openstack.org/heat/latest/template_guide/openstack.html#OS::Neutron::LoadBalancer>`_
- `Sahara Hadoop Cluster <https://docs.openstack.org/heat/latest/template_guide/openstack.html#OS::Sahara::Cluster>`_
- ...
It can be any of the `the official list of available resource types defined in
It can be any of `the official list of available resource types defined in
OpenStack for HEAT
<http://docs.openstack.org/developer/heat/template_guide/openstack.html>`_.
<https://docs.openstack.org/heat/latest/template_guide/openstack.html>`_.
.. _efficacy_indicator_definition:

View File

@@ -39,12 +39,12 @@
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,
clients, Watcher requests new session from Identity service. In the `[watcher_clients_auth]` section,
configure the identity service access to interact with other OpenStack project clients.
.. code-block:: ini
[watcher_client_auth]
[watcher_clients_auth]
...
auth_type = password
auth_url = http://controller:35357
@@ -56,6 +56,16 @@
Replace WATCHER_PASS with the password you chose for the watcher user in the Identity service.
* In the `[api]` section, configure host option.
.. code-block:: ini
[api]
...
host = controller
Replace controller with the IP address of the management network interface on your controller node, typically 10.0.0.11 for the first node in the example architecture.
* In the `[oslo_messaging_notifications]` section, configure the messaging driver.
.. code-block:: ini
@@ -68,4 +78,4 @@
.. code-block:: ini
su -s /bin/sh -c "watcher-db-manage --config-file /etc/watcher/watcher.conf create_schema"
su -s /bin/sh -c "watcher-db-manage --config-file /etc/watcher/watcher.conf upgrade"

View File

@@ -36,4 +36,4 @@ https://docs.openstack.org/watcher/latest/glossary.html
This chapter assumes a working setup of OpenStack following the
`OpenStack Installation Tutorial
<https://docs.openstack.org/project-install-guide/ocata/>`_.
<https://docs.openstack.org/pike/install/>`_.

View File

@@ -1,35 +0,0 @@
.. _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

@@ -15,6 +15,5 @@ Note that installation and configuration vary by distribution.
.. toctree::
:maxdepth: 2
install-obs.rst
install-rdo.rst
install-ubuntu.rst

View File

@@ -6,4 +6,4 @@ Next steps
Your OpenStack environment now includes the watcher service.
To add additional services, see
https://docs.openstack.org/project-install-guide/ocata/.
https://docs.openstack.org/pike/install/.

View File

@@ -5,7 +5,7 @@ Basic Offline Server Consolidation
Synopsis
--------
**display name**: ``basic``
**display name**: ``Basic offline consolidation``
**goal**: ``server_consolidation``
@@ -26,7 +26,7 @@ metric service name plugins comment
``cpu_util`` ceilometer_ none
============================ ============ ======= =======
.. _ceilometer: http://docs.openstack.org/admin-guide/telemetry-measurements.html#openstack-compute
.. _ceilometer: https://docs.openstack.org/ceilometer/latest/admin/telemetry-measurements.html#openstack-compute
Cluster data model
******************

View File

@@ -5,7 +5,7 @@ Outlet Temperature Based Strategy
Synopsis
--------
**display name**: ``outlet_temperature``
**display name**: ``Outlet temperature based strategy``
**goal**: ``thermal_optimization``
@@ -33,7 +33,7 @@ metric service name plugins comment
``hardware.ipmi.node.outlet_temperature`` ceilometer_ IPMI
========================================= ============ ======= =======
.. _ceilometer: http://docs.openstack.org/admin-guide/telemetry-measurements.html#ipmi-based-meters
.. _ceilometer: https://docs.openstack.org/ceilometer/latest/admin/telemetry-measurements.html#ipmi-based-meters
Cluster data model
******************

View File

@@ -0,0 +1,100 @@
======================
Saving Energy Strategy
======================
Synopsis
--------
**display name**: ``Saving Energy Strategy``
**goal**: ``saving_energy``
.. watcher-term:: watcher.decision_engine.strategy.strategies.saving_energy
Requirements
------------
This feature will use Ironic to do the power on/off actions, therefore
this feature requires that the ironic component is configured.
And the compute node should be managed by Ironic.
Ironic installation: https://docs.openstack.org/ironic/latest/install/index.html
Cluster data model
******************
Default Watcher's Compute cluster data model:
.. watcher-term:: watcher.decision_engine.model.collector.nova.NovaClusterDataModelCollector
Actions
*******
.. list-table::
:widths: 30 30
:header-rows: 1
* - action
- description
* - ``change_node_power_state``
- .. watcher-term:: watcher.applier.actions.change_node_power_state.ChangeNodePowerState
Planner
*******
Default Watcher's planner:
.. watcher-term:: watcher.decision_engine.planner.weight.WeightPlanner
Configuration
-------------
Strategy parameter is:
====================== ====== ======= ======================================
parameter type default description
Value
====================== ====== ======= ======================================
``free_used_percent`` Number 10.0 a rational number, which describes the
the quotient of
min_free_hosts_num/nodes_with_VMs_num
``min_free_hosts_num`` Int 1 an int number describes minimum free
compute nodes
====================== ====== ======= ======================================
Efficacy Indicator
------------------
Energy saving strategy efficacy indicator is unclassified.
https://github.com/openstack/watcher/blob/master/watcher/decision_engine/goal/goals.py#L215-L218
Algorithm
---------
For more information on the Energy Saving Strategy please refer to:http://specs.openstack.org/openstack/watcher-specs/specs/pike/implemented/energy-saving-strategy.html
How to use it ?
---------------
step1: Add compute nodes info into ironic node management
.. code-block:: shell
$ ironic node-create -d pxe_ipmitool -i ipmi_address=10.43.200.184 \
ipmi_username=root -i ipmi_password=nomoresecret -e compute_node_id=3
step 2: Create audit to do optimization
.. code-block:: shell
$ openstack optimize audittemplate create \
at1 saving_energy --strategy saving_energy
$ openstack optimize audit create -a at1
External Links
--------------
*Spec URL*
http://specs.openstack.org/openstack/watcher-specs/specs/pike/implemented/energy-saving-strategy.html

View File

@@ -33,7 +33,7 @@ power ceilometer_ kwapi_ one point every 60s
======================= ============ ======= =======
.. _ceilometer: http://docs.openstack.org/admin-guide/telemetry-measurements.html#openstack-compute
.. _ceilometer: https://docs.openstack.org/ceilometer/latest/admin/telemetry-measurements.html#openstack-compute
.. _monasca: https://github.com/openstack/monasca-agent/blob/master/docs/Libvirt.md
.. _kwapi: https://kwapi.readthedocs.io/en/latest/index.html

View File

@@ -5,7 +5,7 @@ Uniform Airflow Migration Strategy
Synopsis
--------
**display name**: ``uniform_airflow``
**display name**: ``Uniform airflow migration strategy``
**goal**: ``airflow_optimization``

View File

@@ -5,7 +5,7 @@ VM Workload Consolidation Strategy
Synopsis
--------
**display name**: ``vm_workload_consolidation``
**display name**: ``VM Workload Consolidation Strategy``
**goal**: ``vm_consolidation``
@@ -36,7 +36,7 @@ metric service name plugins comment
``cpu_util`` ceilometer_ none
============================ ============ ======= =======
.. _ceilometer: http://docs.openstack.org/admin-guide/telemetry-measurements.html#openstack-compute
.. _ceilometer: https://docs.openstack.org/ceilometer/latest/admin/telemetry-measurements.html#openstack-compute
Cluster data model
******************

View File

@@ -5,7 +5,7 @@ Watcher Overload standard deviation algorithm
Synopsis
--------
**display name**: ``workload_stabilization``
**display name**: ``Workload stabilization``
**goal**: ``workload_balancing``
@@ -28,7 +28,7 @@ metric service name plugins comment
``memory.resident`` ceilometer_ none
============================ ============ ======= =======
.. _ceilometer: http://docs.openstack.org/admin-guide/telemetry-measurements.html#openstack-compute
.. _ceilometer: https://docs.openstack.org/ceilometer/latest/admin/telemetry-measurements.html#openstack-compute
.. _SNMP: http://docs.openstack.org/admin-guide/telemetry-measurements.html
Cluster data model
@@ -100,7 +100,7 @@ parameter type default Value description
into which the samples are
grouped for aggregation.
Watcher uses only the last
period of all recieved ones.
period of all received ones.
==================== ====== ===================== =============================
.. |metrics| replace:: ["cpu_util", "memory.resident"]

View File

@@ -5,7 +5,7 @@ Workload Balance Migration Strategy
Synopsis
--------
**display name**: ``workload_balance``
**display name**: ``Workload Balance Migration Strategy``
**goal**: ``workload_balancing``
@@ -25,9 +25,10 @@ The *workload_balance* strategy requires the following metrics:
metric service name plugins comment
======================= ============ ======= =======
``cpu_util`` ceilometer_ none
``memory.resident`` ceilometer_ none
======================= ============ ======= =======
.. _ceilometer: http://docs.openstack.org/admin-guide/telemetry-measurements.html#openstack-compute
.. _ceilometer: https://docs.openstack.org/ceilometer/latest/admin/telemetry-measurements.html#openstack-compute
Cluster data model
@@ -66,6 +67,9 @@ Strategy parameters are:
============== ====== ============= ====================================
parameter type default Value description
============== ====== ============= ====================================
``metrics`` String 'cpu_util' Workload balance base on cpu or ram
utilization. choice: ['cpu_util',
'memory.resident']
``threshold`` Number 25.0 Workload threshold for migration
``period`` Number 300 Aggregate time period of ceilometer
============== ====== ============= ====================================
@@ -90,7 +94,7 @@ How to use it ?
at1 workload_balancing --strategy workload_balance
$ openstack optimize audit create -a at1 -p threshold=26.0 \
-p period=310
-p period=310 -p metrics=cpu_util
External Links
--------------

View File

@@ -39,10 +39,10 @@ named ``watcher``, or by using the `OpenStack CLI`_ ``openstack``.
If you want to deploy Watcher in Horizon, please refer to the `Watcher Horizon
plugin installation guide`_.
.. _`installation guide`: http://docs.openstack.org/developer/python-watcherclient
.. _`Watcher Horizon plugin installation guide`: http://docs.openstack.org/developer/watcher-dashboard/deploy/installation.html
.. _`OpenStack CLI`: http://docs.openstack.org/developer/python-openstackclient/man/openstack.html
.. _`Watcher CLI`: http://docs.openstack.org/developer/python-watcherclient/index.html
.. _`installation guide`: https://docs.openstack.org/python-watcherclient/latest
.. _`Watcher Horizon plugin installation guide`: https://docs.openstack.org/watcher-dashboard/latest/install/installation.html
.. _`OpenStack CLI`: https://docs.openstack.org/python-openstackclient/latest/cli/man/openstack.html
.. _`Watcher CLI`: https://docs.openstack.org/python-watcherclient/latest/cli/index.html
Seeing what the Watcher CLI can do ?
------------------------------------

View File

@@ -27,7 +27,7 @@ Structure
Useful links
------------
* How to install: http://docs.openstack.org/developer/rally/install.html
* How to install: https://docs.openstack.org/rally/latest/install_and_upgrade/install.html
* How to set Rally up and launch your first scenario: https://rally.readthedocs.io/en/latest/tutorial/step_1_setting_up_env_and_running_benchmark_from_samples.html

View File

@@ -0,0 +1,7 @@
---
features:
- Existing workload_balance strategy based on
the VM workloads of CPU. This feature improves
the strategy. By the input parameter "metrics",
it makes decision to migrate a VM base on CPU
or memory utilization.

View File

@@ -22,7 +22,8 @@
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys, os
import os
import sys
from watcher import version as watcher_version
# If extensions (or modules to document with autodoc) are in another directory,
@@ -63,7 +64,7 @@ copyright = u'2016, Watcher developers'
# The short X.Y version.
version = watcher_version.version_info.release_string()
# The full version, including alpha/beta/rc tags.
release = watcher_version.version_info.version_string()
release = watcher_version.version_string
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.

View File

@@ -21,6 +21,7 @@ Contents:
:maxdepth: 1
unreleased
pike
ocata
newton

View File

@@ -0,0 +1,6 @@
===================================
Pike Series Release Notes
===================================
.. release-notes::
:branch: stable/pike

View File

@@ -2,48 +2,48 @@
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
apscheduler # MIT License
enum34;python_version=='2.7' or python_version=='2.6' or python_version=='3.3' # BSD
jsonpatch>=1.1 # BSD
keystoneauth1>=3.1.0 # Apache-2.0
jsonschema!=2.5.0,<3.0.0,>=2.0.0 # MIT
keystonemiddleware>=4.12.0 # Apache-2.0
lxml!=3.7.0,>=2.3 # BSD
apscheduler>=3.0.5 # MIT License
enum34>=1.0.4;python_version=='2.7' or python_version=='2.6' or python_version=='3.3' # BSD
jsonpatch>=1.16 # BSD
keystoneauth1>=3.2.0 # Apache-2.0
jsonschema<3.0.0,>=2.6.0 # MIT
keystonemiddleware>=4.17.0 # Apache-2.0
lxml!=3.7.0,>=3.4.1 # BSD
croniter>=0.3.4 # MIT License
oslo.concurrency>=3.8.0 # Apache-2.0
oslo.cache>=1.5.0 # Apache-2.0
oslo.config!=4.3.0,!=4.4.0,>=4.0.0 # Apache-2.0
oslo.context>=2.14.0 # Apache-2.0
oslo.db>=4.24.0 # 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.concurrency>=3.20.0 # Apache-2.0
oslo.cache>=1.26.0 # Apache-2.0
oslo.config>=4.6.0 # Apache-2.0
oslo.context!=2.19.1,>=2.14.0 # Apache-2.0
oslo.db>=4.27.0 # Apache-2.0
oslo.i18n>=3.15.3 # Apache-2.0
oslo.log>=3.30.0 # Apache-2.0
oslo.messaging>=5.29.0 # Apache-2.0
oslo.policy>=1.23.0 # Apache-2.0
oslo.reports>=0.6.0 # Apache-2.0
oslo.serialization!=2.19.1,>=1.10.0 # Apache-2.0
oslo.service>=1.10.0 # Apache-2.0
oslo.utils>=3.20.0 # Apache-2.0
oslo.versionedobjects>=1.17.0 # Apache-2.0
oslo.reports>=1.18.0 # Apache-2.0
oslo.serialization!=2.19.1,>=2.18.0 # Apache-2.0
oslo.service>=1.24.0 # Apache-2.0
oslo.utils>=3.28.0 # Apache-2.0
oslo.versionedobjects>=1.28.0 # Apache-2.0
PasteDeploy>=1.5.0 # MIT
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
gnocchiclient>=3.3.1 # Apache-2.0
python-ceilometerclient>=2.5.0 # Apache-2.0
python-cinderclient>=3.1.0 # Apache-2.0
python-cinderclient>=3.2.0 # Apache-2.0
python-glanceclient>=2.8.0 # Apache-2.0
python-keystoneclient>=3.8.0 # Apache-2.0
python-monascaclient>=1.7.0 # Apache-2.0
python-neutronclient>=6.3.0 # Apache-2.0
python-novaclient>=9.0.0 # Apache-2.0
python-openstackclient!=3.10.0,>=3.3.0 # Apache-2.0
python-novaclient>=9.1.0 # Apache-2.0
python-openstackclient>=3.12.0 # Apache-2.0
python-ironicclient>=1.14.0 # Apache-2.0
six>=1.9.0 # MIT
SQLAlchemy!=1.1.5,!=1.1.6,!=1.1.7,!=1.1.8,>=1.0.10 # MIT
stevedore>=1.20.0 # Apache-2.0
taskflow>=2.7.0 # Apache-2.0
WebOb>=1.7.1 # MIT
WSME>=0.8 # MIT
networkx>=1.10 # BSD
WSME>=0.8.0 # MIT
networkx<2.0,>=1.10 # BSD

View File

@@ -21,7 +21,6 @@ classifier =
[files]
packages =
watcher
watcher_tempest_plugin
data_files =
etc/ = etc/*
@@ -40,9 +39,6 @@ console_scripts =
watcher-applier = watcher.cmd.applier:main
watcher-sync = watcher.cmd.sync:main
tempest.test_plugins =
watcher_tests = watcher_tempest_plugin.plugin:WatcherTempestPlugin
watcher.database.migration_backend =
sqlalchemy = watcher.db.sqlalchemy.migration
@@ -98,13 +94,11 @@ watcher_cluster_data_model_collectors =
[pbr]
warnerrors = true
autodoc_index_modules = true
autodoc_exclude_modules =
watcher.db.sqlalchemy.alembic.env
watcher.db.sqlalchemy.alembic.versions.*
watcher.tests.*
watcher_tempest_plugin.*
watcher.doc

View File

@@ -3,25 +3,24 @@
# process, which may cause wedges in the gate later.
coverage!=4.4,>=4.0 # Apache-2.0
doc8 # Apache-2.0
doc8>=0.6.0 # Apache-2.0
freezegun>=0.3.6 # Apache-2.0
hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0
mock>=2.0 # BSD
mock>=2.0.0 # BSD
oslotest>=1.10.0 # Apache-2.0
os-testr>=0.8.0 # Apache-2.0
python-subunit>=0.0.18 # Apache-2.0/BSD
os-testr>=1.0.0 # Apache-2.0
testrepository>=0.0.18 # Apache-2.0/BSD
testscenarios>=0.4 # Apache-2.0/BSD
testtools>=1.4.0 # MIT
# Doc requirements
openstackdocstheme>=1.16.0 # Apache-2.0
openstackdocstheme>=1.17.0 # Apache-2.0
sphinx>=1.6.2 # BSD
sphinxcontrib-pecanwsme>=0.8 # Apache-2.0
sphinxcontrib-pecanwsme>=0.8.0 # Apache-2.0
# releasenotes
reno!=2.3.1,>=1.8.0 # Apache-2.0
reno>=2.5.0 # Apache-2.0
# bandit
bandit>=1.1.0 # Apache-2.0

View File

@@ -448,7 +448,7 @@ class AuditTemplatesController(rest.RestController):
sort_key, sort_dir, expand=False,
resource_url=None):
api_utils.validate_search_filters(
filters, list(objects.audit_template.AuditTemplate.fields.keys()) +
filters, list(objects.audit_template.AuditTemplate.fields) +
["goal_uuid", "goal_name", "strategy_uuid", "strategy_name"])
limit = api_utils.validate_limit(limit)
api_utils.validate_sort_dir(sort_dir)

View File

@@ -170,7 +170,7 @@ class GoalsController(rest.RestController):
limit = api_utils.validate_limit(limit)
api_utils.validate_sort_dir(sort_dir)
sort_db_key = (sort_key if sort_key in objects.Goal.fields.keys()
sort_db_key = (sort_key if sort_key in objects.Goal.fields
else None)
marker_obj = None

View File

@@ -104,7 +104,7 @@ class Service(base.APIBase):
def __init__(self, **kwargs):
super(Service, self).__init__()
fields = list(objects.Service.fields.keys()) + ['status']
fields = list(objects.Service.fields) + ['status']
self.fields = []
for field in fields:
self.fields.append(field)
@@ -194,7 +194,7 @@ class ServicesController(rest.RestController):
limit = api_utils.validate_limit(limit)
api_utils.validate_sort_dir(sort_dir)
sort_db_key = (sort_key if sort_key in objects.Service.fields.keys()
sort_db_key = (sort_key if sort_key in objects.Service.fields
else None)
marker_obj = None

View File

@@ -210,12 +210,12 @@ class StrategiesController(rest.RestController):
def _get_strategies_collection(self, filters, marker, limit, sort_key,
sort_dir, expand=False, resource_url=None):
api_utils.validate_search_filters(
filters, list(objects.strategy.Strategy.fields.keys()) +
filters, list(objects.strategy.Strategy.fields) +
["goal_uuid", "goal_name"])
limit = api_utils.validate_limit(limit)
api_utils.validate_sort_dir(sort_dir)
sort_db_key = (sort_key if sort_key in objects.Strategy.fields.keys()
sort_db_key = (sort_key if sort_key in objects.Strategy.fields
else None)
marker_obj = None

View File

@@ -57,7 +57,7 @@ def validate_sort_dir(sort_dir):
def validate_search_filters(filters, allowed_fields):
# Very lightweight validation for now
# todo: improve this (e.g. https://www.parse.com/docs/rest/guide/#queries)
for filter_name in filters.keys():
for filter_name in filters:
if filter_name not in allowed_fields:
raise wsme.exc.ClientSideError(
_("Invalid filter: %s") % filter_name)

View File

@@ -42,7 +42,7 @@ class APISchedulingService(scheduling.BackgroundSchedulerService):
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():
if service.id not in self.services_status:
self.services_status[service.id] = result
continue
if self.services_status[service.id] != result:

View File

@@ -54,6 +54,7 @@ class DefaultActionPlanHandler(base.BaseActionPlanHandler):
applier.execute(self.action_plan_uuid)
action_plan.state = objects.action_plan.State.SUCCEEDED
action_plan.save()
notifications.action_plan.send_action_notification(
self.ctx, action_plan,
action=fields.NotificationAction.EXECUTION,
@@ -63,17 +64,32 @@ class DefaultActionPlanHandler(base.BaseActionPlanHandler):
LOG.exception(e)
action_plan.state = objects.action_plan.State.CANCELLED
self._update_action_from_pending_to_cancelled()
action_plan.save()
notifications.action_plan.send_cancel_notification(
self.ctx, action_plan,
action=fields.NotificationAction.CANCEL,
phase=fields.NotificationPhase.END)
except Exception as e:
LOG.exception(e)
action_plan.state = objects.action_plan.State.FAILED
notifications.action_plan.send_action_notification(
self.ctx, action_plan,
action=fields.NotificationAction.EXECUTION,
priority=fields.NotificationPriority.ERROR,
phase=fields.NotificationPhase.ERROR)
finally:
action_plan.save()
action_plan = objects.ActionPlan.get_by_uuid(
self.ctx, self.action_plan_uuid, eager=True)
if action_plan.state == objects.action_plan.State.CANCELLING:
action_plan.state = objects.action_plan.State.FAILED
action_plan.save()
notifications.action_plan.send_cancel_notification(
self.ctx, action_plan,
action=fields.NotificationAction.CANCEL,
priority=fields.NotificationPriority.ERROR,
phase=fields.NotificationPhase.ERROR)
else:
action_plan.state = objects.action_plan.State.FAILED
action_plan.save()
notifications.action_plan.send_action_notification(
self.ctx, action_plan,
action=fields.NotificationAction.EXECUTION,
priority=fields.NotificationPriority.ERROR,
phase=fields.NotificationPhase.ERROR)
def _update_action_from_pending_to_cancelled(self):
filters = {'action_plan_uuid': self.action_plan_uuid,

View File

@@ -18,6 +18,7 @@
#
import enum
import time
from watcher._i18n import _
from watcher.applier.actions import base
@@ -87,25 +88,39 @@ class ChangeNodePowerState(base.BaseAction):
target_state = NodeState.POWERON.value
return self._node_manage_power(target_state)
def _node_manage_power(self, state):
def _node_manage_power(self, state, retry=60):
if state is None:
raise exception.IllegalArgumentException(
message=_("The target state is not defined"))
result = False
ironic_client = self.osc.ironic()
nova_client = self.osc.nova()
current_state = ironic_client.node.get(self.node_uuid).power_state
# power state: 'power on' or 'power off', if current node state
# is the same as state, just return True
if state in current_state:
return True
if state == NodeState.POWEROFF.value:
node_info = ironic_client.node.get(self.node_uuid).to_dict()
compute_node_id = node_info['extra']['compute_node_id']
compute_node = nova_client.hypervisors.get(compute_node_id)
compute_node = compute_node.to_dict()
if (compute_node['running_vms'] == 0):
result = ironic_client.node.set_power_state(
ironic_client.node.set_power_state(
self.node_uuid, state)
else:
result = ironic_client.node.set_power_state(self.node_uuid, state)
return result
ironic_client.node.set_power_state(self.node_uuid, state)
ironic_node = ironic_client.node.get(self.node_uuid)
while ironic_node.power_state == current_state and retry:
time.sleep(10)
retry -= 1
ironic_node = ironic_client.node.get(self.node_uuid)
if retry > 0:
return True
else:
return False
def pre_condition(self):
pass

View File

@@ -124,7 +124,8 @@ class Migrate(base.BaseAction):
LOG.debug("Nova client exception occurred while live "
"migrating instance %s.Exception: %s" %
(self.instance_uuid, e))
except Exception:
except Exception as e:
LOG.exception(e)
LOG.critical("Unexpected error occurred. Migration failed for "
"instance %s. Leaving instance on previous "
"host.", self.instance_uuid)

View File

@@ -57,6 +57,7 @@ class BaseWorkFlowEngine(loadable.Loadable):
self._applier_manager = applier_manager
self._action_factory = factory.ActionFactory()
self._osc = None
self._is_notified = False
@classmethod
def get_config_opts(cls):
@@ -92,6 +93,17 @@ class BaseWorkFlowEngine(loadable.Loadable):
db_action.save()
return db_action
def notify_cancel_start(self, action_plan_uuid):
action_plan = objects.ActionPlan.get_by_uuid(self.context,
action_plan_uuid,
eager=True)
if not self._is_notified:
self._is_notified = True
notifications.action_plan.send_cancel_notification(
self._context, action_plan,
action=fields.NotificationAction.CANCEL,
phase=fields.NotificationPhase.START)
@abc.abstractmethod
def execute(self, actions):
raise NotImplementedError()
@@ -157,6 +169,7 @@ class BaseTaskFlowActionContainer(flow_task.Task):
fields.NotificationPhase.START)
except exception.ActionPlanCancelled as e:
LOG.exception(e)
self.engine.notify_cancel_start(action_plan.uuid)
raise
except Exception as e:
LOG.exception(e)
@@ -218,6 +231,7 @@ class BaseTaskFlowActionContainer(flow_task.Task):
# taskflow will call revert for the action,
# we will redirect it to abort.
except eventlet.greenlet.GreenletExit:
self.engine.notify_cancel_start(action_plan_object.uuid)
raise exception.ActionPlanCancelled(uuid=action_plan_object.uuid)
except Exception as e:
@@ -241,7 +255,7 @@ class BaseTaskFlowActionContainer(flow_task.Task):
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
# some other exception occurred 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()
@@ -249,15 +263,42 @@ class BaseTaskFlowActionContainer(flow_task.Task):
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
try:
if action_object.state == objects.action.State.ONGOING:
action_object.state = objects.action.State.CANCELLING
action_object.save()
notifications.action.send_cancel_notification(
self.engine.context, action_object,
fields.NotificationAction.CANCEL,
fields.NotificationPhase.START)
action_object = self.abort()
notifications.action.send_cancel_notification(
self.engine.context, action_object,
fields.NotificationAction.CANCEL,
fields.NotificationPhase.END)
if action_object.state == objects.action.State.PENDING:
notifications.action.send_cancel_notification(
self.engine.context, action_object,
fields.NotificationAction.CANCEL,
fields.NotificationPhase.START)
action_object.state = objects.action.State.CANCELLED
action_object.save()
notifications.action.send_cancel_notification(
self.engine.context, action_object,
fields.NotificationAction.CANCEL,
fields.NotificationPhase.END)
except Exception as e:
LOG.exception(e)
action_object.state = objects.action.State.FAILED
action_object.save()
self.abort()
elif action_object.state == objects.action.State.PENDING:
action_object.state = objects.action.State.CANCELLED
action_object.save()
else:
pass
notifications.action.send_cancel_notification(
self.engine.context, action_object,
fields.NotificationAction.CANCEL,
fields.NotificationPhase.ERROR,
priority=fields.NotificationPriority.ERROR)
def abort(self, *args, **kwargs):
self.do_abort(*args, **kwargs)
return self.do_abort(*args, **kwargs)

View File

@@ -34,7 +34,7 @@ class DefaultWorkFlowEngine(base.BaseWorkFlowEngine):
"""Taskflow as a workflow engine for Watcher
Full documentation on taskflow at
http://docs.openstack.org/developer/taskflow/
https://docs.openstack.org/taskflow/latest
"""
def decider(self, history):
@@ -45,7 +45,7 @@ class DefaultWorkFlowEngine(base.BaseWorkFlowEngine):
# (or whether the execution of v should be ignored,
# and therefore not executed). It is expected to take as single
# keyword argument history which will be the execution results of
# all u decideable links that have v as a target. It is expected
# all u decidable links that have v as a target. It is expected
# to return a single boolean
# (True to allow v execution or False to not).
return True
@@ -120,14 +120,17 @@ class TaskFlowActionContainer(base.BaseTaskFlowActionContainer):
def do_execute(self, *args, **kwargs):
LOG.debug("Running action: %s", self.name)
# NOTE: For result is False, set action state fail
# NOTE:Some actions(such as migrate) will return None when exception
# Only when True is returned, the action state is set to SUCCEEDED
result = self.action.execute()
if result is False:
return self.engine.notify(self._db_action,
objects.action.State.FAILED)
else:
if result is True:
return self.engine.notify(self._db_action,
objects.action.State.SUCCEEDED)
else:
self.engine.notify(self._db_action,
objects.action.State.FAILED)
raise exception.ActionExecutionFailure(
action_id=self._db_action.uuid)
def do_post_execute(self):
LOG.debug("Post-condition action: %s", self.name)

View File

@@ -110,8 +110,12 @@ class OpenStackClients(object):
'api_version')
gnocchiclient_interface = self._get_client_option('gnocchi',
'endpoint_type')
adapter_options = {
"interface": gnocchiclient_interface
}
self._gnocchi = gnclient.Client(gnocchiclient_version,
interface=gnocchiclient_interface,
adapter_options=adapter_options,
session=self.session)
return self._gnocchi

View File

@@ -15,8 +15,6 @@ from oslo_log import log as logging
from oslo_utils import timeutils
import six
from watcher.common import utils
LOG = logging.getLogger(__name__)
@@ -102,7 +100,7 @@ class RequestContext(context.RequestContext):
'domain_name': getattr(self, 'domain_name', None),
'auth_token_info': getattr(self, 'auth_token_info', None),
'is_admin': getattr(self, 'is_admin', None),
'timestamp': utils.strtime(self.timestamp) if hasattr(
'timestamp': self.timestamp.isoformat() if hasattr(
self, 'timestamp') else None,
'request_id': getattr(self, 'request_id', None),
})

View File

@@ -435,6 +435,10 @@ class ActionDescriptionNotFound(ResourceNotFound):
msg_fmt = _("The action description %(action_id)s cannot be found.")
class ActionExecutionFailure(WatcherException):
msg_fmt = _("The action %(action_id)s execution failed.")
# Model
class ComputeResourceNotFound(WatcherException):

View File

@@ -70,9 +70,6 @@ class NovaHelper(object):
def get_service(self, service_id):
return self.nova.services.find(id=service_id)
def get_flavor(self, flavor_id):
return self.nova.flavors.get(flavor_id)
def get_aggregate_list(self):
return self.nova.aggregates.list()
@@ -454,8 +451,7 @@ class NovaHelper(object):
"Instance %s found on host '%s'." % (instance_id, host_name))
instance.live_migrate(host=dest_hostname,
block_migration=block_migration,
disk_over_commit=True)
block_migration=block_migration)
instance = self.nova.servers.get(instance_id)
@@ -528,10 +524,10 @@ class NovaHelper(object):
instance_host = getattr(instance, 'OS-EXT-SRV-ATTR:host')
instance_status = getattr(instance, 'status')
# Abort live migration successfull, action is cancelled
# Abort live migration successful, action is cancelled
if instance_host == source and instance_status == 'ACTIVE':
return True
# Nova Unable to abort live migration, action is succeded
# Nova Unable to abort live migration, action is succeeded
elif instance_host == destination and instance_status == 'ACTIVE':
return False

View File

@@ -49,7 +49,7 @@ def init(policy_file=None, rules=None,
"""
global _ENFORCER
if not _ENFORCER:
# http://docs.openstack.org/developer/oslo.policy/usage.html
# https://docs.openstack.org/oslo.policy/latest/admin/index.html
_ENFORCER = policy.Enforcer(CONF,
policy_file=policy_file,
rules=rules,

View File

@@ -26,7 +26,6 @@ from croniter import croniter
from jsonschema import validators
from oslo_log import log as logging
from oslo_utils import strutils
from oslo_utils import timeutils
from oslo_utils import uuidutils
import six
@@ -65,7 +64,6 @@ class Struct(dict):
generate_uuid = uuidutils.generate_uuid
is_uuid_like = uuidutils.is_uuid_like
is_int_like = strutils.is_int_like
strtime = timeutils.strtime
def is_cron_like(value):

View File

@@ -37,13 +37,11 @@ from watcher.conf import nova_client
from watcher.conf import paths
from watcher.conf import planner
from watcher.conf import service
from watcher.conf import utils
CONF = cfg.CONF
service.register_opts(CONF)
api.register_opts(CONF)
utils.register_opts(CONF)
paths.register_opts(CONF)
exception.register_opts(CONF)
db.register_opts(CONF)

View File

@@ -30,7 +30,6 @@ from watcher.conf import neutron_client as conf_neutron_client
from watcher.conf import nova_client as conf_nova_client
from watcher.conf import paths
from watcher.conf import planner as conf_planner
from watcher.conf import utils
def list_opts():
@@ -39,8 +38,7 @@ def list_opts():
('DEFAULT',
(conf_api.AUTH_OPTS +
exception.EXC_LOG_OPTS +
paths.PATH_OPTS +
utils.UTILS_OPTS)),
paths.PATH_OPTS)),
('api', conf_api.API_SERVICE_OPTS),
('database', db.SQL_OPTS),
('watcher_planner', conf_planner.WATCHER_PLANNER_OPTS),

View File

@@ -26,10 +26,10 @@ GNOCCHI_CLIENT_OPTS = [
default='1',
help='Version of Gnocchi API to use in gnocchiclient.'),
cfg.StrOpt('endpoint_type',
default='internalURL',
default='public',
help='Type of endpoint to use in gnocchi client.'
'Supported values: internalURL, publicURL, adminURL'
'The default is internalURL.'),
'Supported values: internal, public, admin'
'The default is public.'),
cfg.IntOpt('query_max_retries',
default=10,
help='How many times Watcher is trying to query again'),

View File

@@ -23,7 +23,7 @@ nova_client = cfg.OptGroup(name='nova_client',
NOVA_CLIENT_OPTS = [
cfg.StrOpt('api_version',
default='2',
default='2.53',
help='Version of Nova API to use in novaclient.'),
cfg.StrOpt('endpoint_type',
default='publicURL',

View File

@@ -1,36 +0,0 @@
# -*- encoding: utf-8 -*-
# Copyright (c) 2016 Intel 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
UTILS_OPTS = [
cfg.StrOpt('rootwrap_config',
default="/etc/watcher/rootwrap.conf",
help='Path to the rootwrap configuration file to use for '
'running commands as root.'),
cfg.StrOpt('tempdir',
help='Explicitly specify the temporary working directory.'),
]
def register_opts(conf):
conf.register_opts(UTILS_OPTS)
def list_opts():
return [('DEFAULT', UTILS_OPTS)]

View File

@@ -6,25 +6,29 @@ Create Date: 2017-07-13 20:33:01.473711
"""
# revision identifiers, used by Alembic.
revision = 'd09a5945e4a0'
down_revision = 'd098df6021e2'
from alembic import op
import oslo_db
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'd09a5945e4a0'
down_revision = 'd098df6021e2'
def upgrade():
op.create_table('action_descriptions',
sa.Column('created_at', sa.DateTime(), nullable=True),
sa.Column('updated_at', sa.DateTime(), nullable=True),
sa.Column('deleted_at', sa.DateTime(), nullable=True),
sa.Column('deleted', oslo_db.sqlalchemy.types.SoftDeleteInteger(), nullable=True),
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('action_type', sa.String(length=255), nullable=False),
sa.Column('description', sa.String(length=255), nullable=False),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('action_type', name='uniq_action_description0action_type')
op.create_table(
'action_descriptions',
sa.Column('created_at', sa.DateTime(), nullable=True),
sa.Column('updated_at', sa.DateTime(), nullable=True),
sa.Column('deleted_at', sa.DateTime(), nullable=True),
sa.Column('deleted', oslo_db.sqlalchemy.types.SoftDeleteInteger(),
nullable=True),
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('action_type', sa.String(length=255), nullable=False),
sa.Column('description', sa.String(length=255), nullable=False),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('action_type',
name='uniq_action_description0action_type')
)

View File

@@ -69,7 +69,7 @@ def create_schema(config=None, engine=None):
# schema, it will only add the new tables, but leave
# existing as is. So we should avoid of this situation.
if version(engine=engine) is not None:
raise db_exc.DbMigrationError(
raise db_exc.DBMigrationError(
_("Watcher database schema is already under version control; "
"use upgrade() instead"))

View File

@@ -96,9 +96,10 @@ class AuditHandler(BaseAuditHandler):
raise
def update_audit_state(self, audit, state):
LOG.debug("Update audit state: %s", state)
audit.state = state
audit.save()
if audit.state != state:
LOG.debug("Update audit state: %s", state)
audit.state = state
audit.save()
def check_ongoing_action_plans(self, request_context):
a_plan_filters = {'state': objects.action_plan.State.ONGOING}

View File

@@ -72,38 +72,6 @@ class IndicatorSpecification(object):
return str(self.to_dict())
class AverageCpuLoad(IndicatorSpecification):
def __init__(self):
super(AverageCpuLoad, self).__init__(
name="avg_cpu_percent",
description=_("Average CPU load as a percentage of the CPU time."),
unit="%",
)
@property
def schema(self):
return voluptuous.Schema(
voluptuous.Range(min=0, max=100), required=True)
class MigrationEfficacy(IndicatorSpecification):
def __init__(self):
super(MigrationEfficacy, self).__init__(
name="migration_efficacy",
description=_("Represents the percentage of released nodes out of "
"the total number of migrations."),
unit="%",
required=True
)
@property
def schema(self):
return voluptuous.Schema(
voluptuous.Range(min=0, max=100), required=True)
class ComputeNodesCount(IndicatorSpecification):
def __init__(self):
super(ComputeNodesCount, self).__init__(

View File

@@ -27,7 +27,7 @@ It is represented as a set of :ref:`Managed resources
<managed_resource_definition>` (which may be a simple tree or a flat list of
key-value pairs) which enables Watcher :ref:`Strategies <strategy_definition>`
to know the current relationships between the different :ref:`resources
<managed_resource_definition>`) of the :ref:`Cluster <cluster_definition>`
<managed_resource_definition>` of the :ref:`Cluster <cluster_definition>`
during an :ref:`Audit <audit_definition>` and enables the :ref:`Strategy
<strategy_definition>` to request information such as:

View File

@@ -117,7 +117,7 @@ class ModelBuilder(object):
# cpu_id, cpu_node = self.build_cpu_compute_node(base_id, node)
# self.add_node(cpu_id, cpu_node)
# # Connect the base compute node to the dependant nodes.
# # Connect the base compute node to the dependent nodes.
# self.add_edges_from([(base_id, disk_id), (base_id, mem_id),
# (base_id, cpu_id), (base_id, net_id)],
# label="contains")
@@ -227,14 +227,14 @@ class ModelBuilder(object):
:param instance: Nova VM object.
:return: A instance node for the graph.
"""
flavor = self.nova_helper.get_flavor(instance.flavor["id"])
flavor = instance.flavor
instance_attributes = {
"uuid": instance.id,
"human_id": instance.human_id,
"memory": flavor.ram,
"disk": flavor.disk,
"disk_capacity": flavor.disk,
"vcpus": flavor.vcpus,
"memory": flavor["ram"],
"disk": flavor["disk"],
"disk_capacity": flavor["disk"],
"vcpus": flavor["vcpus"],
"state": getattr(instance, "OS-EXT-STS:vm_state"),
"metadata": instance.metadata}

View File

@@ -33,7 +33,7 @@ class ServiceState(enum.Enum):
class ComputeNode(compute_resource.ComputeResource):
fields = {
"id": wfields.NonNegativeIntegerField(),
"id": wfields.StringField(),
"hostname": wfields.StringField(),
"status": wfields.StringField(default=ServiceState.ENABLED.value),
"state": wfields.StringField(default=ServiceState.ONLINE.value),

View File

@@ -249,7 +249,9 @@ class InstanceCreated(VersionedNotificationEndpoint):
event_type='instance.update',
# To be "fully" created, an instance transitions
# from the 'building' state to the 'active' one.
# See http://docs.openstack.org/developer/nova/vmstates.html
# See https://docs.openstack.org/nova/latest/reference/
# vm-states.html
payload={
'nova_object.data': {
'state': element.InstanceState.ACTIVE.value,

View File

@@ -87,6 +87,7 @@ class WeightPlanner(base.BasePlanner):
@staticmethod
def chunkify(lst, n):
"""Yield successive n-sized chunks from lst."""
n = int(n)
if n < 1:
# Just to make sure the number is valid
n = 1

View File

@@ -36,12 +36,10 @@ class DefaultScope(base.BaseScope):
"host_aggregates": {
"type": "array",
"items": {
"type": "object",
"properties": {
"anyOf": [
{"type": ["string", "number"]}
]
},
"anyOf": [
{"$ref": "#/host_aggregates/id"},
{"$ref": "#/host_aggregates/name"},
]
}
},
"availability_zones": {
@@ -69,7 +67,8 @@ class DefaultScope(base.BaseScope):
"uuid": {
"type": "string"
}
}
},
"additionalProperties": False
}
},
"compute_nodes": {
@@ -80,18 +79,17 @@ class DefaultScope(base.BaseScope):
"name": {
"type": "string"
}
}
},
"additionalProperties": False
}
},
"host_aggregates": {
"type": "array",
"items": {
"type": "object",
"properties": {
"anyOf": [
{"type": ["string", "number"]}
]
},
"anyOf": [
{"$ref": "#/host_aggregates/id"},
{"$ref": "#/host_aggregates/name"},
]
}
},
"instance_metadata": {
@@ -106,7 +104,29 @@ class DefaultScope(base.BaseScope):
}
},
"additionalProperties": False
}
},
"host_aggregates": {
"id": {
"properties": {
"id": {
"oneOf": [
{"type": "integer"},
{"enum": ["*"]}
]
}
},
"additionalProperties": False
},
"name": {
"properties": {
"name": {
"type": "string"
}
},
"additionalProperties": False
}
},
"additionalProperties": False
}
def __init__(self, scope, config, osc=None):

View File

@@ -170,7 +170,7 @@ class BasicConsolidation(base.ServerConsolidationBaseStrategy):
@property
def ceilometer(self):
if self._ceilometer is None:
self._ceilometer = ceil.CeilometerHelper(osc=self.osc)
self.ceilometer = ceil.CeilometerHelper(osc=self.osc)
return self._ceilometer
@ceilometer.setter
@@ -180,7 +180,7 @@ class BasicConsolidation(base.ServerConsolidationBaseStrategy):
@property
def monasca(self):
if self._monasca is None:
self._monasca = mon.MonascaHelper(osc=self.osc)
self.monasca = mon.MonascaHelper(osc=self.osc)
return self._monasca
@monasca.setter
@@ -190,13 +190,21 @@ class BasicConsolidation(base.ServerConsolidationBaseStrategy):
@property
def gnocchi(self):
if self._gnocchi is None:
self._gnocchi = gnoc.GnocchiHelper(osc=self.osc)
self.gnocchi = gnoc.GnocchiHelper(osc=self.osc)
return self._gnocchi
@gnocchi.setter
def gnocchi(self, gnocchi):
self._gnocchi = gnocchi
def get_available_compute_nodes(self):
default_node_scope = [element.ServiceState.ENABLED.value,
element.ServiceState.DISABLED.value]
return {uuid: cn for uuid, cn in
self.compute_model.get_all_compute_nodes().items()
if cn.state == element.ServiceState.ONLINE.value and
cn.status in default_node_scope}
def check_migration(self, source_node, destination_node,
instance_to_migrate):
"""Check if the migration is possible
@@ -428,7 +436,7 @@ class BasicConsolidation(base.ServerConsolidationBaseStrategy):
def compute_score_of_nodes(self):
"""Calculate score of nodes based on load by VMs"""
score = []
for node in self.compute_model.get_all_compute_nodes().values():
for node in self.get_available_compute_nodes().values():
if node.status == element.ServiceState.ENABLED.value:
self.number_of_enabled_nodes += 1
@@ -502,7 +510,7 @@ class BasicConsolidation(base.ServerConsolidationBaseStrategy):
if not self.compute_model:
raise exception.ClusterStateNotDefined()
if len(self.compute_model.get_all_compute_nodes()) == 0:
if len(self.get_available_compute_nodes()) == 0:
raise exception.ClusterEmpty()
if self.compute_model.stale:

View File

@@ -50,7 +50,7 @@ class NoisyNeighbor(base.NoisyNeighborBaseStrategy):
@property
def ceilometer(self):
if self._ceilometer is None:
self._ceilometer = ceil.CeilometerHelper(osc=self.osc)
self.ceilometer = ceil.CeilometerHelper(osc=self.osc)
return self._ceilometer
@ceilometer.setter

View File

@@ -140,7 +140,7 @@ class OutletTempControl(base.ThermalOptimizationBaseStrategy):
@property
def ceilometer(self):
if self._ceilometer is None:
self._ceilometer = ceil.CeilometerHelper(osc=self.osc)
self.ceilometer = ceil.CeilometerHelper(osc=self.osc)
return self._ceilometer
@ceilometer.setter
@@ -150,7 +150,7 @@ class OutletTempControl(base.ThermalOptimizationBaseStrategy):
@property
def gnocchi(self):
if self._gnocchi is None:
self._gnocchi = gnoc.GnocchiHelper(osc=self.osc)
self.gnocchi = gnoc.GnocchiHelper(osc=self.osc)
return self._gnocchi
@gnocchi.setter
@@ -171,6 +171,13 @@ class OutletTempControl(base.ThermalOptimizationBaseStrategy):
choices=["ceilometer", "gnocchi"])
]
def get_available_compute_nodes(self):
default_node_scope = [element.ServiceState.ENABLED.value]
return {uuid: cn for uuid, cn in
self.compute_model.get_all_compute_nodes().items()
if cn.state == element.ServiceState.ONLINE.value and
cn.status in default_node_scope}
def calc_used_resource(self, node):
"""Calculate the used vcpus, memory and disk based on VM flavors"""
instances = self.compute_model.get_node_instances(node)
@@ -186,7 +193,7 @@ class OutletTempControl(base.ThermalOptimizationBaseStrategy):
def group_hosts_by_outlet_temp(self):
"""Group hosts based on outlet temp meters"""
nodes = self.compute_model.get_all_compute_nodes()
nodes = self.get_available_compute_nodes()
size_cluster = len(nodes)
if size_cluster == 0:
raise wexc.ClusterEmpty()

View File

@@ -29,6 +29,42 @@ LOG = log.getLogger(__name__)
class SavingEnergy(base.SavingEnergyBaseStrategy):
"""Saving Energy Strategy
Saving Energy Strategy together with VM Workload Consolidation Strategy
can perform the Dynamic Power Management (DPM) functionality, which tries
to save power by dynamically consolidating workloads even further during
periods of low resource utilization. Virtual machines are migrated onto
fewer hosts and the unneeded hosts are powered off.
After consolidation, Saving Energy Strategy produces a solution of powering
off/on according to the following detailed policy:
In this policy, a preset number(min_free_hosts_num) is given by user, and
this min_free_hosts_num describes minimum free compute nodes that users
expect to have, where "free compute nodes" refers to those nodes unused
but still powered on.
If the actual number of unused nodes(in power-on state) is larger than
the given number, randomly select the redundant nodes and power off them;
If the actual number of unused nodes(in poweron state) is smaller than
the given number and there are spare unused nodes(in poweroff state),
randomly select some nodes(unused,poweroff) and power on them.
In this policy, in order to calculate the min_free_hosts_num,
users must provide two parameters:
* One parameter("min_free_hosts_num") is a constant int number.
This number should be int type and larger than zero.
* The other parameter("free_used_percent") is a percentage number, which
describes the quotient of min_free_hosts_num/nodes_with_VMs_num,
where nodes_with_VMs_num is the number of nodes with VMs running on it.
This parameter is used to calculate a dynamic min_free_hosts_num.
The nodes with VMs refer to those nodes with VMs running on it.
Then choose the larger one as the final min_free_hosts_num.
"""
def __init__(self, config, osc=None):

View File

@@ -130,7 +130,7 @@ class UniformAirflow(base.BaseStrategy):
@property
def ceilometer(self):
if self._ceilometer is None:
self._ceilometer = ceil.CeilometerHelper(osc=self.osc)
self.ceilometer = ceil.CeilometerHelper(osc=self.osc)
return self._ceilometer
@ceilometer.setter
@@ -140,7 +140,7 @@ class UniformAirflow(base.BaseStrategy):
@property
def gnocchi(self):
if self._gnocchi is None:
self._gnocchi = gnoc.GnocchiHelper(osc=self.osc)
self.gnocchi = gnoc.GnocchiHelper(osc=self.osc)
return self._gnocchi
@gnocchi.setter
@@ -214,6 +214,13 @@ class UniformAirflow(base.BaseStrategy):
choices=["ceilometer", "gnocchi"])
]
def get_available_compute_nodes(self):
default_node_scope = [element.ServiceState.ENABLED.value]
return {uuid: cn for uuid, cn in
self.compute_model.get_all_compute_nodes().items()
if cn.state == element.ServiceState.ONLINE.value and
cn.status in default_node_scope}
def calculate_used_resource(self, node):
"""Compute the used vcpus, memory and disk based on instance flavors"""
instances = self.compute_model.get_node_instances(node)
@@ -334,7 +341,7 @@ class UniformAirflow(base.BaseStrategy):
def group_hosts_by_airflow(self):
"""Group hosts based on airflow meters"""
nodes = self.compute_model.get_all_compute_nodes()
nodes = self.get_available_compute_nodes()
if not nodes:
raise wexc.ClusterEmpty()
overload_hosts = []

View File

@@ -118,7 +118,7 @@ class VMWorkloadConsolidation(base.ServerConsolidationBaseStrategy):
@property
def ceilometer(self):
if self._ceilometer is None:
self._ceilometer = ceil.CeilometerHelper(osc=self.osc)
self.ceilometer = ceil.CeilometerHelper(osc=self.osc)
return self._ceilometer
@ceilometer.setter
@@ -128,7 +128,7 @@ class VMWorkloadConsolidation(base.ServerConsolidationBaseStrategy):
@property
def gnocchi(self):
if self._gnocchi is None:
self._gnocchi = gnoc.GnocchiHelper(osc=self.osc)
self.gnocchi = gnoc.GnocchiHelper(osc=self.osc)
return self._gnocchi
@gnocchi.setter
@@ -169,6 +169,14 @@ class VMWorkloadConsolidation(base.ServerConsolidationBaseStrategy):
choices=["ceilometer", "gnocchi"])
]
def get_available_compute_nodes(self):
default_node_scope = [element.ServiceState.ENABLED.value,
element.ServiceState.DISABLED.value]
return {uuid: cn for uuid, cn in
self.compute_model.get_all_compute_nodes().items()
if cn.state == element.ServiceState.ONLINE.value and
cn.status in default_node_scope}
def get_instance_state_str(self, instance):
"""Get instance state in string format.
@@ -273,7 +281,7 @@ class VMWorkloadConsolidation(base.ServerConsolidationBaseStrategy):
:return: None
"""
for node in self.compute_model.get_all_compute_nodes().values():
for node in self.get_available_compute_nodes().values():
if (len(self.compute_model.get_node_instances(node)) == 0 and
node.status !=
element.ServiceState.DISABLED.value):
@@ -422,7 +430,7 @@ class VMWorkloadConsolidation(base.ServerConsolidationBaseStrategy):
RCU is an average of relative utilizations (rhu) of active nodes.
:return: {'cpu': <0,1>, 'ram': <0,1>, 'disk': <0,1>}
"""
nodes = self.compute_model.get_all_compute_nodes().values()
nodes = self.get_available_compute_nodes().values()
rcu = {}
counters = {}
for node in nodes:
@@ -534,7 +542,7 @@ class VMWorkloadConsolidation(base.ServerConsolidationBaseStrategy):
:param cc: dictionary containing resource capacity coefficients
"""
sorted_nodes = sorted(
self.compute_model.get_all_compute_nodes().values(),
self.get_available_compute_nodes().values(),
key=lambda x: self.get_node_utilization(x)['cpu'])
for node in reversed(sorted_nodes):
if self.is_overloaded(node, cc):
@@ -567,7 +575,7 @@ class VMWorkloadConsolidation(base.ServerConsolidationBaseStrategy):
:param cc: dictionary containing resource capacity coefficients
"""
sorted_nodes = sorted(
self.compute_model.get_all_compute_nodes().values(),
self.get_available_compute_nodes().values(),
key=lambda x: self.get_node_utilization(x)['cpu'])
asc = 0
for node in sorted_nodes:
@@ -630,7 +638,7 @@ class VMWorkloadConsolidation(base.ServerConsolidationBaseStrategy):
rcu_after = self.get_relative_cluster_utilization()
info = {
"compute_nodes_count": len(
self.compute_model.get_all_compute_nodes()),
self.get_available_compute_nodes()),
'number_of_migrations': self.number_of_migrations,
'number_of_released_nodes':
self.number_of_released_nodes,
@@ -643,7 +651,7 @@ class VMWorkloadConsolidation(base.ServerConsolidationBaseStrategy):
def post_execute(self):
self.solution.set_efficacy_indicators(
compute_nodes_count=len(
self.compute_model.get_all_compute_nodes()),
self.get_available_compute_nodes()),
released_compute_nodes_count=self.number_of_released_nodes,
instance_migrations_count=self.number_of_migrations,
)

View File

@@ -22,7 +22,7 @@
*Description*
This strategy migrates a VM based on the VM workload of the hosts.
It makes decision to migrate a workload whenever a host's CPU
It makes decision to migrate a workload whenever a host's CPU or RAM
utilization % is higher than the specified threshold. The VM to
be moved should make the host close to average workload of all
hosts nodes.
@@ -32,7 +32,7 @@ hosts nodes.
* Hardware: compute node should use the same physical CPUs
* Software: Ceilometer component ceilometer-agent-compute
running in each compute node, and Ceilometer API can
report such telemetry "cpu_util" successfully.
report such telemetry "cpu_util" and "memory.resident" successfully.
* You must have at least 2 physical compute nodes to run
this strategy.
@@ -69,16 +69,16 @@ class WorkloadBalance(base.WorkloadStabilizationBaseStrategy):
It is a migration strategy based on the VM workload of physical
servers. It generates solutions to move a workload whenever a server's
CPU utilization % is higher than the specified threshold.
CPU or RAM utilization % is higher than the specified threshold.
The VM to be moved should make the host close to average workload
of all compute nodes.
*Requirements*
* Hardware: compute node should use the same physical CPUs
* Hardware: compute node should use the same physical CPUs/RAMs
* Software: Ceilometer component ceilometer-agent-compute running
in each compute node, and Ceilometer API can report such telemetry
"cpu_util" successfully.
"cpu_util" and "memory.resident" successfully.
* You must have at least 2 physical compute nodes to run this strategy
*Limitations*
@@ -91,8 +91,12 @@ class WorkloadBalance(base.WorkloadStabilizationBaseStrategy):
"""
# The meter to report CPU utilization % of VM in ceilometer
METER_NAME = "cpu_util"
# Unit: %, value range is [0 , 100]
CPU_METER_NAME = "cpu_util"
# The meter to report memory resident of VM in ceilometer
# Unit: MB
MEM_METER_NAME = "memory.resident"
MIGRATION = "migrate"
@@ -104,16 +108,16 @@ class WorkloadBalance(base.WorkloadStabilizationBaseStrategy):
:param osc: :py:class:`~.OpenStackClients` instance
"""
super(WorkloadBalance, self).__init__(config, osc)
# the migration plan will be triggered when the CPU utilization %
# reaches threshold
self._meter = self.METER_NAME
# the migration plan will be triggered when the CPU or RAM
# utilization % reaches threshold
self._meter = None
self._ceilometer = None
self._gnocchi = None
@property
def ceilometer(self):
if self._ceilometer is None:
self._ceilometer = ceil.CeilometerHelper(osc=self.osc)
self.ceilometer = ceil.CeilometerHelper(osc=self.osc)
return self._ceilometer
@ceilometer.setter
@@ -123,7 +127,7 @@ class WorkloadBalance(base.WorkloadStabilizationBaseStrategy):
@property
def gnocchi(self):
if self._gnocchi is None:
self._gnocchi = gnoc.GnocchiHelper(osc=self.osc)
self.gnocchi = gnoc.GnocchiHelper(osc=self.osc)
return self._gnocchi
@gnocchi.setter
@@ -151,6 +155,13 @@ class WorkloadBalance(base.WorkloadStabilizationBaseStrategy):
# Mandatory default setting for each element
return {
"properties": {
"metrics": {
"description": "Workload balance based on metrics: "
"cpu or ram utilization",
"type": "string",
"choice": ["cpu_util", "memory.resident"],
"default": "cpu_util"
},
"threshold": {
"description": "workload threshold for migration",
"type": "number",
@@ -180,6 +191,13 @@ class WorkloadBalance(base.WorkloadStabilizationBaseStrategy):
choices=["ceilometer", "gnocchi"])
]
def get_available_compute_nodes(self):
default_node_scope = [element.ServiceState.ENABLED.value]
return {uuid: cn for uuid, cn in
self.compute_model.get_all_compute_nodes().items()
if cn.state == element.ServiceState.ONLINE.value and
cn.status in default_node_scope}
def calculate_used_resource(self, node):
"""Calculate the used vcpus, memory and disk based on VM flavors"""
instances = self.compute_model.get_node_instances(node)
@@ -251,18 +269,21 @@ class WorkloadBalance(base.WorkloadStabilizationBaseStrategy):
cores_available = host.vcpus - cores_used
disk_available = host.disk - disk_used
mem_available = host.memory - mem_used
if (
cores_available >= required_cores and
disk_available >= required_disk and
if (cores_available >= required_cores and
mem_available >= required_mem and
disk_available >= required_disk):
if (self._meter == self.CPU_METER_NAME and
((src_instance_workload + workload) <
self.threshold / 100 * host.vcpus)
):
destination_hosts.append(instance_data)
self.threshold / 100 * host.vcpus)):
destination_hosts.append(instance_data)
if (self._meter == self.MEM_METER_NAME and
((src_instance_workload + workload) <
self.threshold / 100 * host.memory)):
destination_hosts.append(instance_data)
return destination_hosts
def group_hosts_by_cpu_util(self):
def group_hosts_by_cpu_or_ram_util(self):
"""Calculate the workloads of each node
try to find out the nodes which have reached threshold
@@ -271,7 +292,7 @@ class WorkloadBalance(base.WorkloadStabilizationBaseStrategy):
and also generate the instance workload map.
"""
nodes = self.compute_model.get_all_compute_nodes()
nodes = self.get_available_compute_nodes()
cluster_size = len(nodes)
if not nodes:
raise wexc.ClusterEmpty()
@@ -286,10 +307,10 @@ class WorkloadBalance(base.WorkloadStabilizationBaseStrategy):
instances = self.compute_model.get_node_instances(node)
node_workload = 0.0
for instance in instances:
cpu_util = None
instance_util = None
try:
if self.config.datasource == "ceilometer":
cpu_util = self.ceilometer.statistic_aggregation(
instance_util = self.ceilometer.statistic_aggregation(
resource_id=instance.uuid,
meter_name=self._meter,
period=self._period,
@@ -298,7 +319,7 @@ class WorkloadBalance(base.WorkloadStabilizationBaseStrategy):
stop_time = datetime.datetime.utcnow()
start_time = stop_time - datetime.timedelta(
seconds=int(self._period))
cpu_util = self.gnocchi.statistic_aggregation(
instance_util = self.gnocchi.statistic_aggregation(
resource_id=instance.uuid,
metric=self._meter,
granularity=self.granularity,
@@ -308,23 +329,32 @@ class WorkloadBalance(base.WorkloadStabilizationBaseStrategy):
)
except Exception as exc:
LOG.exception(exc)
LOG.error("Can not get cpu_util from %s",
LOG.error("Can not get %s from %s", self._meter,
self.config.datasource)
continue
if cpu_util is None:
LOG.debug("Instance (%s): cpu_util is None", instance.uuid)
if instance_util is None:
LOG.debug("Instance (%s): %s is None",
instance.uuid, self._meter)
continue
workload_cache[instance.uuid] = cpu_util * instance.vcpus / 100
if self._meter == self.CPU_METER_NAME:
workload_cache[instance.uuid] = (instance_util *
instance.vcpus / 100)
else:
workload_cache[instance.uuid] = instance_util
node_workload += workload_cache[instance.uuid]
LOG.debug("VM (%s): cpu_util %f", instance.uuid, cpu_util)
node_cpu_util = node_workload / node.vcpus * 100
LOG.debug("VM (%s): %s %f", instance.uuid, self._meter,
instance_util)
cluster_workload += node_workload
if self._meter == self.CPU_METER_NAME:
node_util = node_workload / node.vcpus * 100
else:
node_util = node_workload / node.memory * 100
instance_data = {
'node': node, "cpu_util": node_cpu_util,
'node': node, self._meter: node_util,
'workload': node_workload}
if node_cpu_util >= self.threshold:
if node_util >= self.threshold:
# mark the node to release resources
overload_hosts.append(instance_data)
else:
@@ -356,8 +386,9 @@ class WorkloadBalance(base.WorkloadStabilizationBaseStrategy):
"""
self.threshold = self.input_parameters.threshold
self._period = self.input_parameters.period
self._meter = self.input_parameters.metrics
source_nodes, target_nodes, avg_workload, workload_cache = (
self.group_hosts_by_cpu_util())
self.group_hosts_by_cpu_or_ram_util())
if not source_nodes:
LOG.debug("No hosts require optimization")
@@ -373,7 +404,7 @@ class WorkloadBalance(base.WorkloadStabilizationBaseStrategy):
# choose the server with largest cpu_util
source_nodes = sorted(source_nodes,
reverse=True,
key=lambda x: (x[self.METER_NAME]))
key=lambda x: (x[self._meter]))
instance_to_migrate = self.choose_instance_to_migrate(
source_nodes, avg_workload, workload_cache)
@@ -391,7 +422,7 @@ class WorkloadBalance(base.WorkloadStabilizationBaseStrategy):
"be because of there's no enough CPU/Memory/DISK")
return self.solution
destination_hosts = sorted(destination_hosts,
key=lambda x: (x["cpu_util"]))
key=lambda x: (x[self._meter]))
# always use the host with lowerest CPU utilization
mig_destination_node = destination_hosts[0]['node']
# generate solution to migrate the instance to the dest server,

View File

@@ -179,13 +179,13 @@ class WorkloadStabilization(base.WorkloadStabilizationBaseStrategy):
@property
def ceilometer(self):
if self._ceilometer is None:
self._ceilometer = ceil.CeilometerHelper(osc=self.osc)
self.ceilometer = ceil.CeilometerHelper(osc=self.osc)
return self._ceilometer
@property
def nova(self):
if self._nova is None:
self._nova = self.osc.nova()
self.nova = self.osc.nova()
return self._nova
@nova.setter
@@ -199,7 +199,7 @@ class WorkloadStabilization(base.WorkloadStabilizationBaseStrategy):
@property
def gnocchi(self):
if self._gnocchi is None:
self._gnocchi = gnoc.GnocchiHelper(osc=self.osc)
self.gnocchi = gnoc.GnocchiHelper(osc=self.osc)
return self._gnocchi
@gnocchi.setter

View File

@@ -78,6 +78,14 @@ class Syncer(object):
"""Strategies loaded from DB"""
if self._available_strategies is None:
self._available_strategies = objects.Strategy.list(self.ctx)
goal_ids = [g.id for g in self.available_goals]
stale_strategies = [s for s in self._available_strategies
if s.goal_id not in goal_ids]
for s in stale_strategies:
LOG.info("Can't find Goal id %d of strategy %s",
s.goal_id, s.name)
s.soft_delete()
self._available_strategies.remove(s)
return self._available_strategies
@property

View File

@@ -120,6 +120,21 @@ class ActionExecutionPayload(ActionPayload):
**kwargs)
@base.WatcherObjectRegistry.register_notification
class ActionCancelPayload(ActionPayload):
# Version 1.0: Initial version
VERSION = '1.0'
fields = {
'fault': wfields.ObjectField('ExceptionPayload', nullable=True),
}
def __init__(self, action, action_plan, **kwargs):
super(ActionCancelPayload, self).__init__(
action=action,
action_plan=action_plan,
**kwargs)
@base.WatcherObjectRegistry.register_notification
class ActionDeletePayload(ActionPayload):
# Version 1.0: Initial version
@@ -178,6 +193,19 @@ class ActionDeleteNotification(notificationbase.NotificationBase):
}
@notificationbase.notification_sample('action-cancel-error.json')
@notificationbase.notification_sample('action-cancel-end.json')
@notificationbase.notification_sample('action-cancel-start.json')
@base.WatcherObjectRegistry.register_notification
class ActionCancelNotification(notificationbase.NotificationBase):
# Version 1.0: Initial version
VERSION = '1.0'
fields = {
'payload': wfields.ObjectField('ActionCancelPayload')
}
def _get_action_plan_payload(action):
action_plan = None
strategy_uuid = None
@@ -300,3 +328,33 @@ def send_execution_notification(context, action, notification_action, phase,
payload=versioned_payload)
notification.emit(context)
def send_cancel_notification(context, action, notification_action, phase,
priority=wfields.NotificationPriority.INFO,
service='infra-optim', host=None):
"""Emit an action cancel notification."""
action_plan_payload = _get_action_plan_payload(action)
fault = None
if phase == wfields.NotificationPhase.ERROR:
fault = exception_notifications.ExceptionPayload.from_exception()
versioned_payload = ActionCancelPayload(
action=action,
action_plan=action_plan_payload,
fault=fault,
)
notification = ActionCancelNotification(
priority=priority,
event_type=notificationbase.EventType(
object='action',
action=notification_action,
phase=phase),
publisher=notificationbase.NotificationPublisher(
host=host or CONF.host,
binary=service),
payload=versioned_payload)
notification.emit(context)

View File

@@ -167,6 +167,22 @@ class ActionPlanDeletePayload(ActionPlanPayload):
strategy=strategy)
@base.WatcherObjectRegistry.register_notification
class ActionPlanCancelPayload(ActionPlanPayload):
# Version 1.0: Initial version
VERSION = '1.0'
fields = {
'fault': wfields.ObjectField('ExceptionPayload', nullable=True),
}
def __init__(self, action_plan, audit, strategy, **kwargs):
super(ActionPlanCancelPayload, self).__init__(
action_plan=action_plan,
audit=audit,
strategy=strategy,
**kwargs)
@notificationbase.notification_sample('action_plan-execution-error.json')
@notificationbase.notification_sample('action_plan-execution-end.json')
@notificationbase.notification_sample('action_plan-execution-start.json')
@@ -213,6 +229,19 @@ class ActionPlanDeleteNotification(notificationbase.NotificationBase):
}
@notificationbase.notification_sample('action_plan-cancel-error.json')
@notificationbase.notification_sample('action_plan-cancel-end.json')
@notificationbase.notification_sample('action_plan-cancel-start.json')
@base.WatcherObjectRegistry.register_notification
class ActionPlanCancelNotification(notificationbase.NotificationBase):
# Version 1.0: Initial version
VERSION = '1.0'
fields = {
'payload': wfields.ObjectField('ActionPlanCancelPayload')
}
def _get_common_payload(action_plan):
audit = None
strategy = None
@@ -338,3 +367,34 @@ def send_action_notification(context, action_plan, action, phase=None,
payload=versioned_payload)
notification.emit(context)
def send_cancel_notification(context, action_plan, action, phase=None,
priority=wfields.NotificationPriority.INFO,
service='infra-optim', host=None):
"""Emit an action_plan cancel notification."""
audit_payload, strategy_payload = _get_common_payload(action_plan)
fault = None
if phase == wfields.NotificationPhase.ERROR:
fault = exception_notifications.ExceptionPayload.from_exception()
versioned_payload = ActionPlanCancelPayload(
action_plan=action_plan,
audit=audit_payload,
strategy=strategy_payload,
fault=fault,
)
notification = ActionPlanCancelNotification(
priority=priority,
event_type=notificationbase.EventType(
object='action_plan',
action=action,
phase=phase),
publisher=notificationbase.NotificationPublisher(
host=host or CONF.host,
binary=service),
payload=versioned_payload)
notification.emit(context)

View File

@@ -153,7 +153,10 @@ class NotificationAction(BaseWatcherEnum):
PLANNER = 'planner'
EXECUTION = 'execution'
ALL = (CREATE, UPDATE, EXCEPTION, DELETE, STRATEGY, PLANNER, EXECUTION)
CANCEL = 'cancel'
ALL = (CREATE, UPDATE, EXCEPTION, DELETE, STRATEGY, PLANNER, EXECUTION,
CANCEL)
class NotificationPriorityField(BaseEnumField):

View File

@@ -41,7 +41,7 @@ def datetime_or_none(value, tzinfo_aware=False):
# NOTE(danms): Legacy objects from sqlalchemy are stored in UTC,
# but are returned without a timezone attached.
# As a transitional aid, assume a tz-naive object is in UTC.
value = value.replace(tzinfo=iso8601.iso8601.Utc())
value = value.replace(tzinfo=iso8601.UTC)
elif not tzinfo_aware:
value = value.replace(tzinfo=None)

View File

@@ -511,7 +511,7 @@ class TestPost(FunctionalTestWithSetup):
response.json['created_at']).replace(tzinfo=None)
self.assertEqual(test_time, return_created_at)
def test_create_audit_template_vlidation_with_aggregates(self):
def test_create_audit_template_validation_with_aggregates(self):
scope = [{'host_aggregates': [{'id': '*'}]},
{'availability_zones': [{'name': 'AZ1'},
{'name': 'AZ2'}]},
@@ -532,6 +532,14 @@ class TestPost(FunctionalTestWithSetup):
"be included and excluded together"):
self.post_json('/audit_templates', audit_template_dict)
scope = [{'host_aggregates': [{'id1': '*'}]}]
audit_template_dict = post_get_test_audit_template(
goal=self.fake_goal1.uuid,
strategy=self.fake_strategy1.uuid, scope=scope)
response = self.post_json('/audit_templates',
audit_template_dict, expect_errors=True)
self.assertEqual(500, response.status_int)
def test_create_audit_template_does_autogenerate_id(self):
audit_template_dict = post_get_test_audit_template(
goal=self.fake_goal1.uuid, strategy=None)

View File

@@ -829,8 +829,10 @@ class TestDelete(api_base.FunctionalTest):
self.context.show_deleted = True
audit = objects.Audit.get_by_uuid(self.context, self.audit.uuid)
return_deleted_at = timeutils.strtime(audit['deleted_at'])
self.assertEqual(timeutils.strtime(test_time), return_deleted_at)
return_deleted_at = \
audit['deleted_at'].strftime('%Y-%m-%dT%H:%M:%S.%f')
self.assertEqual(test_time.strftime('%Y-%m-%dT%H:%M:%S.%f'),
return_deleted_at)
self.assertEqual(objects.audit.State.DELETED, audit['state'])
def test_delete_audit_not_found(self):

View File

@@ -16,5 +16,4 @@ from watcher.tests.api import base as api_base
class TestV1Routing(api_base.FunctionalTest):
def setUp(self):
super(TestV1Routing, self).setUp()
pass

View File

@@ -90,7 +90,14 @@ class TestChangeNodePowerState(base.TestCase):
def test_execute_node_service_state_with_poweron_target(
self, mock_ironic, mock_nova):
mock_irclient = mock_ironic.return_value
self.action.execute()
self.action.input_parameters["state"] = (
change_node_power_state.NodeState.POWERON.value)
mock_irclient.node.get.side_effect = [
mock.MagicMock(power_state='power off'),
mock.MagicMock(power_state='power on')]
result = self.action.execute()
self.assertTrue(result)
mock_irclient.node.set_power_state.assert_called_once_with(
COMPUTE_NODE, change_node_power_state.NodeState.POWERON.value)
@@ -104,7 +111,12 @@ class TestChangeNodePowerState(base.TestCase):
mock_nvclient.hypervisors.get.return_value = mock_get
self.action.input_parameters["state"] = (
change_node_power_state.NodeState.POWEROFF.value)
self.action.execute()
mock_irclient.node.get.side_effect = [
mock.MagicMock(power_state='power on'),
mock.MagicMock(power_state='power on'),
mock.MagicMock(power_state='power off')]
result = self.action.execute()
self.assertTrue(result)
mock_irclient.node.set_power_state.assert_called_once_with(
COMPUTE_NODE, change_node_power_state.NodeState.POWEROFF.value)
@@ -118,6 +130,10 @@ class TestChangeNodePowerState(base.TestCase):
mock_nvclient.hypervisors.get.return_value = mock_get
self.action.input_parameters["state"] = (
change_node_power_state.NodeState.POWERON.value)
mock_irclient.node.get.side_effect = [
mock.MagicMock(power_state='power on'),
mock.MagicMock(power_state='power on'),
mock.MagicMock(power_state='power off')]
self.action.revert()
mock_irclient.node.set_power_state.assert_called_once_with(
@@ -128,6 +144,9 @@ class TestChangeNodePowerState(base.TestCase):
mock_irclient = mock_ironic.return_value
self.action.input_parameters["state"] = (
change_node_power_state.NodeState.POWEROFF.value)
mock_irclient.node.get.side_effect = [
mock.MagicMock(power_state='power off'),
mock.MagicMock(power_state='power on')]
self.action.revert()
mock_irclient.node.set_power_state.assert_called_once_with(

View File

@@ -31,9 +31,6 @@ class TestTriggerActionPlan(base.TestCase):
self.applier = mock.MagicMock()
self.endpoint = trigger.TriggerActionPlan(self.applier)
def setUp(self):
super(TestTriggerActionPlan, self).setUp()
def test_launch_action_plan(self):
action_plan_uuid = utils.generate_uuid()
expected_uuid = self.endpoint.launch_action_plan(self.context,

View File

@@ -30,9 +30,6 @@ class TestApplierAPI(base.TestCase):
api = rpcapi.ApplierAPI()
def setUp(self):
super(TestApplierAPI, self).setUp()
def test_get_api_version(self):
with mock.patch.object(om.RPCClient, 'call') as mock_call:
expected_context = self.context

View File

@@ -51,7 +51,7 @@ class FakeAction(abase.BaseAction):
pass
def execute(self):
raise ExpectedException()
return False
def get_description(self):
return "fake action, just for test"
@@ -311,7 +311,8 @@ class TestDefaultWorkFlowEngine(base.DbTestCase):
exc = self.assertRaises(exception.WorkflowExecutionException,
self.engine.execute, actions)
self.assertIsInstance(exc.kwargs['error'], ExpectedException)
self.assertIsInstance(exc.kwargs['error'],
exception.ActionExecutionFailure)
self.check_action_state(actions[0], objects.action.State.FAILED)
@mock.patch.object(objects.ActionPlan, "get_by_uuid")

View File

@@ -20,6 +20,9 @@ import eventlet
import mock
from watcher.applier.workflow_engine import default as tflow
from watcher.common import clients
from watcher.common import exception
from watcher.common import nova_helper
from watcher import objects
from watcher.tests.db import base
from watcher.tests.objects import utils as obj_utils
@@ -55,6 +58,34 @@ class TestTaskFlowActionContainer(base.DbTestCase):
self.assertTrue(action.state, objects.action.State.SUCCEEDED)
@mock.patch.object(clients.OpenStackClients, 'nova', mock.Mock())
def test_execute_with_failed(self):
nova_util = nova_helper.NovaHelper()
instance = "31b9dd5c-b1fd-4f61-9b68-a47096326dac"
nova_util.nova.servers.get.return_value = instance
action_plan = obj_utils.create_test_action_plan(
self.context, audit_id=self.audit.id,
strategy_id=self.strategy.id,
state=objects.action.State.ONGOING)
action = obj_utils.create_test_action(
self.context, action_plan_id=action_plan.id,
state=objects.action.State.ONGOING,
action_type='migrate',
input_parameters={"resource_id":
instance,
"migration_type": "live",
"destination_node": "host2",
"source_node": "host1"})
action_container = tflow.TaskFlowActionContainer(
db_action=action,
engine=self.engine)
self.assertRaises(exception.ActionExecutionFailure,
action_container.execute, action_id=action.uuid)
self.assertTrue(action.state, objects.action.State.FAILED)
@mock.patch('eventlet.spawn')
def test_execute_with_cancel_action_plan(self, mock_eventlet_spawn):
action_plan = obj_utils.create_test_action_plan(

View File

@@ -25,9 +25,6 @@ from watcher.tests import base
@mock.patch.object(clients.OpenStackClients, 'cinder')
class TestCinderHelper(base.TestCase):
def setUp(self):
super(TestCinderHelper, self).setUp()
@staticmethod
def fake_storage_node(**kwargs):
node = mock.MagicMock()

View File

@@ -190,7 +190,8 @@ class TestClients(base.TestCase):
osc.gnocchi()
mock_call.assert_called_once_with(
CONF.gnocchi_client.api_version,
interface=CONF.gnocchi_client.endpoint_type,
adapter_options={
"interface": CONF.gnocchi_client.endpoint_type},
session=mock_session)
@mock.patch.object(clients.OpenStackClients, 'session')

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