Compare commits

...

193 Commits
1.5.0 ... 1.8.1

Author SHA1 Message Date
OpenDev Sysadmins
5307f5a80e OpenDev Migration Patch
This commit was bulk generated and pushed by the OpenDev sysadmins
as a part of the Git hosting and code review systems migration
detailed in these mailing list posts:

http://lists.openstack.org/pipermail/openstack-discuss/2019-March/003603.html
http://lists.openstack.org/pipermail/openstack-discuss/2019-April/004920.html

Attempts have been made to correct repository namespaces and
hostnames based on simple pattern matching, but it's possible some
were updated incorrectly or missed entirely. Please reach out to us
via the contact information listed at https://opendev.org/ with any
questions you may have.
2019-04-19 19:40:46 +00:00
Ian Wienand
b5467a2a1f Replace openstack.org git:// URLs with https://
This is a mechanically generated change to replace openstack.org
git:// URLs with https:// equivalents.

This is in aid of a planned future move of the git hosting
infrastructure to a self-hosted instance of gitea (https://gitea.io),
which does not support the git wire protocol at this stage.

This update should result in no functional change.

For more information see the thread at

 http://lists.openstack.org/pipermail/openstack-discuss/2019-March/003825.html

Change-Id: I886b29ba8a1814cf876e70b5b20504a221d32fa1
2019-03-24 20:36:26 +00:00
Alexander Chadin
83411ec89f Fix stop_watcher function
Apache should be reloaded after watcher-api is disabled.

Change-Id: Ifee0e7701849348630568aa36b3f3c4c62d3382e
2018-12-10 13:55:44 +00:00
licanwei
08750536e7 optimize get_instances_by_node
We can set host filed in search_opts.
refer to:
https://developer.openstack.org/api-ref/compute/?expanded=list-servers-detail#list-servers

Change-Id: I36b27167d7223f3bf6bb05995210af41ad01fc6d
2018-11-06 13:39:14 +00:00
Tatiana Kholkina
9f7ccfe408 Use limit -1 for nova servers list
By default nova has a limit for returned items in a single response [1].
We should pass limit=-1 to get all items.

[1] https://docs.openstack.org/nova/rocky/configuration/config.html

Change-Id: I1fabd909c4c0356ef5fcb7c51718fb4513e6befa
2018-10-16 08:37:45 +00:00
Tatiana Kholkina
fb2619e538 Provide region name while initialize clients
Add new option 'region_name' to config for each client section.

Change-Id: Ifad8908852f4be69dd294a4c4ab28d2e1df265e8
Closes-Bug: #1787937
(cherry picked from commit 925b971377)
2018-09-21 12:31:04 +00:00
Nguyen Hai
6bd857fa0e import zuul job settings from project-config
This is a mechanically generated patch to complete step 1 of moving
the zuul job settings out of project-config and into each project
repository.

Because there will be a separate patch on each branch, the branch
specifiers for branch-specific jobs have been removed.

Because this patch is generated by a script, there may be some
cosmetic changes to the layout of the YAML file(s) as the contents are
normalized.

See the python3-first goal document for details:
https://governance.openstack.org/tc/goals/stein/python3-first.html

Change-Id: I35a8ce3dc54cb662ee9154e343cf50fe96f64807
Story: #2002586
Task: #24344
2018-08-19 00:59:08 +09:00
Clark Boylan
e0faeea608 Remove undefined job
The legacy-rally-dsvm-watcher-rally job does not exist but it is listed
in the .zuul.yaml config. This is a zuul configuration error. Remove
this job which does not exist to fix zuul.

Change-Id: I1bbfd373ad12b98696ab2ddb78e56e6503cc4c4d
2018-07-03 13:27:12 -07:00
Zuul
61aca40e6e Merge "Update auth_uri option to www_authenticate_uri" into stable/queens 2018-06-05 07:49:22 +00:00
caoyuan
b293389734 Delete the unnecessary '-'
fix a typo

Change-Id: I4ecdb827d94ef0ae88e2f37db9d1a53525140947
(cherry picked from commit 4844baa816)
2018-05-16 05:03:45 +00:00
caoyuan
050e6d58f1 Update auth_uri option to www_authenticate_uri
Option auth_uri from group keystone_authtoken is deprecated in Queens [1].
Use option www_authenticate_uri from group keystone_authtoken.

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

Change-Id: I2ef330d7f9b632e9a81d22a8edec3c88eb532ff5
(cherry picked from commit 8c916930c8)
2018-05-15 07:57:53 +00:00
Zuul
7223d35c47 Merge "Imported Translations from Zanata" into stable/queens 2018-03-06 05:30:53 +00:00
Zuul
57f1971982 Merge "Add a hacking rule for string interpolation at logging" into stable/queens 2018-03-06 02:42:13 +00:00
OpenStack Proposal Bot
c9b2b2aa39 Imported Translations from Zanata
For more information about this automatic import see:
https://docs.openstack.org/i18n/latest/reviewing-translation-import.html

Change-Id: Ia00d11dd76a27a5c052c7a512cadaefa168d0340
2018-03-03 07:22:16 +00:00
Andreas Jaeger
a42c31c221 Fix exception string format
The string %(action) is not valid, it misses the conversion specified,
add s for string.

Note that this leads to an untranslatable string, since our translation
tools check for valid formats and fail. In this case the failure comes
from a source code fail.

Change-Id: I2e630928dc32542a8a7c02657a9f0ab1eaab62ff
2018-03-02 20:57:41 +00:00
ForestLee
403ec94bc1 Add a hacking rule for string interpolation at logging
String interpolation should be delayed to be handled by
the logging code, rather than being done at the point
of the logging call.
See the oslo i18n guideline
* https://docs.openstack.org/oslo.i18n/latest/user/guidelines.html#adding-variables-to-log-messages
and
* https://github.com/openstack-dev/hacking/blob/master/hacking/checks/other.py#L39
Closes-Bug: #1596829

Change-Id: Ibba5791669c137be1483805db657beb907030227
2018-02-28 12:13:10 +00:00
OpenStack Release Bot
3431b77388 Update UPPER_CONSTRAINTS_FILE for stable/queens
The new stable upper-constraints file is only available
after the openstack/requirements repository is branched.
This will happen around the RC1 timeframe.

Recheck and merge this change once the requirements
repository has been branched.

The CI system will work with this patch before the requirements
repository is branched because zuul configues the job to run
with a local copy of the file and defaults to the master branch.
However, accepting the patch will break the test configuration
on developers' local systems, so please wait until after the
requirements repository is branched to merge the patch.

Change-Id: I8ec196a62e7c0146f25045e643073f414ae69249
2018-02-08 16:34:03 +00:00
OpenStack Release Bot
eb4cacc00e Update .gitreview for stable/queens
Change-Id: I4ac0da37285c34471654bb5125c034b415c6031d
2018-02-08 16:33:58 +00:00
Zuul
40a653215f Merge "Zuul: Remove project name" 2018-02-07 07:24:53 +00:00
Zuul
1492f5d8dc Merge "Repalce Chinese double quotes to English double quotes" 2018-02-07 07:22:41 +00:00
Zuul
76263f149a Merge "Fix issues with aggregate and granularity attributes" 2018-02-06 06:05:50 +00:00
James E. Blair
028006d15d Zuul: Remove project name
Zuul no longer requires the project-name for in-repo configuration.
Omitting it makes forking or renaming projects easier.

Change-Id: Ib3be82015be1d6853c44cf53faacb238237ad701
2018-02-05 14:18:38 -08:00
Alexander Chadin
d27ba8cc2a Fix issues with aggregate and granularity attributes
This patch set fixes issues that have appeared after merging
watcher-multi-datasource and strategy-requirements patches.
It is final commit in watcher-multi-datasource blueprint.

Partially-Implements: blueprint watcher-multi-datasource
Change-Id: I25b4cb0e1b85379ff0c4da9d0c1474380d75ce3a
2018-02-05 11:08:48 +00:00
chengebj5238
33750ce7a9 Repalce Chinese double quotes to English double quotes
Change-Id: I566ce10064c3dc51b875fc973c0ad9b58449001c
2018-02-05 17:59:08 +08:00
Zuul
cb8d1a98d6 Merge "Fix get_compute_node_by_hostname in nova_helper" 2018-02-05 06:47:10 +00:00
Hidekazu Nakamura
f32252d510 Fix get_compute_node_by_hostname in nova_helper
If hostname is different from uuid in Compute CDM,
get_compute_node_by_hostname method returns empty.
This patch set fixes to return a compute node even if hostname
is different from uuid.

Change-Id: I6cbc0be1a79cc238f480caed9adb8dc31256754a
Closes-Bug: #1746162
2018-02-02 14:26:20 +09:00
Zuul
4849f8dde9 Merge "Add zone migration strategy document" 2018-02-02 04:51:26 +00:00
Hidekazu Nakamura
0cafdcdee9 Add zone migration strategy document
This patch set adds zone migration strategy document.

Change-Id: Ifd9d85d635977900929efd376f0d7990a6fec627
2018-02-02 09:35:58 +09:00
OpenStack Proposal Bot
3a70225164 Updated from global requirements
Change-Id: Ifb8d8d6cb1248eaf8715c84539d74fa04dd753dd
2018-02-01 07:36:19 +00:00
Zuul
892c766ac4 Merge "Fixed AttributeError in storage_model" 2018-01-31 13:58:53 +00:00
Zuul
63a3fd84ae Merge "Remove redundant import alias" 2018-01-31 12:45:21 +00:00
Zuul
287ace1dcc Merge "Update zone_migration comment" 2018-01-31 06:14:15 +00:00
Zuul
4b302e415e Merge "Zuul: Remove project name" 2018-01-30 12:22:41 +00:00
licanwei
f24744c910 Fixed AttributeError in storage_model
self.audit.scope should be self.audit_scope

Closes-Bug: #1746191

Change-Id: I0cce165a2bc1afd4c9e09c51e4d3250ee70d3705
2018-01-30 00:32:19 -08:00
Zuul
d9a85eda2c Merge "Imported Translations from Zanata" 2018-01-29 14:12:36 +00:00
Zuul
82c8633e42 Merge "[Doc] Add actuator strategy doc" 2018-01-29 14:12:35 +00:00
Hidekazu Nakamura
d3f23795f5 Update zone_migration comment
This patch updates zone_migration comment for document and
removes unnecessary TODO.

Change-Id: Ib1eadad6496fe202e406108f432349c82696ea88
2018-01-29 17:48:48 +09:00
Hoang Trung Hieu
e7f4456a80 Zuul: Remove project name
Zuul no longer requires the project-name for in-repo configuration[1].
Omitting it makes forking or renaming projects easier.

[1] https://docs.openstack.org/infra/manual/drivers.html#consistent-naming-for-jobs-with-zuul-v3

Change-Id: Iddf89707289a22ea322c14d1b11f58840871304d
2018-01-29 07:24:44 +00:00
OpenStack Proposal Bot
a36a309e2e Updated from global requirements
Change-Id: I29ebfe2e3398dab6f2e22f3d97c16b72843f1e34
2018-01-29 00:42:54 +00:00
Hidekazu Nakamura
8e3affd9ac [Doc] Add actuator strategy doc
This patch adds actuator strategy document.

Change-Id: I5f0415754c83e4f152155988625ada2208d6c35a
2018-01-28 20:00:05 +09:00
OpenStack Proposal Bot
71e979cae0 Imported Translations from Zanata
For more information about this automatic import see:
https://docs.openstack.org/i18n/latest/reviewing-translation-import.html

Change-Id: Ie34aafe6d9b54bb97469844d21de38d7c6249031
2018-01-28 07:16:20 +00:00
Luong Anh Tuan
6edfd34a53 Remove redundant import alias
This patch remove redundant import aliases and add pep8 hacking function
to check no redundant import aliases.

Co-Authored-By: Dao Cong Tien <tiendc@vn.fujitsu.com>

Change-Id: I3207cb9f0eb4b4a029b7e822b9c59cf48d1e0f9d
Closes-Bug: #1745527
2018-01-26 09:11:43 +07:00
Alexander Chadin
0c8c32e69e Fix strategy state
Change-Id: I003bb3b41aac69cc40a847f52a50c7bc4cc8d020
2018-01-25 15:41:34 +03:00
Alexander Chadin
9138b7bacb Add datasources to strategies
This patch set add datasources instead of datasource.

Change-Id: I94f17ae3a0b6a8990293dc9e33be1a2bd3432a14
2018-01-24 20:51:38 +03:00
Zuul
072822d920 Merge "Add baremetal strategy validation" 2018-01-24 14:59:14 +00:00
Zuul
f67ce8cca5 Merge "Add zone migration strategy" 2018-01-24 14:56:07 +00:00
Zuul
9e6f768263 Merge "Strategy requirements" 2018-01-24 14:53:47 +00:00
Zuul
ba9c89186b Merge "Update unreachable link" 2018-01-24 14:21:49 +00:00
Alexander Chadin
16e7d9c13b Add baremetal strategy validation
This patch set adds validation of baremetal model.

It also fixes PEP issues with storage capacity balance
strategy.

Change-Id: I53e37d91fa6c65f7c3d290747169007809100304
Depends-On: I177b443648301eb50da0da63271ecbfd9408bd4f
2018-01-24 14:35:52 +03:00
Zuul
c3536406bd Merge "Audit scoper for storage CDM" 2018-01-24 10:57:37 +00:00
Alexander Chadin
0c66fe2e65 Strategy requirements
This patch set adds /state resource to strategy API
which allows to retrieve strategy requirements.

Partially-Implements: blueprint check-strategy-requirements
Change-Id: I177b443648301eb50da0da63271ecbfd9408bd4f
2018-01-24 13:39:42 +03:00
Zuul
74933bf0ba Merge "Fix workload_stabilization unavailable nodes and instances" 2018-01-24 10:35:25 +00:00
Hidekazu Nakamura
1dae83da57 Add zone migration strategy
This patch adds hardware maintenance goal, efficacy and zone
migration strategy.

Change-Id: I5bfee421780233ffeea8c1539aba720ae554983d
Implements: blueprint zone-migration-strategy
2018-01-24 19:33:22 +09:00
Zuul
5ec8932182 Merge "Add storage capacity balance Strategy" 2018-01-24 10:22:25 +00:00
Alexander Chadin
701b258dc7 Fix workload_stabilization unavailable nodes and instances
This patch set excludes nodes and instances from auditing
if appropriate metrics aren't available.

Change-Id: I87c6c249e3962f45d082f92d7e6e0be04e101799
Closes-Bug: #1736982
2018-01-24 11:37:43 +03:00
gaofei
f7fcdf14d0 Update unreachable link
Change-Id: I74bbe5a8c4ca9df550f1279aa80a836d6a2f8a93
2018-01-24 14:40:43 +08:00
OpenStack Proposal Bot
47ba6c0808 Updated from global requirements
Change-Id: I4cbf5308061707e28c202f22e8a9bf8492742040
2018-01-24 01:42:12 +00:00
Zuul
5b5fbbedb4 Merge "Fix compute api ref link" 2018-01-23 15:16:19 +00:00
Zuul
a1c575bfc5 Merge "check audit name length" 2018-01-23 11:21:14 +00:00
deepak_mourya
27e887556d Fix compute api ref link
This is to fix some compute api ref link.

Change-Id: Id5acc4d0f635f3d19b916721b6839a0eef544b2a
2018-01-23 09:23:55 +00:00
Alexander Chadin
891f6bc241 Adapt workload_balance strategy to multiple datasource backend
This patch set:
1. Removes nova, ceilometer and gnocchi properties.
2. Adds using of datasource_backend properties along with
   statistic_aggregation method.
3. Changes type of datasource config.

Change-Id: I09d2dce00378f0ee5381d7c85006752aea6975d2
Partially-Implements: blueprint watcher-multi-datasource
2018-01-23 11:51:02 +03:00
Alexander Chadin
5dd6817d47 Adapt noisy_neighbor strategy to multiple datasource backend
Partially-Implements: blueprint watcher-multi-datasource
Change-Id: Ibcd5d0776280bb68ed838f88ebfcde27fc1a3d35
2018-01-23 11:51:02 +03:00
Alexander Chadin
7cdcb4743e Adapt basic_consolidation strategy to multiple datasource backend
Change-Id: Ie30308fd08ed1fd103b70f58f1d17b3749a6fe04
2018-01-23 11:51:02 +03:00
licanwei
6d03c4c543 check audit name length
No more than 63 characters

Change-Id: I52adbd7e9f12dd4a8b6977756d788ee0e5d6391a
Closes-Bug: #1744231
2018-01-23 00:47:26 -08:00
aditi
bcc129cf94 Audit scoper for storage CDM
This patch adds audit scoper for Storage CDM.

Change-Id: I0c5b3b652027e1394fd7744d904397ce87ed35a1
Implements: blueprint audit-scoper-for-storage-data-model
2018-01-23 13:53:31 +05:30
Zuul
40cff311c6 Merge "Adapt workload_stabilization strategy to new datasource backend" 2018-01-23 01:08:32 +00:00
OpenStack Proposal Bot
1a48a7fc57 Imported Translations from Zanata
For more information about this automatic import see:
https://docs.openstack.org/i18n/latest/reviewing-translation-import.html

Change-Id: I19a628bc7a0623e2f1ff8ab8794658bfe25801f5
2018-01-20 07:21:59 +00:00
Zuul
652aa54586 Merge "Update link address" 2018-01-19 11:40:25 +00:00
zhangdebo
42a3886ded Update link address
Link to new measurements is out of date and should be updated.
Change
https://docs.openstack.org/ceilometer/latest/contributor/new_meters.html#meters
to
https://docs.openstack.org/ceilometer/latest/contributor/measurements.html#new-measurements

Change-Id: Idc77e29a69a1f1eb9f8827fa74c9fde79e5619df
2018-01-19 07:59:15 +00:00
licanwei
3430493de1 Fix tempest devstack error
Devstack failed because mysql wasn't enabled.

Change-Id: Ifc1c00f2dddd0f3d67c6672d3b9d3d4bd78a4a90
Closes-Bug: #1744224
2018-01-18 23:33:08 -08:00
licanwei
f5bcf9d355 Add storage capacity balance Strategy
This patch adds Storage Capacity Balance Strategy to balance the
storage capacity through volume migration.

Change-Id: I52ea7ce00deb609a2f668db330f1fbc1c9932613
Implements: blueprint storage-workload-balance
2018-01-18 22:18:18 -08:00
Zuul
d809523bef Merge "Add baremetal data model" 2018-01-18 10:38:12 +00:00
Zuul
bfe3c28986 Merge "Fix compute scope test bug" 2018-01-18 09:37:24 +00:00
OpenStack Proposal Bot
3c8caa3d0a Updated from global requirements
Change-Id: I4814a236f5d015ee25b9de95dd1f3f97e375d382
2018-01-18 03:39:36 +00:00
Zuul
766d064dd0 Merge "Update pike install supermark to queens" 2018-01-17 12:34:35 +00:00
Alexander Chadin
ce196b68c4 Adapt workload_stabilization strategy to new datasource backend
This patch set:
1. Removes nova, ceilometer and gnocchi properties.
2. Adds using of datasource_backend properties along with
   statistic_aggregation method.
3. Changes type of datasource config.

Change-Id: I4a2f05772248fddd97a41e27be4094eb59ee0bdb
Partially-Implements: blueprint watcher-multi-datasource
2018-01-17 13:01:05 +03:00
OpenStack Proposal Bot
42130c42a1 Updated from global requirements
Change-Id: I4ef734eeaeee414c3e6340490f1146d537370127
2018-01-16 12:57:22 +00:00
caoyuan
1a8639d256 Update pike install supermark to queens
Change-Id: If981c77518d0605b4113f4bb4345d152545ffc52
2018-01-15 11:56:36 +00:00
zhang.lei
1702fe1a83 Add the title of API Guide
Currently, The title of API Guide is missing.[1] We should add a
title just like other projects.[2]

[1] https://docs.openstack.org/watcher/latest/api
[2] https://developer.openstack.org/api-ref/application-catalog

Change-Id: I012d746e99a68fc5f259a189188d9cea00d5a4f7
2018-01-13 08:04:36 +00:00
aditi
354ebd35cc Fix compute scope test bug
We were excluding 'INSTANCE_6'from scope, which belongs to 'NODE_3'
in scenerio_1.xml [1]. But NODE_3 is removed from model before only
as it is not in scope.

So, This Patch adds 'AZ3' in fake_scope.

[1] https://github.com/openstack/watcher/blob/master/watcher/tests/decision_engine/model/data/scenario_1.xml
Closes-Bug: #1737901

Change-Id: Ib1aaca7045908418ad0c23b718887cd89db98a83
2018-01-12 16:17:25 +05:30
Zuul
7297603f65 Merge "reset job interval when audit was updated" 2018-01-11 09:12:38 +00:00
Zuul
9626cb1356 Merge "check actionplan state when deleting actionplan" 2018-01-11 09:12:37 +00:00
Zuul
9e027940d7 Merge "use current weighted sd as min_sd when starting to simulate migrations" 2018-01-11 08:48:43 +00:00
Zuul
3754938d96 Merge "Set apscheduler logs to WARN level" 2018-01-11 05:39:10 +00:00
Zuul
8a7f930a64 Merge "update audit API description" 2018-01-11 05:32:50 +00:00
Zuul
f7e506155b Merge "Fix configuration doc link" 2018-01-10 17:02:26 +00:00
Yumeng_Bao
54da2a75fb Add baremetal data model
Change-Id: I57b7bb53b3bc84ad383ae485069274f5c5362c50
Implements: blueprint build-baremetal-data-model-in-watcher
2018-01-10 14:46:41 +08:00
Zuul
5cbb9aca7e Merge "bug fix remove volume migration type 'cold'" 2018-01-10 06:15:01 +00:00
Alexander Chadin
bd79882b16 Set apscheduler logs to WARN level
This patch set defines level of apscheduler logs as WARN.

Closes-Bug: #1742153
Change-Id: Idbb4b3e16187afc5c3969096deaf3248fcef2164
2018-01-09 16:30:14 +03:00
licanwei
960c50ba45 Fix configuration doc link
Change-Id: I7b144194287514144948f8547bc45d6bc4551a52
2018-01-07 23:36:20 -08:00
licanwei
9411f85cd2 update audit API description
Change-Id: I1d3eb9364fb5597788a282d275c71f5a314a0923
2018-01-02 23:51:05 -08:00
licanwei
b4370f0461 update action API description
POST/PATCH/DELETE actions APIs aren't permitted.

Change-Id: I4126bcc6bf6fe2628748d1f151617a38be06efd8
2017-12-28 22:06:33 -08:00
Zuul
97799521f9 Merge "correct audit parameter typo" 2017-12-28 10:54:57 +00:00
suzhengwei
96fa7f33ac use current weighted sd as min_sd when starting to simulate migrations
If it uses a specific value(usually 1 or 2) as the min_sd when starting
to simulate migrations. The first simulate_migration case will always be
less than the min_sd and come into the solution, even though the migration
will increase the weighted sd. This is unreasonable, and make migrations
among hosts back and forth

Change-Id: I7813c4c92c380c489c349444b85187c5611d9c92
Closes-Bug: #1739723
2017-12-27 15:00:57 +03:00
Zuul
1c2d0aa1f2 Merge "Updated from global requirements" 2017-12-27 10:00:01 +00:00
licanwei
070aed7076 correct audit parameter typo
Change-Id: Id98294a093ac9a704791cdbf52046ce1377f1796
2017-12-25 23:52:43 -08:00
Zuul
2b402d3cbf Merge "Fix watcher audit list command" 2017-12-26 04:49:49 +00:00
Zuul
cca3e75ac1 Merge "Add Datasource Abstraction" 2017-12-26 03:02:36 +00:00
OpenStack Proposal Bot
6f27275f44 Updated from global requirements
Change-Id: I26c1f4be398496b88b69094ec1804b07f7c1d7f1
2017-12-23 10:18:41 +00:00
Alexander Chadin
95548af426 Fix watcher audit list command
This patch set adds data migration version that fills noname audits
with name like strategy.name + '-' + audit.created_at.

Closes-Bug: #1738758
Change-Id: I1d65b3110166e9f64ce5b80a34672d24d629807d
2017-12-22 08:43:28 +00:00
licanwei
cdc847d352 check actionplan state when deleting actionplan
If actionplan is 'ONGOING' or 'PENDING',
don't delete it.

Change-Id: I8bfa31a70bba0a7adb1bfd09fc22e6a66b9ebf3a
Closes-Bug: #1738360
2017-12-21 22:32:09 -08:00
Zuul
b69244f8ef Merge "TrivialFix: remove redundant import alias" 2017-12-21 15:43:42 +00:00
Dao Cong Tien
cbd6d88025 TrivialFix: remove redundant import alias
Change-Id: Idf53683def6588e626144ecc3b74033d57ab3f87
2017-12-21 20:09:07 +07:00
Zuul
028d7c939c Merge "check audit state when deleting audit" 2017-12-20 09:04:02 +00:00
licanwei
a8fa969379 check audit state when deleting audit
If audit is 'ONGOING' or 'PENDING', don't delete audit.

Change-Id: Iac714e7e78e7bb5b52f401e5b2ad0e1d8af8bb45
Closes-Bug: #1738358
2017-12-19 18:09:42 -08:00
licanwei
80ee4b29f5 reset job interval when audit was updated
when we update a existing audit's interval, the interval of
'execute_audit' job is still the old value.
We need to update the interval of 'execute_audit' job.

Change-Id: I402efaa6b2fd3a454717c3df9746c827927ffa91
Closes-Bug: #1738140
2017-12-19 17:57:37 -08:00
Zuul
e562c9173c Merge "Updated from global requirements" 2017-12-19 16:38:39 +00:00
OpenStack Proposal Bot
ec0c359037 Updated from global requirements
Change-Id: I96d4a5a7e2b05df3f06d7c08f64cd9bcf83ff99b
2017-12-19 01:52:42 +00:00
Andreas Jaeger
3b6bef180b Fix releasenotes build
Remove a stray import of watcher project that breaks releasenotes build.

Change-Id: I4d107449b88adb19a3f269b2f33221addef0d9d6
2017-12-18 15:39:25 +01:00
Zuul
640e4e1fea Merge "Update getting scoped storage CDM" 2017-12-18 14:31:39 +00:00
Zuul
eeb817cd6e Merge "listen to 'compute.instance.rebuild.end' event" 2017-12-18 13:12:26 +00:00
Hidekazu Nakamura
c6afa7c320 Update getting scoped storage CDM
Now that CDM-scoping was implemented, Getting scoped storage model
have to be updated.
This patch updates getting storage cluster data model.

Change-Id: Iefc22b54995aa8d2f3a7b3698575f6eb800d4289
2017-12-16 15:20:58 +00:00
OpenStack Proposal Bot
9ccd17e40b Updated from global requirements
Change-Id: I0af2c9fd266f925af5e3e8731b37a00dab91d6a8
2017-12-15 22:24:15 +00:00
Zuul
2a7e0d652c Merge "'get_volume_type_by_backendname' returns a list" 2017-12-14 06:18:04 +00:00
Zuul
a94e35b60e Merge "Fix 'unable to exclude instance'" 2017-12-14 05:38:34 +00:00
Zuul
72e3d5c7f9 Merge "Add and identify excluded instances in compute CDM" 2017-12-13 13:34:33 +00:00
aditi
be56441e55 Fix 'unable to exclude instance'
Change-Id: I1599a86a2ba7d3af755fb1412a5e38516c736957
Closes-Bug: #1736129
2017-12-12 10:29:35 +00:00
Zuul
aa2b213a45 Merge "Register default policies in code" 2017-12-12 03:38:13 +00:00
Zuul
668513d771 Merge "Updated from global requirements" 2017-12-12 02:57:47 +00:00
Lance Bragstad
0242d33adb Register default policies in code
This commit registers all policies formally kept in policy.json as
defaults in code. This is an effort to make policy management easier
for operators. More information on this initiative can be found
below:

  https://governance.openstack.org/tc/goals/queens/policy-in-code.html

bp policy-and-docs-in-code

Change-Id: Ibab08f8e1c95b86e08737c67a39c293566dbabc7
2017-12-11 15:19:10 +03:00
suzhengwei
c38dc9828b listen to 'compute.instance.rebuild.end' event
In one integrated cloud env, there would be many solutions, which would
make the compute resource strongly relocated. Watcher should listen to
all the notifications which represent the compute resource changes, to
update compute CDM. If not, the compute CDM will be stale, Watcher
couldn't work steadily and harmoniously.

Change-Id: I793131dd8f24f1ac5f5a6a070bb4fe7980c8dfb2
Implements:blueprint listen-all-necessary-notifications
2017-12-08 16:18:35 +08:00
Zuul
c2e16bfa96 Merge "listen to 'compute.instance.resize.confirm.end' event" 2017-12-08 03:11:54 +00:00
OpenStack Proposal Bot
4ce1a9096b Updated from global requirements
Change-Id: I04a2a04de3b32570bb0afaf9eb736976e888a031
2017-12-07 13:53:09 +00:00
Zuul
13644429b7 Merge "Fix migrate action with migration_type 'cold'" 2017-12-07 13:15:28 +00:00
Zuul
b8cc506fbe Merge "Updated from global requirements" 2017-12-07 05:06:45 +00:00
Yumeng_Bao
02163d64aa bug fix remove volume migration type 'cold'
Migration action 'cold' is not intuitive for the developers and users,
so this patch replaces it with ‘migrate’ and 'retype'.

Change-Id: I58acac741499f47e79630a6031d44088681e038a
Closes-Bug: #1733247
2017-12-06 18:03:25 +08:00
suzhengwei
d91f0bff22 Add and identify excluded instances in compute CDM
Change-Id: If03893c5e9b6a37e1126ad91e4f3bfafe0f101d9
Implements:blueprint compute-cdm-include-all-instances
2017-12-06 17:43:42 +08:00
licanwei
c91f6479f0 Server with PAUSE status can also live-migrate
Closes-Bug: #1728477
Change-Id: I39a2672df842b62177fd0c4dbec7b92b398cfb96
2017-12-06 02:02:44 +00:00
Hidekazu Nakamura
92572c5dec Fix migrate action with migration_type 'cold'
Migration action with migration_type 'cold' does not work.
This patch fixes nova_helper to follow Pike release python-novaclient.

Change-Id: I0637cefad68cd4b7077a5d3e6b5db5562e7f2917
Closes-Bug: #1736624
2017-12-06 09:39:30 +09:00
OpenStack Proposal Bot
a8f08065fd Updated from global requirements
Change-Id: I2171946082a8a9daf7e5edc20bfe0c8cb084768f
2017-12-05 16:58:02 +00:00
aditi
e401cb7c9d Add Datasource Abstraction
This patch set adds, datasource abstraction layer.

Change-Id: Id828e427b998aa34efa07e04e615c82c5730d3c9
Partially-Implements: blueprint watcher-multi-datasource
2017-12-05 17:33:04 +03:00
Zuul
0745d904fc Merge "Notifications Changes Multiple Global Efficacy" 2017-12-01 09:26:17 +00:00
Zuul
bc4a58d2d7 Merge "Make gnocchi as default datasource" 2017-12-01 09:08:57 +00:00
Alexander Chadin
f14795d29f Make gnocchi as default datasource
This patch set follows deprecation steps
and changes default datasource to gnocchi

Closes-Bug: #1735180
Change-Id: I3b7ec47af7707359373a424a6469d28cbf9ce177
2017-12-01 08:21:44 +00:00
Zuul
e0104074b6 Merge "Updated from global requirements" 2017-11-30 14:04:55 +00:00
Zuul
2993dea376 Merge "extend-node-status" 2017-11-29 13:35:54 +00:00
Zuul
17b6019ea9 Merge "Fix Bug Unable to get scoped data model" 2017-11-29 10:06:17 +00:00
OpenStack Proposal Bot
5969e5b52a Updated from global requirements
Change-Id: Idc1a12df6d888880ff7858cff18cc1972920204d
2017-11-29 09:26:19 +00:00
aditi
e55f3793b6 Fix Bug Unable to get scoped data model
This patch removes 'audit_scope' from __init__ of
BaseClusterDataModelCollector class, as it is a singleton class
and cannot be instantiate more than once.

A new method is defined in BaseClusterDataModelCollector in place
of property audit_scope_handler, which takes audit_scope as
argument.

Change-Id: I0664c151d71a711c118d43c180d8b0760b1c81fa
Closes-Bug: #1732849
2017-11-28 10:24:15 +00:00
suzhengwei
901c598dd7 listen to 'compute.instance.resize.confirm.end' event
In one integrated cloud env, there would be many solutions, which would
make the compute resource strongly relocated. Watcher should listen to
all the notifications which represent the compute resource changes, to
update compute CDM. If not, the compute CDM will be stale, Watcher
couldn't work steadily and harmoniously.

Change-Id: I57173f0cce0717aa36c5ff758d972d38013e3ef8
Implements:blueprint listen-all-necessary-notifications
2017-11-27 17:20:49 +08:00
aditi
e41a90d7ad Notifications Changes Multiple Global Efficacy
This patch adds notfication changes after changing the type
of global_efficacy in ActionPlan objects.

Change-Id: I1116cf1d19e4b19e19789f943a631d0400871766
Partially-Implements: blueprint multiple-global-efficacy-indicator
2017-11-27 14:47:02 +05:30
licanwei
fa31341bbb 'get_volume_type_by_backendname' returns a list
Storage pool can have many volume types,
'get_volume_type_by_backendname' should return a list of types.

Closes-Bug: #1733257
Change-Id: I877d5886259e482089ed0f9944d97bb99f375824
2017-11-26 23:28:56 -08:00
Zuul
051b4fcd06 Merge "Remove setting of version/release from releasenotes" 2017-11-22 12:15:57 +00:00
Zuul
cd045400ed Merge "Can't cancell CONTINUOUS audit" 2017-11-22 06:57:50 +00:00
Zuul
2db668af30 Merge "Add app.wsgi to target of pep8" 2017-11-20 08:35:00 +00:00
Zuul
39b1fcf07f Merge "[Doc] Fix ubuntu version in devstack installation" 2017-11-20 01:09:46 +00:00
chao liu
94babf61da Add app.wsgi to target of pep8
The app.wsgi file should be adjusted to meet pep8 standards and
apply pep8 check to app.wsgi automatically.

Change-Id: I34ec9ce56a329ede76d3d69f6e973d66350d85d1
2017-11-18 09:41:37 +00:00
Hidekazu Nakamura
a5fba7ce28 [Doc] Fix ubuntu version in devstack installation
This patch updates ubuntu version from 14.04 to 16.04
in devstack installation.

Change-Id: Icf096dd8f3fc366567f9cde329987c4f9f02ad48
2017-11-17 13:25:34 +09:00
aditi
24e01b6c98 Remove setting of version/release from releasenotes
Release notes are version independent, so remove version/release
values.
see the discussion [1] and patch [2]
[1] http://lists.openstack.org/pipermail/openstack-dev/2017-November/124480.html
[2] https://review.openstack.org/#/c/520748/

Change-Id: I2c76dc467e1b722531ba71fb589594ae9fcc88d3
2017-11-17 11:33:20 +09:00
OpenStack Proposal Bot
4007f93aac Updated from global requirements
Change-Id: I9be5c9b8b858f5d5d555da5c02337885ecfa901d
2017-11-16 11:31:33 +00:00
OpenStack Proposal Bot
77c9f88fc4 Updated from global requirements
Change-Id: Iccd6926b31e04e4a24fbd6bf68692bd840c66f7f
2017-11-13 22:00:07 +00:00
Zuul
e9b7f067c5 Merge "Migrate to Zuul v3" 2017-11-10 08:27:28 +00:00
Zuul
f8aa02c4a7 Merge "Multiple global efficacy" 2017-11-10 08:21:26 +00:00
Alexander Chadin
3595108e49 Migrate to Zuul v3
This patch does step 1 in the docs: Move Legacy Jobs to Projects.

Partial-Implements: blueprint migrate-to-zuulv3
Change-Id: I0c0713260c2dfa2ba64a5746c342db01c1bc3d75
2017-11-09 11:51:13 +03:00
Hidekazu Nakamura
d536ed248b Fix test runner config issues with os-testr 1.0.0
The os-testr 1.0.0 release had a couple of required config changes due
to it's internal usage of stestr. This commit fixes those by adding a
.stestr.conf (to remove a warning) sets the fixture env variables in
the tox.ini instead of being hidden in .testr.conf and removing the
quotes around posargs to make passing args to ostestr actually work.
Also to keep the expected dev experience stestr is used directly for
places where ostestr was called directly.

Change-Id: I785b0dc1720328b119f0978aa573ad0b89e54c75
Closes-Bug: #1731155
2017-11-09 17:31:39 +09:00
aditi
71730c0eaf Multiple global efficacy
This patch update the global efficacy for server consolidation
strategy, test cases and general format.

Change-Id: I62af1e4be415998669f938b3d587c1ccf4293419
Implements: blueprint multiple-global-efficacy-indicator
2017-11-09 14:51:17 +09:00
Vu Cong Tuan
1b4c5dfc8b Do not use “-y” for package install
According to "code conventions" [1], do not use "-y" option.
Instead, use apt-get install package, yum install package,
or zypper install package.

[1] https://docs.openstack.org/doc-contrib-guide/writing-style/
code-conventions.html

Change-Id: I174c8a0c653e322bbf951d72445b1a43251baa7e
2017-11-08 16:13:30 +07:00
Zuul
4179cfd036 Merge "check task_state in the live_migrate_instance" 2017-11-08 01:50:38 +00:00
Zuul
49550db566 Merge "Change HTTP to HTTPS" 2017-11-08 01:43:26 +00:00
Zuul
e0eba0ee7b Merge "Update doc and add release note about cdm-scoping" 2017-11-07 02:36:38 +00:00
licanwei
165853ee2c check task_state in the live_migrate_instance
If server migration fails, the while loop will not break
until retry to 0,
we can check the task_state to avoid this situation.

Closes-Bug: #1728476
Change-Id: I07e1048eb736263a261456ee78c96fee9db13cb5
2017-11-05 20:04:45 -08:00
XieYingYun
0a7152fa55 Change HTTP to HTTPS
Use https instead of http to ensure the safety without containing our
account/password information

Change-Id: I2e4f120f1d57c6c666d65a9a279eddefd112bf23
2017-11-05 20:20:46 -07:00
OpenStack Proposal Bot
6c29df11ca Updated from global requirements
Change-Id: I691bd81b1b9933211faa336b1ac49aa5a1a7bf17
2017-11-06 02:07:12 +00:00
licanwei
55bd0fd038 Can't cancell CONTINUOUS audit
If scheduler uses db job store, the self.scheduler is None
beacuse execute_audit is class method.
We get [] from self.scheduler.get_jobs()
and can't remove the cancelled audit.

Change-Id: I1768c847465bbefbc9794281328edb07fea83b03
Closes-Bug: #1726345
2017-11-02 21:05:41 -07:00
suzhengwei
907cc2df16 add name for audit, update audit notifications
upgrade notifications

Change-Id: Ia8b7f36a8a2965bc8ec2243a10556592926297b2
Implements:blueprint add-name-for-audit
2017-11-01 10:39:43 +08:00
Hidekazu Nakamura
8dcac1597b Update doc and add release note about cdm-scoping
This patch updates document and add release note for cdm-scoping.

Change-Id: I8e9099aa5caf6bf17ea912e7b1a600af3b6d519d
Partially-Implements: blueprint cdm-scoping
2017-10-31 10:01:52 +09:00
Zuul
a3be1587e3 Merge "Update the useful links for Rally job" 2017-10-30 03:13:09 +00:00
Zuul
aa72f984e4 Merge "add name for audit, changes for watcher api/db" 2017-10-30 02:11:26 +00:00
caoyuan
bcd2040025 Update the useful links for Rally job
Change-Id: I1d6463701f9e3d99c261e8738ba0291c32632947
2017-10-30 00:32:50 +00:00
Zuul
f2c9dc9c32 Merge "update API ref doc for ScoringEngine" 2017-10-27 03:33:55 +00:00
Zuul
6c94c235fc Merge "Fix the strategy path of outlet_temp_control.py" 2017-10-26 02:30:20 +00:00
Zuul
7ed45e3ef1 Merge "Add cdm-scoping" 2017-10-25 13:52:10 +00:00
aditi
8722951022 update API ref doc for ScoringEngine
Change-Id: Icdfff4659d280a30768aebc0e8f161a699ffd793
Closes-Bug: #1726646
2017-10-24 14:16:19 +09:00
caoyuan
568d4e831c Fix the strategy path of outlet_temp_control.py
1. fix the path of outlet_temp_control.py
2. remove the unnecessary noqa

Change-Id: Ieb33776baeaa936faf940d9886ffed8ec30e91b3
2017-10-24 01:29:17 +00:00
Zuul
deefc857ba Merge "Optimize the link address" 2017-10-24 00:25:52 +00:00
Zuul
d33736e7f0 Merge "Imported Translations from Zanata" 2017-10-24 00:21:44 +00:00
Zuul
1b1779cc49 Merge "Fix a typo" 2017-10-24 00:21:43 +00:00
Zuul
d727bc3076 Merge "Unify the oslo_log import usage" 2017-10-24 00:21:43 +00:00
Zuul
875b7e1ca3 Merge "Optimise indentation for db client" 2017-10-24 00:21:42 +00:00
Zuul
c7f8755f9c Merge "Correct the schema format" 2017-10-24 00:20:55 +00:00
zhengwei6082
0472715e0c Optimize the link address
Use https instead of http to ensure the safety without containing our
account/password information

Change-Id: I16bdf6067fba4ea841071100d68edae7750946de
2017-10-23 07:03:41 +00:00
OpenStack Proposal Bot
2482e82548 Imported Translations from Zanata
For more information about this automatic import see:
https://docs.openstack.org/i18n/latest/reviewing-translation-import.html

Change-Id: I73cd252d637f890ed4ba1ea9abe06d5c47917a86
2017-10-23 06:17:23 +00:00
Zuul
e9c420467e Merge "Optimize check_migrated in cinder_helper.py" 2017-10-23 03:53:17 +00:00
Zuul
2d5db7082b Merge "Optimize live_migrate_instance" 2017-10-23 03:53:17 +00:00
caoyuan
4a3a50435a Fix a typo
Update the "peformance" to "performance"

Change-Id: Ief94893db2a3d6d83d865cfe2aa45f524309ff8d
2017-10-21 14:54:16 +08:00
caoyuan
05b57fee7a Unify the oslo_log import usage
In watcher project, some py file use "from oslo_log import log as logging"
for import, but more use "from oslo_log import log"
like https://github.com/openstack/watcher/blob/master/watcher/decision_engine/strategy/strategies/dummy_strategy.py#L19
this patch to unify it.

Change-Id: I9c667bb202bebc7942d1af5ce438375285c2e2ba
2017-10-21 06:32:59 +00:00
caoyuan
3729e39552 Optimise indentation for db client
Optimise indentation for db client, just like the others:
https://github.com/openstack/watcher/blob/master/watcher/conf/nova_client.py#L22

Change-Id: Icfbd4f26ce048fe3c3db430d95795fb0e58b7161
2017-10-21 13:55:47 +08:00
caoyuan
91911c8284 Correct the schema format
refer to https://github.com/openstack/watcher/blob/master/watcher/applier/actions/migration.py#L46

Change-Id: I2da8585ce978034fc9a79c2a0cf7bfb6eed487e2
2017-10-21 13:03:01 +08:00
suzhengwei
d7d56cbd79 add name for audit, changes for watcher api/db
Change-Id: Ibe04f5375d741d15999fde6faf767f15311c6351
Implements:blueprint add-name-for-audit
2017-10-20 14:17:20 +08:00
licanwei
d722b62b97 Optimize check_migrated in cinder_helper.py
There are more than one 'migrating' status in the volume migration.
Others include starting, completing and so on.
So we should check the final status 'success' and 'error'.

Change-Id: I8ee9330aa32ec4516f2bf9e046ea68a72bc8a53d
2017-10-16 00:55:55 -07:00
licanwei
bf713ac7e1 Optimize live_migrate_instance
https://github.com/openstack/python-novaclient/blob/
master/novaclient/v2/servers.py#L468
From nova api version 2.25(Mitaka release), the default value of
block_migration is None which is mapped to 'auto'.
So we can remove 'block_migration' from live_migrate_instance.

Change-Id: I75a581d3146824b1146e2acf5a7fbe4f8368a4e8
2017-10-15 20:22:13 -07:00
Hidekazu Nakamura
51b3a15c90 Add cdm-scoping
This patch implements cdm-scoping.
Scoping yaml file is the following:

- compute:
  - availability_zones:
    - name: nova
  - host_aggregates:
    - id: 1
    - name: agg
  - exclude:
    - compute_nodes:
      - name: w012

Change-Id: I44e00218e90c5b08b397b2a9d7fed7c195f6dc55
Partially-Implements: blueprint cdm-scoping
2017-09-27 17:39:24 +09:00
suzhengwei
74bc31e562 extend-node-status
add 'disabled_reason' filed into 'ComputeNode' resource, to distinguish
which nodes are disabled by Watcher and which are not by Watcher.

Implements:blueprint extend-node-status

Change-Id: I7175f14870834a4582e45309529d7e8d9fbb2e6f
2017-09-18 14:27:58 +08:00
226 changed files with 9576 additions and 1702 deletions

1
.gitignore vendored
View File

@@ -24,6 +24,7 @@ pip-log.txt
.coverage*
.tox
nosetests.xml
.stestr/
.testrepository
.venv
.idea

View File

@@ -1,4 +1,5 @@
[gerrit]
host=review.openstack.org
host=review.opendev.org
port=29418
project=openstack/watcher.git
defaultbranch=stable/queens

4
.stestr.conf Normal file
View File

@@ -0,0 +1,4 @@
[DEFAULT]
test_path=${OS_TEST_PATH:-./watcher/tests}
top_dir=./

45
.zuul.yaml Normal file
View File

@@ -0,0 +1,45 @@
- project:
templates:
- openstack-python-jobs
- openstack-python35-jobs
- publish-openstack-sphinx-docs
- check-requirements
- release-notes-jobs
check:
jobs:
- watcher-tempest-multinode
gate:
queue: watcher
- job:
name: watcher-tempest-base-multinode
parent: legacy-dsvm-base-multinode
run: playbooks/legacy/watcher-tempest-base-multinode/run.yaml
post-run: playbooks/legacy/watcher-tempest-base-multinode/post.yaml
timeout: 4200
required-projects:
- openstack/devstack-gate
- openstack/python-openstackclient
- openstack/python-watcherclient
- openstack/watcher
- openstack/watcher-tempest-plugin
nodeset: legacy-ubuntu-xenial-2-node
- job:
name: watcher-tempest-multinode
parent: watcher-tempest-base-multinode
voting: false
- job:
# This job is used by python-watcherclient repo
name: watcherclient-tempest-functional
parent: legacy-dsvm-base
run: playbooks/legacy/watcherclient-tempest-functional/run.yaml
post-run: playbooks/legacy/watcherclient-tempest-functional/post.yaml
timeout: 4200
required-projects:
- openstack/devstack
- openstack/devstack-gate
- openstack/python-openstackclient
- openstack/python-watcherclient
- openstack/watcher

View File

@@ -42,7 +42,7 @@ WATCHER_AUTH_CACHE_DIR=${WATCHER_AUTH_CACHE_DIR:-/var/cache/watcher}
WATCHER_CONF_DIR=/etc/watcher
WATCHER_CONF=$WATCHER_CONF_DIR/watcher.conf
WATCHER_POLICY_JSON=$WATCHER_CONF_DIR/policy.json
WATCHER_POLICY_YAML=$WATCHER_CONF_DIR/policy.yaml.sample
WATCHER_DEVSTACK_DIR=$WATCHER_DIR/devstack
WATCHER_DEVSTACK_FILES_DIR=$WATCHER_DEVSTACK_DIR/files
@@ -106,7 +106,25 @@ function configure_watcher {
# Put config files in ``/etc/watcher`` for everyone to find
sudo install -d -o $STACK_USER $WATCHER_CONF_DIR
install_default_policy watcher
local project=watcher
local project_uc
project_uc=$(echo watcher|tr a-z A-Z)
local conf_dir="${project_uc}_CONF_DIR"
# eval conf dir to get the variable
conf_dir="${!conf_dir}"
local project_dir="${project_uc}_DIR"
# eval project dir to get the variable
project_dir="${!project_dir}"
local sample_conf_dir="${project_dir}/etc/${project}"
local sample_policy_dir="${project_dir}/etc/${project}/policy.d"
local sample_policy_generator="${project_dir}/etc/${project}/oslo-policy-generator/watcher-policy-generator.conf"
# first generate policy.yaml
oslopolicy-sample-generator --config-file $sample_policy_generator
# then optionally copy over policy.d
if [[ -d $sample_policy_dir ]]; then
cp -r $sample_policy_dir $conf_dir/policy.d
fi
# Rebuild the config file from scratch
create_watcher_conf
@@ -163,7 +181,7 @@ function create_watcher_conf {
iniset $WATCHER_CONF api host "$WATCHER_SERVICE_HOST"
iniset $WATCHER_CONF api port "$WATCHER_SERVICE_PORT"
iniset $WATCHER_CONF oslo_policy policy_file $WATCHER_POLICY_JSON
iniset $WATCHER_CONF oslo_policy policy_file $WATCHER_POLICY_YAML
iniset $WATCHER_CONF oslo_messaging_rabbit rabbit_userid $RABBIT_USERID
iniset $WATCHER_CONF oslo_messaging_rabbit rabbit_password $RABBIT_PASSWORD
@@ -296,6 +314,7 @@ function start_watcher {
function stop_watcher {
if [[ "$WATCHER_USE_MOD_WSGI" == "True" ]]; then
disable_apache_site watcher-api
restart_apache_server
else
stop_process watcher-api
fi

View File

@@ -35,7 +35,7 @@ VNCSERVER_PROXYCLIENT_ADDRESS=$HOST_IP
NOVA_INSTANCES_PATH=/opt/stack/data/instances
# Enable the Ceilometer plugin for the compute agent
enable_plugin ceilometer git://git.openstack.org/openstack/ceilometer
enable_plugin ceilometer https://git.openstack.org/openstack/ceilometer
disable_service ceilometer-acentral,ceilometer-collector,ceilometer-api
LOGFILE=$DEST/logs/stack.sh.log

View File

@@ -25,13 +25,13 @@ MULTI_HOST=1
disable_service n-cpu
# Enable the Watcher Dashboard plugin
enable_plugin watcher-dashboard git://git.openstack.org/openstack/watcher-dashboard
enable_plugin watcher-dashboard https://git.openstack.org/openstack/watcher-dashboard
# Enable the Watcher plugin
enable_plugin watcher git://git.openstack.org/openstack/watcher
enable_plugin watcher https://git.openstack.org/openstack/watcher
# Enable the Ceilometer plugin
enable_plugin ceilometer git://git.openstack.org/openstack/ceilometer
enable_plugin ceilometer https://git.openstack.org/openstack/ceilometer
# This is the controller node, so disable the ceilometer compute agent
disable_service ceilometer-acompute

View File

@@ -3,6 +3,9 @@
# Make sure rabbit is enabled
enable_service rabbit
# Make sure mysql is enabled
enable_service mysql
# Enable Watcher services
enable_service watcher-api
enable_service watcher-decision-engine

View File

@@ -20,7 +20,7 @@
"watcher_object.name": "TerseActionPlanPayload",
"watcher_object.data": {
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
"global_efficacy": {},
"global_efficacy": [],
"created_at": "2016-10-18T09:52:05Z",
"updated_at": null,
"state": "CANCELLING",

View File

@@ -30,7 +30,7 @@
"watcher_object.name": "TerseActionPlanPayload",
"watcher_object.data": {
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
"global_efficacy": {},
"global_efficacy": [],
"created_at": "2016-10-18T09:52:05Z",
"updated_at": null,
"state": "CANCELLING",

View File

@@ -20,7 +20,7 @@
"watcher_object.name": "TerseActionPlanPayload",
"watcher_object.data": {
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
"global_efficacy": {},
"global_efficacy": [],
"created_at": "2016-10-18T09:52:05Z",
"updated_at": null,
"state": "CANCELLING",

View File

@@ -20,7 +20,7 @@
"watcher_object.name": "TerseActionPlanPayload",
"watcher_object.data": {
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
"global_efficacy": {},
"global_efficacy": [],
"created_at": "2016-10-18T09:52:05Z",
"updated_at": null,
"state": "ONGOING",

View File

@@ -30,7 +30,7 @@
"watcher_object.name": "TerseActionPlanPayload",
"watcher_object.data": {
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
"global_efficacy": {},
"global_efficacy":[],
"created_at": "2016-10-18T09:52:05Z",
"updated_at": null,
"state": "ONGOING",

View File

@@ -20,7 +20,7 @@
"watcher_object.name": "TerseActionPlanPayload",
"watcher_object.data": {
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
"global_efficacy": {},
"global_efficacy": [],
"created_at": "2016-10-18T09:52:05Z",
"updated_at": null,
"state": "ONGOING",

View File

@@ -29,7 +29,7 @@
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
"fault": null,
"state": "CANCELLED",
"global_efficacy": {},
"global_efficacy": [],
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
"strategy": {
"watcher_object.namespace": "watcher",

View File

@@ -57,7 +57,7 @@
"state": "SUCCEEDED"
}
},
"global_efficacy": {},
"global_efficacy": [],
"state": "CANCELLING"
}
},

View File

@@ -29,7 +29,7 @@
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
"fault": null,
"state": "CANCELLING",
"global_efficacy": {},
"global_efficacy": [],
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
"strategy": {
"watcher_object.namespace": "watcher",

View File

@@ -23,6 +23,7 @@
"audit": {
"watcher_object.version": "1.0",
"watcher_object.data": {
"name": "my_audit",
"audit_type": "ONESHOT",
"scope": [],
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",

View File

@@ -8,6 +8,7 @@
"audit_uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
"audit": {
"watcher_object.data": {
"name": "my_audit",
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",

View File

@@ -15,6 +15,7 @@
"watcher_object.data": {
"created_at": "2016-10-18T09:52:05Z",
"deleted_at": null,
"name": "my_audit",
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
@@ -29,7 +30,7 @@
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
"fault": null,
"state": "ONGOING",
"global_efficacy": {},
"global_efficacy": [],
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
"strategy": {
"watcher_object.namespace": "watcher",

View File

@@ -45,6 +45,7 @@
"watcher_object.name": "TerseAuditPayload",
"watcher_object.data": {
"parameters": {},
"name": "my_audit",
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
@@ -57,7 +58,7 @@
"state": "PENDING"
}
},
"global_efficacy": {},
"global_efficacy": [],
"state": "ONGOING"
}
},

View File

@@ -15,6 +15,7 @@
"watcher_object.data": {
"created_at": "2016-10-18T09:52:05Z",
"deleted_at": null,
"name": "my_audit",
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
@@ -29,7 +30,7 @@
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
"fault": null,
"state": "ONGOING",
"global_efficacy": {},
"global_efficacy": [],
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
"strategy": {
"watcher_object.namespace": "watcher",

View File

@@ -6,6 +6,7 @@
"audit": {
"watcher_object.version": "1.0",
"watcher_object.data": {
"name": "my_audit",
"audit_type": "ONESHOT",
"scope": [],
"created_at": "2016-10-18T09:52:05Z",

View File

@@ -2,6 +2,7 @@
"priority": "INFO",
"payload": {
"watcher_object.data": {
"name": "my_audit",
"audit_type": "ONESHOT",
"parameters": {
"para2": "hello",

View File

@@ -2,6 +2,7 @@
"priority": "INFO",
"payload": {
"watcher_object.data": {
"name": "my_audit",
"audit_type": "ONESHOT",
"parameters": {
"para2": "hello",

View File

@@ -2,6 +2,7 @@
"priority": "INFO",
"payload": {
"watcher_object.data": {
"name": "my_audit",
"audit_type": "ONESHOT",
"parameters": {
"para2": "hello",

View File

@@ -2,6 +2,7 @@
"priority": "ERROR",
"payload": {
"watcher_object.data": {
"name": "my_audit",
"audit_type": "ONESHOT",
"parameters": {
"para2": "hello",

View File

@@ -2,6 +2,7 @@
"priority": "INFO",
"payload": {
"watcher_object.data": {
"name": "my_audit",
"audit_type": "ONESHOT",
"parameters": {
"para2": "hello",

View File

@@ -2,6 +2,7 @@
"priority": "INFO",
"payload": {
"watcher_object.data": {
"name": "my_audit",
"audit_type": "ONESHOT",
"parameters": {
"para2": "hello",

View File

@@ -2,6 +2,7 @@
"priority": "ERROR",
"payload": {
"watcher_object.data": {
"name": "my_audit",
"audit_type": "ONESHOT",
"parameters": {
"para2": "hello",

View File

@@ -2,6 +2,7 @@
"priority": "INFO",
"payload": {
"watcher_object.data": {
"name": "my_audit",
"audit_type": "ONESHOT",
"parameters": {
"para2": "hello",

View File

@@ -4,6 +4,7 @@
"payload": {
"watcher_object.name": "AuditUpdatePayload",
"watcher_object.data": {
"name": "my_audit",
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
"strategy": {
"watcher_object.name": "StrategyPayload",

View File

@@ -126,7 +126,7 @@ Here is single Dockerfile snippet you can use to run your Docker container:
MAINTAINER David TARDIVEL <david.tardivel@b-com.com>
RUN apt-get update
RUN apt-get dist-upgrade -y
RUN apt-get dist-upgrade
RUN apt-get install vim net-tools
RUN apt-get install experimental watcher-api

View File

@@ -1,3 +1,7 @@
==================================================
OpenStack Infrastructure Optimization Service APIs
==================================================
.. toctree::
:maxdepth: 1

View File

@@ -86,3 +86,15 @@ Actions
.. autotype:: watcher.api.controllers.v1.action.Action
:members:
Scoring Engine
==============
.. rest-controller:: watcher.api.controllers.v1.scoring_engine:ScoringEngineController
:webprefix: /v1/scoring_engine
.. autotype:: watcher.api.controllers.v1.scoring_engine.ScoringEngineCollection
:members:
.. autotype:: watcher.api.controllers.v1.scoring_engine.ScoringEngine
:members:

View File

@@ -165,7 +165,7 @@ You can easily generate and update a sample configuration file
named :ref:`watcher.conf.sample <watcher_sample_configuration_files>` by using
these following commands::
$ git clone git://git.openstack.org/openstack/watcher
$ git clone https://git.openstack.org/openstack/watcher
$ cd watcher/
$ tox -e genconfig
$ vi etc/watcher/watcher.conf.sample
@@ -200,8 +200,8 @@ configuration file, in order:
Although some configuration options are mentioned here, it is recommended that
you review all the `available options
<https://git.openstack.org/cgit/openstack/watcher/tree/etc/watcher/watcher.conf.sample>`_
you review all the :ref:`available options
<watcher_sample_configuration_files>`
so that the watcher service is configured for your needs.
#. The Watcher Service stores information in a database. This guide uses the
@@ -391,7 +391,7 @@ 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:
#. https://docs.openstack.org/ceilometer/latest/contributor/new_meters.html#meters
#. https://docs.openstack.org/ceilometer/latest/contributor/measurements.html#new-measurements
The Ceilometer collector uses a pluggable storage system, meaning that you can
pick any database system you prefer.

View File

@@ -24,8 +24,8 @@ signed OpenStack's contributor's agreement.
.. seealso::
* http://docs.openstack.org/infra/manual/developers.html
* http://wiki.openstack.org/CLA
* https://docs.openstack.org/infra/manual/developers.html
* https://wiki.openstack.org/CLA
LaunchPad Project
-----------------
@@ -37,22 +37,22 @@ notifications of important events.
.. seealso::
* http://launchpad.net
* http://launchpad.net/watcher
* http://launchpad.net/~openstack
* https://launchpad.net
* https://launchpad.net/watcher
* https://launchpad.net/~openstack
Project Hosting Details
-----------------------
Bug tracker
http://launchpad.net/watcher
https://launchpad.net/watcher
Mailing list (prefix subjects with ``[watcher]`` for faster responses)
http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev
https://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev
Wiki
http://wiki.openstack.org/Watcher
https://wiki.openstack.org/Watcher
Code Hosting
https://git.openstack.org/cgit/openstack/watcher

View File

@@ -19,7 +19,7 @@ model. To enable the Watcher plugin with DevStack, add the following to the
`[[local|localrc]]` section of your controller's `local.conf` to enable the
Watcher plugin::
enable_plugin watcher git://git.openstack.org/openstack/watcher
enable_plugin watcher https://git.openstack.org/openstack/watcher
For more detailed instructions, see `Detailed DevStack Instructions`_. Check
out the `DevStack documentation`_ for more information regarding DevStack.
@@ -37,7 +37,7 @@ Detailed DevStack Instructions
needed (i.e., no computes are needed if you want to just experiment with
the Watcher services). These servers can be VMs running on your local
machine via VirtualBox if you prefer. DevStack currently recommends that
you use Ubuntu 14.04 LTS. The servers should also have connections to the
you use Ubuntu 16.04 LTS. The servers should also have connections to the
same network such that they are all able to communicate with one another.
#. For each server, clone the DevStack repository and create the stack user::

View File

@@ -69,8 +69,8 @@ itself.
These dependencies can be installed from PyPi_ using the Python tool pip_.
.. _PyPi: http://pypi.python.org/
.. _pip: http://pypi.python.org/pypi/pip
.. _PyPi: https://pypi.python.org/
.. _pip: https://pypi.python.org/pypi/pip
However, your system *may* need additional dependencies that `pip` (and by
extension, PyPi) cannot satisfy. These dependencies should be installed
@@ -125,7 +125,7 @@ You can re-activate this virtualenv for your current shell using:
For more information on virtual environments, see virtualenv_.
.. _virtualenv: http://www.virtualenv.org/
.. _virtualenv: https://www.virtualenv.org/

View File

@@ -28,6 +28,8 @@ In order to create a new cluster data model collector, you have to:
- Implement its :py:meth:`~.BaseClusterDataModelCollector.execute` abstract
method to return your entire cluster data model that this method should
build.
- Implement its :py:meth:`~.BaseClusterDataModelCollector.audit_scope_handler`
abstract property to return your audit scope handler.
- Implement its :py:meth:`~.Goal.notification_endpoints` abstract property to
return the list of all the :py:class:`~.base.NotificationEndpoint` instances
that will be responsible for handling incoming notifications in order to
@@ -57,6 +59,10 @@ Here is an example showing how you can write a plugin called
# Do something here...
return model
@property
def audit_scope_handler(self):
return None
@property
def notification_endpoints(self):
return []
@@ -135,6 +141,10 @@ class method as followed:
# Do something here...
return model
@property
def audit_scope_handler(self):
return None
@property
def notification_endpoints(self):
return []

View File

@@ -263,7 +263,7 @@ requires new metrics not covered by Ceilometer, you can add them through a
`Ceilometer plugin`_.
.. _`Helper`: https://github.com/openstack/watcher/blob/master/watcher/decision_engine/cluster/history/ceilometer.py
.. _`Helper`: https://github.com/openstack/watcher/blob/master/watcher/datasource/ceilometer.py
.. _`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

View File

@@ -267,7 +267,7 @@ the same goal and same workload of the :ref:`Cluster <cluster_definition>`.
Project
=======
:ref:`Projects <project_definition>` represent the base unit of ownership
:ref:`Projects <project_definition>` represent the base unit of "ownership"
in OpenStack, in that all :ref:`resources <managed_resource_definition>` in
OpenStack should be owned by a specific :ref:`project <project_definition>`.
In OpenStack Identity, a :ref:`project <project_definition>` must be owned by a

View File

@@ -75,7 +75,7 @@ table(action_plans) {
foreign_key("strategy_id : Integer")
uuid : String[36]
state : String[20], nullable
global_efficacy : JSONEncodedDict, nullable
global_efficacy : JSONEncodedList, nullable
created_at : DateTime
updated_at : DateTime

View File

@@ -26,7 +26,7 @@
[keystone_authtoken]
...
auth_uri = http://controller:5000
www_authenticate_uri = http://controller:5000
auth_url = http://controller:35357
memcached_servers = controller:11211
auth_type = password

View File

@@ -10,7 +10,7 @@ Infrastructure Optimization service
verify.rst
next-steps.rst
The Infrastructure Optimization service (watcher) provides
The Infrastructure Optimization service (Watcher) provides
flexible and scalable resource optimization service for
multi-tenant OpenStack-based clouds.
@@ -21,7 +21,7 @@ applier. This provides a robust framework to realize a wide
range of cloud optimization goals, including the reduction
of data center operating costs, increased system performance
via intelligent virtual machine migration, increased energy
efficiencyand more!
efficiency and more!
Watcher also supports a pluggable architecture by which custom
optimization algorithms, data metrics and data profilers can be
@@ -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/pike/install/>`_.
<https://docs.openstack.org/queens/install/>`_.

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/pike/install/.
https://docs.openstack.org/queens/install/.

View File

@@ -0,0 +1,86 @@
=============
Actuator
=============
Synopsis
--------
**display name**: ``Actuator``
**goal**: ``unclassified``
.. watcher-term:: watcher.decision_engine.strategy.strategies.actuation
Requirements
------------
Metrics
*******
None
Cluster data model
******************
None
Actions
*******
Default Watcher's actions.
Planner
*******
Default Watcher's planner:
.. watcher-term:: watcher.decision_engine.planner.weight.WeightPlanner
Configuration
-------------
Strategy parameters are:
==================== ====== ===================== =============================
parameter type default Value description
==================== ====== ===================== =============================
``actions`` array None Actions to be executed.
==================== ====== ===================== =============================
The elements of actions array are:
==================== ====== ===================== =============================
parameter type default Value description
==================== ====== ===================== =============================
``action_type`` string None Action name defined in
setup.cfg(mandatory)
``resource_id`` string None Resource_id of the action.
``input_parameters`` object None Input_parameters of the
action(mandatory).
==================== ====== ===================== =============================
Efficacy Indicator
------------------
None
Algorithm
---------
This strategy create an action plan with a predefined set of actions.
How to use it ?
---------------
.. code-block:: shell
$ openstack optimize audittemplate create \
at1 unclassified --strategy actuator
$ openstack optimize audit create -a at1 \
-p actions='[{"action_type": "migrate", "resource_id": "56a40802-6fde-4b59-957c-c84baec7eaed", "input_parameters": {"migration_type": "live", "source_node": "s01"}}]'
External Links
--------------
None

View File

@@ -0,0 +1,154 @@
==============
Zone migration
==============
Synopsis
--------
**display name**: ``Zone migration``
**goal**: ``hardware_maintenance``
.. watcher-term:: watcher.decision_engine.strategy.strategies.zone_migration
Requirements
------------
Metrics
*******
None
Cluster data model
******************
Default Watcher's Compute cluster data model:
.. watcher-term:: watcher.decision_engine.model.collector.nova.NovaClusterDataModelCollector
Storage cluster data model is also required:
.. watcher-term:: watcher.decision_engine.model.collector.cinder.CinderClusterDataModelCollector
Actions
*******
Default Watcher's actions:
.. list-table::
:widths: 30 30
:header-rows: 1
* - action
- description
* - ``migrate``
- .. watcher-term:: watcher.applier.actions.migration.Migrate
* - ``volume_migrate``
- .. watcher-term:: watcher.applier.actions.volume_migration.VolumeMigrate
Planner
*******
Default Watcher's planner:
.. watcher-term:: watcher.decision_engine.planner.weight.WeightPlanner
Configuration
-------------
Strategy parameters are:
======================== ======== ============= ==============================
parameter type default Value description
======================== ======== ============= ==============================
``compute_nodes`` array None Compute nodes to migrate.
``storage_pools`` array None Storage pools to migrate.
``parallel_total`` integer 6 The number of actions to be
run in parallel in total.
``parallel_per_node`` integer 2 The number of actions to be
run in parallel per compute
node.
``parallel_per_pool`` integer 2 The number of actions to be
run in parallel per storage
pool.
``priority`` object None List prioritizes instances
and volumes.
``with_attached_volume`` boolean False False: Instances will migrate
after all volumes migrate.
True: An instance will migrate
after the attached volumes
migrate.
======================== ======== ============= ==============================
The elements of compute_nodes array are:
============= ======= =============== =============================
parameter type default Value description
============= ======= =============== =============================
``src_node`` string None Compute node from which
instances migrate(mandatory).
``dst_node`` string None Compute node to which
instances migrate.
============= ======= =============== =============================
The elements of storage_pools array are:
============= ======= =============== ==============================
parameter type default Value description
============= ======= =============== ==============================
``src_pool`` string None Storage pool from which
volumes migrate(mandatory).
``dst_pool`` string None Storage pool to which
volumes migrate.
``src_type`` string None Source volume type(mandatory).
``dst_type`` string None Destination volume type
(mandatory).
============= ======= =============== ==============================
The elements of priority object are:
================ ======= =============== ======================
parameter type default Value description
================ ======= =============== ======================
``project`` array None Project names.
``compute_node`` array None Compute node names.
``storage_pool`` array None Storage pool names.
``compute`` enum None Instance attributes.
|compute|
``storage`` enum None Volume attributes.
|storage|
================ ======= =============== ======================
.. |compute| replace:: ["vcpu_num", "mem_size", "disk_size", "created_at"]
.. |storage| replace:: ["size", "created_at"]
Efficacy Indicator
------------------
.. watcher-func::
:format: literal_block
watcher.decision_engine.goal.efficacy.specs.HardwareMaintenance.get_global_efficacy_indicator
Algorithm
---------
For more information on the zone migration strategy please refer
to: http://specs.openstack.org/openstack/watcher-specs/specs/queens/implemented/zone-migration-strategy.html
How to use it ?
---------------
.. code-block:: shell
$ openstack optimize audittemplate create \
at1 hardware_maintenance --strategy zone_migration
$ openstack optimize audit create -a at1 \
-p compute_nodes='[{"src_node": "s01", "dst_node": "d01"}]'
External Links
--------------
None

View File

@@ -0,0 +1,3 @@
[DEFAULT]
output_file = /etc/watcher/policy.yaml.sample
namespace = watcher

View File

@@ -1,45 +0,0 @@
{
"admin_api": "role:admin or role:administrator",
"show_password": "!",
"default": "rule:admin_api",
"action:detail": "rule:default",
"action:get": "rule:default",
"action:get_all": "rule:default",
"action_plan:delete": "rule:default",
"action_plan:detail": "rule:default",
"action_plan:get": "rule:default",
"action_plan:get_all": "rule:default",
"action_plan:update": "rule:default",
"audit:create": "rule:default",
"audit:delete": "rule:default",
"audit:detail": "rule:default",
"audit:get": "rule:default",
"audit:get_all": "rule:default",
"audit:update": "rule:default",
"audit_template:create": "rule:default",
"audit_template:delete": "rule:default",
"audit_template:detail": "rule:default",
"audit_template:get": "rule:default",
"audit_template:get_all": "rule:default",
"audit_template:update": "rule:default",
"goal:detail": "rule:default",
"goal:get": "rule:default",
"goal:get_all": "rule:default",
"scoring_engine:detail": "rule:default",
"scoring_engine:get": "rule:default",
"scoring_engine:get_all": "rule:default",
"strategy:detail": "rule:default",
"strategy:get": "rule:default",
"strategy:get_all": "rule:default",
"service:detail": "rule:default",
"service:get": "rule:default",
"service:get_all": "rule:default"
}

View File

@@ -0,0 +1,15 @@
- hosts: primary
tasks:
- name: Copy files from {{ ansible_user_dir }}/workspace/ on node
synchronize:
src: '{{ ansible_user_dir }}/workspace/'
dest: '{{ zuul.executor.log_root }}'
mode: pull
copy_links: true
verify_host: true
rsync_opts:
- --include=/logs/**
- --include=*/
- --exclude=*
- --prune-empty-dirs

View File

@@ -0,0 +1,67 @@
- hosts: primary
name: Legacy Watcher tempest base multinode
tasks:
- name: Ensure legacy workspace directory
file:
path: '{{ ansible_user_dir }}/workspace'
state: directory
- shell:
cmd: |
set -e
set -x
cat > clonemap.yaml << EOF
clonemap:
- name: openstack/devstack-gate
dest: devstack-gate
EOF
/usr/zuul-env/bin/zuul-cloner -m clonemap.yaml --cache-dir /opt/git \
https://opendev.org \
openstack/devstack-gate
executable: /bin/bash
chdir: '{{ ansible_user_dir }}/workspace'
environment: '{{ zuul | zuul_legacy_vars }}'
- shell:
cmd: |
set -e
set -x
cat << 'EOF' >>"/tmp/dg-local.conf"
[[local|localrc]]
TEMPEST_PLUGINS='/opt/stack/new/watcher-tempest-plugin'
enable_plugin ceilometer https://opendev.org/openstack/ceilometer
# Enable watcher devstack plugin.
enable_plugin watcher https://opendev.org/openstack/watcher
EOF
executable: /bin/bash
chdir: '{{ ansible_user_dir }}/workspace'
environment: '{{ zuul | zuul_legacy_vars }}'
- shell:
cmd: |
set -e
set -x
export DEVSTACK_SUBNODE_CONFIG=" "
export PYTHONUNBUFFERED=true
export DEVSTACK_GATE_TEMPEST=1
export DEVSTACK_GATE_NEUTRON=1
export DEVSTACK_GATE_TOPOLOGY="multinode"
export PROJECTS="openstack/watcher $PROJECTS"
export PROJECTS="openstack/python-watcherclient $PROJECTS"
export PROJECTS="openstack/watcher-tempest-plugin $PROJECTS"
export DEVSTACK_GATE_TEMPEST_REGEX="watcher_tempest_plugin"
export BRANCH_OVERRIDE=default
if [ "$BRANCH_OVERRIDE" != "default" ] ; then
export OVERRIDE_ZUUL_BRANCH=$BRANCH_OVERRIDE
fi
cp devstack-gate/devstack-vm-gate-wrap.sh ./safe-devstack-vm-gate-wrap.sh
./safe-devstack-vm-gate-wrap.sh
executable: /bin/bash
chdir: '{{ ansible_user_dir }}/workspace'
environment: '{{ zuul | zuul_legacy_vars }}'

View File

@@ -0,0 +1,80 @@
- hosts: primary
tasks:
- name: Copy files from {{ ansible_user_dir }}/workspace/ on node
synchronize:
src: '{{ ansible_user_dir }}/workspace/'
dest: '{{ zuul.executor.log_root }}'
mode: pull
copy_links: true
verify_host: true
rsync_opts:
- --include=**/*nose_results.html
- --include=*/
- --exclude=*
- --prune-empty-dirs
- name: Copy files from {{ ansible_user_dir }}/workspace/ on node
synchronize:
src: '{{ ansible_user_dir }}/workspace/'
dest: '{{ zuul.executor.log_root }}'
mode: pull
copy_links: true
verify_host: true
rsync_opts:
- --include=**/*testr_results.html.gz
- --include=*/
- --exclude=*
- --prune-empty-dirs
- name: Copy files from {{ ansible_user_dir }}/workspace/ on node
synchronize:
src: '{{ ansible_user_dir }}/workspace/'
dest: '{{ zuul.executor.log_root }}'
mode: pull
copy_links: true
verify_host: true
rsync_opts:
- --include=/.testrepository/tmp*
- --include=*/
- --exclude=*
- --prune-empty-dirs
- name: Copy files from {{ ansible_user_dir }}/workspace/ on node
synchronize:
src: '{{ ansible_user_dir }}/workspace/'
dest: '{{ zuul.executor.log_root }}'
mode: pull
copy_links: true
verify_host: true
rsync_opts:
- --include=**/*testrepository.subunit.gz
- --include=*/
- --exclude=*
- --prune-empty-dirs
- name: Copy files from {{ ansible_user_dir }}/workspace/ on node
synchronize:
src: '{{ ansible_user_dir }}/workspace/'
dest: '{{ zuul.executor.log_root }}/tox'
mode: pull
copy_links: true
verify_host: true
rsync_opts:
- --include=/.tox/*/log/*
- --include=*/
- --exclude=*
- --prune-empty-dirs
- name: Copy files from {{ ansible_user_dir }}/workspace/ on node
synchronize:
src: '{{ ansible_user_dir }}/workspace/'
dest: '{{ zuul.executor.log_root }}'
mode: pull
copy_links: true
verify_host: true
rsync_opts:
- --include=/logs/**
- --include=*/
- --exclude=*
- --prune-empty-dirs

View File

@@ -0,0 +1,64 @@
- hosts: all
name: Legacy watcherclient-dsvm-functional
tasks:
- name: Ensure legacy workspace directory
file:
path: '{{ ansible_user_dir }}/workspace'
state: directory
- shell:
cmd: |
set -e
set -x
cat > clonemap.yaml << EOF
clonemap:
- name: openstack/devstack-gate
dest: devstack-gate
EOF
/usr/zuul-env/bin/zuul-cloner -m clonemap.yaml --cache-dir /opt/git \
https://opendev.org \
openstack/devstack-gate
executable: /bin/bash
chdir: '{{ ansible_user_dir }}/workspace'
environment: '{{ zuul | zuul_legacy_vars }}'
- shell:
cmd: |
set -e
set -x
cat << 'EOF' >>"/tmp/dg-local.conf"
[[local|localrc]]
enable_plugin watcher https://opendev.org/openstack/watcher
EOF
executable: /bin/bash
chdir: '{{ ansible_user_dir }}/workspace'
environment: '{{ zuul | zuul_legacy_vars }}'
- shell:
cmd: |
set -e
set -x
ENABLED_SERVICES=tempest
ENABLED_SERVICES+=,watcher-api,watcher-decision-engine,watcher-applier
export ENABLED_SERVICES
export PYTHONUNBUFFERED=true
export BRANCH_OVERRIDE=default
export PROJECTS="openstack/watcher $PROJECTS"
export DEVSTACK_PROJECT_FROM_GIT=python-watcherclient
if [ "$BRANCH_OVERRIDE" != "default" ] ; then
export OVERRIDE_ZUUL_BRANCH=$BRANCH_OVERRIDE
fi
function post_test_hook {
# Configure and run functional tests
$BASE/new/python-watcherclient/watcherclient/tests/functional/hooks/post_test_hook.sh
}
export -f post_test_hook
cp devstack-gate/devstack-vm-gate-wrap.sh ./safe-devstack-vm-gate-wrap.sh
./safe-devstack-vm-gate-wrap.sh
executable: /bin/bash
chdir: '{{ ansible_user_dir }}/workspace'
environment: '{{ zuul | zuul_legacy_vars }}'

View File

@@ -29,14 +29,14 @@ Useful links
* 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
* 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
* More about Rally: https://rally.readthedocs.org/en/latest/
* More about Rally: https://docs.openstack.org/rally/latest/
* Rally release notes: https://rally.readthedocs.org/en/latest/release_notes.html
* Rally project info and release notes: https://docs.openstack.org/rally/latest/project_info/index.html
* How to add rally-gates: https://rally.readthedocs.org/en/latest/gates.html
* How to add rally-gates: https://docs.openstack.org/rally/latest/quick_start/gates.html#gate-jobs
* About plugins: https://rally.readthedocs.org/en/latest/plugins.html
* About plugins: https://docs.openstack.org/rally/latest/plugins/index.html
* Plugin samples: https://github.com/openstack/rally/tree/master/samples/plugins
* Plugin samples: https://github.com/openstack/rally/tree/master/samples/

View File

@@ -0,0 +1,5 @@
---
features:
- |
Adds audit scoper for storage data model, now watcher users can specify
audit scope for storage CDM in the same manner as compute scope.

View File

@@ -0,0 +1,4 @@
---
features:
- |
Adds baremetal data model in Watcher

View File

@@ -0,0 +1,6 @@
---
features:
- |
Each CDM collector can have its own CDM scoper now. This changed Scope
JSON schema definition for the audit template POST data. Please see audit
template create help message in python-watcherclient.

View File

@@ -0,0 +1,6 @@
---
features:
- Added a way to check state of strategy before audit's execution.
Administrator can use "watcher strategy state <strategy_name>" command
to get information about metrics' availability, datasource's availability
and CDM's availability.

View File

@@ -1,5 +1,5 @@
---
features:
- Added strategy to identify and migrate a Noisy Neighbor - a low priority VM
that negatively affects peformance of a high priority VM by over utilizing
that negatively affects performance of a high priority VM by over utilizing
Last Level Cache.

View File

@@ -0,0 +1,4 @@
---
features:
- |
Added storage capacity balance strategy.

View File

@@ -0,0 +1,6 @@
---
features:
- |
Added strategy "Zone migration" and it's goal "Hardware maintenance".
The strategy migrates many instances and volumes efficiently with
minimum downtime automatically.

View File

@@ -24,7 +24,6 @@
import os
import sys
from watcher import version as watcher_version
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
@@ -57,14 +56,11 @@ master_doc = 'index'
project = u'watcher'
copyright = u'2016, Watcher developers'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# Release notes are version independent
# The short X.Y version.
version = watcher_version.version_info.release_string()
version = ''
# The full version, including alpha/beta/rc tags.
release = watcher_version.version_string
release = ''
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.

View File

@@ -1,33 +0,0 @@
# Gérald LONLAS <g.lonlas@gmail.com>, 2016. #zanata
msgid ""
msgstr ""
"Project-Id-Version: watcher 1.0.1.dev51\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-03-21 11:57+0000\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"PO-Revision-Date: 2016-10-22 06:44+0000\n"
"Last-Translator: Gérald LONLAS <g.lonlas@gmail.com>\n"
"Language-Team: French\n"
"Language: fr\n"
"X-Generator: Zanata 3.9.6\n"
"Plural-Forms: nplurals=2; plural=(n > 1)\n"
msgid "0.29.0"
msgstr "0.29.0"
msgid "Contents:"
msgstr "Contenu :"
msgid "Current Series Release Notes"
msgstr "Note de la release actuelle"
msgid "New Features"
msgstr "Nouvelles fonctionnalités"
msgid "Newton Series Release Notes"
msgstr "Note de release pour Newton"
msgid "Welcome to watcher's Release Notes documentation!"
msgstr "Bienvenue dans la documentation de la note de Release de Watcher"

View File

@@ -4,26 +4,26 @@
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
jsonpatch!=1.20,>=1.16 # BSD
keystoneauth1>=3.3.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.20.0 # Apache-2.0
oslo.concurrency>=3.25.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.config>=5.1.0 # Apache-2.0
oslo.context>=2.19.2 # 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.log>=3.36.0 # Apache-2.0
oslo.messaging>=5.29.0 # Apache-2.0
oslo.policy>=1.23.0 # Apache-2.0
oslo.policy>=1.30.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
oslo.service!=1.28.1,>=1.24.0 # Apache-2.0
oslo.utils>=3.33.0 # Apache-2.0
oslo.versionedobjects>=1.31.2 # 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
@@ -31,18 +31,18 @@ PrettyTable<0.8,>=0.7.1 # BSD
voluptuous>=0.8.9 # BSD License
gnocchiclient>=3.3.1 # Apache-2.0
python-ceilometerclient>=2.5.0 # Apache-2.0
python-cinderclient>=3.2.0 # Apache-2.0
python-cinderclient>=3.3.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.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
python-ironicclient>=2.2.0 # Apache-2.0
six>=1.10.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
taskflow>=2.16.0 # Apache-2.0
WebOb>=1.7.1 # MIT
WSME>=0.8.0 # MIT
networkx<2.0,>=1.10 # BSD

View File

@@ -32,6 +32,12 @@ setup-hooks =
oslo.config.opts =
watcher = watcher.conf.opts:list_opts
oslo.policy.policies =
watcher = watcher.common.policies:list_rules
oslo.policy.enforcer =
watcher = watcher.common.policy:get_enforcer
console_scripts =
watcher-api = watcher.cmd.api:main
watcher-db-manage = watcher.cmd.dbmanage:main
@@ -51,6 +57,7 @@ watcher_goals =
airflow_optimization = watcher.decision_engine.goal.goals:AirflowOptimization
noisy_neighbor = watcher.decision_engine.goal.goals:NoisyNeighborOptimization
saving_energy = watcher.decision_engine.goal.goals:SavingEnergy
hardware_maintenance = watcher.decision_engine.goal.goals:HardwareMaintenance
watcher_scoring_engines =
dummy_scorer = watcher.decision_engine.scoring.dummy_scorer:DummyScorer
@@ -71,6 +78,8 @@ watcher_strategies =
workload_balance = watcher.decision_engine.strategy.strategies.workload_balance:WorkloadBalance
uniform_airflow = watcher.decision_engine.strategy.strategies.uniform_airflow:UniformAirflow
noisy_neighbor = watcher.decision_engine.strategy.strategies.noisy_neighbor:NoisyNeighbor
storage_capacity_balance = watcher.decision_engine.strategy.strategies.storage_capacity_balance:StorageCapacityBalance
zone_migration = watcher.decision_engine.strategy.strategies.zone_migration:ZoneMigration
watcher_actions =
migrate = watcher.applier.actions.migration:Migrate
@@ -91,6 +100,7 @@ watcher_planners =
watcher_cluster_data_model_collectors =
compute = watcher.decision_engine.model.collector.nova:NovaClusterDataModelCollector
storage = watcher.decision_engine.model.collector.cinder:CinderClusterDataModelCollector
baremetal = watcher.decision_engine.model.collector.ironic:BaremetalClusterDataModelCollector
[pbr]

View File

@@ -7,15 +7,15 @@ 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.0 # BSD
oslotest>=1.10.0 # Apache-2.0
oslotest>=3.2.0 # Apache-2.0
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
testtools>=2.2.0 # MIT
# Doc requirements
openstackdocstheme>=1.17.0 # Apache-2.0
sphinx>=1.6.2 # BSD
openstackdocstheme>=1.18.1 # Apache-2.0
sphinx!=1.6.6,>=1.6.2 # BSD
sphinxcontrib-pecanwsme>=0.8.0 # Apache-2.0

11
tox.ini
View File

@@ -7,14 +7,14 @@ skipsdist = True
usedevelop = True
whitelist_externals = find
rm
install_command = pip install -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} {opts} {packages}
install_command = pip install -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt?h=stable/queens} {opts} {packages}
setenv =
VIRTUAL_ENV={envdir}
deps = -r{toxinidir}/test-requirements.txt
commands =
rm -f .testrepository/times.dbm
find . -type f -name "*.py[c|o]" -delete
ostestr --concurrency=6 {posargs}
stestr run {posargs}
passenv = http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY
[testenv:pep8]
@@ -46,11 +46,16 @@ sitepackages = False
commands =
oslo-config-generator --config-file etc/watcher/oslo-config-generator/watcher.conf
[testenv:genpolicy]
commands =
oslopolicy-sample-generator --config-file etc/watcher/oslo-policy-generator/watcher-policy-generator.conf
[flake8]
filename = *.py,app.wsgi
show-source=True
ignore= H105,E123,E226,N320,H202
builtins= _
enable-extensions = H106,H203
enable-extensions = H106,H203,H904
exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build,*sqlalchemy/alembic/versions/*,demo/,releasenotes
[testenv:wheel]

View File

@@ -37,4 +37,3 @@ LOG.debug("Configuration:")
CONF.log_opt_values(LOG, log.DEBUG)
application = app.VersionSelectorApplication()

View File

@@ -341,7 +341,7 @@ class ActionsController(rest.RestController):
@wsme_pecan.wsexpose(Action, body=Action, status_code=201)
def post(self, action):
"""Create a new action.
"""Create a new action(forbidden).
:param action: a action within the request body.
"""
@@ -364,7 +364,7 @@ class ActionsController(rest.RestController):
@wsme.validate(types.uuid, [ActionPatchType])
@wsme_pecan.wsexpose(Action, types.uuid, body=[ActionPatchType])
def patch(self, action_uuid, patch):
"""Update an existing action.
"""Update an existing action(forbidden).
:param action_uuid: UUID of a action.
:param patch: a json PATCH document to apply to this action.
@@ -401,7 +401,7 @@ class ActionsController(rest.RestController):
@wsme_pecan.wsexpose(None, types.uuid, status_code=204)
def delete(self, action_uuid):
"""Delete a action.
"""Delete a action(forbidden).
:param action_uuid: UUID of a action.
"""

View File

@@ -460,6 +460,15 @@ class ActionPlansController(rest.RestController):
policy.enforce(context, 'action_plan:delete', action_plan,
action='action_plan:delete')
allowed_states = (ap_objects.State.SUCCEEDED,
ap_objects.State.RECOMMENDED,
ap_objects.State.FAILED,
ap_objects.State.SUPERSEDED,
ap_objects.State.CANCELLED)
if action_plan.state not in allowed_states:
raise exception.DeleteError(
state=action_plan.state)
action_plan.soft_delete()
@wsme.validate(types.uuid, [ActionPlanPatchType])

View File

@@ -37,6 +37,8 @@ import wsme
from wsme import types as wtypes
import wsmeext.pecan as wsme_pecan
from oslo_log import log
from watcher._i18n import _
from watcher.api.controllers import base
from watcher.api.controllers import link
@@ -49,9 +51,13 @@ from watcher.common import utils
from watcher.decision_engine import rpcapi
from watcher import objects
LOG = log.getLogger(__name__)
class AuditPostType(wtypes.Base):
name = wtypes.wsattr(wtypes.text, mandatory=False)
audit_template_uuid = wtypes.wsattr(types.uuid, mandatory=False)
goal = wtypes.wsattr(wtypes.text, mandatory=False)
@@ -111,7 +117,30 @@ class AuditPostType(wtypes.Base):
setattr(self, k, at_attr)
except AttributeError:
pass
# Note: If audit name was not provided, used a default name
if not self.name:
if self.strategy:
strategy = objects.Strategy.get(context, self.strategy)
self.name = "%s-%s" % (strategy.name,
datetime.datetime.utcnow().isoformat())
elif self.audit_template_uuid:
audit_template = objects.AuditTemplate.get(
context, self.audit_template_uuid)
self.name = "%s-%s" % (audit_template.name,
datetime.datetime.utcnow().isoformat())
else:
goal = objects.Goal.get(context, self.goal)
self.name = "%s-%s" % (goal.name,
datetime.datetime.utcnow().isoformat())
# No more than 63 characters
if len(self.name) > 63:
LOG.warning("Audit: %s length exceeds 63 characters",
self.name)
self.name = self.name[0:63]
return Audit(
name=self.name,
audit_type=self.audit_type,
parameters=self.parameters,
goal_id=self.goal,
@@ -146,10 +175,10 @@ class AuditPatchType(types.JsonPatchType):
class Audit(base.APIBase):
"""API representation of a audit.
"""API representation of an audit.
This class enforces type checking and value constraints, and converts
between the internal object model and the API representation of a audit.
between the internal object model and the API representation of an audit.
"""
_goal_uuid = None
_goal_name = None
@@ -233,6 +262,9 @@ class Audit(base.APIBase):
uuid = types.uuid
"""Unique UUID for this audit"""
name = wtypes.text
"""Name of this audit"""
audit_type = wtypes.text
"""Type of this audit"""
@@ -241,19 +273,19 @@ class Audit(base.APIBase):
goal_uuid = wsme.wsproperty(
wtypes.text, _get_goal_uuid, _set_goal_uuid, mandatory=True)
"""Goal UUID the audit template refers to"""
"""Goal UUID the audit refers to"""
goal_name = wsme.wsproperty(
wtypes.text, _get_goal_name, _set_goal_name, mandatory=False)
"""The name of the goal this audit template refers to"""
"""The name of the goal this audit refers to"""
strategy_uuid = wsme.wsproperty(
wtypes.text, _get_strategy_uuid, _set_strategy_uuid, mandatory=False)
"""Strategy UUID the audit template refers to"""
"""Strategy UUID the audit refers to"""
strategy_name = wsme.wsproperty(
wtypes.text, _get_strategy_name, _set_strategy_name, mandatory=False)
"""The name of the strategy this audit template refers to"""
"""The name of the strategy this audit refers to"""
parameters = {wtypes.text: types.jsontype}
"""The strategy parameters for this audit"""
@@ -301,7 +333,7 @@ class Audit(base.APIBase):
@staticmethod
def _convert_with_links(audit, url, expand=True):
if not expand:
audit.unset_fields_except(['uuid', 'audit_type', 'state',
audit.unset_fields_except(['uuid', 'name', 'audit_type', 'state',
'goal_uuid', 'interval', 'scope',
'strategy_uuid', 'goal_name',
'strategy_name', 'auto_trigger',
@@ -324,6 +356,7 @@ class Audit(base.APIBase):
@classmethod
def sample(cls, expand=True):
sample = cls(uuid='27e3153e-d5bf-4b7e-b517-fb518e17f34c',
name='My Audit',
audit_type='ONESHOT',
state='PENDING',
created_at=datetime.datetime.utcnow(),
@@ -483,17 +516,17 @@ class AuditsController(rest.RestController):
resource_url,
goal=goal)
@wsme_pecan.wsexpose(Audit, types.uuid)
def get_one(self, audit_uuid):
@wsme_pecan.wsexpose(Audit, wtypes.text)
def get_one(self, audit):
"""Retrieve information about the given audit.
:param audit_uuid: UUID of a audit.
:param audit: UUID or name of an audit.
"""
if self.from_audits:
raise exception.OperationNotPermitted
context = pecan.request.context
rpc_audit = api_utils.get_resource('Audit', audit_uuid)
rpc_audit = api_utils.get_resource('Audit', audit)
policy.enforce(context, 'audit:get', rpc_audit, action='audit:get')
return Audit.convert_with_links(rpc_audit)
@@ -502,7 +535,7 @@ class AuditsController(rest.RestController):
def post(self, audit_p):
"""Create a new audit.
:param audit_p: a audit within the request body.
:param audit_p: an audit within the request body.
"""
context = pecan.request.context
policy.enforce(context, 'audit:create',
@@ -532,7 +565,7 @@ class AuditsController(rest.RestController):
if no_schema and audit.parameters:
raise exception.Invalid(_('Specify parameters but no predefined '
'strategy for audit template, or no '
'strategy for audit, or no '
'parameter spec in predefined strategy'))
audit_dict = audit.as_dict()
@@ -551,11 +584,11 @@ class AuditsController(rest.RestController):
return Audit.convert_with_links(new_audit)
@wsme.validate(types.uuid, [AuditPatchType])
@wsme_pecan.wsexpose(Audit, types.uuid, body=[AuditPatchType])
def patch(self, audit_uuid, patch):
@wsme_pecan.wsexpose(Audit, wtypes.text, body=[AuditPatchType])
def patch(self, audit, patch):
"""Update an existing audit.
:param audit_uuid: UUID of a audit.
:param audit: UUID or name of an audit.
:param patch: a json PATCH document to apply to this audit.
"""
if self.from_audits:
@@ -563,7 +596,7 @@ class AuditsController(rest.RestController):
context = pecan.request.context
audit_to_update = api_utils.get_resource(
'Audit', audit_uuid, eager=True)
'Audit', audit, eager=True)
policy.enforce(context, 'audit:update', audit_to_update,
action='audit:update')
@@ -600,16 +633,23 @@ class AuditsController(rest.RestController):
audit_to_update.save()
return Audit.convert_with_links(audit_to_update)
@wsme_pecan.wsexpose(None, types.uuid, status_code=204)
def delete(self, audit_uuid):
"""Delete a audit.
@wsme_pecan.wsexpose(None, wtypes.text, status_code=204)
def delete(self, audit):
"""Delete an audit.
:param audit_uuid: UUID of a audit.
:param audit: UUID or name of an audit.
"""
context = pecan.request.context
audit_to_delete = api_utils.get_resource(
'Audit', audit_uuid, eager=True)
'Audit', audit, eager=True)
policy.enforce(context, 'audit:update', audit_to_delete,
action='audit:update')
initial_state = audit_to_delete.state
new_state = objects.audit.State.DELETED
if not objects.audit.AuditStateTransitionManager(
).check_transition(initial_state, new_state):
raise exception.DeleteError(
state=initial_state)
audit_to_delete.soft_delete()

View File

@@ -51,6 +51,8 @@ import wsme
from wsme import types as wtypes
import wsmeext.pecan as wsme_pecan
from oslo_log import log
from watcher._i18n import _
from watcher.api.controllers import base
from watcher.api.controllers import link
@@ -61,9 +63,11 @@ from watcher.common import context as context_utils
from watcher.common import exception
from watcher.common import policy
from watcher.common import utils as common_utils
from watcher.decision_engine.scope import default
from watcher.decision_engine.loading import default as default_loading
from watcher import objects
LOG = log.getLogger(__name__)
class AuditTemplatePostType(wtypes.Base):
_ctx = context_utils.make_context()
@@ -94,6 +98,27 @@ class AuditTemplatePostType(wtypes.Base):
scope=self.scope,
)
@staticmethod
def _build_schema():
SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "array",
"items": {
"type": "object",
"properties": AuditTemplatePostType._get_schemas(),
"additionalProperties": False
}
}
return SCHEMA
@staticmethod
def _get_schemas():
collectors = default_loading.ClusterDataModelCollectorLoader(
).list_available()
schemas = {k: c.SCHEMA for k, c
in collectors.items() if hasattr(c, "SCHEMA")}
return schemas
@staticmethod
def validate(audit_template):
available_goals = objects.Goal.list(AuditTemplatePostType._ctx)
@@ -106,23 +131,25 @@ class AuditTemplatePostType(wtypes.Base):
else:
raise exception.InvalidGoal(goal=audit_template.goal)
common_utils.Draft4Validator(
default.DefaultScope.DEFAULT_SCHEMA).validate(audit_template.scope)
if audit_template.scope:
common_utils.Draft4Validator(
AuditTemplatePostType._build_schema()
).validate(audit_template.scope)
include_host_aggregates = False
exclude_host_aggregates = False
for rule in audit_template.scope:
if 'host_aggregates' in rule:
include_host_aggregates = True
elif 'exclude' in rule:
for resource in rule['exclude']:
if 'host_aggregates' in resource:
exclude_host_aggregates = True
if include_host_aggregates and exclude_host_aggregates:
raise exception.Invalid(
message=_(
"host_aggregates can't be "
"included and excluded together"))
include_host_aggregates = False
exclude_host_aggregates = False
for rule in audit_template.scope[0]['compute']:
if 'host_aggregates' in rule:
include_host_aggregates = True
elif 'exclude' in rule:
for resource in rule['exclude']:
if 'host_aggregates' in resource:
exclude_host_aggregates = True
if include_host_aggregates and exclude_host_aggregates:
raise exception.Invalid(
message=_(
"host_aggregates can't be "
"included and excluded together"))
if audit_template.strategy:
available_strategies = objects.Strategy.list(

View File

@@ -41,6 +41,7 @@ from watcher.api.controllers.v1 import utils as api_utils
from watcher.common import exception
from watcher.common import policy
from watcher.common import utils as common_utils
from watcher.decision_engine import rpcapi
from watcher import objects
@@ -205,6 +206,7 @@ class StrategiesController(rest.RestController):
_custom_actions = {
'detail': ['GET'],
'state': ['GET'],
}
def _get_strategies_collection(self, filters, marker, limit, sort_key,
@@ -288,6 +290,26 @@ class StrategiesController(rest.RestController):
return self._get_strategies_collection(
filters, marker, limit, sort_key, sort_dir, expand, resource_url)
@wsme_pecan.wsexpose(wtypes.text, wtypes.text)
def state(self, strategy):
"""Retrieve a inforamation about strategy requirements.
:param strategy: name of the strategy.
"""
context = pecan.request.context
policy.enforce(context, 'strategy:state', action='strategy:state')
parents = pecan.request.path.split('/')[:-1]
if parents[-2] != "strategies":
raise exception.HTTPNotFound
rpc_strategy = api_utils.get_resource('Strategy', strategy)
de_client = rpcapi.DecisionEngineAPI()
strategy_state = de_client.get_strategy_info(context,
rpc_strategy.name)
strategy_state.extend([{
'type': 'Name', 'state': rpc_strategy.name,
'mandatory': '', 'comment': ''}])
return strategy_state
@wsme_pecan.wsexpose(Strategy, wtypes.text)
def get_one(self, strategy):
"""Retrieve information about the given strategy.

View File

@@ -63,7 +63,7 @@ class ContextHook(hooks.PecanHook):
auth_url = headers.get('X-Auth-Url')
if auth_url is None:
importutils.import_module('keystonemiddleware.auth_token')
auth_url = cfg.CONF.keystone_authtoken.auth_uri
auth_url = cfg.CONF.keystone_authtoken.www_authenticate_uri
state.request.context = context.make_context(
auth_token=auth_token,

View File

@@ -36,15 +36,20 @@ class ChangeNovaServiceState(base.BaseAction):
schema = Schema({
'resource_id': str,
'state': str,
'disabled_reason': str,
})
The `resource_id` references a nova-compute service name (list of available
nova-compute services is returned by this command: ``nova service-list
--binary nova-compute``).
The `state` value should either be `ONLINE` or `OFFLINE`.
The `disabled_reason` references the reason why Watcher disables this
nova-compute service. The value should be with `watcher_` prefix, such as
`watcher_disabled`, `watcher_maintaining`.
"""
STATE = 'state'
REASON = 'disabled_reason'
@property
def schema(self):
@@ -61,6 +66,10 @@ class ChangeNovaServiceState(base.BaseAction):
element.ServiceState.OFFLINE.value,
element.ServiceState.ENABLED.value,
element.ServiceState.DISABLED.value]
},
'disabled_reason': {
'type': 'string',
"minlength": 1
}
},
'required': ['resource_id', 'state'],
@@ -75,6 +84,10 @@ class ChangeNovaServiceState(base.BaseAction):
def state(self):
return self.input_parameters.get(self.STATE)
@property
def reason(self):
return self.input_parameters.get(self.REASON)
def execute(self):
target_state = None
if self.state == element.ServiceState.DISABLED.value:
@@ -100,7 +113,7 @@ class ChangeNovaServiceState(base.BaseAction):
if state is True:
return nova.enable_service_nova_compute(self.host)
else:
return nova.disable_service_nova_compute(self.host)
return nova.disable_service_nova_compute(self.host, self.reason)
def pre_condition(self):
pass

View File

@@ -112,18 +112,11 @@ class Migrate(base.BaseAction):
result = nova.live_migrate_instance(instance_id=self.instance_uuid,
dest_hostname=destination)
except nova_helper.nvexceptions.ClientException as e:
if e.code == 400:
LOG.debug("Live migration of instance %s failed. "
"Trying to live migrate using block migration."
% self.instance_uuid)
result = nova.live_migrate_instance(
instance_id=self.instance_uuid,
dest_hostname=destination,
block_migration=True)
else:
LOG.debug("Nova client exception occurred while live "
"migrating instance %s.Exception: %s" %
(self.instance_uuid, e))
LOG.debug("Nova client exception occurred while live "
"migrating instance "
"%(instance)s.Exception: %(exception)s",
{'instance': self.instance_uuid, 'exception': e})
except Exception as e:
LOG.exception(e)
LOG.critical("Unexpected error occurred. Migration failed for "

View File

@@ -36,16 +36,19 @@ class VolumeMigrate(base.BaseAction):
By using this action, you will be able to migrate cinder volume.
Migration type 'swap' can only be used for migrating attached volume.
Migration type 'cold' can only be used for migrating detached volume.
Migration type 'migrate' can be used for migrating detached volume to
the pool of same volume type.
Migration type 'retype' can be used for changing volume type of
detached volume.
The action schema is::
schema = Schema({
'resource_id': str, # should be a UUID
'migration_type': str, # choices -> "swap", "cold"
'migration_type': str, # choices -> "swap", "migrate","retype"
'destination_node': str,
'destination_type': str,
)}
})
The `resource_id` is the UUID of cinder volume to migrate.
The `destination_node` is the destination block storage pool name.
@@ -60,7 +63,8 @@ class VolumeMigrate(base.BaseAction):
MIGRATION_TYPE = 'migration_type'
SWAP = 'swap'
COLD = 'cold'
RETYPE = 'retype'
MIGRATE = 'migrate'
DESTINATION_NODE = "destination_node"
DESTINATION_TYPE = "destination_type"
@@ -85,7 +89,7 @@ class VolumeMigrate(base.BaseAction):
},
'migration_type': {
'type': 'string',
"enum": ["swap", "cold"]
"enum": ["swap", "retype", "migrate"]
},
'destination_node': {
"anyof": [
@@ -127,20 +131,6 @@ class VolumeMigrate(base.BaseAction):
def destination_type(self):
return self.input_parameters.get(self.DESTINATION_TYPE)
def _cold_migrate(self, volume, dest_node, dest_type):
if not self.cinder_util.can_cold(volume, dest_node):
raise exception.Invalid(
message=(_("Invalid state for cold migration")))
if dest_node:
return self.cinder_util.migrate(volume, dest_node)
elif dest_type:
return self.cinder_util.retype(volume, dest_type)
else:
raise exception.Invalid(
message=(_("destination host or destination type is "
"required when migration type is cold")))
def _can_swap(self, volume):
"""Judge volume can be swapped"""
@@ -212,12 +202,14 @@ class VolumeMigrate(base.BaseAction):
try:
volume = self.cinder_util.get_volume(volume_id)
if self.migration_type == self.COLD:
return self._cold_migrate(volume, dest_node, dest_type)
elif self.migration_type == self.SWAP:
if self.migration_type == self.SWAP:
if dest_node:
LOG.warning("dest_node is ignored")
return self._swap_volume(volume, dest_type)
elif self.migration_type == self.RETYPE:
return self.cinder_util.retype(volume, dest_type)
elif self.migration_type == self.MIGRATE:
return self.cinder_util.migrate(volume, dest_node)
else:
raise exception.Invalid(
message=(_("Migration of type '%(migration_type)s' is not "

View File

@@ -20,13 +20,13 @@
import sys
from oslo_config import cfg
from oslo_log import log as logging
from oslo_log import log
from watcher.api import scheduling
from watcher.common import service
from watcher import conf
LOG = logging.getLogger(__name__)
LOG = log.getLogger(__name__)
CONF = conf.CONF
@@ -40,10 +40,10 @@ def main():
if host == '127.0.0.1':
LOG.info('serving on 127.0.0.1:%(port)s, '
'view at %(protocol)s://127.0.0.1:%(port)s' %
'view at %(protocol)s://127.0.0.1:%(port)s',
dict(protocol=protocol, port=port))
else:
LOG.info('serving on %(protocol)s://%(host)s:%(port)s' %
LOG.info('serving on %(protocol)s://%(host)s:%(port)s',
dict(protocol=protocol, host=host, port=port))
api_schedule = scheduling.APISchedulingService()

View File

@@ -20,14 +20,14 @@
import os
import sys
from oslo_log import log as logging
from oslo_log import log
from watcher.applier import manager
from watcher.applier import sync
from watcher.common import service as watcher_service
from watcher import conf
LOG = logging.getLogger(__name__)
LOG = log.getLogger(__name__)
CONF = conf.CONF

View File

@@ -20,7 +20,7 @@
import os
import sys
from oslo_log import log as logging
from oslo_log import log
from watcher.common import service as watcher_service
from watcher import conf
@@ -29,7 +29,7 @@ from watcher.decision_engine import manager
from watcher.decision_engine import scheduling
from watcher.decision_engine import sync
LOG = logging.getLogger(__name__)
LOG = log.getLogger(__name__)
CONF = conf.CONF

View File

@@ -20,13 +20,13 @@
import sys
from oslo_log import log as logging
from oslo_log import log
from watcher.common import service as service
from watcher.common import service
from watcher import conf
from watcher.decision_engine import sync
LOG = logging.getLogger(__name__)
LOG = log.getLogger(__name__)
CONF = conf.CONF

View File

@@ -70,16 +70,18 @@ class CinderHelper(object):
def get_volume_type_list(self):
return self.cinder.volume_types.list()
def get_volume_snapshots_list(self):
return self.cinder.volume_snapshots.list(
search_opts={'all_tenants': True})
def get_volume_type_by_backendname(self, backendname):
"""Retrun a list of volume type"""
volume_type_list = self.get_volume_type_list()
volume_type = [volume_type for volume_type in volume_type_list
volume_type = [volume_type.name for volume_type in volume_type_list
if volume_type.extra_specs.get(
'volume_backend_name') == backendname]
if volume_type:
return volume_type[0].name
else:
return ""
return volume_type
def get_volume(self, volume):
@@ -111,23 +113,6 @@ class CinderHelper(object):
return True
return False
def can_cold(self, volume, host=None):
"""Judge volume can be migrated"""
can_cold = False
status = self.get_volume(volume).status
snapshot = self._has_snapshot(volume)
same_host = False
if host and getattr(volume, 'os-vol-host-attr:host') == host:
same_host = True
if (status == 'available' and
snapshot is False and
same_host is False):
can_cold = True
return can_cold
def get_deleting_volume(self, volume):
volume = self.get_volume(volume)
all_volume = self.get_volume_list()
@@ -154,18 +139,19 @@ class CinderHelper(object):
volume = self.get_volume(volume.id)
time.sleep(retry_interval)
retry -= 1
LOG.debug("retry count: %s" % retry)
LOG.debug("Waiting to complete deletion of volume %s" % volume.id)
LOG.debug("retry count: %s", retry)
LOG.debug("Waiting to complete deletion of volume %s", volume.id)
if self._can_get_volume(volume.id):
LOG.error("Volume deletion error: %s" % volume.id)
LOG.error("Volume deletion error: %s", volume.id)
return False
LOG.debug("Volume %s was deleted successfully." % volume.id)
LOG.debug("Volume %s was deleted successfully.", volume.id)
return True
def check_migrated(self, volume, retry_interval=10):
volume = self.get_volume(volume)
while getattr(volume, 'migration_status') == 'migrating':
final_status = ('success', 'error')
while getattr(volume, 'migration_status') not in final_status:
volume = self.get_volume(volume.id)
LOG.debug('Waiting the migration of {0}'.format(volume))
time.sleep(retry_interval)
@@ -193,8 +179,7 @@ class CinderHelper(object):
LOG.error(error_msg)
return False
LOG.debug(
"Volume migration succeeded : "
"volume %s is now on host '%s'." % (
"Volume migration succeeded : volume %s is now on host '%s'.", (
volume.id, host_name))
return True
@@ -203,13 +188,13 @@ class CinderHelper(object):
volume = self.get_volume(volume)
dest_backend = self.backendname_from_poolname(dest_node)
dest_type = self.get_volume_type_by_backendname(dest_backend)
if volume.volume_type != dest_type:
if volume.volume_type not in dest_type:
raise exception.Invalid(
message=(_("Volume type must be same for migrating")))
source_node = getattr(volume, 'os-vol-host-attr:host')
LOG.debug("Volume %s found on host '%s'."
% (volume.id, source_node))
LOG.debug("Volume %s found on host '%s'.",
(volume.id, source_node))
self.cinder.volumes.migrate_volume(
volume, dest_node, False, True)
@@ -225,8 +210,8 @@ class CinderHelper(object):
source_node = getattr(volume, 'os-vol-host-attr:host')
LOG.debug(
"Volume %s found on host '%s'." % (
volume.id, source_node))
"Volume %s found on host '%s'.",
(volume.id, source_node))
self.cinder.volumes.retype(
volume, dest_type, "on-demand")
@@ -248,14 +233,14 @@ class CinderHelper(object):
LOG.debug('Waiting volume creation of {0}'.format(new_volume))
time.sleep(retry_interval)
retry -= 1
LOG.debug("retry count: %s" % retry)
LOG.debug("retry count: %s", retry)
if getattr(new_volume, 'status') != 'available':
error_msg = (_("Failed to create volume '%(volume)s. ") %
{'volume': new_volume.id})
raise Exception(error_msg)
LOG.debug("Volume %s was created successfully." % new_volume)
LOG.debug("Volume %s was created successfully.", new_volume)
return new_volume
def delete_volume(self, volume):

View File

@@ -83,8 +83,10 @@ class OpenStackClients(object):
novaclient_version = self._get_client_option('nova', 'api_version')
nova_endpoint_type = self._get_client_option('nova', 'endpoint_type')
nova_region_name = self._get_client_option('nova', 'region_name')
self._nova = nvclient.Client(novaclient_version,
endpoint_type=nova_endpoint_type,
region_name=nova_region_name,
session=self.session)
return self._nova
@@ -96,8 +98,10 @@ class OpenStackClients(object):
glanceclient_version = self._get_client_option('glance', 'api_version')
glance_endpoint_type = self._get_client_option('glance',
'endpoint_type')
glance_region_name = self._get_client_option('glance', 'region_name')
self._glance = glclient.Client(glanceclient_version,
interface=glance_endpoint_type,
region_name=glance_region_name,
session=self.session)
return self._glance
@@ -110,8 +114,11 @@ class OpenStackClients(object):
'api_version')
gnocchiclient_interface = self._get_client_option('gnocchi',
'endpoint_type')
gnocchiclient_region_name = self._get_client_option('gnocchi',
'region_name')
adapter_options = {
"interface": gnocchiclient_interface
"interface": gnocchiclient_interface,
"region_name": gnocchiclient_region_name
}
self._gnocchi = gnclient.Client(gnocchiclient_version,
@@ -127,8 +134,10 @@ class OpenStackClients(object):
cinderclient_version = self._get_client_option('cinder', 'api_version')
cinder_endpoint_type = self._get_client_option('cinder',
'endpoint_type')
cinder_region_name = self._get_client_option('cinder', 'region_name')
self._cinder = ciclient.Client(cinderclient_version,
endpoint_type=cinder_endpoint_type,
region_name=cinder_region_name,
session=self.session)
return self._cinder
@@ -141,9 +150,12 @@ class OpenStackClients(object):
'api_version')
ceilometer_endpoint_type = self._get_client_option('ceilometer',
'endpoint_type')
ceilometer_region_name = self._get_client_option('ceilometer',
'region_name')
self._ceilometer = ceclient.get_client(
ceilometerclient_version,
endpoint_type=ceilometer_endpoint_type,
region_name=ceilometer_region_name,
session=self.session)
return self._ceilometer
@@ -156,6 +168,8 @@ class OpenStackClients(object):
'monasca', 'api_version')
monascaclient_interface = self._get_client_option(
'monasca', 'interface')
monascaclient_region = self._get_client_option(
'monasca', 'region_name')
token = self.session.get_token()
watcher_clients_auth_config = CONF.get(_CLIENTS_AUTH_GROUP)
service_type = 'monitoring'
@@ -172,7 +186,8 @@ class OpenStackClients(object):
'password': watcher_clients_auth_config.password,
}
endpoint = self.session.get_endpoint(service_type=service_type,
interface=monascaclient_interface)
interface=monascaclient_interface,
region_name=monascaclient_region)
self._monasca = monclient.Client(
monascaclient_version, endpoint, **monasca_kwargs)
@@ -188,9 +203,11 @@ class OpenStackClients(object):
'api_version')
neutron_endpoint_type = self._get_client_option('neutron',
'endpoint_type')
neutron_region_name = self._get_client_option('neutron', 'region_name')
self._neutron = netclient.Client(neutronclient_version,
endpoint_type=neutron_endpoint_type,
region_name=neutron_region_name,
session=self.session)
self._neutron.format = 'json'
return self._neutron
@@ -202,7 +219,9 @@ class OpenStackClients(object):
ironicclient_version = self._get_client_option('ironic', 'api_version')
endpoint_type = self._get_client_option('ironic', 'endpoint_type')
ironic_region_name = self._get_client_option('ironic', 'region_name')
self._ironic = irclient.get_client(ironicclient_version,
os_endpoint_type=endpoint_type,
region_name=ironic_region_name,
session=self.session)
return self._ironic

View File

@@ -11,11 +11,11 @@
# under the License.
from oslo_context import context
from oslo_log import log as logging
from oslo_log import log
from oslo_utils import timeutils
import six
LOG = logging.getLogger(__name__)
LOG = log.getLogger(__name__)
class RequestContext(context.RequestContext):

View File

@@ -26,14 +26,14 @@ import functools
import sys
from keystoneclient import exceptions as keystone_exceptions
from oslo_log import log as logging
from oslo_log import log
import six
from watcher._i18n import _
from watcher import conf
LOG = logging.getLogger(__name__)
LOG = log.getLogger(__name__)
CONF = conf.CONF
@@ -249,7 +249,7 @@ class AuditNotFound(ResourceNotFound):
class AuditAlreadyExists(Conflict):
msg_fmt = _("An audit with UUID %(uuid)s already exists")
msg_fmt = _("An audit with UUID or name %(audit)s already exists")
class AuditIntervalNotSpecified(Invalid):
@@ -305,7 +305,7 @@ class ActionFilterCombinationProhibited(Invalid):
class UnsupportedActionType(UnsupportedError):
msg_fmt = _("Provided %(action_type) is not supported yet")
msg_fmt = _("Provided %(action_type)s is not supported yet")
class EfficacyIndicatorNotFound(ResourceNotFound):
@@ -332,6 +332,10 @@ class PatchError(Invalid):
msg_fmt = _("Couldn't apply patch '%(patch)s'. Reason: %(reason)s")
class DeleteError(Invalid):
msg_fmt = _("Couldn't delete when state is '%(state)s'.")
# decision engine
class WorkflowExecutionException(WatcherException):
@@ -362,6 +366,14 @@ class ClusterEmpty(WatcherException):
msg_fmt = _("The list of compute node(s) in the cluster is empty")
class ComputeClusterEmpty(WatcherException):
msg_fmt = _("The list of compute node(s) in the cluster is empty")
class StorageClusterEmpty(WatcherException):
msg_fmt = _("The list of storage node(s) in the cluster is empty")
class MetricCollectorNotDefined(WatcherException):
msg_fmt = _("The metrics resource collector is not defined")
@@ -405,6 +417,10 @@ class UnsupportedDataSource(UnsupportedError):
"by strategy %(strategy)s")
class DataSourceNotAvailable(WatcherException):
msg_fmt = _("Datasource %(datasource)s is not available.")
class NoSuchMetricForHost(WatcherException):
msg_fmt = _("No %(metric)s metric for %(host)s found.")
@@ -469,6 +485,14 @@ class VolumeNotFound(StorageResourceNotFound):
msg_fmt = _("The volume '%(name)s' could not be found")
class BaremetalResourceNotFound(WatcherException):
msg_fmt = _("The baremetal resource '%(name)s' could not be found")
class IronicNodeNotFound(BaremetalResourceNotFound):
msg_fmt = _("The ironic node %(uuid)s could not be found")
class LoadingError(WatcherException):
msg_fmt = _("Error loading plugin '%(name)s'")

View File

@@ -0,0 +1,49 @@
# -*- encoding: utf-8 -*-
# Copyright (c) 2017 ZTE Corporation
#
# Authors:Yumeng Bao <bao.yumeng@zte.com.cn>
# 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_log import log
from watcher.common import clients
from watcher.common import exception
from watcher.common import utils
LOG = log.getLogger(__name__)
class IronicHelper(object):
def __init__(self, osc=None):
""":param osc: an OpenStackClients instance"""
self.osc = osc if osc else clients.OpenStackClients()
self.ironic = self.osc.ironic()
def get_ironic_node_list(self):
return self.ironic.node.list()
def get_ironic_node_by_uuid(self, node_uuid):
"""Get ironic node by node UUID"""
try:
node = self.ironic.node.get(utils.Struct(uuid=node_uuid))
if not node:
raise exception.IronicNodeNotFound(uuid=node_uuid)
except Exception as exc:
LOG.exception(exc)
raise exception.IronicNodeNotFound(uuid=node_uuid)
# We need to pass an object with an 'uuid' attribute to make it work
return node

View File

@@ -52,20 +52,31 @@ class NovaHelper(object):
return self.nova.hypervisors.get(utils.Struct(id=node_id))
def get_compute_node_by_hostname(self, node_hostname):
"""Get compute node by ID (*not* UUID)"""
# We need to pass an object with an 'id' attribute to make it work
"""Get compute node by hostname"""
try:
compute_nodes = self.nova.hypervisors.search(node_hostname)
if len(compute_nodes) != 1:
hypervisors = [hv for hv in self.get_compute_node_list()
if hv.service['host'] == node_hostname]
if len(hypervisors) != 1:
# TODO(hidekazu)
# this may occur if VMware vCenter driver is used
raise exception.ComputeNodeNotFound(name=node_hostname)
else:
compute_nodes = self.nova.hypervisors.search(
hypervisors[0].hypervisor_hostname)
if len(compute_nodes) != 1:
raise exception.ComputeNodeNotFound(name=node_hostname)
return self.get_compute_node_by_id(compute_nodes[0].id)
return self.get_compute_node_by_id(compute_nodes[0].id)
except Exception as exc:
LOG.exception(exc)
raise exception.ComputeNodeNotFound(name=node_hostname)
def get_instance_list(self):
return self.nova.servers.list(search_opts={'all_tenants': True})
return self.nova.servers.list(search_opts={'all_tenants': True},
limit=-1)
def get_flavor_list(self):
return self.nova.flavors.list(**{'is_public': None})
def get_service(self, service_id):
return self.nova.services.find(id=service_id)
@@ -96,7 +107,7 @@ class NovaHelper(object):
return True
else:
LOG.debug("confirm resize failed for the "
"instance %s" % instance.id)
"instance %s", instance.id)
return False
def wait_for_volume_status(self, volume, status, timeout=60,
@@ -144,19 +155,20 @@ class NovaHelper(object):
"""
new_image_name = ""
LOG.debug(
"Trying a non-live migrate of instance '%s' " % instance_id)
"Trying a non-live migrate of instance '%s' ", instance_id)
# Looking for the instance to migrate
instance = self.find_instance(instance_id)
if not instance:
LOG.debug("Instance %s not found !" % instance_id)
LOG.debug("Instance %s not found !", instance_id)
return False
else:
# NOTE: If destination node is None call Nova API to migrate
# instance
host_name = getattr(instance, "OS-EXT-SRV-ATTR:host")
LOG.debug(
"Instance %s found on host '%s'." % (instance_id, host_name))
"Instance %(instance)s found on host '%(host)s'.",
{'instance': instance_id, 'host': host_name})
if dest_hostname is None:
previous_status = getattr(instance, 'status')
@@ -176,12 +188,12 @@ class NovaHelper(object):
return False
LOG.debug(
"cold migration succeeded : "
"instance %s is now on host '%s'." % (
"instance %s is now on host '%s'.", (
instance_id, new_hostname))
return True
else:
LOG.debug(
"cold migration for instance %s failed" % instance_id)
"cold migration for instance %s failed", instance_id)
return False
if not keep_original_image_name:
@@ -200,11 +212,7 @@ class NovaHelper(object):
new_image_name = getattr(image, "name")
instance_name = getattr(instance, "name")
flavordict = getattr(instance, "flavor")
# a_dict = dict([flavorstr.strip('{}').split(":"),])
flavor_id = flavordict["id"]
flavor = self.nova.flavors.get(flavor_id)
flavor_name = getattr(flavor, "name")
flavor_name = instance.flavor.get('original_name')
keypair_name = getattr(instance, "key_name")
addresses = getattr(instance, "addresses")
@@ -214,7 +222,7 @@ class NovaHelper(object):
for network_name, network_conf_obj in addresses.items():
LOG.debug(
"Extracting network configuration for network '%s'" %
"Extracting network configuration for network '%s'",
network_name)
network_names_list.append(network_name)
@@ -235,7 +243,7 @@ class NovaHelper(object):
stopped_ok = self.stop_instance(instance_id)
if not stopped_ok:
LOG.debug("Could not stop instance: %s" % instance_id)
LOG.debug("Could not stop instance: %s", instance_id)
return False
# Building the temporary image which will be used
@@ -245,7 +253,7 @@ class NovaHelper(object):
if not image_uuid:
LOG.debug(
"Could not build temporary image of instance: %s" %
"Could not build temporary image of instance: %s",
instance_id)
return False
@@ -293,8 +301,10 @@ class NovaHelper(object):
blocks.append(
block_device_mapping_v2_item)
LOG.debug("Detaching volume %s from instance: %s" % (
volume_id, instance_id))
LOG.debug(
"Detaching volume %(volume)s from "
"instance: %(instance)s",
{'volume': volume_id, 'instance': instance_id})
# volume.detach()
self.nova.volumes.delete_server_volume(instance_id,
volume_id)
@@ -302,11 +312,12 @@ class NovaHelper(object):
if not self.wait_for_volume_status(volume, "available", 5,
10):
LOG.debug(
"Could not detach volume %s from instance: %s" % (
volume_id, instance_id))
"Could not detach volume %(volume)s "
"from instance: %(instance)s",
{'volume': volume_id, 'instance': instance_id})
return False
except ciexceptions.NotFound:
LOG.debug("Volume '%s' not found " % image_id)
LOG.debug("Volume '%s' not found ", image_id)
return False
# We create the new instance from
@@ -325,18 +336,21 @@ class NovaHelper(object):
if not new_instance:
LOG.debug(
"Could not create new instance "
"for non-live migration of instance %s" % instance_id)
"for non-live migration of instance %s", instance_id)
return False
try:
LOG.debug("Detaching floating ip '%s' from instance %s" % (
floating_ip, instance_id))
LOG.debug(
"Detaching floating ip '%(floating_ip)s' "
"from instance %(instance)s",
{'floating_ip': floating_ip, 'instance': instance_id})
# We detach the floating ip from the current instance
instance.remove_floating_ip(floating_ip)
LOG.debug(
"Attaching floating ip '%s' to the new instance %s" % (
floating_ip, new_instance.id))
"Attaching floating ip '%(ip)s' to the new "
"instance %(id)s",
{'ip': floating_ip, 'id': new_instance.id})
# We attach the same floating ip to the new instance
new_instance.add_floating_ip(floating_ip)
@@ -348,12 +362,12 @@ class NovaHelper(object):
# Deleting the old instance (because no more useful)
delete_ok = self.delete_instance(instance_id)
if not delete_ok:
LOG.debug("Could not delete instance: %s" % instance_id)
LOG.debug("Could not delete instance: %s", instance_id)
return False
LOG.debug(
"Instance %s has been successfully migrated "
"to new host '%s' and its new id is %s." % (
"to new host '%s' and its new id is %s.", (
instance_id, new_host_name, new_instance.id))
return True
@@ -370,8 +384,10 @@ class NovaHelper(object):
:param instance_id: the unique id of the instance to resize.
:param flavor: the name or ID of the flavor to resize to.
"""
LOG.debug("Trying a resize of instance %s to flavor '%s'" % (
instance_id, flavor))
LOG.debug(
"Trying a resize of instance %(instance)s to "
"flavor '%(flavor)s'",
{'instance': instance_id, 'flavor': flavor})
# Looking for the instance to resize
instance = self.find_instance(instance_id)
@@ -388,17 +404,17 @@ class NovaHelper(object):
"instance %s. Exception: %s", instance_id, e)
if not flavor_id:
LOG.debug("Flavor not found: %s" % flavor)
LOG.debug("Flavor not found: %s", flavor)
return False
if not instance:
LOG.debug("Instance not found: %s" % instance_id)
LOG.debug("Instance not found: %s", instance_id)
return False
instance_status = getattr(instance, 'OS-EXT-STS:vm_state')
LOG.debug(
"Instance %s is in '%s' status." % (instance_id,
instance_status))
"Instance %(id)s is in '%(status)s' status.",
{'id': instance_id, 'status': instance_status})
instance.resize(flavor=flavor_id)
while getattr(instance,
@@ -422,8 +438,7 @@ class NovaHelper(object):
return True
def live_migrate_instance(self, instance_id, dest_hostname,
block_migration=False, retry=120):
def live_migrate_instance(self, instance_id, dest_hostname, retry=120):
"""This method does a live migration of a given instance
This method uses the Nova built-in live_migrate()
@@ -436,22 +451,25 @@ class NovaHelper(object):
:param dest_hostname: the name of the destination compute node, if
destination_node is None, nova scheduler choose
the destination host
:param block_migration: No shared storage is required.
"""
LOG.debug("Trying to live migrate instance %s " % (instance_id))
LOG.debug(
"Trying a live migrate instance %(instance)s ",
{'instance': instance_id})
# Looking for the instance to migrate
instance = self.find_instance(instance_id)
if not instance:
LOG.debug("Instance not found: %s" % instance_id)
LOG.debug("Instance not found: %s", instance_id)
return False
else:
host_name = getattr(instance, 'OS-EXT-SRV-ATTR:host')
LOG.debug(
"Instance %s found on host '%s'." % (instance_id, host_name))
"Instance %(instance)s found on host '%(host)s'.",
{'instance': instance_id, 'host': host_name})
instance.live_migrate(host=dest_hostname,
block_migration=block_migration)
# From nova api version 2.25(Mitaka release), the default value of
# block_migration is None which is mapped to 'auto'.
instance.live_migrate(host=dest_hostname)
instance = self.nova.servers.get(instance_id)
@@ -469,7 +487,7 @@ class NovaHelper(object):
if host_name != new_hostname and instance.status == 'ACTIVE':
LOG.debug(
"Live migration succeeded : "
"instance %s is now on host '%s'." % (
"instance %s is now on host '%s'.", (
instance_id, new_hostname))
return True
else:
@@ -479,6 +497,9 @@ class NovaHelper(object):
'OS-EXT-SRV-ATTR:host') != dest_hostname \
and retry:
instance = self.nova.servers.get(instance.id)
if not getattr(instance, 'OS-EXT-STS:task_state'):
LOG.debug("Instance task state: %s is null", instance_id)
break
LOG.debug(
'Waiting the migration of {0} to {1}'.format(
instance,
@@ -493,13 +514,13 @@ class NovaHelper(object):
LOG.debug(
"Live migration succeeded : "
"instance %s is now on host '%s'." % (
instance_id, host_name))
"instance %(instance)s is now on host '%(host)s'.",
{'instance': instance_id, 'host': host_name})
return True
def abort_live_migrate(self, instance_id, source, destination, retry=240):
LOG.debug("Aborting live migration of instance %s" % instance_id)
LOG.debug("Aborting live migration of instance %s", instance_id)
migration = self.get_running_migration(instance_id)
if migration:
migration_id = getattr(migration[0], "id")
@@ -512,7 +533,7 @@ class NovaHelper(object):
LOG.exception(e)
else:
LOG.debug(
"No running migrations found for instance %s" % instance_id)
"No running migrations found for instance %s", instance_id)
while retry:
instance = self.nova.servers.get(instance_id)
@@ -543,16 +564,17 @@ class NovaHelper(object):
else:
return False
def disable_service_nova_compute(self, hostname):
if self.nova.services.disable(host=hostname,
binary='nova-compute'). \
def disable_service_nova_compute(self, hostname, reason=None):
if self.nova.services.disable_log_reason(host=hostname,
binary='nova-compute',
reason=reason). \
status == 'disabled':
return True
else:
return False
def set_host_offline(self, hostname):
# See API on http://developer.openstack.org/api-ref-compute-v2.1.html
# See API on https://developer.openstack.org/api-ref/compute/
# especially the PUT request
# regarding this resource : /v2.1/os-hosts/{host_name}
#
@@ -576,7 +598,7 @@ class NovaHelper(object):
host = self.nova.hosts.get(hostname)
if not host:
LOG.debug("host not found: %s" % hostname)
LOG.debug("host not found: %s", hostname)
return False
else:
host[0].update(
@@ -598,18 +620,19 @@ class NovaHelper(object):
key-value pairs to associate to the image as metadata.
"""
LOG.debug(
"Trying to create an image from instance %s ..." % instance_id)
"Trying to create an image from instance %s ...", instance_id)
# Looking for the instance
instance = self.find_instance(instance_id)
if not instance:
LOG.debug("Instance not found: %s" % instance_id)
LOG.debug("Instance not found: %s", instance_id)
return None
else:
host_name = getattr(instance, 'OS-EXT-SRV-ATTR:host')
LOG.debug(
"Instance %s found on host '%s'." % (instance_id, host_name))
"Instance %(instance)s found on host '%(host)s'.",
{'instance': instance_id, 'host': host_name})
# We need to wait for an appropriate status
# of the instance before we can build an image from it
@@ -636,14 +659,15 @@ class NovaHelper(object):
if not image:
break
status = image.status
LOG.debug("Current image status: %s" % status)
LOG.debug("Current image status: %s", status)
if not image:
LOG.debug("Image not found: %s" % image_uuid)
LOG.debug("Image not found: %s", image_uuid)
else:
LOG.debug(
"Image %s successfully created for instance %s" % (
image_uuid, instance_id))
"Image %(image)s successfully created for "
"instance %(instance)s",
{'image': image_uuid, 'instance': instance_id})
return image_uuid
return None
@@ -652,16 +676,16 @@ class NovaHelper(object):
:param instance_id: the unique id of the instance to delete.
"""
LOG.debug("Trying to remove instance %s ..." % instance_id)
LOG.debug("Trying to remove instance %s ...", instance_id)
instance = self.find_instance(instance_id)
if not instance:
LOG.debug("Instance not found: %s" % instance_id)
LOG.debug("Instance not found: %s", instance_id)
return False
else:
self.nova.servers.delete(instance_id)
LOG.debug("Instance %s removed." % instance_id)
LOG.debug("Instance %s removed.", instance_id)
return True
def stop_instance(self, instance_id):
@@ -669,21 +693,21 @@ class NovaHelper(object):
:param instance_id: the unique id of the instance to stop.
"""
LOG.debug("Trying to stop instance %s ..." % instance_id)
LOG.debug("Trying to stop instance %s ...", instance_id)
instance = self.find_instance(instance_id)
if not instance:
LOG.debug("Instance not found: %s" % instance_id)
LOG.debug("Instance not found: %s", instance_id)
return False
elif getattr(instance, 'OS-EXT-STS:vm_state') == "stopped":
LOG.debug("Instance has been stopped: %s" % instance_id)
LOG.debug("Instance has been stopped: %s", instance_id)
return True
else:
self.nova.servers.stop(instance_id)
if self.wait_for_instance_state(instance, "stopped", 8, 10):
LOG.debug("Instance %s stopped." % instance_id)
LOG.debug("Instance %s stopped.", instance_id)
return True
else:
return False
@@ -724,11 +748,11 @@ class NovaHelper(object):
return False
while instance.status not in status_list and retry:
LOG.debug("Current instance status: %s" % instance.status)
LOG.debug("Current instance status: %s", instance.status)
time.sleep(sleep)
instance = self.nova.servers.get(instance.id)
retry -= 1
LOG.debug("Current instance status: %s" % instance.status)
LOG.debug("Current instance status: %s", instance.status)
return instance.status in status_list
def create_instance(self, node_id, inst_name="test", image_id=None,
@@ -744,35 +768,34 @@ class NovaHelper(object):
It returns the unique id of the created instance.
"""
LOG.debug(
"Trying to create new instance '%s' "
"from image '%s' with flavor '%s' ..." % (
inst_name, image_id, flavor_name))
"Trying to create new instance '%(inst)s' "
"from image '%(image)s' with flavor '%(flavor)s' ...",
{'inst': inst_name, 'image': image_id, 'flavor': flavor_name})
try:
self.nova.keypairs.findall(name=keypair_name)
except nvexceptions.NotFound:
LOG.debug("Key pair '%s' not found " % keypair_name)
LOG.debug("Key pair '%s' not found ", keypair_name)
return
try:
image = self.glance.images.get(image_id)
except glexceptions.NotFound:
LOG.debug("Image '%s' not found " % image_id)
LOG.debug("Image '%s' not found ", image_id)
return
try:
flavor = self.nova.flavors.find(name=flavor_name)
except nvexceptions.NotFound:
LOG.debug("Flavor '%s' not found " % flavor_name)
LOG.debug("Flavor '%s' not found ", flavor_name)
return
# Make sure all security groups exist
for sec_group_name in sec_group_list:
try:
self.nova.security_groups.find(name=sec_group_name)
group_id = self.get_security_group_id_from_name(sec_group_name)
except nvexceptions.NotFound:
LOG.debug("Security group '%s' not found " % sec_group_name)
if not group_id:
LOG.debug("Security group '%s' not found ", sec_group_name)
return
net_list = list()
@@ -781,7 +804,7 @@ class NovaHelper(object):
nic_id = self.get_network_id_from_name(network_name)
if not nic_id:
LOG.debug("Network '%s' not found " % network_name)
LOG.debug("Network '%s' not found ", network_name)
return
net_obj = {"net-id": nic_id}
net_list.append(net_obj)
@@ -807,17 +830,27 @@ class NovaHelper(object):
if create_new_floating_ip and instance.status == 'ACTIVE':
LOG.debug(
"Creating a new floating IP"
" for instance '%s'" % instance.id)
" for instance '%s'", instance.id)
# Creating floating IP for the new instance
floating_ip = self.nova.floating_ips.create()
instance.add_floating_ip(floating_ip)
LOG.debug("Instance %s associated to Floating IP '%s'" % (
instance.id, floating_ip.ip))
LOG.debug(
"Instance %(instance)s associated to "
"Floating IP '%(ip)s'",
{'instance': instance.id, 'ip': floating_ip.ip})
return instance
def get_security_group_id_from_name(self, group_name="default"):
"""This method returns the security group of the provided group name"""
security_groups = self.neutron.list_security_groups(name=group_name)
security_group_id = security_groups['security_groups'][0]['id']
return security_group_id
def get_network_id_from_name(self, net_name="private"):
"""This method returns the unique id of the provided network name"""
networks = self.neutron.list_networks(name=net_name)
@@ -839,8 +872,9 @@ class NovaHelper(object):
def get_instances_by_node(self, host):
return [instance for instance in
self.nova.servers.list(search_opts={"all_tenants": True})
if self.get_hostname(instance) == host]
self.nova.servers.list(search_opts={"all_tenants": True,
"host": host},
limit=-1)]
def get_hostname(self, instance):
return str(getattr(instance, 'OS-EXT-SRV-ATTR:host'))
@@ -880,7 +914,7 @@ class NovaHelper(object):
LOG.debug('Waiting volume update to {0}'.format(new_volume))
time.sleep(retry_interval)
retry -= 1
LOG.debug("retry count: %s" % retry)
LOG.debug("retry count: %s", retry)
if getattr(new_volume, 'status') != "in-use":
LOG.error("Volume update retry timeout or error")
return False
@@ -888,5 +922,6 @@ class NovaHelper(object):
host_name = getattr(new_volume, "os-vol-host-attr:host")
LOG.debug(
"Volume update succeeded : "
"Volume %s is now on host '%s'." % (new_volume.id, host_name))
"Volume %s is now on host '%s'.",
(new_volume.id, host_name))
return True

View File

@@ -0,0 +1,37 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import itertools
from watcher.common.policies import action
from watcher.common.policies import action_plan
from watcher.common.policies import audit
from watcher.common.policies import audit_template
from watcher.common.policies import base
from watcher.common.policies import goal
from watcher.common.policies import scoring_engine
from watcher.common.policies import service
from watcher.common.policies import strategy
def list_rules():
return itertools.chain(
base.list_rules(),
action.list_rules(),
action_plan.list_rules(),
audit.list_rules(),
audit_template.list_rules(),
goal.list_rules(),
scoring_engine.list_rules(),
service.list_rules(),
strategy.list_rules(),
)

View File

@@ -0,0 +1,57 @@
# 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_policy import policy
from watcher.common.policies import base
ACTION = 'action:%s'
rules = [
policy.DocumentedRuleDefault(
name=ACTION % 'detail',
check_str=base.RULE_ADMIN_API,
description='Retrieve a list of actions with detail.',
operations=[
{
'path': '/v1/actions/detail',
'method': 'GET'
}
]
),
policy.DocumentedRuleDefault(
name=ACTION % 'get',
check_str=base.RULE_ADMIN_API,
description='Retrieve information about a given action.',
operations=[
{
'path': '/v1/actions/{action_id}',
'method': 'GET'
}
]
),
policy.DocumentedRuleDefault(
name=ACTION % 'get_all',
check_str=base.RULE_ADMIN_API,
description='Retrieve a list of all actions.',
operations=[
{
'path': '/v1/actions',
'method': 'GET'
}
]
)
]
def list_rules():
return rules

View File

@@ -0,0 +1,79 @@
# 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_policy import policy
from watcher.common.policies import base
ACTION_PLAN = 'action_plan:%s'
rules = [
policy.DocumentedRuleDefault(
name=ACTION_PLAN % 'delete',
check_str=base.RULE_ADMIN_API,
description='Delete an action plan.',
operations=[
{
'path': '/v1/action_plans/{action_plan_uuid}',
'method': 'DELETE'
}
]
),
policy.DocumentedRuleDefault(
name=ACTION_PLAN % 'detail',
check_str=base.RULE_ADMIN_API,
description='Retrieve a list of action plans with detail.',
operations=[
{
'path': '/v1/action_plans/detail',
'method': 'GET'
}
]
),
policy.DocumentedRuleDefault(
name=ACTION_PLAN % 'get',
check_str=base.RULE_ADMIN_API,
description='Get an action plan.',
operations=[
{
'path': '/v1/action_plans/{action_plan_id}',
'method': 'GET'
}
]
),
policy.DocumentedRuleDefault(
name=ACTION_PLAN % 'get_all',
check_str=base.RULE_ADMIN_API,
description='Get all action plans.',
operations=[
{
'path': '/v1/action_plans',
'method': 'GET'
}
]
),
policy.DocumentedRuleDefault(
name=ACTION_PLAN % 'update',
check_str=base.RULE_ADMIN_API,
description='Update an action plans.',
operations=[
{
'path': '/v1/action_plans/{action_plan_uuid}',
'method': 'PATCH'
}
]
)
]
def list_rules():
return rules

View File

@@ -0,0 +1,90 @@
# 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_policy import policy
from watcher.common.policies import base
AUDIT = 'audit:%s'
rules = [
policy.DocumentedRuleDefault(
name=AUDIT % 'create',
check_str=base.RULE_ADMIN_API,
description='Create a new audit.',
operations=[
{
'path': '/v1/audits',
'method': 'POST'
}
]
),
policy.DocumentedRuleDefault(
name=AUDIT % 'delete',
check_str=base.RULE_ADMIN_API,
description='Delete an audit.',
operations=[
{
'path': '/v1/audits/{audit_uuid}',
'method': 'DELETE'
}
]
),
policy.DocumentedRuleDefault(
name=AUDIT % 'detail',
check_str=base.RULE_ADMIN_API,
description='Retrieve audit list with details.',
operations=[
{
'path': '/v1/audits/detail',
'method': 'GET'
}
]
),
policy.DocumentedRuleDefault(
name=AUDIT % 'get',
check_str=base.RULE_ADMIN_API,
description='Get an audit.',
operations=[
{
'path': '/v1/audits/{audit_uuid}',
'method': 'GET'
}
]
),
policy.DocumentedRuleDefault(
name=AUDIT % 'get_all',
check_str=base.RULE_ADMIN_API,
description='Get all audits.',
operations=[
{
'path': '/v1/audits',
'method': 'GET'
}
]
),
policy.DocumentedRuleDefault(
name=AUDIT % 'update',
check_str=base.RULE_ADMIN_API,
description='Update an audit.',
operations=[
{
'path': '/v1/audits/{audit_uuid}',
'method': 'PATCH'
}
]
)
]
def list_rules():
return rules

View File

@@ -0,0 +1,90 @@
# 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_policy import policy
from watcher.common.policies import base
AUDIT_TEMPLATE = 'audit_template:%s'
rules = [
policy.DocumentedRuleDefault(
name=AUDIT_TEMPLATE % 'create',
check_str=base.RULE_ADMIN_API,
description='Create an audit template.',
operations=[
{
'path': '/v1/audit_templates',
'method': 'POST'
}
]
),
policy.DocumentedRuleDefault(
name=AUDIT_TEMPLATE % 'delete',
check_str=base.RULE_ADMIN_API,
description='Delete an audit template.',
operations=[
{
'path': '/v1/audit_templates/{audit_template_uuid}',
'method': 'DELETE'
}
]
),
policy.DocumentedRuleDefault(
name=AUDIT_TEMPLATE % 'detail',
check_str=base.RULE_ADMIN_API,
description='Retrieve a list of audit templates with details.',
operations=[
{
'path': '/v1/audit_templates/detail',
'method': 'GET'
}
]
),
policy.DocumentedRuleDefault(
name=AUDIT_TEMPLATE % 'get',
check_str=base.RULE_ADMIN_API,
description='Get an audit template.',
operations=[
{
'path': '/v1/audit_templates/{audit_template_uuid}',
'method': 'GET'
}
]
),
policy.DocumentedRuleDefault(
name=AUDIT_TEMPLATE % 'get_all',
check_str=base.RULE_ADMIN_API,
description='Get a list of all audit templates.',
operations=[
{
'path': '/v1/audit_templates',
'method': 'GET'
}
]
),
policy.DocumentedRuleDefault(
name=AUDIT_TEMPLATE % 'update',
check_str=base.RULE_ADMIN_API,
description='Update an audit template.',
operations=[
{
'path': '/v1/audit_templates/{audit_template_uuid}',
'method': 'PATCH'
}
]
)
]
def list_rules():
return rules

View File

@@ -0,0 +1,32 @@
# 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_policy import policy
RULE_ADMIN_API = 'rule:admin_api'
ROLE_ADMIN_OR_ADMINISTRATOR = 'role:admin or role:administrator'
ALWAYS_DENY = '!'
rules = [
policy.RuleDefault(
name='admin_api',
check_str=ROLE_ADMIN_OR_ADMINISTRATOR
),
policy.RuleDefault(
name='show_password',
check_str=ALWAYS_DENY
)
]
def list_rules():
return rules

View File

@@ -0,0 +1,57 @@
# 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_policy import policy
from watcher.common.policies import base
GOAL = 'goal:%s'
rules = [
policy.DocumentedRuleDefault(
name=GOAL % 'detail',
check_str=base.RULE_ADMIN_API,
description='Retrieve a list of goals with detail.',
operations=[
{
'path': '/v1/goals/detail',
'method': 'DELETE'
}
]
),
policy.DocumentedRuleDefault(
name=GOAL % 'get',
check_str=base.RULE_ADMIN_API,
description='Get a goal.',
operations=[
{
'path': '/v1/goals/{goal_uuid}',
'method': 'GET'
}
]
),
policy.DocumentedRuleDefault(
name=GOAL % 'get_all',
check_str=base.RULE_ADMIN_API,
description='Get all goals.',
operations=[
{
'path': '/v1/goals',
'method': 'GET'
}
]
)
]
def list_rules():
return rules

View File

@@ -0,0 +1,66 @@
# 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_policy import policy
from watcher.common.policies import base
SCORING_ENGINE = 'scoring_engine:%s'
rules = [
# FIXME(lbragstad): Find someone from watcher to double check this
# information. This API isn't listed in watcher's API reference
# documentation.
policy.DocumentedRuleDefault(
name=SCORING_ENGINE % 'detail',
check_str=base.RULE_ADMIN_API,
description='List scoring engines with details.',
operations=[
{
'path': '/v1/scoring_engines/detail',
'method': 'GET'
}
]
),
# FIXME(lbragstad): Find someone from watcher to double check this
# information. This API isn't listed in watcher's API reference
# documentation.
policy.DocumentedRuleDefault(
name=SCORING_ENGINE % 'get',
check_str=base.RULE_ADMIN_API,
description='Get a scoring engine.',
operations=[
{
'path': '/v1/scoring_engines/{scoring_engine_id}',
'method': 'GET'
}
]
),
# FIXME(lbragstad): Find someone from watcher to double check this
# information. This API isn't listed in watcher's API reference
# documentation.
policy.DocumentedRuleDefault(
name=SCORING_ENGINE % 'get_all',
check_str=base.RULE_ADMIN_API,
description='Get all scoring engines.',
operations=[
{
'path': '/v1/scoring_engines',
'method': 'GET'
}
]
)
]
def list_rules():
return rules

View File

@@ -0,0 +1,57 @@
# 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_policy import policy
from watcher.common.policies import base
SERVICE = 'service:%s'
rules = [
policy.DocumentedRuleDefault(
name=SERVICE % 'detail',
check_str=base.RULE_ADMIN_API,
description='List services with detail.',
operations=[
{
'path': '/v1/services/',
'method': 'GET'
}
]
),
policy.DocumentedRuleDefault(
name=SERVICE % 'get',
check_str=base.RULE_ADMIN_API,
description='Get a specific service.',
operations=[
{
'path': '/v1/services/{service_id}',
'method': 'GET'
}
]
),
policy.DocumentedRuleDefault(
name=SERVICE % 'get_all',
check_str=base.RULE_ADMIN_API,
description='List all services.',
operations=[
{
'path': '/v1/services/',
'method': 'GET'
}
]
),
]
def list_rules():
return rules

View File

@@ -0,0 +1,68 @@
# 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_policy import policy
from watcher.common.policies import base
STRATEGY = 'strategy:%s'
rules = [
policy.DocumentedRuleDefault(
name=STRATEGY % 'detail',
check_str=base.RULE_ADMIN_API,
description='List strategies with detail.',
operations=[
{
'path': '/v1/strategies/detail',
'method': 'GET'
}
]
),
policy.DocumentedRuleDefault(
name=STRATEGY % 'get',
check_str=base.RULE_ADMIN_API,
description='Get a strategy.',
operations=[
{
'path': '/v1/strategies/{strategy_uuid}',
'method': 'GET'
}
]
),
policy.DocumentedRuleDefault(
name=STRATEGY % 'get_all',
check_str=base.RULE_ADMIN_API,
description='List all strategies.',
operations=[
{
'path': '/v1/strategies',
'method': 'GET'
}
]
),
policy.DocumentedRuleDefault(
name=STRATEGY % 'state',
check_str=base.RULE_ADMIN_API,
description='Get state of strategy.',
operations=[
{
'path': '/v1/strategies{strategy_uuid}/state',
'method': 'GET'
}
]
)
]
def list_rules():
return rules

View File

@@ -15,11 +15,13 @@
"""Policy Engine For Watcher."""
import sys
from oslo_config import cfg
from oslo_policy import policy
from watcher.common import exception
from watcher.common import policies
_ENFORCER = None
CONF = cfg.CONF
@@ -56,6 +58,7 @@ def init(policy_file=None, rules=None,
default_rule=default_rule,
use_conf=use_conf,
overwrite=overwrite)
_ENFORCER.register_defaults(policies.list_rules())
return _ENFORCER
@@ -92,3 +95,23 @@ def enforce(context, rule=None, target=None,
'user_id': context.user_id}
return enforcer.enforce(rule, target, credentials,
do_raise=do_raise, exc=exc, *args, **kwargs)
def get_enforcer():
# This method is for use by oslopolicy CLI scripts. Those scripts need the
# 'output-file' and 'namespace' options, but having those in sys.argv means
# loading the Watcher config options will fail as those are not expected
# to be present. So we pass in an arg list with those stripped out.
conf_args = []
# Start at 1 because cfg.CONF expects the equivalent of sys.argv[1:]
i = 1
while i < len(sys.argv):
if sys.argv[i].strip('-') in ['namespace', 'output-file']:
i += 2
continue
conf_args.append(sys.argv[i])
i += 1
cfg.CONF(conf_args, project='watcher')
init()
return _ENFORCER

View File

@@ -69,7 +69,8 @@ _DEFAULT_LOG_LEVELS = ['amqp=WARN', 'amqplib=WARN', 'qpid.messaging=INFO',
'keystoneclient=INFO', 'stevedore=INFO',
'eventlet.wsgi.server=WARN', 'iso8601=WARN',
'paramiko=WARN', 'requests=WARN', 'neutronclient=WARN',
'glanceclient=WARN', 'watcher.openstack.common=WARN']
'glanceclient=WARN', 'watcher.openstack.common=WARN',
'apscheduler=WARN']
Singleton = service.Singleton

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