Compare commits

...

100 Commits

Author SHA1 Message Date
Alfredo Moralejo
2b103c40a7 Fix compatibility with oslo.db 12.1.0
oslo.db 12.1.0 has changed the default value for the 'autocommit'
parameter of 'LegacyEngineFacade' from 'True' to 'False'. This is a
necessary step to ensure compatibility with SQLAlchemy 2.0. However, we
are currently relying on the autocommit behavior and need changes to
explicitly manage sessions. Until that happens, we need to override the
default.

This also moves the watcher queue declaration from the pipeline level
(where it is no longer valid) to the project level.

Co-Authored-By: Thierry Carrez <thierry@openstack.org>
Co-Authored-By: Stephen Finucane <stephenfin@redhat.com>
(cherry picked from commit 5d70c207cd)
Change-Id: I7db39d958d087322bfa0aad70dfbd04de9228dd7
2022-09-26 14:16:27 +02:00
Zuul
a43b040ebc Merge "Imported Translations from Zanata" 2022-08-30 10:44:52 +00:00
Zuul
749fa2507a Merge "Tests: fix requirements for unit tests" 2022-08-30 08:15:05 +00:00
OpenStack Proposal Bot
76d61362ee Imported Translations from Zanata
For more information about this automatic import see:
https://docs.openstack.org/i18n/latest/reviewing-translation-import.html

Change-Id: I95133dece6fdaf931dfed64015806430ba8d04f0
2022-08-29 04:12:15 +00:00
wangjiaqi07
c55143bc21 remove unicode from code
Change-Id: I747445d482a2fb40c2f39139c5fd2a0cb26c27bc
2022-08-19 14:17:10 +08:00
suzhengwei
7609df3370 Tests: fix requirements for unit tests
Add WebTest to test-requirements which used to be imported as a
transitive requirement via pecan, but the latest release of
pecan dropped this dependency. So make this requirement explicit.

Related-Bug: #1982110
Change-Id: I4852be23b489257aaa56d3fa22d27f72bcabf919
2022-07-28 16:14:13 +08:00
chenker
b57eac12cb Watcher DB upgrde compatibility consideration for add_apscheduler_jobs
Change-Id: I8896ff5731bb8c1bf88a5d7b926bd2a884100ea8
2022-04-28 02:21:06 +00:00
OpenStack Release Bot
ac6911d3c4 Add Python3 zed unit tests
This is an automatically generated patch to ensure unit testing
is in place for all the of the tested runtimes for zed.

See also the PTI in governance [1].

[1]: https://governance.openstack.org/tc/reference/project-testing-interface.html

Change-Id: I5cf874842550de18ff777b909fd28e2c32e6d530
2022-03-10 12:14:06 +00:00
OpenStack Release Bot
23c2010681 Update master for stable/yoga
Add file to the reno documentation build to show release notes for
stable/yoga.

Use pbr instruction to increment the minor version number
automatically so that master versions are higher than the versions on
stable/yoga.

Sem-Ver: feature
Change-Id: Ic7c275b38fef9afc29577f81fe92546bb94b2930
2022-03-10 12:14:04 +00:00
zhurong
01d74d0a87 Remove ceilometerclient dependecy
Change-Id: Ifa0f2493aa8414a29dc2722b6636a33bc5808be6
2022-01-07 05:48:22 +00:00
OpenStack Release Bot
e4fab0ce7f Add Python3 yoga unit tests
This is an automatically generated patch to ensure unit testing
is in place for all the of the tested runtimes for yoga.

See also the PTI in governance [1].

[1]: https://governance.openstack.org/tc/reference/project-testing-interface.html

Change-Id: I328b3ccb76153fa0dbb4d174dd976412be049200
2021-09-15 17:14:09 +00:00
OpenStack Release Bot
76ecaaeb3a Update master for stable/xena
Add file to the reno documentation build to show release notes for
stable/xena.

Use pbr instruction to increment the minor version number
automatically so that master versions are higher than the versions on
stable/xena.

Sem-Ver: feature
Change-Id: If1c02305a153575c6a550844b0c6f45b74ea5ef3
2021-09-15 17:14:07 +00:00
chenker
6dd2f2a9c1 BugFix: Prevent float type variables from being passed to random
>>> random.sample([5,10], 1.3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python3.6/random.py", line 321, in sample
    result = [None] * k
TypeError: can't multiply sequence by non-int of type 'float'

Change-Id: Ifa5dca06f07220512579e4fe3c5c741aeffc71cc
2021-08-23 01:58:52 +00:00
Takashi Kajinami
a993849928 Use Block Storage API v3 instead of API v2
Block Storage API v2 was deprecated during Pike cycle and is being
removed during Xena cycle, and current v3 API should be used instead.

Change-Id: Ia5247742b31f5f07186ef908588f0972d3ac609f
2021-07-27 11:04:16 +09:00
Zuul
6dbac1f6ae Merge "Add watcher dashboard to devstack documentation" 2021-07-13 14:31:16 +00:00
sue
c28756c48b use HTTPStatus instead of direct code
Python introduced http.HTTPStatus since version 3.5,
and Wallaby has targeted a minimum version of python 3.6.

Change-Id: I45f732f0f59b8fae831bb6c07f4fdd98cdd7409a
2021-07-09 11:02:36 +02:00
Dantali0n
2414f66e38 Add watcher dashboard to devstack documentation
Since installing watcher dashboard is fixed in devstack deployments
we can update documentation so it recommends to install dashboard
plugin.

Change-Id: I284a1ec31536ea258cc1979ffd46b22d3e1ac18b
2021-07-09 10:37:28 +02:00
Dantali0n
546b730c9b Changed minversion in tox to 3.18.0
The patch bumps min version of tox to 3.18.0 in order to
replace tox's whitelist_externals by allowlist_externals option:
https://github.com/tox-dev/tox/blob/master/docs/changelog.rst#v3180-2020-07-23

Change-Id: I00b6af1560c84d0b99b6044078c1d65d22b206b0
2021-07-06 12:48:55 +02:00
Zuul
75be54aa89 Merge "Manage constraints with testenv install_command" 2021-07-06 07:25:03 +00:00
Zuul
4e9e75f4a0 Merge "Enable tls-proxy as default in test jobs" 2021-07-05 14:17:37 +00:00
Dantali0n
e0779175cf Manage constraints with testenv install_command
This prevents having to duplicate the -c{} deps argument
across all environments in tox.ini

Change-Id: I621b581417f6967271b3a93385d592098689ae9e
2021-07-02 10:43:44 +00:00
songwenping
1235153b4c Use py3 as the default runtime for tox
Moving on py3 as the default runtime for tox to avoid to update this at
each new cycle.

Wallaby support officially the following runtimes [1]:
- Python 3.6
- Python 3.8

During Victoria Python 3.7 was used as the default runtime [2] however this
version isn't longer officially supported.

[1] https://governance.openstack.org/tc/reference/runtimes/wallaby.html#python-runtimes-for-wallaby
[2] https://governance.openstack.org/tc/reference/runtimes/victoria.html#python-runtimes-for-victoria

Change-Id: Id4b5cb679c60fda4132a10f684ed5128c0965230
2021-07-01 09:37:08 +00:00
Zuul
bf5ce9aa3f Merge "setup.cfg: Replace dashes with underscores" 2021-07-01 09:06:01 +00:00
ricolin
204992ff6f Enable tls-proxy as default in test jobs
Change-Id: Idbc8850269d84d0a3041c17f4453b00452c9dab8
2021-07-01 08:25:12 +00:00
Zuul
386e288543 Merge "Add Python3 xena unit tests" 2021-07-01 07:59:41 +00:00
maaoyu
6f668133ad setup.cfg: Replace dashes with underscores
Setuptools v54.1.0 introduces a warning that the use of dash-separated
options in 'setup.cfg' will not be supported in a future version [1].
Get ahead of the issue by replacing the dashes with underscores. Without
this, we see 'UserWarning' messages like the following on new enough
versions of setuptools:

  UserWarning: Usage of dash-separated 'description-file' will not be
  supported in future versions. Please use the underscore name
  'description_file' instead

[1] https://github.com/pypa/setuptools/commit/a2e9ae4cb

Change-Id: Ide4d650a78829a6bc16d86b620e6b3fbed0bba06
2021-07-01 07:19:01 +00:00
Zuul
fb625bfa56 Merge "Update master for stable/wallaby" 2021-06-30 15:27:12 +00:00
Zuul
32cb132712 Merge "requirements: Drop os-testr" 2021-06-30 11:48:43 +00:00
ericxiett
9ca44fa3ab Replace deprecated with_lockmode with with_for_update
The Query.with_lockmode() method is deprecated since version 0.9.0
and will be removed in a future release. [1]
This patch replaces it with Query.with_for_update().
The 'faultstring' was been modified to 'Exactly 5 or 6 columns has to be
specified for iterator expression', so adds one space between "iterator"
and "expression" for 'expected_error_msg'.

Also use upper-constraints in doc build to avoid issues in pdf build.

[1]
https://docs.sqlalchemy.org/en/13/orm/query.html#sqlalchemy.orm.query.Query.with_lockmode

Closes-Bug: #1933226
Change-Id: I0ad514da647bb08790259fd27e56a41f6dbbbaa0
2021-06-30 09:18:54 +00:00
OpenStack Release Bot
2205f4e4e3 Add Python3 xena unit tests
This is an automatically generated patch to ensure unit testing
is in place for all the of the tested runtimes for xena.

See also the PTI in governance [1].

[1]: https://governance.openstack.org/tc/reference/project-testing-interface.html

Change-Id: Ib957dae35926bf4c18e5a0c126904bbc67939f21
2021-03-22 10:01:44 +00:00
OpenStack Release Bot
7cd4373707 Update master for stable/wallaby
Add file to the reno documentation build to show release notes for
stable/wallaby.

Use pbr instruction to increment the minor version number
automatically so that master versions are higher than the versions on
stable/wallaby.

Sem-Ver: feature
Change-Id: Ic38b5071799ca733545381e79b956d7f82db2a87
2021-03-22 10:01:40 +00:00
wangzihao
a2123088bf requirements: Drop os-testr
Drop os-testr switched to stestr

Change-Id: I116f6028641ab38a611c8085b145a2ef796aea8e
2021-03-12 15:08:43 +08:00
Ghanshyam Mann
863815153e [goal] Deprecate the JSON formatted policy file
As per the community goal of migrating the policy file
the format from JSON to YAML[1], we need to do two things:

1. Change the default value of '[oslo_policy] policy_file''
config option from 'policy.json' to 'policy.yaml' with
upgrade checks.

2. Deprecate the JSON formatted policy file on the project side
via warning in doc and releasenotes.

Also replace policy.json to policy.yaml ref from doc and tests.

[1]https://governance.openstack.org/tc/goals/selected/wallaby/migrate-policy-format-from-json-to-yaml.html

Change-Id: I207c02ba71fe60635fd3406c9c9364c11f259bae
2021-02-12 19:59:27 +00:00
Ghanshyam Mann
76270c8383 Fix gate requirement checks job
Current requirements-check job is failing with
below error:

ERROR: Requirement for package PrettyTable excludes a version not excluded in the global list.
  Local settings : {'<0.8'}
  Global settings: set()
  Unexpected     : set()
Validating test-requirements.txt

Keeping PrettyTable same as what we have in openstack/requirements repo

Change-Id: I63633d2932757ca23bcea69fd655a2499a5b6d31
2021-02-12 18:58:23 +00:00
Zuul
58de9c405a Merge "Use common rpc pattern for all services" 2021-02-03 10:09:25 +00:00
Zuul
8f0126f1fe Merge "incorrect name in unit test" 2021-02-03 10:02:43 +00:00
sue
ec21898978 incorrect name in unit test
Incorrect name would mislead new developer.

Change-Id: I6ea228035df4437162b6c559ebb7bfb16853c520
2021-01-26 09:43:05 +08:00
Erik Olof Gunnar Andersson
e61f9b5e88 Use common rpc pattern for all services
There is a commonly shared and proven rpc pattern used
across most OpenStack services that is already implemented
in watcher, but the functions are not used.

This patch basically makes use of the existing
rpc classes and removes some unnecessary code.

Change-Id: I57424561e0675a836d10b712ef1579a334f72018
2021-01-25 12:47:52 -08:00
Zuul
e91efbde01 Merge "remove bandit B322 check" 2021-01-25 06:40:08 +00:00
sue
63b6997c83 Drop lower-constraints
Lower-constraints is not a requirement of the OpenStack Python PTI
[0] and there currently is a discussion on the mailing list [1]
about dropping the test, with the oslo team already having done
so [2].

The new dependency resolver in pip fails due to incompatible
dependency versions in our lower-constraints file, meaning that
we were never providing any real guarantees with it.

To unblock the CI, I am disabling lower-constraints job for now,
with the option to reenable it in case we fix the constraints,
and based on the outcome of the mailing list discussions and
consensus.

[0]. https://governance.openstack.org/tc/reference/pti/python.html
[1]. http://lists.openstack.org/pipermail/openstack-discuss/2021-January/019672.html
[2]. http://lists.openstack.org/pipermail/openstack-discuss/2021-January/019659.html

Change-Id: I588fa809839cf3112dae24e356547100f7e89bc5
2021-01-21 03:28:56 +00:00
suzhengwei
262edc8cc9 remove bandit B322 check
The check for this call to input() has been removed.
The input method in Python 2 will read from standard input, evaluate and
run the resulting string as python source code. This is similar, though
in many ways worse, than using eval. On Python 2, use raw_input instead,
input is safe in Python 3.

Change-Id: I8654f0c197bfe88796b56e9d85f563cdded6e8a8
2021-01-04 07:36:44 +00:00
zhufl
204b276693 Fix missing self argument in instances_no_attached
instances_no_attached should have self as the first argument, this is
to add it.

Change-Id: I010d9d1e9ddb8790c398bcf06d0772a0d17f57ec
2020-11-27 17:01:52 +08:00
Zuul
f8a2877f24 Merge "Imported Translations from Zanata" 2020-11-10 09:43:45 +00:00
zhufl
af02bebca9 Fix parameter passed to IronicNodeNotFound exception
IronicNodeNotFound expects uuid parameter for the error message,
not name.

Change-Id: I9fefa98fa9fe6f6491e5f621190cac7d376db6c9
2020-11-02 15:48:27 +08:00
OpenStack Proposal Bot
3aaa20908d Imported Translations from Zanata
For more information about this automatic import see:
https://docs.openstack.org/i18n/latest/reviewing-translation-import.html

Change-Id: I1c07f65533761586bf9563376004eaf0897743cb
2020-10-29 10:29:55 +00:00
wu.chunyang
5097665be3 Remove the unused coding style modules
Python modules related to coding style checks (listed in blacklist.txt in
openstack/requirements repo) are dropped from lower-constraints.txt
they are not needed during installation.

Change-Id: Iadf4581646131f87803c2cebbc66bd55fdb56685
2020-10-22 00:19:35 +08:00
root
09f6e3bde5 Remove usage of six
Remove six-library Replace the following items with Python 3 style code.
- six.string_types
- six.moves
- six.iteritems

Change-Id: I30358b3b08cc076ac59bd325d0e11a3e2deabde3
2020-10-12 05:41:00 +00:00
root
f488636fb8 Bump py37 to py38 in tox.ini
In 'victoria' cycle, we should test py38 by default.

ref:
  https://governance.openstack.org/tc/reference/runtimes/victoria.html

Change-Id: I0a1d49d3f0b2401b5941cd510bc7627863947532
2020-10-12 03:24:16 +00:00
Zuul
11cb88c2cd Merge "Remove six" 2020-10-10 02:31:22 +00:00
xuanyandong
16a0486655 Remove six
Replace the following items with Python 3 style code.

- six.string_types
- six.integer_types
- six.moves
- six.PY2

Implements: blueprint six-removal

Change-Id: I2a0624bd4b455c7e5a0617f1253efa05485dc673
2020-09-30 16:25:13 +08:00
Zuul
2454d4d199 Merge "Add Python3 wallaby unit tests" 2020-09-30 04:06:23 +00:00
Zuul
45dca00dee Merge "Implements base method for time series metrics" 2020-09-27 02:45:20 +00:00
Zuul
09b2383685 Merge "[goal] Migrate testing to ubuntu focal" 2020-09-25 07:06:43 +00:00
OpenStack Release Bot
f8797a7f70 Add Python3 wallaby unit tests
This is an automatically generated patch to ensure unit testing
is in place for all the of the tested runtimes for wallaby.

See also the PTI in governance [1].

[1]: https://governance.openstack.org/tc/reference/project-testing-interface.html

Change-Id: I8951721c8c06ba6ebde9b68665c9aa791ab7ef9b
2020-09-22 14:12:54 +00:00
OpenStack Release Bot
da283b49b8 Update master for stable/victoria
Add file to the reno documentation build to show release notes for
stable/victoria.

Use pbr instruction to increment the minor version number
automatically so that master versions are higher than the versions on
stable/victoria.

Change-Id: I311548732398a680ba50a72273fb98bb16009be4
Sem-Ver: feature
2020-09-22 14:12:53 +00:00
Ghanshyam Mann
e21e5f609e [goal] Migrate testing to ubuntu focal
As per victoria cycle testing runtime and community goal[1]
we need to migrate upstream CI/CD to Ubuntu Focal(20.04).

Fixing:
- bug#1886298
Bump the lower constraints for required deps which added python3.8 support
in their later version.

- Move multinode jobs to focal nodeset

Story: #2007865
Task: #40227

Closes-Bug: #1886298

[1] https://governance.openstack.org/tc/goals/selected/victoria/migrate-ci-cd-jobs-to-ubuntu-focal>

Depends-On: https://review.opendev.org/#/c/752294/

Change-Id: Iec953f3294087cd0b628b701ad3d684cea61c057
2020-09-17 10:59:59 +00:00
zhoulinhui
583c946061 Use importlib to take place of im module
The imp module is deprecated[1] since version 3.4, use importlib to
instead

1: https://docs.python.org/3/library/imp.html#imp.reload

Change-Id: Ic126bc8e0936e5d7a2c7a910b54b7348026fedcb
2020-08-29 16:12:52 +00:00
Dantali0n
cca0d9f7d7 Implements base method for time series metrics
Implements base method as well as some basic implementations to
retrieve time series metrics. Ceilometer can not be supported
as API documentation has been unavailable. Grafana will be
supported in follow-up patch.

Partially Implements: blueprint time-series-framework

Change-Id: I55414093324c8cff379b28f5b855f41a9265c2d3
2020-08-26 16:01:15 +02:00
Zuul
25a0b184a1 Merge "option to rollback action_plan when it fails" 2020-08-18 07:55:59 +00:00
Luigi Toscano
ed59145354 Native Zuul v3 watcher-grenade job + some cleanup
Create a native Zuul v3 grenade job. It matches the existing job,
even though it doesn't call any local hook as the current legacy
job does (because no local hook exists and it should be rewritten
as zuul configuration if it did).

The new job reuses the variable definition of the devstack watcher
job, so clean up that job as well:
- do not depend on devstack-gate, which is not needed and will be
  deprecated soon anyway;
- use the new way (tempest_plugins) to define which tempest plugin
  should be installed;
- remove the definition of USE_PYTHON3: true and simply inherit
  the value set by devstack;
- remove the definition of PYTHONUNBUFFERED, not really set
  anywhere else and only useful back in the days in Jenkins.

Change-Id: Ib0ed3c0f395e1b85b8f25f6e438c414165baab32
2020-07-29 09:45:17 +02:00
suzhengwei
19adfda3b9 option to rollback action_plan when it fails
It has costs when rollback action_plan.
So give users an option whether to rollback it
when the action_plan fails.

Change-Id: I20c0afded795eda7fb1b57ffdd2ae1ca36c45301
2020-07-10 10:31:26 +08:00
Zuul
fa56bc715e Merge "resize action don't support revert" 2020-07-06 01:48:00 +00:00
Zuul
350ce66d3c Merge "Watcher API supports strategy name when creating audit template" 2020-07-06 01:47:59 +00:00
licanwei
1667046f58 resize action don't support revert
Change-Id: Ia2df0e0a4f242392915aa2a89d4fbae39b6c70e9
2020-07-02 14:48:55 +08:00
limin0801
3f7a508a2e Watcher API supports strategy name when creating audit template
when directly using the `curl` command to create audit template,
strategy name can be accepted.

Closes-Bug: #1884174

Change-Id: I7c0ca760a7fa414faca03c5293df34a84aad6fac
2020-07-01 01:46:44 +00:00
Zuul
f7f5659bca Merge "Revert "Don't revert Migrate action"" 2020-06-25 03:28:11 +00:00
suzhengwei
57f55190ff Revert "Don't revert Migrate action"
Whether to revert migrate action when the action_plan fails is determained by 'rollback_actionplan' option.

This reverts commit c522e881b1.

Change-Id: I5379018b7838dff4caf0ee0ce06cfa32e7b37b12
2020-06-22 09:26:46 +00:00
Zuul
237550ad57 Merge "remove mox3" 2020-06-19 07:24:56 +00:00
Zuul
cad67702d6 Merge "Use unittest.mock instead of mock" 2020-06-19 02:19:21 +00:00
licanwei
ae678dfaaa remove mox3
Change-Id: Ia7a4dce8ccc8d9062d6fcca74b8184d85ee7fccb
2020-06-19 09:49:32 +08:00
Zuul
5ad3960286 Merge "voting watcher-grenade" 2020-06-18 08:09:19 +00:00
licanwei
dbd86be363 voting watcher-grenade
Change-Id: I69ef17b545c62fe5b17e002b4c154e80e7fa5ffa
2020-06-18 10:14:01 +08:00
licanwei
9f0138e1cf Check if scope is None
if scope is None, don't create data model

Change-Id: Icf611966c9b0a3882615d778ee6c72a8da73841d
Closed-Bug: #1881920
2020-06-18 00:58:16 +00:00
zhurong
097ac06f0b Use uwsgi binary from path and mark grenade non-voting
Change-Id: Iaa6283e3f34166210cc2d0c918e610484bfd3ab9
2020-06-16 08:02:26 +00:00
Hervé Beraud
0869b1c75c Use unittest.mock instead of mock
The mock third party library was needed for mock support in py2
runtimes. Since we now only support py36 and later, we can use the
standard lib unittest.mock module instead.

Change-Id: I4ee01710d04d650a3ad5ae069015255d3f674c74
2020-06-09 12:20:06 +02:00
Zuul
527578a147 Merge "Compatible with old scope format" 2020-06-09 07:32:12 +00:00
Hervé Beraud
b0c411b22a Cap jsonschema 3.2.0 as the minimal version
Previous versions of jsonschema (<3.2.0) doesn't support python 3.8 [1].
Python 3.8 is part of the victoria supported runtimes [2] so we now force
to use jsonschema version 3.2.0 to avoid issues, remove ambiguity and ensure
that everything works with python 3 in general.

[1] https://github.com/Julian/jsonschema/pull/627
[2] https://governance.openstack.org/tc/reference/runtimes/victoria.html#python-runtimes-for-victoria

Change-Id: Id476227552c3fa91eecadbc6c4370c354f56a40d
2020-06-05 03:39:13 +00:00
licanwei
4a1915bec4 Compatible with old scope format
Scope format changed from old to new after bp cdm-scoping.

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

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

Change-Id: I2b5cd4d1cee19f5588e4d2185eb074343fff1187
Closed-Bug: #1882049
2020-06-04 17:24:41 +08:00
Sean McGinnis
751027858b Use unittest.mock instead of third party mock
Now that we no longer support py27, we can use the standard library
unittest.mock module instead of the third party mock lib.

Change-Id: I6cdd4c35a52a014ba3c4dfe4cc2bd4d670c96bc3
Signed-off-by: Sean McGinnis <sean.mcginnis@gmail.com>
2020-05-29 13:48:06 -05:00
Zuul
12bd9c0590 Merge "Remove translation sections from setup.cfg" 2020-05-28 02:30:26 +00:00
Andreas Jaeger
1ff940598f Switch to newer openstackdocstheme and reno versions
Switch to openstackdocstheme 2.2.1 and reno 3.1.0 versions. Using
these versions will allow especially:
* Linking from HTML to PDF document
* Allow parallel building of documents
* Fix some rendering problems

Update Sphinx version as well.

Set openstackdocs_pdf_link to link to PDF file. Note that
the link to the published document only works on docs.openstack.org
where the PDF file is placed in the top-level html directory. The
site-preview places the PDF in a pdf directory.

Set openstackdocs_auto_name to False to use 'project' variable as name.

Change pygments_style to 'native' since old theme version always used
'native' and the theme now respects the setting and using 'sphinx' can
lead to some strange rendering.

Remove docs requirements from lower-constraints, they are not needed
during install or test but only for docs building.

openstackdocstheme renames some variables, so follow the renames
before the next release removes them. A couple of variables are also
not needed anymore, remove them.

See also
http://lists.openstack.org/pipermail/openstack-discuss/2020-May/014971.html

Change-Id: Ia9a3fb804fb59bb70edc150a3eb20c07a279170b
2020-05-21 15:15:16 +00:00
Andreas Jaeger
9d495618d2 Fix requirements check
Remove python_version so that requirements-check passes again.

Change-Id: I46c6118d9b29a17a3186b3fd5f47115236913a16
2020-05-21 12:35:46 +02:00
jacky06
c6d2690aa3 Remove translation sections from setup.cfg
These translation sections are not needed anymore, Babel can
generate translation files without them.

Change-Id: I95bde8575638511449edaa1e546e3399bf0e6451
2020-05-15 00:56:16 +08:00
Zuul
623e44ecf9 Merge "Monkey patch original current_thread _active" 2020-05-14 03:54:43 +00:00
zhangbailin
5c34b6bc47 hacking: force explicit import of python's mock
Since we dropped support for python 2 [1], we no longer need to use the
mock library, which existed to backport py3 functionality into py2.
Which must be done by saying::

    from unittest import mock

...because if you say::

    import mock

...you definitely will not be getting the standard library mock.
That will always import the third party mock library.

This commit adds hacking check N366 to enforce the former.

This check can be removed in the future (and we can start saying
``import mock`` again) if we manage to purge these transitive
dependencies. I'm not holding my breath.

[1]https://review.opendev.org/#/c/717540

Change-Id: I8c8c99024e8de61d9151480d70543f809a100998
2020-05-13 15:42:42 +08:00
zhangbailin
8a36ad5f87 Use unittest.mock instead of third party mock
Now that we no longer support py27, we can use the standard library
unittest.mock module instead of the third party mock lib.

The remainder was auto-generated with the following (hacky) script, with
one or two manual tweaks after the fact:

  import glob

  for path in glob.glob('watcher/tests/**/*.py', recursive=True):
      with open(path) as fh:
          lines = fh.readlines()
      if 'import mock\n' not in lines:
          continue
      import_group_found = False
      create_first_party_group = False
      for num, line in enumerate(lines):
          line = line.strip()
          if line.startswith('import ') or line.startswith('from '):
              tokens = line.split()
              for lib in (
                  'ddt', 'six', 'webob', 'fixtures', 'testtools'
                  'neutron', 'cinder', 'ironic', 'keystone', 'oslo',
              ):
                  if lib in tokens[1]:
                      create_first_party_group = True
                      break
              if create_first_party_group:
                  break
              import_group_found = True
          if not import_group_found:
              continue
          if line.startswith('import ') or line.startswith('from '):
              tokens = line.split()
              if tokens[1] > 'unittest':
                  break
              elif tokens[1] == 'unittest' and (
                  len(tokens) == 2 or tokens[4] > 'mock'
              ):
                  break
          elif not line:
              break
      if create_first_party_group:
          lines.insert(num, 'from unittest import mock\n\n')
      else:
          lines.insert(num, 'from unittest import mock\n')
      del lines[lines.index('import mock\n')]
      with open(path, 'w+') as fh:
          fh.writelines(lines)

Co-Authored-By: Sean McGinnis <sean.mcginnis@gmail.com>

Change-Id: Icf35d3a6c10c529e07d1a4edaa36f504e5bf553a
2020-05-13 15:41:55 +08:00
Ghanshyam Mann
6ff95efaf6 Fix hacking min version to 3.0.1
flake8 new release 3.8.0 added new checks and gate pep8
job start failing. hacking 3.0.1 fix the pinning of flake8 to
avoid bringing in a new version with new checks.

Though it is fixed in latest hacking but 2.0 and 3.0 has cap for
flake8 as <4.0.0 which mean flake8 new version 3.9.0 can also
break the pep8 job if new check are added.

To avoid similar gate break in future, we need to bump the hacking min
version.

- http://lists.openstack.org/pipermail/openstack-discuss/2020-May/014828.html

Change-Id: I1fe394ebd1f161eb73f53bfa17d2ccc860b9f51b
2020-05-12 21:35:41 -05:00
Zuul
ba2f1804b0 Merge "Add py38 package metadata" 2020-05-07 09:27:32 +00:00
Zuul
44061326e9 Merge "Remove future imports" 2020-05-07 08:57:16 +00:00
Chris MacNaughton
0b4c4f1de6 Monkey patch original current_thread _active
Monkey patch the original current_thread to use the up-to-date _active
global variable. This solution is based on that documented at:
https://github.com/eventlet/eventlet/issues/592

Change-Id: I194eedd505d45137963eb40d1b1d5da2309caeac
Closes-Bug: #1863021
2020-05-06 10:21:32 +02:00
Sean McGinnis
9652571437 Add py38 package metadata
Now that we are running the Victoria tests that include a
voting py38, we can now add the Python 3.8 metadata to the
package information to reflect that support.

Change-Id: Icf85483ff64055d16d35f189755e5fb01fabf574
Signed-off-by: Sean McGinnis <sean.mcginnis@gmail.com>
2020-05-02 07:48:18 -05:00
zhangbailin
f0f15f89c6 Remove future imports
These particular imports are no longer needed in a Python 3-only world.

Change-Id: I5e9e15556c04871c451f6363380f2a7ac026c968
2020-05-02 00:33:39 +00:00
qiufossen
075e374b3d Remove Babel requirement
Babel is not needed as requirement, remove it.

See also
http://lists.openstack.org/pipermail/openstack-discuss/2020-April/014227.html

Change-Id: Id5c54668738e3de8ded900f389b646dcdef5d007
2020-04-29 15:38:43 +08:00
Zuul
eaa0dfea4b Merge "Remove six[8] remove requirement&low-requirement" 2020-04-29 03:03:40 +00:00
Zuul
b7956de761 Merge "Remove six[7]" 2020-04-29 03:03:39 +00:00
OpenStack Proposal Bot
a30dbdd724 Imported Translations from Zanata
For more information about this automatic import see:
https://docs.openstack.org/i18n/latest/reviewing-translation-import.html

Change-Id: I7cdff6bcc91edf445f60365a1cb921bb582c7c13
2020-04-26 09:05:59 +00:00
OpenStack Release Bot
60a829e982 Add Python3 victoria unit tests
This is an automatically generated patch to ensure unit testing
is in place for all the of the tested runtimes for victoria.

See also the PTI in governance [1].

[1]: https://governance.openstack.org/tc/reference/project-testing-interface.html

Change-Id: Ia59e92394115c4b672c86772840a1e188695079f
2020-04-23 09:48:55 +00:00
OpenStack Release Bot
74cfa0fc8c Update master for stable/ussuri
Add file to the reno documentation build to show release notes for
stable/ussuri.

Use pbr instruction to increment the minor version number
automatically so that master versions are higher than the versions on
stable/ussuri.

Change-Id: I63fc3e49802f89ac2d967ee089a9dd9dffbe9c78
Sem-Ver: feature
2020-04-23 09:48:53 +00:00
chenker
5071c8f8fa Remove six[8] remove requirement&low-requirement
Change-Id: I84de517a08a87936f6a9015de350dcda2e24bcef
2020-04-22 16:04:00 +08:00
chenke
0ef0f165cb Remove six[7]
Since our code will only support py3. So remove six is necessary.

Change-Id: I3738118b1898421ee41e9e2902c255ead73f3915
2020-04-22 15:59:15 +08:00
227 changed files with 1648 additions and 1319 deletions

View File

@@ -1,9 +1,9 @@
- project: - project:
queue: watcher
templates: templates:
- check-requirements - check-requirements
- openstack-cover-jobs - openstack-cover-jobs
- openstack-lower-constraints-jobs - openstack-python3-zed-jobs
- openstack-python3-ussuri-jobs
- publish-openstack-docs-pti - publish-openstack-docs-pti
- release-notes-jobs-python3 - release-notes-jobs-python3
check: check:
@@ -13,10 +13,8 @@
- watcher-tempest-strategies - watcher-tempest-strategies
- watcher-tempest-actuator - watcher-tempest-actuator
- watcherclient-tempest-functional - watcherclient-tempest-functional
- watcher-tls-test
- watcher-tempest-functional-ipv6-only - watcher-tempest-functional-ipv6-only
gate: gate:
queue: watcher
jobs: jobs:
- watcher-tempest-functional - watcher-tempest-functional
- watcher-tempest-functional-ipv6-only - watcher-tempest-functional-ipv6-only
@@ -88,21 +86,10 @@
tempest_concurrency: 1 tempest_concurrency: 1
tempest_test_regex: watcher_tempest_plugin.tests.scenario.test_execute_strategies tempest_test_regex: watcher_tempest_plugin.tests.scenario.test_execute_strategies
- job:
name: watcher-tls-test
parent: watcher-tempest-multinode
group-vars:
subnode:
devstack_services:
tls-proxy: true
vars:
devstack_services:
tls-proxy: true
- job: - job:
name: watcher-tempest-multinode name: watcher-tempest-multinode
parent: watcher-tempest-functional parent: watcher-tempest-functional
nodeset: openstack-two-node-bionic nodeset: openstack-two-node-focal
roles: roles:
- zuul: openstack/tempest - zuul: openstack/tempest
group-vars: group-vars:
@@ -120,8 +107,6 @@
watcher-api: false watcher-api: false
watcher-decision-engine: true watcher-decision-engine: true
watcher-applier: false watcher-applier: false
# We need to add TLS support for watcher plugin
tls-proxy: false
ceilometer: false ceilometer: false
ceilometer-acompute: false ceilometer-acompute: false
ceilometer-acentral: false ceilometer-acentral: false
@@ -160,7 +145,6 @@
timeout: 7200 timeout: 7200
required-projects: &base_required_projects required-projects: &base_required_projects
- openstack/ceilometer - openstack/ceilometer
- openstack/devstack-gate
- openstack/python-openstackclient - openstack/python-openstackclient
- openstack/python-watcherclient - openstack/python-watcherclient
- openstack/watcher - openstack/watcher
@@ -170,7 +154,6 @@
devstack_plugins: devstack_plugins:
watcher: https://opendev.org/openstack/watcher watcher: https://opendev.org/openstack/watcher
devstack_services: devstack_services:
tls-proxy: false
watcher-api: true watcher-api: true
watcher-decision-engine: true watcher-decision-engine: true
watcher-applier: true watcher-applier: true
@@ -179,14 +162,10 @@
s-container: false s-container: false
s-object: false s-object: false
s-proxy: false s-proxy: false
devstack_localrc: tempest_plugins:
TEMPEST_PLUGINS: /opt/stack/watcher-tempest-plugin - watcher-tempest-plugin
USE_PYTHON3: true
tempest_test_regex: watcher_tempest_plugin.tests.api tempest_test_regex: watcher_tempest_plugin.tests.api
tox_envlist: all tox_envlist: all
tox_environment:
# Do we really need to set this? It's cargo culted
PYTHONUNBUFFERED: 'true'
zuul_copy_output: zuul_copy_output:
/etc/hosts: logs /etc/hosts: logs
@@ -200,10 +179,12 @@
- job: - job:
name: watcher-grenade name: watcher-grenade
parent: legacy-dsvm-base parent: grenade
timeout: 10800 required-projects:
run: playbooks/legacy/grenade-devstack-watcher/run.yaml - openstack/watcher
post-run: playbooks/legacy/grenade-devstack-watcher/post.yaml - openstack/python-watcherclient
- openstack/watcher-tempest-plugin
vars: *base_vars
irrelevant-files: irrelevant-files:
- ^(test-|)requirements.txt$ - ^(test-|)requirements.txt$
- ^.*\.rst$ - ^.*\.rst$
@@ -215,12 +196,6 @@
- ^setup.cfg$ - ^setup.cfg$
- ^tools/.*$ - ^tools/.*$
- ^tox.ini$ - ^tox.ini$
required-projects:
- openstack/grenade
- openstack/devstack-gate
- openstack/watcher
- openstack/python-watcherclient
- openstack/watcher-tempest-plugin
- job: - job:
# This job is used in python-watcherclient repo # This job is used in python-watcherclient repo

View File

@@ -22,9 +22,6 @@
# All configuration values have a default; values that are commented out # All configuration values have a default; values that are commented out
# serve to show the default. # serve to show the default.
from watcher import version as watcher_version
extensions = [ extensions = [
'openstackdocstheme', 'openstackdocstheme',
'os_api_ref', 'os_api_ref',
@@ -46,21 +43,13 @@ project = u'Infrastructure Optimization API Reference'
copyright = u'2010-present, OpenStack Foundation' copyright = u'2010-present, OpenStack Foundation'
# openstackdocstheme options # openstackdocstheme options
repository_name = 'openstack/watcher' openstackdocs_repo_name = 'openstack/watcher'
bug_project = 'watcher' openstackdocs_auto_name = False
bug_tag = '' openstackdocs_bug_project = 'watcher'
openstackdocs_bug_tag = ''
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The full version, including alpha/beta/rc tags.
release = watcher_version.version_info.release_string()
# The short X.Y version.
version = watcher_version.version_string
# The name of the Pygments (syntax highlighting) style to use. # The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx' pygments_style = 'native'
# -- Options for HTML output -------------------------------------------------- # -- Options for HTML output --------------------------------------------------
@@ -75,10 +64,6 @@ html_theme_options = {
"sidebar_mode": "toc", "sidebar_mode": "toc",
} }
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
html_last_updated_fmt = '%Y-%m-%d %H:%M'
# -- Options for LaTeX output ------------------------------------------------- # -- Options for LaTeX output -------------------------------------------------
# Grouping the document tree into LaTeX files. List of tuples # Grouping the document tree into LaTeX files. List of tuples

View File

@@ -1,2 +0,0 @@
[python: **.py]

View File

@@ -298,7 +298,7 @@ function start_watcher_api {
service_protocol="http" service_protocol="http"
fi fi
if [[ "$WATCHER_USE_WSGI_MODE" == "uwsgi" ]]; then if [[ "$WATCHER_USE_WSGI_MODE" == "uwsgi" ]]; then
run_process "watcher-api" "$WATCHER_BIN_DIR/uwsgi --procname-prefix watcher-api --ini $WATCHER_UWSGI_CONF" run_process "watcher-api" "$(which uwsgi) --procname-prefix watcher-api --ini $WATCHER_UWSGI_CONF"
watcher_url=$service_protocol://$SERVICE_HOST/infra-optim watcher_url=$service_protocol://$SERVICE_HOST/infra-optim
else else
watcher_url=$service_protocol://$SERVICE_HOST:$service_port watcher_url=$service_protocol://$SERVICE_HOST:$service_port

View File

@@ -13,8 +13,6 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from __future__ import unicode_literals
import importlib import importlib
import inspect import inspect

View File

@@ -1,10 +1,10 @@
# The order of packages is significant, because pip processes them in the order # The order of packages is significant, because pip processes them in the order
# of appearance. Changing the order has an impact on the overall integration # of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later. # process, which may cause wedges in the gate later.
openstackdocstheme>=1.20.0 # Apache-2.0 openstackdocstheme>=2.2.1 # Apache-2.0
sphinx>=1.8.0,!=2.1.0,!=3.0.0 # BSD sphinx>=2.0.0,!=2.1.0 # BSD
sphinxcontrib-pecanwsme>=0.8.0 # Apache-2.0 sphinxcontrib-pecanwsme>=0.8.0 # Apache-2.0
sphinxcontrib-svg2pdfconverter>=0.1.0 # BSD sphinxcontrib-svg2pdfconverter>=0.1.0 # BSD
reno>=2.7.0 # Apache-2.0 reno>=3.1.0 # Apache-2.0
sphinxcontrib-apidoc>=0.2.0 # BSD sphinxcontrib-apidoc>=0.2.0 # BSD
os-api-ref>=1.4.0 # Apache-2.0 os-api-ref>=1.4.0 # Apache-2.0

View File

@@ -17,6 +17,14 @@
Policies Policies
======== ========
.. warning::
JSON formatted policy file is deprecated since Watcher 6.0.0 (Wallaby).
This `oslopolicy-convert-json-to-yaml`__ tool will migrate your existing
JSON-formatted policy file to YAML in a backward-compatible way.
.. __: https://docs.openstack.org/oslo.policy/latest/cli/oslopolicy-convert-json-to-yaml.html
Watcher's public API calls may be restricted to certain sets of users using a Watcher's public API calls may be restricted to certain sets of users using a
policy configuration file. This document explains exactly how policies are policy configuration file. This document explains exactly how policies are
configured and what they apply to. configured and what they apply to.

View File

@@ -14,7 +14,6 @@
import os import os
import sys import sys
from watcher import version as watcher_version
from watcher import objects from watcher import objects
objects.register_all() objects.register_all()
@@ -57,18 +56,8 @@ source_suffix = '.rst'
master_doc = 'index' master_doc = 'index'
# General information about the project. # General information about the project.
project = u'Watcher' project = 'Watcher'
copyright = u'OpenStack Foundation' copyright = 'OpenStack Foundation'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
# The full version, including alpha/beta/rc tags.
release = watcher_version.version_info.release_string()
# The short X.Y version.
version = watcher_version.version_string
# A list of ignored prefixes for module index sorting. # A list of ignored prefixes for module index sorting.
modindex_common_prefix = ['watcher.'] modindex_common_prefix = ['watcher.']
@@ -94,7 +83,7 @@ add_module_names = True
suppress_warnings = ['app.add_directive'] suppress_warnings = ['app.add_directive']
# The name of the Pygments (syntax highlighting) style to use. # The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx' pygments_style = 'native'
# -- Options for man page output -------------------------------------------- # -- Options for man page output --------------------------------------------
@@ -102,14 +91,14 @@ pygments_style = 'sphinx'
# List of tuples 'sourcefile', 'target', u'title', u'Authors name', 'manual' # List of tuples 'sourcefile', 'target', u'title', u'Authors name', 'manual'
man_pages = [ man_pages = [
('man/watcher-api', 'watcher-api', u'Watcher API Server', ('man/watcher-api', 'watcher-api', 'Watcher API Server',
[u'OpenStack'], 1), ['OpenStack'], 1),
('man/watcher-applier', 'watcher-applier', u'Watcher Applier', ('man/watcher-applier', 'watcher-applier', 'Watcher Applier',
[u'OpenStack'], 1), ['OpenStack'], 1),
('man/watcher-db-manage', 'watcher-db-manage', ('man/watcher-db-manage', 'watcher-db-manage',
u'Watcher Db Management Utility', [u'OpenStack'], 1), 'Watcher Db Management Utility', ['OpenStack'], 1),
('man/watcher-decision-engine', 'watcher-decision-engine', ('man/watcher-decision-engine', 'watcher-decision-engine',
u'Watcher Decision Engine', [u'OpenStack'], 1), 'Watcher Decision Engine', ['OpenStack'], 1),
] ]
# -- Options for HTML output -------------------------------------------------- # -- Options for HTML output --------------------------------------------------
@@ -125,12 +114,13 @@ html_theme = 'openstackdocs'
# Output file base name for HTML help builder. # Output file base name for HTML help builder.
htmlhelp_basename = '%sdoc' % project htmlhelp_basename = '%sdoc' % project
html_last_updated_fmt = '%Y-%m-%d %H:%M'
#openstackdocstheme options #openstackdocstheme options
repository_name = 'openstack/watcher' openstackdocs_repo_name = 'openstack/watcher'
bug_project = 'watcher' openstackdocs_pdf_link = True
bug_tag = '' openstackdocs_auto_name = False
openstackdocs_bug_project = 'watcher'
openstackdocs_bug_tag = ''
# Grouping the document tree into LaTeX files. List of tuples # Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass # (source start file, target name, title, author, documentclass
@@ -138,8 +128,8 @@ bug_tag = ''
latex_documents = [ latex_documents = [
('index', ('index',
'doc-watcher.tex', 'doc-watcher.tex',
u'%s Documentation' % project, 'Watcher Documentation',
u'OpenStack Foundation', 'manual'), 'OpenStack Foundation', 'manual'),
] ]
# If false, no module index is generated. # If false, no module index is generated.

View File

@@ -47,6 +47,8 @@ unavailable as well as `instance_l3_cpu_cache`::
[[local|localrc]] [[local|localrc]]
enable_plugin watcher https://opendev.org/openstack/watcher enable_plugin watcher https://opendev.org/openstack/watcher
enable_plugin watcher-dashboard https://opendev.org/openstack/watcher-dashboard
enable_plugin ceilometer https://opendev.org/openstack/ceilometer.git enable_plugin ceilometer https://opendev.org/openstack/ceilometer.git
CEILOMETER_BACKEND=gnocchi CEILOMETER_BACKEND=gnocchi

View File

@@ -56,9 +56,6 @@ Here is an example showing how you can write a plugin called ``NewStrategy``:
# filepath: thirdparty/new.py # filepath: thirdparty/new.py
# import path: thirdparty.new # import path: thirdparty.new
import abc import abc
import six
from watcher._i18n import _ from watcher._i18n import _
from watcher.decision_engine.strategy.strategies import base from watcher.decision_engine.strategy.strategies import base

View File

@@ -1,161 +0,0 @@
alabaster==0.7.10
alembic==0.9.8
amqp==2.2.2
appdirs==1.4.3
APScheduler==3.5.1
asn1crypto==0.24.0
automaton==1.14.0
Babel==2.5.3
beautifulsoup4==4.6.0
cachetools==2.0.1
certifi==2018.1.18
cffi==1.11.5
chardet==3.0.4
cliff==2.11.0
cmd2==0.8.1
contextlib2==0.5.5
coverage==4.5.1
croniter==0.3.20
cryptography==2.1.4
debtcollector==1.19.0
decorator==4.2.1
deprecation==2.0
doc8==0.8.0
docutils==0.14
dogpile.cache==0.6.5
dulwich==0.19.0
enum34==1.1.6
enum-compat==0.0.2
eventlet==0.20.0
extras==1.0.0
fasteners==0.14.1
fixtures==3.0.0
freezegun==0.3.10
future==0.16.0
futurist==1.8.0
gitdb2==2.0.3
GitPython==2.1.8
gnocchiclient==7.0.1
greenlet==0.4.13
idna==2.6
imagesize==1.0.0
iso8601==0.1.12
Jinja2==2.10
jmespath==0.9.3
jsonpatch==1.21
jsonpointer==2.0
jsonschema==2.6.0
keystoneauth1==3.4.0
keystonemiddleware==4.21.0
kombu==4.1.0
linecache2==1.0.0
logutils==0.3.5
lxml==4.1.1
Mako==1.0.7
MarkupSafe==1.0
mccabe==0.2.1
microversion_parse==0.2.1
mock==2.0.0
monotonic==1.4
mox3==0.25.0
msgpack==0.5.6
munch==2.2.0
netaddr==0.7.19
netifaces==0.10.6
networkx==2.2
openstackdocstheme==1.20.0
openstacksdk==0.12.0
os-api-ref===1.4.0
os-client-config==1.29.0
os-service-types==1.2.0
os-testr==1.0.0
osc-lib==1.10.0
os-resource-classes==0.4.0
oslo.cache==1.29.0
oslo.concurrency==3.26.0
oslo.config==5.2.0
oslo.context==2.21.0
oslo.db==4.35.0
oslo.i18n==3.20.0
oslo.log==3.37.0
oslo.messaging==8.1.2
oslo.middleware==3.35.0
oslo.policy==1.34.0
oslo.reports==1.27.0
oslo.serialization==2.25.0
oslo.service==1.30.0
oslo.upgradecheck==0.1.0
oslo.utils==3.36.0
oslo.versionedobjects==1.32.0
oslotest==3.3.0
packaging==17.1
Paste==2.0.3
PasteDeploy==1.5.2
pbr==3.1.1
pecan==1.3.2
pika==0.10.0
pika-pool==0.1.3
prettytable==0.7.2
psutil==5.4.3
pycadf==2.7.0
pycparser==2.18
Pygments==2.2.0
pyinotify==0.9.6
pyOpenSSL==17.5.0
pyparsing==2.2.0
pyperclip==1.6.0
python-ceilometerclient==2.9.0
python-cinderclient==3.5.0
python-dateutil==2.7.0
python-editor==1.0.3
python-glanceclient==2.9.1
python-ironicclient==2.5.0
python-keystoneclient==3.15.0
python-mimeparse==1.6.0
python-monascaclient==1.12.0
python-neutronclient==6.7.0
python-novaclient==14.1.0
python-openstackclient==3.14.0
python-subunit==1.2.0
pytz==2018.3
PyYAML==3.12
reno==2.7.0
repoze.lru==0.7
requests==2.18.4
requestsexceptions==1.4.0
restructuredtext-lint==1.1.3
rfc3986==1.1.0
Routes==2.4.1
simplegeneric==0.8.1
simplejson==3.13.2
six==1.11.0
smmap2==2.0.3
snowballstemmer==1.2.1
Sphinx==1.6.5
sphinxcontrib-httpdomain==1.6.1
sphinxcontrib-pecanwsme==0.8.0
sphinxcontrib-websupport==1.0.1
SQLAlchemy==1.2.5
sqlalchemy-migrate==0.11.0
sqlparse==0.2.4
statsd==3.2.2
stestr==2.0.0
stevedore==1.28.0
taskflow==3.7.1
Tempita==0.5.2
tenacity==4.9.0
testresources==2.0.1
testscenarios==0.5.0
testtools==2.3.0
traceback2==1.4.0
tzlocal==1.5.1
ujson==1.35
unittest2==1.1.0
urllib3==1.22
vine==1.1.4
waitress==1.1.0
warlock==1.3.0
WebOb==1.8.5
WebTest==2.0.29
wrapt==1.10.11
WSME==0.9.2

View File

@@ -1,15 +0,0 @@
- 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

@@ -1,60 +0,0 @@
- hosts: all
name: legacy-grenade-dsvm-watcher
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
export PYTHONUNBUFFERED=true
export PROJECTS="openstack/grenade $PROJECTS"
export PROJECTS="openstack/watcher $PROJECTS"
export PROJECTS="openstack/watcher-tempest-plugin $PROJECTS"
export PROJECTS="openstack/python-watcherclient $PROJECTS"
export DEVSTACK_PROJECT_FROM_GIT="python-watcherclient $DEVSTACK_PROJECT_FROM_GIT"
export GRENADE_PLUGINRC="enable_grenade_plugin watcher https://opendev.org/openstack/watcher"
export DEVSTACK_LOCAL_CONFIG+=$'\n'"export TEMPEST_PLUGINS='/opt/stack/new/watcher-tempest-plugin'"
export DEVSTACK_GATE_TEMPEST_NOTESTS=1
export DEVSTACK_GATE_GRENADE=pullup
export DEVSTACK_GATE_USE_PYTHON3=True
export BRANCH_OVERRIDE=default
if [ "$BRANCH_OVERRIDE" != "default" ] ; then
export OVERRIDE_ZUUL_BRANCH=$BRANCH_OVERRIDE
fi
# Add configuration values for enabling security features in local.conf
function pre_test_hook {
if [ -f /opt/stack/old/watcher-tempest-plugin/tools/pre_test_hook.sh ] ; then
. /opt/stack/old/watcher-tempest-plugin/tools/pre_test_hook.sh
fi
}
export -f pre_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

@@ -0,0 +1,20 @@
---
upgrade:
- |
The default value of ``[oslo_policy] policy_file`` config option has
been changed from ``policy.json`` to ``policy.yaml``.
Operators who are utilizing customized or previously generated
static policy JSON files (which are not needed by default), should
generate new policy files or convert them in YAML format. Use the
`oslopolicy-convert-json-to-yaml
<https://docs.openstack.org/oslo.policy/latest/cli/oslopolicy-convert-json-to-yaml.html>`_
tool to convert a JSON to YAML formatted policy file in
backward compatible way.
deprecations:
- |
Use of JSON policy files was deprecated by the ``oslo.policy`` library
during the Victoria development cycle. As a result, this deprecation is
being noted in the Wallaby cycle with an anticipated future removal of support
by ``oslo.policy``. As such operators will need to convert to YAML policy
files. Please see the upgrade notes for details on migration of any
custom policy files.

View File

@@ -53,8 +53,7 @@ source_suffix = '.rst'
master_doc = 'index' master_doc = 'index'
# General information about the project. # General information about the project.
project = u'watcher' copyright = '2016, Watcher developers'
copyright = u'2016, Watcher developers'
# Release notes are version independent # Release notes are version independent
# The short X.Y version. # The short X.Y version.
@@ -91,11 +90,15 @@ exclude_patterns = ['_build']
#show_authors = False #show_authors = False
# The name of the Pygments (syntax highlighting) style to use. # The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx' pygments_style = 'native'
# A list of ignored prefixes for module index sorting. # A list of ignored prefixes for module index sorting.
#modindex_common_prefix = [] #modindex_common_prefix = []
# openstackdocstheme options
openstackdocs_repo_name = 'openstack/watcher'
openstackdocs_bug_project = 'watcher'
openstackdocs_bug_tag = ''
# -- Options for HTML output -------------------------------------------------- # -- Options for HTML output --------------------------------------------------
@@ -193,8 +196,8 @@ latex_elements = {
# Grouping the document tree into LaTeX files. List of tuples # Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]) # (source start file, target name, title, author, documentclass [howto/manual])
latex_documents = [ latex_documents = [
('index', 'watcher.tex', u'Watcher Documentation', ('index', 'watcher.tex', 'Watcher Documentation',
u'Watcher developers', 'manual'), 'Watcher developers', 'manual'),
] ]
# The name of an image file (relative to this directory) to place at the top of # The name of an image file (relative to this directory) to place at the top of
@@ -223,8 +226,8 @@ latex_documents = [
# One entry per manual page. List of tuples # One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section). # (source start file, name, description, authors, manual section).
man_pages = [ man_pages = [
('index', 'watcher', u'Watcher Documentation', ('index', 'watcher', 'Watcher Documentation',
[u'Watcher developers'], 1) ['Watcher developers'], 1)
] ]
# If true, show URL addresses after external links. # If true, show URL addresses after external links.
@@ -237,8 +240,8 @@ man_pages = [
# (source start file, target name, title, author, # (source start file, target name, title, author,
# dir menu entry, description, category) # dir menu entry, description, category)
texinfo_documents = [ texinfo_documents = [
('index', 'watcher', u'Watcher Documentation', ('index', 'watcher', 'Watcher Documentation',
u'Watcher developers', 'watcher', 'One line description of project.', 'Watcher developers', 'watcher', 'One line description of project.',
'Miscellaneous'), 'Miscellaneous'),
] ]

View File

@@ -21,6 +21,11 @@ Contents:
:maxdepth: 1 :maxdepth: 1
unreleased unreleased
yoga
xena
wallaby
victoria
ussuri
train train
stein stein
rocky rocky

View File

@@ -1,14 +1,16 @@
# Andi Chandler <andi@gowling.com>, 2017. #zanata # Andi Chandler <andi@gowling.com>, 2017. #zanata
# Andi Chandler <andi@gowling.com>, 2018. #zanata # Andi Chandler <andi@gowling.com>, 2018. #zanata
# Andi Chandler <andi@gowling.com>, 2020. #zanata
# Andi Chandler <andi@gowling.com>, 2022. #zanata
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: python-watcher\n" "Project-Id-Version: python-watcher\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-11-08 01:22+0000\n" "POT-Creation-Date: 2022-08-29 03:02+0000\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"PO-Revision-Date: 2018-11-07 06:15+0000\n" "PO-Revision-Date: 2022-05-31 08:39+0000\n"
"Last-Translator: Andi Chandler <andi@gowling.com>\n" "Last-Translator: Andi Chandler <andi@gowling.com>\n"
"Language-Team: English (United Kingdom)\n" "Language-Team: English (United Kingdom)\n"
"Language: en_GB\n" "Language: en_GB\n"
@@ -54,6 +56,64 @@ msgstr "1.7.0"
msgid "1.9.0" msgid "1.9.0"
msgstr "1.9.0" msgstr "1.9.0"
msgid "2.0.0"
msgstr "2.0.0"
msgid "3.0.0"
msgstr "3.0.0"
msgid "4.0.0"
msgstr "4.0.0"
msgid "6.0.0"
msgstr "6.0.0"
msgid "A ``watcher-status upgrade check`` has been added for this."
msgstr "A ``watcher-status upgrade check`` has been added for this."
msgid ""
"A new threadpool for the decision engine that contributors can use to "
"improve the performance of many operations, primarily I/O bound onces. The "
"amount of workers used by the decision engine threadpool can be configured "
"to scale according to the available infrastructure using the "
"`watcher_decision_engine.max_general_workers` config option. Documentation "
"for contributors to effectively use this threadpool is available online: "
"https://docs.openstack.org/watcher/latest/contributor/concurrency.html"
msgstr ""
"A new threadpool for the decision engine that contributors can use to "
"improve the performance of many operations, primarily I/O bound onces. The "
"amount of workers used by the decision engine threadpool can be configured "
"to scale according to the available infrastructure using the "
"`watcher_decision_engine.max_general_workers` config option. Documentation "
"for contributors to effectively use this threadpool is available online: "
"https://docs.openstack.org/watcher/latest/contributor/concurrency.html"
msgid ""
"API calls while building the Compute data model will be retried upon "
"failure. The amount of failures allowed before giving up and the time before "
"reattempting are configurable. The `api_call_retries` and "
"`api_query_timeout` parameters in the `[collector]` group can be used to "
"adjust these paremeters. 10 retries with a 1 second time in between "
"reattempts is the default."
msgstr ""
"API calls while building the Compute data model will be retried upon "
"failure. The amount of failures allowed before giving up and the time before "
"reattempting are configurable. The `api_call_retries` and "
"`api_query_timeout` parameters in the `[collector]` group can be used to "
"adjust these parameters. 10 retries with a 1 second time in between "
"reattempts is the default."
msgid ""
"Add a new webhook API and a new audit type EVENT, the microversion is 1.4. "
"Now Watcher user can create audit with EVENT type and the audit will be "
"triggered by webhook API. The user guide is available online: https://docs."
"openstack.org/watcher/latest/user/event_type_audit.html"
msgstr ""
"Add a new webhook API and a new audit type EVENT, the microversion is 1.4. "
"Now Watcher user can create audit with EVENT type and the audit will be "
"triggered by webhook API. The user guide is available online: https://docs."
"openstack.org/watcher/latest/user/event_type_audit.html"
msgid "Add a service supervisor to watch Watcher deamons." msgid "Add a service supervisor to watch Watcher deamons."
msgstr "Add a service supervisor to watch Watcher daemons." msgstr "Add a service supervisor to watch Watcher daemons."
@@ -67,6 +127,24 @@ msgstr ""
"Add description property for dynamic action. Admin can see detail " "Add description property for dynamic action. Admin can see detail "
"information of any specify action." "information of any specify action."
msgid ""
"Add force field to Audit. User can set --force to enable the new option when "
"launching audit. If force is True, audit will be executed despite of ongoing "
"actionplan. The new audit may create a wrong actionplan if they use the same "
"data model."
msgstr ""
"Add force field to Audit. User can set --force to enable the new option when "
"launching audit. If force is True, audit will be executed despite of ongoing "
"actionplan. The new audit may create a wrong actionplan if they use the same "
"data model."
msgid ""
"Add keystone_client Group for user to configure 'interface' and "
"'region_name' by watcher.conf. The default value of 'interface' is 'admin'."
msgstr ""
"Add keystone_client Group for user to configure 'interface' and "
"'region_name' by watcher.conf. The default value of 'interface' is 'admin'."
msgid "Add notifications related to Action object." msgid "Add notifications related to Action object."
msgstr "Add notifications related to Action object." msgstr "Add notifications related to Action object."
@@ -79,6 +157,25 @@ msgstr "Add notifications related to Audit object."
msgid "Add notifications related to Service object." msgid "Add notifications related to Service object."
msgstr "Add notifications related to Service object." msgstr "Add notifications related to Service object."
msgid ""
"Add show data model api for Watcher. New in version 1.3. User can use "
"'openstack optimize datamodel list' command to view the current data model "
"information in memory. User can also add '--audit <Audit_UUID>' to view "
"specific data model in memory filted by the scope in audit. User can also "
"add '--detail' to view detailed information about current data model. User "
"can also add '--type <type>' to specify the type of data model. Default type "
"is 'compute'. In the future, type 'storage' and 'baremetal' will be "
"supported."
msgstr ""
"Add show data model API for Watcher. New in version 1.3. User can use "
"'openstack optimize datamodel list' command to view the current data model "
"information in memory. User can also add '--audit <Audit_UUID>' to view "
"specific data model in memory filtered by the scope in audit. User can also "
"add '--detail' to view detailed information about current data model. User "
"can also add '--type <type>' to specify the type of data model. Default type "
"is 'compute'. In the future, type 'storage' and 'baremetal' will be "
"supported."
msgid "" msgid ""
"Add start_time and end_time fields in audits table. User can set the start " "Add start_time and end_time fields in audits table. User can set the start "
"time and/or end time when creating CONTINUOUS audit." "time and/or end time when creating CONTINUOUS audit."
@@ -93,6 +190,19 @@ msgstr ""
"Add superseded state for an action plan if the cluster data model has " "Add superseded state for an action plan if the cluster data model has "
"changed after it has been created." "changed after it has been created."
msgid ""
"Added Placement API helper to Watcher. Now Watcher can get information about "
"resource providers, it can be used for the data model and strategies. Config "
"group placement_client with options 'api_version', 'interface' and "
"'region_name' is also added. The default values for 'api_version' and "
"'interface' are 1.29 and 'public', respectively."
msgstr ""
"Added Placement API helper to Watcher. Now Watcher can get information about "
"resource providers, it can be used for the data model and strategies. Config "
"group placement_client with options 'api_version', 'interface' and "
"'region_name' is also added. The default values for 'api_version' and "
"'interface' are 1.29 and 'public', respectively."
msgid "Added SUSPENDED audit state" msgid "Added SUSPENDED audit state"
msgstr "Added SUSPENDED audit state" msgstr "Added SUSPENDED audit state"
@@ -107,6 +217,31 @@ msgstr ""
"scoring engine by different Strategies, which improve the code and data " "scoring engine by different Strategies, which improve the code and data "
"model re-use." "model re-use."
msgid ""
"Added a new config option 'action_execution_rule' which is a dict type. Its "
"key field is strategy name and the value is 'ALWAYS' or 'ANY'. 'ALWAYS' "
"means the callback function returns True as usual. 'ANY' means the return "
"depends on the result of previous action execution. The callback returns "
"True if previous action gets failed, and the engine continues to run the "
"next action. If previous action executes success, the callback returns False "
"then the next action will be ignored. For strategies that aren't in "
"'action_execution_rule', the callback always returns True. Please add the "
"next section in the watcher.conf file if your strategy needs this feature. "
"[watcher_workflow_engines.taskflow] action_execution_rule = {'your strategy "
"name': 'ANY'}"
msgstr ""
"Added a new config option 'action_execution_rule' which is a dict type. Its "
"key field is strategy name and the value is 'ALWAYS' or 'ANY'. 'ALWAYS' "
"means the callback function returns True as usual. 'ANY' means the return "
"depends on the result of previous action execution. The callback returns "
"True if previous action gets failed, and the engine continues to run the "
"next action. If previous action executes success, the callback returns False "
"then the next action will be ignored. For strategies that aren't in "
"'action_execution_rule', the callback always returns True. Please add the "
"next section in the watcher.conf file if your strategy needs this feature. "
"[watcher_workflow_engines.taskflow] action_execution_rule = {'your strategy "
"name': 'ANY'}"
msgid "" msgid ""
"Added a new strategy based on the airflow of servers. This strategy makes " "Added a new strategy based on the airflow of servers. This strategy makes "
"decisions to migrate VMs to make the airflow uniform." "decisions to migrate VMs to make the airflow uniform."
@@ -248,6 +383,15 @@ msgstr ""
"The strategy migrates many instances and volumes efficiently with minimum " "The strategy migrates many instances and volumes efficiently with minimum "
"downtime automatically." "downtime automatically."
msgid ""
"Added strategy \"node resource consolidation\". This strategy is used to "
"centralize VMs to as few nodes as possible by VM migration. User can set an "
"input parameter to decide how to select the destination node."
msgstr ""
"Added strategy \"node resource consolidation\". This strategy is used to "
"centralize VMs to as few nodes as possible by VM migration. User can set an "
"input parameter to decide how to select the destination node."
msgid "" msgid ""
"Added strategy to identify and migrate a Noisy Neighbor - a low priority VM " "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 peformance of a high priority VM by over utilizing "
@@ -284,6 +428,19 @@ msgstr ""
msgid "Adds baremetal data model in Watcher" msgid "Adds baremetal data model in Watcher"
msgstr "Adds baremetal data model in Watcher" msgstr "Adds baremetal data model in Watcher"
msgid ""
"All datasources can now be configured to retry retrieving a metric upon "
"encountering an error. Between each attempt will be a set amount of time "
"which can be adjusted from the configuration. These configuration options "
"can be found in the `[watcher_datasources]` group and are named "
"`query_max_retries` and `query_timeout`."
msgstr ""
"All datasources can now be configured to retry retrieving a metric upon "
"encountering an error. Between each attempt will be a set amount of time "
"which can be adjusted from the configuration. These configuration options "
"can be found in the `[watcher_datasources]` group and are named "
"`query_max_retries` and `query_timeout`."
msgid "" msgid ""
"Allow decision engine to pass strategy parameters, like optimization " "Allow decision engine to pass strategy parameters, like optimization "
"threshold, to selected strategy, also strategy to provide parameters info to " "threshold, to selected strategy, also strategy to provide parameters info to "
@@ -293,6 +450,34 @@ msgstr ""
"threshold, to selected strategy, also strategy to provide parameters info to " "threshold, to selected strategy, also strategy to provide parameters info to "
"end user." "end user."
msgid ""
"Allow using file to override metric map. Override the metric map of each "
"datasource as soon as it is created by the manager. This override comes from "
"a file whose path is provided by a setting in config file. The setting is "
"`watcher_decision_engine/metric_map_path`. The file contains a map per "
"datasource whose keys are the metric names as recognized by watcher and the "
"value is the real name of the metric in the datasource. This setting "
"defaults to `/etc/watcher/metric_map.yaml`, and presence of this file is "
"optional."
msgstr ""
"Allow using file to override metric map. Override the metric map of each "
"datasource as soon as it is created by the manager. This override comes from "
"a file whose path is provided by a setting in config file. The setting is "
"`watcher_decision_engine/metric_map_path`. The file contains a map per "
"datasource whose keys are the metric names as recognized by watcher and the "
"value is the real name of the metric in the datasource. This setting "
"defaults to `/etc/watcher/metric_map.yaml`, and presence of this file is "
"optional."
msgid ""
"An Watcher API WSGI application script ``watcher-api-wsgi`` is now "
"available. It is auto-generated by ``pbr`` and allows to run the API service "
"using WSGI server (for example Nginx and uWSGI)."
msgstr ""
"An Watcher API WSGI application script ``watcher-api-wsgi`` is now "
"available. It is auto-generated by ``pbr`` and allows to run the API service "
"using WSGI server (for example Nginx and uWSGI)."
msgid "" msgid ""
"Audits have 'name' field now, that is more friendly to end users. Audit's " "Audits have 'name' field now, that is more friendly to end users. Audit's "
"name can't exceed 63 characters." "name can't exceed 63 characters."
@@ -300,9 +485,25 @@ msgstr ""
"Audits have 'name' field now, that is more friendly to end users. Audit's " "Audits have 'name' field now, that is more friendly to end users. Audit's "
"name can't exceed 63 characters." "name can't exceed 63 characters."
msgid ""
"Baremetal Model gets Audit scoper with an ability to exclude Ironic nodes."
msgstr ""
"Baremetal Model gets Audit scope with an ability to exclude Ironic nodes."
msgid "Bug Fixes" msgid "Bug Fixes"
msgstr "Bug Fixes" msgstr "Bug Fixes"
msgid ""
"Ceilometer Datasource has been deprecated since its API has been deprecated "
"in Ocata cycle. Watcher has supported Ceilometer for some releases after "
"Ocata to let users migrate to Gnocchi/Monasca datasources. Since Train "
"release, Ceilometer support will be removed."
msgstr ""
"Ceilometer Datasource has been deprecated since its API has been deprecated "
"in Ocata cycle. Watcher has supported Ceilometer for some releases after "
"Ocata to let users migrate to Gnocchi/Monasca datasources. Since Train "
"release, Ceilometer support will be removed."
msgid "Centralize all configuration options for Watcher." msgid "Centralize all configuration options for Watcher."
msgstr "Centralise all configuration options for Watcher." msgstr "Centralise all configuration options for Watcher."
@@ -360,6 +561,52 @@ msgstr ""
"Now instances from particular project in OpenStack can be excluded from " "Now instances from particular project in OpenStack can be excluded from "
"audit defining scope in audit templates." "audit defining scope in audit templates."
msgid ""
"For a large cloud infrastructure, retrieving data from Nova may take a long "
"time. To avoid getting too much data from Nova, building the compute data "
"model according to the scope of audit."
msgstr ""
"For a large cloud infrastructure, retrieving data from Nova may take a long "
"time. To avoid getting too much data from Nova, building the compute data "
"model according to the scope of audit."
msgid ""
"Grafana has been added as datasource that can be used for collecting "
"metrics. The configuration options allow to specify what metrics and how "
"they are stored in grafana so that no matter how Grafana is configured it "
"can still be used. The configuration can be done via the typical "
"configuration file but it is recommended to configure most options in the "
"yaml file for metrics. For a complete walkthrough on configuring Grafana "
"see: https://docs.openstack.org/watcher/latest/datasources/grafana.html"
msgstr ""
"Grafana has been added as datasource that can be used for collecting "
"metrics. The configuration options allow to specify what metrics and how "
"they are stored in Grafana so that no matter how Grafana is configured it "
"can still be used. The configuration can be done via the typical "
"configuration file but it is recommended to configure most options in the "
"yaml file for metrics. For a complete walkthrough on configuring Grafana "
"see: https://docs.openstack.org/watcher/latest/datasources/grafana.html"
msgid ""
"If Gnocchi was configured to have a custom amount of retries and or a custom "
"timeout then the configuration needs to moved into the "
"`[watcher_datasources]` group instead of the `[gnocchi_client]` group."
msgstr ""
"If Gnocchi was configured to have a custom amount of retries and or a custom "
"timeout then the configuration needs to moved into the "
"`[watcher_datasources]` group instead of the `[gnocchi_client]` group."
msgid ""
"Improved interface for datasource baseclass that better defines expected "
"values and types for parameters and return types of all abstract methods. "
"This allows all strategies to work with every datasource provided the "
"metrics are configured for that given datasource."
msgstr ""
"Improved interface for datasource baseclass that better defines expected "
"values and types for parameters and return types of all abstract methods. "
"This allows all strategies to work with every datasource provided the "
"metrics are configured for that given datasource."
msgid "" msgid ""
"Instance cold migration logic is now replaced with using Nova migrate " "Instance cold migration logic is now replaced with using Nova migrate "
"Server(migrate Action) API which has host option since v2.56." "Server(migrate Action) API which has host option since v2.56."
@@ -367,6 +614,17 @@ msgstr ""
"Instance cold migration logic is now replaced with using Nova migrate " "Instance cold migration logic is now replaced with using Nova migrate "
"Server(migrate Action) API which has host option since v2.56." "Server(migrate Action) API which has host option since v2.56."
msgid ""
"Many operations in the decision engine will block on I/O. Such I/O "
"operations can stall the execution of a sequential application "
"significantly. To reduce the potential bottleneck of many operations the "
"general purpose decision engine threadpool is introduced."
msgstr ""
"Many operations in the decision engine will block on I/O. Such I/O "
"operations can stall the execution of a sequential application "
"significantly. To reduce the potential bottleneck of many operations the "
"general purpose decision engine threadpool is introduced."
msgid "New Features" msgid "New Features"
msgstr "New Features" msgstr "New Features"
@@ -389,6 +647,13 @@ msgstr ""
"Nova API version is now set to 2.56 by default. This needs the migrate " "Nova API version is now set to 2.56 by default. This needs the migrate "
"action of migration type cold with destination_node parameter to work." "action of migration type cold with destination_node parameter to work."
msgid ""
"Now Watcher strategy can select specific planner beyond default. Strategy "
"can set planner property to specify its own planner."
msgstr ""
"Now Watcher strategy can select specific planner beyond default. Strategy "
"can set planner property to specify its own planner."
msgid "Ocata Series Release Notes" msgid "Ocata Series Release Notes"
msgstr "Ocata Series Release Notes" msgstr "Ocata Series Release Notes"
@@ -429,12 +694,77 @@ msgstr ""
"resources will be called \"Audit scope\" and will be defined in each audit " "resources will be called \"Audit scope\" and will be defined in each audit "
"template (which contains the audit settings)." "template (which contains the audit settings)."
msgid ""
"Python 2.7 support has been dropped. Last release of Watcher to support "
"py2.7 is OpenStack Train. The minimum version of Python now supported by "
"Watcher is Python 3.6."
msgstr ""
"Python 2.7 support has been dropped. Last release of Watcher to support "
"py2.7 is OpenStack Train. The minimum version of Python now supported by "
"Watcher is Python 3.6."
msgid "Queens Series Release Notes" msgid "Queens Series Release Notes"
msgstr "Queens Series Release Notes" msgstr "Queens Series Release Notes"
msgid "Rocky Series Release Notes" msgid "Rocky Series Release Notes"
msgstr "Rocky Series Release Notes" msgstr "Rocky Series Release Notes"
msgid ""
"Several strategies have changed the `node` parameter to `compute_node` to be "
"better aligned with terminology. These strategies include "
"`basic_consolidation` and `workload_stabilzation`. The `node` parameter will "
"remain supported during Train release and will be removed in the subsequent "
"release."
msgstr ""
"Several strategies have changed the `node` parameter to `compute_node` to be "
"better aligned with terminology. These strategies include "
"`basic_consolidation` and `workload_stabilzation`. The `node` parameter will "
"remain supported during Train release and will be removed in the subsequent "
"release."
msgid ""
"Specific strategies can override this order and use datasources which are "
"not listed in the global preference."
msgstr ""
"Specific strategies can override this order and use datasources which are "
"not listed in the global preference."
msgid "Stein Series Release Notes"
msgstr "Stein Series Release Notes"
msgid ""
"The building of the compute (Nova) data model will be done using the "
"decision engine threadpool, thereby, significantly reducing the total time "
"required to build it."
msgstr ""
"The building of the compute (Nova) data model will be done using the "
"decision engine threadpool, thereby, significantly reducing the total time "
"required to build it."
msgid ""
"The configuration options for query retries in `[gnocchi_client]` are "
"deprecated and the option in `[watcher_datasources]` should now be used."
msgstr ""
"The configuration options for query retries in `[gnocchi_client]` are "
"deprecated and the option in `[watcher_datasources]` should now be used."
msgid ""
"The default value of ``[oslo_policy] policy_file`` config option has been "
"changed from ``policy.json`` to ``policy.yaml``. Operators who are utilizing "
"customized or previously generated static policy JSON files (which are not "
"needed by default), should generate new policy files or convert them in YAML "
"format. Use the `oslopolicy-convert-json-to-yaml <https://docs.openstack.org/"
"oslo.policy/latest/cli/oslopolicy-convert-json-to-yaml.html>`_ tool to "
"convert a JSON to YAML formatted policy file in backward compatible way."
msgstr ""
"The default value of ``[oslo_policy] policy_file`` config option has been "
"changed from ``policy.json`` to ``policy.yaml``. Operators who are utilizing "
"customized or previously generated static policy JSON files (which are not "
"needed by default), should generate new policy files or convert them in YAML "
"format. Use the `oslopolicy-convert-json-to-yaml <https://docs.openstack.org/"
"oslo.policy/latest/cli/oslopolicy-convert-json-to-yaml.html>`_ tool to "
"convert a JSON to YAML formatted policy file in backward compatible way."
msgid "" msgid ""
"The graph model describes how VMs are associated to compute hosts. This " "The graph model describes how VMs are associated to compute hosts. This "
"allows for seeing relationships upfront between the entities and hence can " "allows for seeing relationships upfront between the entities and hence can "
@@ -455,6 +785,22 @@ msgstr ""
"was fixed. Before fixing, it booted an instance in the service project as a " "was fixed. Before fixing, it booted an instance in the service project as a "
"migrated instance." "migrated instance."
msgid ""
"The minimum required version of the ``[nova_client]/api_version`` value is "
"now enforced to be ``2.56`` which is available since the Queens version of "
"the nova compute service."
msgstr ""
"The minimum required version of the ``[nova_client]/api_version`` value is "
"now enforced to be ``2.56`` which is available since the Queens version of "
"the Nova compute service."
msgid ""
"The new strategy baseclass has significant changes in method parameters and "
"any out-of-tree strategies will have to be adopted."
msgstr ""
"The new strategy baseclass has significant changes in method parameters and "
"any out-of-tree strategies will have to be adopted."
msgid "" msgid ""
"There is new ability to create Watcher continuous audits with cron interval. " "There is new ability to create Watcher continuous audits with cron interval. "
"It means you may use, for example, optional argument '--interval \"\\*/5 \\* " "It means you may use, for example, optional argument '--interval \"\\*/5 \\* "
@@ -468,9 +814,45 @@ msgstr ""
"best effort basis and therefore, we recommend you to use a minimal cron " "best effort basis and therefore, we recommend you to use a minimal cron "
"interval of at least one minute." "interval of at least one minute."
msgid "Train Series Release Notes"
msgstr "Train Series Release Notes"
msgid "Upgrade Notes" msgid "Upgrade Notes"
msgstr "Upgrade Notes" msgstr "Upgrade Notes"
msgid ""
"Use of JSON policy files was deprecated by the ``oslo.policy`` library "
"during the Victoria development cycle. As a result, this deprecation is "
"being noted in the Wallaby cycle with an anticipated future removal of "
"support by ``oslo.policy``. As such operators will need to convert to YAML "
"policy files. Please see the upgrade notes for details on migration of any "
"custom policy files."
msgstr ""
"Use of JSON policy files was deprecated by the ``oslo.policy`` library "
"during the Victoria development cycle. As a result, this deprecation is "
"being noted in the Wallaby cycle with an anticipated future removal of "
"support by ``oslo.policy``. As such operators will need to convert to YAML "
"policy files. Please see the upgrade notes for details on migration of any "
"custom policy files."
msgid ""
"Using ``watcher/api/app.wsgi`` script is deprecated and it will be removed "
"in U release. Please switch to automatically generated ``watcher-api-wsgi`` "
"script instead."
msgstr ""
"Using ``watcher/api/app.wsgi`` script is deprecated and it will be removed "
"in U release. Please switch to automatically generated ``watcher-api-wsgi`` "
"script instead."
msgid "Ussuri Series Release Notes"
msgstr "Ussuri Series Release Notes"
msgid "Victoria Series Release Notes"
msgstr "Victoria Series Release Notes"
msgid "Wallaby Series Release Notes"
msgstr "Wallaby Series Release Notes"
msgid "" msgid ""
"Watcher can continuously optimize the OpenStack cloud for a specific " "Watcher can continuously optimize the OpenStack cloud for a specific "
"strategy or goal by triggering an audit periodically which generates an " "strategy or goal by triggering an audit periodically which generates an "
@@ -480,6 +862,15 @@ msgstr ""
"strategy or goal by triggering an audit periodically which generates an " "strategy or goal by triggering an audit periodically which generates an "
"action plan and run it automatically." "action plan and run it automatically."
msgid ""
"Watcher can get resource information such as total, allocation ratio and "
"reserved information from Placement API. Now we add some new fields to the "
"Watcher Data Model:"
msgstr ""
"Watcher can get resource information such as total, allocation ratio and "
"reserved information from Placement API. Now we add some new fields to the "
"Watcher Data Model:"
msgid "" msgid ""
"Watcher can now run specific actions in parallel improving the performances " "Watcher can now run specific actions in parallel improving the performances "
"dramatically when executing an action plan." "dramatically when executing an action plan."
@@ -517,6 +908,15 @@ msgstr ""
"includes all instances. It filters excluded instances when migration during " "includes all instances. It filters excluded instances when migration during "
"the audit." "the audit."
msgid ""
"Watcher now supports configuring which datasource to use and in which order. "
"This configuration is done by specifying datasources in the "
"watcher_datasources section:"
msgstr ""
"Watcher now supports configuring which datasource to use and in which order. "
"This configuration is done by specifying datasources in the "
"watcher_datasources section:"
msgid "" msgid ""
"Watcher removes the support to Nova legacy notifications because of Nova " "Watcher removes the support to Nova legacy notifications because of Nova "
"will deprecate them." "will deprecate them."
@@ -557,9 +957,21 @@ msgstr ""
"Watcher supports multiple metrics backend and relies on Ceilometer and " "Watcher supports multiple metrics backend and relies on Ceilometer and "
"Monasca." "Monasca."
msgid "We also add some new propeties:"
msgstr "We also add some new properties:"
msgid "Welcome to watcher's Release Notes documentation!" msgid "Welcome to watcher's Release Notes documentation!"
msgstr "Welcome to watcher's Release Notes documentation!" msgstr "Welcome to watcher's Release Notes documentation!"
msgid "Xena Series Release Notes"
msgstr "Xena Series Release Notes"
msgid "Yoga Series Release Notes"
msgstr "Yoga Series Release Notes"
msgid "``[watcher_datasources] datasources = gnocchi,monasca,ceilometer``"
msgstr "``[watcher_datasources] datasources = gnocchi,monasca,ceilometer``"
msgid "" msgid ""
"all Watcher objects have been refactored to support OVO (oslo." "all Watcher objects have been refactored to support OVO (oslo."
"versionedobjects) which was a prerequisite step in order to implement " "versionedobjects) which was a prerequisite step in order to implement "
@@ -569,6 +981,21 @@ msgstr ""
"versionedobjects) which was a prerequisite step in order to implement " "versionedobjects) which was a prerequisite step in order to implement "
"versioned notifications." "versioned notifications."
msgid ""
"disk_gb_capacity: The amount of disk, take allocation ratio into account, "
"but do not include reserved."
msgstr ""
"disk_gb_capacity: The amount of disk, take allocation ratio into account, "
"but do not include reserved."
msgid ""
"disk_gb_reserved: The amount of disk a node has reserved for its own use."
msgstr ""
"disk_gb_reserved: The amount of disk a node has reserved for its own use."
msgid "disk_ratio: Disk allocation ratio."
msgstr "disk_ratio: Disk allocation ratio."
msgid "instance.create.end" msgid "instance.create.end"
msgstr "instance.create.end" msgstr "instance.create.end"
@@ -635,6 +1062,21 @@ msgstr "instance.unshelve.end"
msgid "instance.update" msgid "instance.update"
msgstr "instance.update" msgstr "instance.update"
msgid ""
"memory_mb_capacity: The amount of memory, take allocation ratio into "
"account, but do not include reserved."
msgstr ""
"memory_mb_capacity: The amount of memory, take allocation ratio into "
"account, but do not include reserved."
msgid ""
"memory_mb_reserved: The amount of memory a node has reserved for its own use."
msgstr ""
"memory_mb_reserved: The amount of memory a node has reserved for its own use."
msgid "memory_ratio: Memory allocation ratio."
msgstr "memory_ratio: Memory allocation ratio."
msgid "new:" msgid "new:"
msgstr "new:" msgstr "new:"
@@ -649,3 +1091,16 @@ msgstr "service.delete"
msgid "service.update" msgid "service.update"
msgstr "service.update" msgstr "service.update"
msgid ""
"vcpu_capacity: The amount of vcpu, take allocation ratio into account, but "
"do not include reserved."
msgstr ""
"vcpu_capacity: The amount of vcpu, take allocation ratio into account, but "
"do not include reserved."
msgid "vcpu_ratio: CPU allocation ratio."
msgstr "vcpu_ratio: CPU allocation ratio."
msgid "vcpu_reserved: The amount of cpu a node has reserved for its own use."
msgstr "vcpu_reserved: The amount of CPU a node has reserved for its own use."

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,36 +1,35 @@
# The order of packages is significant, because pip processes them in the order # The order of packages is significant, because pip processes them in the order
# of appearance. Changing the order has an impact on the overall integration # of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later. # process, which may cause wedges in the gate later.
apscheduler>=3.5.1 # MIT License apscheduler>=3.5.1 # MIT License
jsonpatch>=1.21 # BSD jsonpatch>=1.21 # BSD
keystoneauth1>=3.4.0 # Apache-2.0 keystoneauth1>=3.4.0 # Apache-2.0
jsonschema>=2.6.0 # MIT jsonschema>=3.2.0 # MIT
keystonemiddleware>=4.21.0 # Apache-2.0 keystonemiddleware>=4.21.0 # Apache-2.0
lxml>=4.1.1 # BSD lxml>=4.5.1 # BSD
croniter>=0.3.20 # MIT License croniter>=0.3.20 # MIT License
os-resource-classes>=0.4.0 os-resource-classes>=0.4.0
oslo.concurrency>=3.26.0 # Apache-2.0 oslo.concurrency>=3.26.0 # Apache-2.0
oslo.cache>=1.29.0 # Apache-2.0 oslo.cache>=1.29.0 # Apache-2.0
oslo.config>=5.2.0 # Apache-2.0 oslo.config>=6.8.0 # Apache-2.0
oslo.context>=2.21.0 # Apache-2.0 oslo.context>=2.21.0 # Apache-2.0
oslo.db>=4.35.0 # Apache-2.0 oslo.db>=4.44.0 # Apache-2.0
oslo.i18n>=3.20.0 # Apache-2.0 oslo.i18n>=3.20.0 # Apache-2.0
oslo.log>=3.37.0 # Apache-2.0 oslo.log>=3.37.0 # Apache-2.0
oslo.messaging>=8.1.2 # Apache-2.0 oslo.messaging>=8.1.2 # Apache-2.0
oslo.policy>=1.34.0 # Apache-2.0 oslo.policy>=3.6.0 # Apache-2.0
oslo.reports>=1.27.0 # Apache-2.0 oslo.reports>=1.27.0 # Apache-2.0
oslo.serialization>=2.25.0 # Apache-2.0 oslo.serialization>=2.25.0 # Apache-2.0
oslo.service>=1.30.0 # Apache-2.0 oslo.service>=1.30.0 # Apache-2.0
oslo.upgradecheck>=0.1.0 # Apache-2.0 oslo.upgradecheck>=1.3.0 # Apache-2.0
oslo.utils>=3.36.0 # Apache-2.0 oslo.utils>=3.36.0 # Apache-2.0
oslo.versionedobjects>=1.32.0 # Apache-2.0 oslo.versionedobjects>=1.32.0 # Apache-2.0
PasteDeploy>=1.5.2 # MIT PasteDeploy>=1.5.2 # MIT
pbr>=3.1.1 # Apache-2.0 pbr>=3.1.1 # Apache-2.0
pecan>=1.3.2 # BSD pecan>=1.3.2 # BSD
PrettyTable<0.8,>=0.7.2 # BSD PrettyTable>=0.7.2 # BSD
gnocchiclient>=7.0.1 # Apache-2.0 gnocchiclient>=7.0.1 # Apache-2.0
python-ceilometerclient>=2.9.0 # Apache-2.0
python-cinderclient>=3.5.0 # Apache-2.0 python-cinderclient>=3.5.0 # Apache-2.0
python-glanceclient>=2.9.1 # Apache-2.0 python-glanceclient>=2.9.1 # Apache-2.0
python-keystoneclient>=3.15.0 # Apache-2.0 python-keystoneclient>=3.15.0 # Apache-2.0
@@ -39,12 +38,11 @@ python-neutronclient>=6.7.0 # Apache-2.0
python-novaclient>=14.1.0 # Apache-2.0 python-novaclient>=14.1.0 # Apache-2.0
python-openstackclient>=3.14.0 # Apache-2.0 python-openstackclient>=3.14.0 # Apache-2.0
python-ironicclient>=2.5.0 # Apache-2.0 python-ironicclient>=2.5.0 # Apache-2.0
six>=1.11.0 # MIT
SQLAlchemy>=1.2.5 # MIT SQLAlchemy>=1.2.5 # MIT
stevedore>=1.28.0 # Apache-2.0 stevedore>=1.28.0 # Apache-2.0
taskflow>=3.7.1 # Apache-2.0 taskflow>=3.8.0 # Apache-2.0
WebOb>=1.8.5 # MIT WebOb>=1.8.5 # MIT
WSME>=0.9.2 # MIT WSME>=0.9.2 # MIT
networkx>=2.2;python_version>='3.4' # BSD networkx>=2.4 # BSD
microversion_parse>=0.2.1 # Apache-2.0 microversion_parse>=0.2.1 # Apache-2.0
futurist>=1.8.0 # Apache-2.0 futurist>=1.8.0 # Apache-2.0

View File

@@ -1,12 +1,12 @@
[metadata] [metadata]
name = python-watcher name = python-watcher
summary = OpenStack Watcher provides a flexible and scalable resource optimization service for multi-tenant OpenStack-based clouds. summary = OpenStack Watcher provides a flexible and scalable resource optimization service for multi-tenant OpenStack-based clouds.
description-file = description_file =
README.rst README.rst
author = OpenStack author = OpenStack
author-email = openstack-discuss@lists.openstack.org author_email = openstack-discuss@lists.openstack.org
home-page = https://docs.openstack.org/watcher/latest/ home_page = https://docs.openstack.org/watcher/latest/
python-requires = >=3.6 python_requires = >=3.6
classifier = classifier =
Environment :: OpenStack Environment :: OpenStack
Intended Audience :: Information Technology Intended Audience :: Information Technology
@@ -19,6 +19,7 @@ classifier =
Programming Language :: Python :: 3 Programming Language :: Python :: 3
Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
[files] [files]
packages = packages =
@@ -107,18 +108,3 @@ watcher_cluster_data_model_collectors =
compute = watcher.decision_engine.model.collector.nova:NovaClusterDataModelCollector compute = watcher.decision_engine.model.collector.nova:NovaClusterDataModelCollector
storage = watcher.decision_engine.model.collector.cinder:CinderClusterDataModelCollector storage = watcher.decision_engine.model.collector.cinder:CinderClusterDataModelCollector
baremetal = watcher.decision_engine.model.collector.ironic:BaremetalClusterDataModelCollector baremetal = watcher.decision_engine.model.collector.ironic:BaremetalClusterDataModelCollector
[compile_catalog]
directory = watcher/locale
domain = watcher
[update_catalog]
domain = watcher
output_dir = watcher/locale
input_file = watcher/locale/watcher.pot
[extract_messages]
keywords = _ gettext ngettext l_ lazy_gettext _LI _LW _LE _LC
mapping_file = babel.cfg
output_file = watcher/locale/watcher.pot

View File

@@ -5,12 +5,11 @@
coverage>=4.5.1 # Apache-2.0 coverage>=4.5.1 # Apache-2.0
doc8>=0.8.0 # Apache-2.0 doc8>=0.8.0 # Apache-2.0
freezegun>=0.3.10 # Apache-2.0 freezegun>=0.3.10 # Apache-2.0
hacking>=3.0,<3.1.0 # Apache-2.0 hacking>=3.0.1,<3.1.0 # Apache-2.0
mock>=2.0.0 # BSD
oslotest>=3.3.0 # Apache-2.0 oslotest>=3.3.0 # Apache-2.0
os-testr>=1.0.0 # Apache-2.0
testscenarios>=0.5.0 # Apache-2.0/BSD testscenarios>=0.5.0 # Apache-2.0/BSD
testtools>=2.3.0 # MIT testtools>=2.3.0 # MIT
stestr>=2.0.0 # Apache-2.0 stestr>=2.0.0 # Apache-2.0
os-api-ref>=1.4.0 # Apache-2.0 os-api-ref>=1.4.0 # Apache-2.0
bandit>=1.6.0 # Apache-2.0 bandit>=1.6.0 # Apache-2.0
WebTest>=2.0.27 # MIT

67
tox.ini
View File

@@ -1,19 +1,18 @@
[tox] [tox]
minversion = 2.0 minversion = 3.18.0
envlist = py36,py37,pep8 envlist = py3,pep8
skipsdist = True skipsdist = True
ignore_basepython_conflict = True ignore_basepython_conflict = True
[testenv] [testenv]
basepython = python3 basepython = python3
usedevelop = True usedevelop = True
whitelist_externals = find allowlist_externals = find
rm rm
install_command = pip install {opts} {packages} install_command = pip install -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} {opts} {packages}
setenv = setenv =
VIRTUAL_ENV={envdir} VIRTUAL_ENV={envdir}
deps = deps =
-c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
-r{toxinidir}/test-requirements.txt -r{toxinidir}/test-requirements.txt
-r{toxinidir}/requirements.txt -r{toxinidir}/requirements.txt
commands = commands =
@@ -31,7 +30,6 @@ commands =
[testenv:venv] [testenv:venv]
setenv = PYTHONHASHSEED=0 setenv = PYTHONHASHSEED=0
deps = deps =
-c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
-r{toxinidir}/doc/requirements.txt -r{toxinidir}/doc/requirements.txt
-r{toxinidir}/test-requirements.txt -r{toxinidir}/test-requirements.txt
-r{toxinidir}/requirements.txt -r{toxinidir}/requirements.txt
@@ -49,14 +47,15 @@ commands =
[testenv:docs] [testenv:docs]
setenv = PYTHONHASHSEED=0 setenv = PYTHONHASHSEED=0
deps = -r{toxinidir}/doc/requirements.txt deps =
-r{toxinidir}/doc/requirements.txt
commands = commands =
rm -fr doc/build doc/source/api/ .autogenerated rm -fr doc/build doc/source/api/ .autogenerated
sphinx-build -W --keep-going -b html doc/source doc/build/html sphinx-build -W --keep-going -b html doc/source doc/build/html
[testenv:api-ref] [testenv:api-ref]
deps = -r{toxinidir}/doc/requirements.txt deps = -r{toxinidir}/doc/requirements.txt
whitelist_externals = bash allowlist_externals = bash
commands = commands =
bash -c 'rm -rf api-ref/build' bash -c 'rm -rf api-ref/build'
sphinx-build -W --keep-going -b html -d api-ref/build/doctrees api-ref/source api-ref/build/html sphinx-build -W --keep-going -b html -d api-ref/build/doctrees api-ref/source api-ref/build/html
@@ -73,6 +72,28 @@ commands =
commands = commands =
oslopolicy-sample-generator --config-file etc/watcher/oslo-policy-generator/watcher-policy-generator.conf oslopolicy-sample-generator --config-file etc/watcher/oslo-policy-generator/watcher-policy-generator.conf
[testenv:wheel]
commands = python setup.py bdist_wheel
[testenv:pdf-docs]
envdir = {toxworkdir}/docs
deps = {[testenv:docs]deps}
allowlist_externals =
rm
make
commands =
rm -rf doc/build/pdf
sphinx-build -W --keep-going -b latex doc/source doc/build/pdf
make -C doc/build/pdf
[testenv:releasenotes]
deps = -r{toxinidir}/doc/requirements.txt
commands = sphinx-build -a -W -E -d releasenotes/build/doctrees --keep-going -b html releasenotes/source releasenotes/build/html
[testenv:bandit]
deps = -r{toxinidir}/test-requirements.txt
commands = bandit -r watcher -x watcher/tests/* -n5 -ll -s B320
[flake8] [flake8]
filename = *.py,app.wsgi filename = *.py,app.wsgi
show-source=True show-source=True
@@ -82,9 +103,6 @@ builtins= _
enable-extensions = H106,H203,H904 enable-extensions = H106,H203,H904
exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build,*sqlalchemy/alembic/versions/*,demo/,releasenotes exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build,*sqlalchemy/alembic/versions/*,demo/,releasenotes
[testenv:wheel]
commands = python setup.py bdist_wheel
[hacking] [hacking]
import_exceptions = watcher._i18n import_exceptions = watcher._i18n
@@ -105,35 +123,10 @@ extension =
N340 = checks:check_oslo_i18n_wrapper N340 = checks:check_oslo_i18n_wrapper
N341 = checks:check_builtins_gettext N341 = checks:check_builtins_gettext
N342 = checks:no_redundant_import_alias N342 = checks:no_redundant_import_alias
N366 = checks:import_stock_mock
paths = ./watcher/hacking paths = ./watcher/hacking
[doc8] [doc8]
extension=.rst extension=.rst
# todo: stop ignoring doc/source/man when https://bugs.launchpad.net/doc8/+bug/1502391 is fixed # todo: stop ignoring doc/source/man when https://bugs.launchpad.net/doc8/+bug/1502391 is fixed
ignore-path=doc/source/image_src,doc/source/man,doc/source/api ignore-path=doc/source/image_src,doc/source/man,doc/source/api
[testenv:pdf-docs]
envdir = {toxworkdir}/docs
deps = {[testenv:docs]deps}
whitelist_externals =
rm
make
commands =
rm -rf doc/build/pdf
sphinx-build -W --keep-going -b latex doc/source doc/build/pdf
make -C doc/build/pdf
[testenv:releasenotes]
deps = -r{toxinidir}/doc/requirements.txt
commands = sphinx-build -a -W -E -d releasenotes/build/doctrees --keep-going -b html releasenotes/source releasenotes/build/html
[testenv:bandit]
deps = -r{toxinidir}/test-requirements.txt
commands = bandit -r watcher -x watcher/tests/* -n5 -ll -s B320
[testenv:lower-constraints]
deps =
-c{toxinidir}/lower-constraints.txt
-r{toxinidir}/test-requirements.txt
-r{toxinidir}/requirements.txt

View File

@@ -13,8 +13,6 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from __future__ import unicode_literals
from oslo_config import cfg from oslo_config import cfg
from watcher.api import hooks from watcher.api import hooks

View File

@@ -57,6 +57,7 @@ are dynamically loaded by Watcher at launch time.
import datetime import datetime
from http import HTTPStatus
import pecan import pecan
from pecan import rest from pecan import rest
import wsme import wsme
@@ -362,7 +363,7 @@ class ActionsController(rest.RestController):
return Action.convert_with_links(action) return Action.convert_with_links(action)
@wsme_pecan.wsexpose(Action, body=Action, status_code=201) @wsme_pecan.wsexpose(Action, body=Action, status_code=HTTPStatus.CREATED)
def post(self, action): def post(self, action):
"""Create a new action(forbidden). """Create a new action(forbidden).
@@ -422,7 +423,7 @@ class ActionsController(rest.RestController):
action_to_update.save() action_to_update.save()
return Action.convert_with_links(action_to_update) return Action.convert_with_links(action_to_update)
@wsme_pecan.wsexpose(None, types.uuid, status_code=204) @wsme_pecan.wsexpose(None, types.uuid, status_code=HTTPStatus.NO_CONTENT)
def delete(self, action_uuid): def delete(self, action_uuid):
"""Delete a action(forbidden). """Delete a action(forbidden).

View File

@@ -56,6 +56,7 @@ state machine <action_plan_state_machine>`.
import datetime import datetime
from http import HTTPStatus
from oslo_log import log from oslo_log import log
import pecan import pecan
from pecan import rest from pecan import rest
@@ -460,7 +461,7 @@ class ActionPlansController(rest.RestController):
return ActionPlan.convert_with_links(action_plan) return ActionPlan.convert_with_links(action_plan)
@wsme_pecan.wsexpose(None, types.uuid, status_code=204) @wsme_pecan.wsexpose(None, types.uuid, status_code=HTTPStatus.NO_CONTENT)
def delete(self, action_plan_uuid): def delete(self, action_plan_uuid):
"""Delete an action plan. """Delete an action plan.

View File

@@ -32,6 +32,7 @@ states, visit :ref:`the Audit State machine <audit_state_machine>`.
import datetime import datetime
from dateutil import tz from dateutil import tz
from http import HTTPStatus
import pecan import pecan
from pecan import rest from pecan import rest
import wsme import wsme
@@ -595,7 +596,8 @@ class AuditsController(rest.RestController):
return Audit.convert_with_links(rpc_audit) return Audit.convert_with_links(rpc_audit)
@wsme_pecan.wsexpose(Audit, body=AuditPostType, status_code=201) @wsme_pecan.wsexpose(Audit, body=AuditPostType,
status_code=HTTPStatus.CREATED)
def post(self, audit_p): def post(self, audit_p):
"""Create a new audit. """Create a new audit.
@@ -717,7 +719,7 @@ class AuditsController(rest.RestController):
audit_to_update.save() audit_to_update.save()
return Audit.convert_with_links(audit_to_update) return Audit.convert_with_links(audit_to_update)
@wsme_pecan.wsexpose(None, wtypes.text, status_code=204) @wsme_pecan.wsexpose(None, wtypes.text, status_code=HTTPStatus.NO_CONTENT)
def delete(self, audit): def delete(self, audit):
"""Delete an audit. """Delete an audit.

View File

@@ -45,6 +45,7 @@ will be launched automatically or will need a manual confirmation from the
import datetime import datetime
from http import HTTPStatus
import pecan import pecan
from pecan import rest from pecan import rest
import wsme import wsme
@@ -138,6 +139,9 @@ class AuditTemplatePostType(wtypes.Base):
raise exception.InvalidGoal(goal=audit_template.goal) raise exception.InvalidGoal(goal=audit_template.goal)
if audit_template.scope: if audit_template.scope:
keys = [list(s)[0] for s in audit_template.scope]
if keys[0] not in ('compute', 'storage'):
audit_template.scope = [dict(compute=audit_template.scope)]
common_utils.Draft4Validator( common_utils.Draft4Validator(
AuditTemplatePostType._build_schema() AuditTemplatePostType._build_schema()
).validate(audit_template.scope) ).validate(audit_template.scope)
@@ -158,18 +162,23 @@ class AuditTemplatePostType(wtypes.Base):
"included and excluded together")) "included and excluded together"))
if audit_template.strategy: if audit_template.strategy:
available_strategies = objects.Strategy.list( try:
AuditTemplatePostType._ctx) if (common_utils.is_uuid_like(audit_template.strategy) or
available_strategies_map = { common_utils.is_int_like(audit_template.strategy)):
s.uuid: s for s in available_strategies} strategy = objects.Strategy.get(
if audit_template.strategy not in available_strategies_map: AuditTemplatePostType._ctx, audit_template.strategy)
else:
strategy = objects.Strategy.get_by_name(
AuditTemplatePostType._ctx, audit_template.strategy)
except Exception:
raise exception.InvalidStrategy( raise exception.InvalidStrategy(
strategy=audit_template.strategy) strategy=audit_template.strategy)
strategy = available_strategies_map[audit_template.strategy]
# Check that the strategy we indicate is actually related to the # Check that the strategy we indicate is actually related to the
# specified goal # specified goal
if strategy.goal_id != goal.id: if strategy.goal_id != goal.id:
available_strategies = objects.Strategy.list(
AuditTemplatePostType._ctx)
choices = ["'%s' (%s)" % (s.uuid, s.name) choices = ["'%s' (%s)" % (s.uuid, s.name)
for s in available_strategies] for s in available_strategies]
raise exception.InvalidStrategy( raise exception.InvalidStrategy(
@@ -610,7 +619,7 @@ class AuditTemplatesController(rest.RestController):
@wsme.validate(types.uuid, AuditTemplatePostType) @wsme.validate(types.uuid, AuditTemplatePostType)
@wsme_pecan.wsexpose(AuditTemplate, body=AuditTemplatePostType, @wsme_pecan.wsexpose(AuditTemplate, body=AuditTemplatePostType,
status_code=201) status_code=HTTPStatus.CREATED)
def post(self, audit_template_postdata): def post(self, audit_template_postdata):
"""Create a new audit template. """Create a new audit template.
@@ -686,7 +695,7 @@ class AuditTemplatesController(rest.RestController):
audit_template_to_update.save() audit_template_to_update.save()
return AuditTemplate.convert_with_links(audit_template_to_update) return AuditTemplate.convert_with_links(audit_template_to_update)
@wsme_pecan.wsexpose(None, wtypes.text, status_code=204) @wsme_pecan.wsexpose(None, wtypes.text, status_code=HTTPStatus.NO_CONTENT)
def delete(self, audit_template): def delete(self, audit_template):
"""Delete a audit template. """Delete a audit template.

View File

@@ -19,8 +19,6 @@ Service mechanism provides ability to monitor Watcher services state.
""" """
import datetime import datetime
import six
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log from oslo_log import log
from oslo_utils import timeutils from oslo_utils import timeutils
@@ -70,7 +68,7 @@ class Service(base.APIBase):
service = objects.Service.get(pecan.request.context, id) service = objects.Service.get(pecan.request.context, id)
last_heartbeat = (service.last_seen_up or service.updated_at or last_heartbeat = (service.last_seen_up or service.updated_at or
service.created_at) service.created_at)
if isinstance(last_heartbeat, six.string_types): if isinstance(last_heartbeat, str):
# NOTE(russellb) If this service came in over rpc via # NOTE(russellb) If this service came in over rpc via
# conductor, then the timestamp will be a string and needs to be # conductor, then the timestamp will be a string and needs to be
# converted back to a datetime. # converted back to a datetime.

View File

@@ -15,7 +15,6 @@
from oslo_serialization import jsonutils from oslo_serialization import jsonutils
from oslo_utils import strutils from oslo_utils import strutils
import six
import wsme import wsme
from wsme import types as wtypes from wsme import types as wtypes
@@ -132,7 +131,7 @@ class JsonType(wtypes.UserType):
def __str__(self): def __str__(self):
# These are the json serializable native types # These are the json serializable native types
return ' | '.join(map(str, (wtypes.text, six.integer_types, float, return ' | '.join(map(str, (wtypes.text, int, float,
BooleanType, list, dict, None))) BooleanType, list, dict, None)))
@staticmethod @staticmethod

View File

@@ -14,6 +14,7 @@
Webhook endpoint for Watcher v1 REST API. Webhook endpoint for Watcher v1 REST API.
""" """
from http import HTTPStatus
from oslo_log import log from oslo_log import log
import pecan import pecan
from pecan import rest from pecan import rest
@@ -36,7 +37,7 @@ class WebhookController(rest.RestController):
self.dc_client = rpcapi.DecisionEngineAPI() self.dc_client = rpcapi.DecisionEngineAPI()
@wsme_pecan.wsexpose(None, wtypes.text, body=types.jsontype, @wsme_pecan.wsexpose(None, wtypes.text, body=types.jsontype,
status_code=202) status_code=HTTPStatus.ACCEPTED)
def post(self, audit_ident, body): def post(self, audit_ident, body):
"""Trigger the given audit. """Trigger the given audit.

View File

@@ -15,9 +15,9 @@
# under the License. # under the License.
from http import HTTPStatus
from oslo_config import cfg from oslo_config import cfg
from pecan import hooks from pecan import hooks
from six.moves import http_client
from watcher.common import context from watcher.common import context
@@ -91,8 +91,8 @@ class NoExceptionTracebackHook(hooks.PecanHook):
# Do nothing if there is no error. # Do nothing if there is no error.
# Status codes in the range 200 (OK) to 399 (400 = BAD_REQUEST) are not # Status codes in the range 200 (OK) to 399 (400 = BAD_REQUEST) are not
# an error. # an error.
if (http_client.OK <= state.response.status_int < if (HTTPStatus.OK <= state.response.status_int <
http_client.BAD_REQUEST): HTTPStatus.BAD_REQUEST):
return return
json_body = state.response.json json_body = state.response.json

View File

@@ -24,7 +24,6 @@ from xml import etree as et
from oslo_log import log from oslo_log import log
from oslo_serialization import jsonutils from oslo_serialization import jsonutils
import six
import webob import webob
from watcher._i18n import _ from watcher._i18n import _
@@ -84,12 +83,10 @@ class ParsableErrorMiddleware(object):
'</error_message>' % state['status_code']] '</error_message>' % state['status_code']]
state['headers'].append(('Content-Type', 'application/xml')) state['headers'].append(('Content-Type', 'application/xml'))
else: else:
if six.PY3: app_iter = [i.decode('utf-8') for i in app_iter]
app_iter = [i.decode('utf-8') for i in app_iter]
body = [jsonutils.dumps( body = [jsonutils.dumps(
{'error_message': '\n'.join(app_iter)})] {'error_message': '\n'.join(app_iter)})]
if six.PY3: body = [item.encode('utf-8') for item in body]
body = [item.encode('utf-8') for item in body]
state['headers'].append(('Content-Type', 'application/json')) state['headers'].append(('Content-Type', 'application/json'))
state['headers'].append(('Content-Length', str(len(body[0])))) state['headers'].append(('Content-Length', str(len(body[0]))))
else: else:

View File

@@ -20,7 +20,6 @@ import itertools
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log from oslo_log import log
from oslo_utils import timeutils from oslo_utils import timeutils
import six
from watcher.common import context as watcher_context from watcher.common import context as watcher_context
from watcher.common import scheduling from watcher.common import scheduling
@@ -83,7 +82,7 @@ class APISchedulingService(scheduling.BackgroundSchedulerService):
service = objects.Service.get(context, service_id) service = objects.Service.get(context, service_id)
last_heartbeat = (service.last_seen_up or service.updated_at or last_heartbeat = (service.last_seen_up or service.updated_at or
service.created_at) service.created_at)
if isinstance(last_heartbeat, six.string_types): if isinstance(last_heartbeat, str):
# NOTE(russellb) If this service came in over rpc via # NOTE(russellb) If this service came in over rpc via
# conductor, then the timestamp will be a string and needs to be # conductor, then the timestamp will be a string and needs to be
# converted back to a datetime. # converted back to a datetime.

View File

@@ -18,11 +18,9 @@
# #
import abc import abc
import six
@six.add_metaclass(abc.ABCMeta) class BaseActionPlanHandler(object, metaclass=abc.ABCMeta):
class BaseActionPlanHandler(object):
@abc.abstractmethod @abc.abstractmethod
def execute(self): def execute(self):
raise NotImplementedError() raise NotImplementedError()

View File

@@ -19,14 +19,12 @@
import abc import abc
import jsonschema import jsonschema
import six
from watcher.common import clients from watcher.common import clients
from watcher.common.loader import loadable from watcher.common.loader import loadable
@six.add_metaclass(abc.ABCMeta) class BaseAction(loadable.Loadable, metaclass=abc.ABCMeta):
class BaseAction(loadable.Loadable):
# NOTE(jed): by convention we decided # NOTE(jed): by convention we decided
# that the attribute "resource_id" is the unique id of # that the attribute "resource_id" is the unique id of
# the resource to which the Action applies to allow us to use it in the # the resource to which the Action applies to allow us to use it in the

View File

@@ -15,8 +15,6 @@
# limitations under the License. # limitations under the License.
# #
from __future__ import unicode_literals
from oslo_log import log from oslo_log import log
from watcher.applier.loading import default from watcher.applier.loading import default

View File

@@ -186,7 +186,7 @@ class Migrate(base.BaseAction):
return self.migrate(destination=self.destination_node) return self.migrate(destination=self.destination_node)
def revert(self): def revert(self):
LOG.info('Migrate action do not revert!') return self.migrate(destination=self.source_node)
def abort(self): def abort(self):
nova = nova_helper.NovaHelper(osc=self.osc) nova = nova_helper.NovaHelper(osc=self.osc)

View File

@@ -95,7 +95,7 @@ class Resize(base.BaseAction):
return self.resize() return self.resize()
def revert(self): def revert(self):
return self.migrate(destination=self.source_node) LOG.warning("revert not supported")
def pre_condition(self): def pre_condition(self):
# TODO(jed): check if the instance exists / check if the instance is on # TODO(jed): check if the instance exists / check if the instance is on

View File

@@ -26,11 +26,9 @@ See: :doc:`../architecture` for more details on this component.
""" """
import abc import abc
import six
@six.add_metaclass(abc.ABCMeta) class BaseApplier(object, metaclass=abc.ABCMeta):
class BaseApplier(object):
@abc.abstractmethod @abc.abstractmethod
def execute(self, action_plan_uuid): def execute(self, action_plan_uuid):
raise NotImplementedError() raise NotImplementedError()

View File

@@ -11,9 +11,6 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from __future__ import unicode_literals
from watcher.common.loader import default from watcher.common.loader import default

View File

@@ -17,7 +17,6 @@
# #
import abc import abc
import six
import time import time
import eventlet import eventlet
@@ -40,8 +39,7 @@ CANCEL_STATE = [objects.action_plan.State.CANCELLING,
objects.action_plan.State.CANCELLED] objects.action_plan.State.CANCELLED]
@six.add_metaclass(abc.ABCMeta) class BaseWorkFlowEngine(loadable.Loadable, metaclass=abc.ABCMeta):
class BaseWorkFlowEngine(loadable.Loadable):
def __init__(self, config, context=None, applier_manager=None): def __init__(self, config, context=None, applier_manager=None):
"""Constructor """Constructor

View File

@@ -25,8 +25,11 @@ from taskflow import task as flow_task
from watcher.applier.workflow_engine import base from watcher.applier.workflow_engine import base
from watcher.common import exception from watcher.common import exception
from watcher import conf
from watcher import objects from watcher import objects
CONF = conf.CONF
LOG = log.getLogger(__name__) LOG = log.getLogger(__name__)
@@ -127,9 +130,11 @@ class DefaultWorkFlowEngine(base.BaseWorkFlowEngine):
class TaskFlowActionContainer(base.BaseTaskFlowActionContainer): class TaskFlowActionContainer(base.BaseTaskFlowActionContainer):
def __init__(self, db_action, engine): def __init__(self, db_action, engine):
name = "action_type:{0} uuid:{1}".format(db_action.action_type, self.name = "action_type:{0} uuid:{1}".format(db_action.action_type,
db_action.uuid) db_action.uuid)
super(TaskFlowActionContainer, self).__init__(name, db_action, engine) super(TaskFlowActionContainer, self).__init__(self.name,
db_action,
engine)
def do_pre_execute(self): def do_pre_execute(self):
db_action = self.engine.notify(self._db_action, db_action = self.engine.notify(self._db_action,
@@ -158,6 +163,12 @@ class TaskFlowActionContainer(base.BaseTaskFlowActionContainer):
self.action.post_condition() self.action.post_condition()
def do_revert(self, *args, **kwargs): def do_revert(self, *args, **kwargs):
# NOTE: Not rollback action plan
if not CONF.watcher_applier.rollback_when_actionplan_failed:
LOG.info("Failed actionplan rollback option is turned off, and "
"the following action will be skipped: %s", self.name)
return
LOG.warning("Revert action: %s", self.name) LOG.warning("Revert action: %s", self.name)
try: try:
# TODO(jed): do we need to update the states in case of failure? # TODO(jed): do we need to update the states in case of failure?

View File

@@ -18,3 +18,10 @@
import eventlet import eventlet
eventlet.monkey_patch() eventlet.monkey_patch()
# Monkey patch the original current_thread to use the up-to-date _active
# global variable. See https://bugs.launchpad.net/bugs/1863021 and
# https://github.com/eventlet/eventlet/issues/592
import __original_module_threading as orig_threading # noqa
import threading # noqa
orig_threading.current_thread.__globals__['_active'] = threading._active

View File

@@ -14,6 +14,7 @@
import sys import sys
from oslo_upgradecheck import common_checks
from oslo_upgradecheck import upgradecheck from oslo_upgradecheck import upgradecheck
from watcher._i18n import _ from watcher._i18n import _
@@ -43,6 +44,10 @@ class Checks(upgradecheck.UpgradeCommands):
_upgrade_checks = ( _upgrade_checks = (
# Added in Train. # Added in Train.
(_('Minimum Nova API Version'), _minimum_nova_api_version), (_('Minimum Nova API Version'), _minimum_nova_api_version),
# Added in Wallaby.
(_("Policy File JSON to YAML Migration"),
(common_checks.check_policy_json, {'conf': CONF})),
) )

View File

@@ -17,7 +17,7 @@ import time
from oslo_log import log from oslo_log import log
from cinderclient import exceptions as cinder_exception from cinderclient import exceptions as cinder_exception
from cinderclient.v2.volumes import Volume from cinderclient.v3.volumes import Volume
from watcher._i18n import _ from watcher._i18n import _
from watcher.common import clients from watcher.common import clients
from watcher.common import exception from watcher.common import exception

View File

@@ -13,7 +13,6 @@
from oslo_context import context from oslo_context import context
from oslo_log import log from oslo_log import log
from oslo_utils import timeutils from oslo_utils import timeutils
import six
LOG = log.getLogger(__name__) LOG = log.getLogger(__name__)
@@ -69,7 +68,7 @@ class RequestContext(context.RequestContext):
self.project_id = project_id self.project_id = project_id
if not timestamp: if not timestamp:
timestamp = timeutils.utcnow() timestamp = timeutils.utcnow()
if isinstance(timestamp, six.string_types): if isinstance(timestamp, str):
timestamp = timeutils.parse_isotime(timestamp) timestamp = timeutils.parse_isotime(timestamp)
self.timestamp = timestamp self.timestamp = timestamp
self.user_name = user_name self.user_name = user_name

View File

@@ -25,6 +25,7 @@ SHOULD include dedicated exception logging.
import functools import functools
import sys import sys
from http import HTTPStatus
from keystoneclient import exceptions as keystone_exceptions from keystoneclient import exceptions as keystone_exceptions
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log from oslo_log import log
@@ -62,7 +63,7 @@ class WatcherException(Exception):
""" """
msg_fmt = _("An unknown exception occurred") msg_fmt = _("An unknown exception occurred")
code = 500 code = HTTPStatus.INTERNAL_SERVER_ERROR
headers = {} headers = {}
safe = False safe = False
@@ -114,12 +115,12 @@ class UnsupportedError(WatcherException):
class NotAuthorized(WatcherException): class NotAuthorized(WatcherException):
msg_fmt = _("Not authorized") msg_fmt = _("Not authorized")
code = 403 code = HTTPStatus.FORBIDDEN
class NotAcceptable(WatcherException): class NotAcceptable(WatcherException):
msg_fmt = _("Request not acceptable.") msg_fmt = _("Request not acceptable.")
code = 406 code = HTTPStatus.NOT_ACCEPTABLE
class PolicyNotAuthorized(NotAuthorized): class PolicyNotAuthorized(NotAuthorized):
@@ -132,7 +133,7 @@ class OperationNotPermitted(NotAuthorized):
class Invalid(WatcherException, ValueError): class Invalid(WatcherException, ValueError):
msg_fmt = _("Unacceptable parameters") msg_fmt = _("Unacceptable parameters")
code = 400 code = HTTPStatus.BAD_REQUEST
class ObjectNotFound(WatcherException): class ObjectNotFound(WatcherException):
@@ -141,12 +142,12 @@ class ObjectNotFound(WatcherException):
class Conflict(WatcherException): class Conflict(WatcherException):
msg_fmt = _('Conflict') msg_fmt = _('Conflict')
code = 409 code = HTTPStatus.CONFLICT
class ResourceNotFound(ObjectNotFound): class ResourceNotFound(ObjectNotFound):
msg_fmt = _("The %(name)s resource %(id)s could not be found") msg_fmt = _("The %(name)s resource %(id)s could not be found")
code = 404 code = HTTPStatus.NOT_FOUND
class InvalidParameter(Invalid): class InvalidParameter(Invalid):

View File

@@ -14,14 +14,10 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from __future__ import unicode_literals
import abc import abc
import six
@six.add_metaclass(abc.ABCMeta) class BaseLoader(object, metaclass=abc.ABCMeta):
class BaseLoader(object):
@abc.abstractmethod @abc.abstractmethod
def list_available(self): def list_available(self):

View File

@@ -14,8 +14,6 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from __future__ import unicode_literals
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log from oslo_log import log
from stevedore import driver as drivermanager from stevedore import driver as drivermanager

View File

@@ -16,13 +16,10 @@
import abc import abc
import six
from watcher.common import service from watcher.common import service
@six.add_metaclass(abc.ABCMeta) class Loadable(object, metaclass=abc.ABCMeta):
class Loadable(object):
"""Generic interface for dynamically loading a driver/entry point. """Generic interface for dynamically loading a driver/entry point.
This defines the contract in order to let the loader manager inject This defines the contract in order to let the loader manager inject
@@ -48,8 +45,7 @@ LoadableSingletonMeta = type(
"LoadableSingletonMeta", (abc.ABCMeta, service.Singleton), {}) "LoadableSingletonMeta", (abc.ABCMeta, service.Singleton), {})
@six.add_metaclass(LoadableSingletonMeta) class LoadableSingleton(object, metaclass=LoadableSingletonMeta):
class LoadableSingleton(object):
"""Generic interface for dynamically loading a driver as a singleton. """Generic interface for dynamically loading a driver as a singleton.
This defines the contract in order to let the loader manager inject This defines the contract in order to let the loader manager inject

View File

@@ -11,6 +11,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from http import HTTPStatus
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log as logging from oslo_log import log as logging
@@ -53,7 +54,7 @@ class PlacementHelper(object):
if rp_name: if rp_name:
url += '?name=%s' % rp_name url += '?name=%s' % rp_name
resp = self.get(url) resp = self.get(url)
if resp.status_code == 200: if resp.status_code == HTTPStatus.OK:
json_resp = resp.json() json_resp = resp.json()
return json_resp['resource_providers'] return json_resp['resource_providers']
@@ -77,7 +78,7 @@ class PlacementHelper(object):
""" """
url = '/resource_providers/%s/inventories' % rp_uuid url = '/resource_providers/%s/inventories' % rp_uuid
resp = self.get(url) resp = self.get(url)
if resp.status_code == 200: if resp.status_code == HTTPStatus.OK:
json = resp.json() json = resp.json()
return json['inventories'] return json['inventories']
msg = ("Failed to get resource provider %(rp_uuid)s inventories. " msg = ("Failed to get resource provider %(rp_uuid)s inventories. "
@@ -97,7 +98,7 @@ class PlacementHelper(object):
""" """
resp = self.get("/resource_providers/%s/traits" % rp_uuid) resp = self.get("/resource_providers/%s/traits" % rp_uuid)
if resp.status_code == 200: if resp.status_code == HTTPStatus.OK:
json = resp.json() json = resp.json()
return json['traits'] return json['traits']
msg = ("Failed to get resource provider %(rp_uuid)s traits. " msg = ("Failed to get resource provider %(rp_uuid)s traits. "
@@ -118,7 +119,7 @@ class PlacementHelper(object):
""" """
url = '/allocations/%s' % consumer_uuid url = '/allocations/%s' % consumer_uuid
resp = self.get(url) resp = self.get(url)
if resp.status_code == 200: if resp.status_code == HTTPStatus.OK:
json = resp.json() json = resp.json()
return json['allocations'] return json['allocations']
msg = ("Failed to get allocations for consumer %(c_uuid). " msg = ("Failed to get allocations for consumer %(c_uuid). "
@@ -139,7 +140,7 @@ class PlacementHelper(object):
""" """
url = '/resource_providers/%s/usages' % rp_uuid url = '/resource_providers/%s/usages' % rp_uuid
resp = self.get(url) resp = self.get(url)
if resp.status_code == 200: if resp.status_code == HTTPStatus.OK:
json = resp.json() json = resp.json()
return json['usages'] return json['usages']
msg = ("Failed to get resource provider %(rp_uuid)s usages. " msg = ("Failed to get resource provider %(rp_uuid)s usages. "
@@ -164,7 +165,7 @@ class PlacementHelper(object):
""" """
url = "/allocation_candidates?%s" % resources url = "/allocation_candidates?%s" % resources
resp = self.get(url) resp = self.get(url)
if resp.status_code == 200: if resp.status_code == HTTPStatus.OK:
data = resp.json() data = resp.json()
return data['provider_summaries'] return data['provider_summaries']

View File

@@ -18,6 +18,7 @@
import sys import sys
from oslo_config import cfg from oslo_config import cfg
from oslo_policy import opts
from oslo_policy import policy from oslo_policy import policy
from watcher.common import exception from watcher.common import exception
@@ -26,6 +27,12 @@ from watcher.common import policies
_ENFORCER = None _ENFORCER = None
CONF = cfg.CONF CONF = cfg.CONF
# TODO(gmann): Remove setting the default value of config policy_file
# once oslo_policy change the default value to 'policy.yaml'.
# https://github.com/openstack/oslo.policy/blob/a626ad12fe5a3abd49d70e3e5b95589d279ab578/oslo_policy/opts.py#L49
DEFAULT_POLICY_FILE = 'policy.yaml'
opts.set_defaults(CONF, DEFAULT_POLICY_FILE)
# we can get a policy enforcer by this init. # we can get a policy enforcer by this init.
# oslo policy support change policy rule dynamically. # oslo policy support change policy rule dynamically.

View File

@@ -121,22 +121,40 @@ class RequestContextSerializer(messaging.Serializer):
def get_client(target, version_cap=None, serializer=None): def get_client(target, version_cap=None, serializer=None):
assert TRANSPORT is not None assert TRANSPORT is not None
serializer = RequestContextSerializer(serializer) serializer = RequestContextSerializer(serializer)
return messaging.RPCClient(TRANSPORT, return messaging.RPCClient(
target, TRANSPORT,
version_cap=version_cap, target,
serializer=serializer) version_cap=version_cap,
serializer=serializer
)
def get_server(target, endpoints, serializer=None): def get_server(target, endpoints, serializer=None):
assert TRANSPORT is not None assert TRANSPORT is not None
access_policy = dispatcher.DefaultRPCAccessPolicy access_policy = dispatcher.DefaultRPCAccessPolicy
serializer = RequestContextSerializer(serializer) serializer = RequestContextSerializer(serializer)
return messaging.get_rpc_server(TRANSPORT, return messaging.get_rpc_server(
target, TRANSPORT,
endpoints, target,
executor='eventlet', endpoints,
serializer=serializer, executor='eventlet',
access_policy=access_policy) serializer=serializer,
access_policy=access_policy
)
def get_notification_listener(targets, endpoints, serializer=None, pool=None):
assert NOTIFICATION_TRANSPORT is not None
serializer = RequestContextSerializer(serializer)
return messaging.get_notification_listener(
NOTIFICATION_TRANSPORT,
targets,
endpoints,
allow_requeue=False,
executor='eventlet',
pool=pool,
serializer=serializer
)
def get_notifier(publisher_id): def get_notifier(publisher_id):

View File

@@ -21,14 +21,12 @@ from oslo_concurrency import processutils
from oslo_config import cfg from oslo_config import cfg
from oslo_log import _options from oslo_log import _options
from oslo_log import log from oslo_log import log
import oslo_messaging as om import oslo_messaging as messaging
from oslo_reports import guru_meditation_report as gmr from oslo_reports import guru_meditation_report as gmr
from oslo_reports import opts as gmr_opts from oslo_reports import opts as gmr_opts
from oslo_service import service from oslo_service import service
from oslo_service import wsgi from oslo_service import wsgi
from oslo_messaging.rpc import dispatcher
from watcher._i18n import _ from watcher._i18n import _
from watcher.api import app from watcher.api import app
from watcher.common import config from watcher.common import config
@@ -183,11 +181,6 @@ class Service(service.ServiceBase):
] ]
self.notification_endpoints = self.manager.notification_endpoints self.notification_endpoints = self.manager.notification_endpoints
self.serializer = rpc.RequestContextSerializer(
base.WatcherObjectSerializer())
self._transport = None
self._notification_transport = None
self._conductor_client = None self._conductor_client = None
self.conductor_topic_handler = None self.conductor_topic_handler = None
@@ -201,27 +194,17 @@ class Service(service.ServiceBase):
self.notification_topics, self.notification_endpoints self.notification_topics, self.notification_endpoints
) )
@property
def transport(self):
if self._transport is None:
self._transport = om.get_rpc_transport(CONF)
return self._transport
@property
def notification_transport(self):
if self._notification_transport is None:
self._notification_transport = om.get_notification_transport(CONF)
return self._notification_transport
@property @property
def conductor_client(self): def conductor_client(self):
if self._conductor_client is None: if self._conductor_client is None:
target = om.Target( target = messaging.Target(
topic=self.conductor_topic, topic=self.conductor_topic,
version=self.API_VERSION, version=self.API_VERSION,
) )
self._conductor_client = om.RPCClient( self._conductor_client = rpc.get_client(
self.transport, target, serializer=self.serializer) target,
serializer=base.WatcherObjectSerializer()
)
return self._conductor_client return self._conductor_client
@conductor_client.setter @conductor_client.setter
@@ -229,21 +212,18 @@ class Service(service.ServiceBase):
self.conductor_client = c self.conductor_client = c
def build_topic_handler(self, topic_name, endpoints=()): def build_topic_handler(self, topic_name, endpoints=()):
access_policy = dispatcher.DefaultRPCAccessPolicy target = messaging.Target(
serializer = rpc.RequestContextSerializer(rpc.JsonPayloadSerializer())
target = om.Target(
topic=topic_name, topic=topic_name,
# For compatibility, we can override it with 'host' opt # For compatibility, we can override it with 'host' opt
server=CONF.host or socket.gethostname(), server=CONF.host or socket.gethostname(),
version=self.api_version, version=self.api_version,
) )
return om.get_rpc_server( return rpc.get_server(
self.transport, target, endpoints, target, endpoints,
executor='eventlet', serializer=serializer, serializer=rpc.JsonPayloadSerializer()
access_policy=access_policy) )
def build_notification_handler(self, topic_names, endpoints=()): def build_notification_handler(self, topic_names, endpoints=()):
serializer = rpc.RequestContextSerializer(rpc.JsonPayloadSerializer())
targets = [] targets = []
for topic in topic_names: for topic in topic_names:
kwargs = {} kwargs = {}
@@ -251,11 +231,13 @@ class Service(service.ServiceBase):
exchange, topic = topic.split('.') exchange, topic = topic.split('.')
kwargs['exchange'] = exchange kwargs['exchange'] = exchange
kwargs['topic'] = topic kwargs['topic'] = topic
targets.append(om.Target(**kwargs)) targets.append(messaging.Target(**kwargs))
return om.get_notification_listener(
self.notification_transport, targets, endpoints, return rpc.get_notification_listener(
executor='eventlet', serializer=serializer, targets, endpoints,
allow_requeue=False, pool=CONF.host) serializer=rpc.JsonPayloadSerializer(),
pool=CONF.host
)
def start(self): def start(self):
LOG.debug("Connecting to '%s'", CONF.transport_url) LOG.debug("Connecting to '%s'", CONF.transport_url)

View File

@@ -15,11 +15,9 @@
# under the License. # under the License.
import abc import abc
import six
@six.add_metaclass(abc.ABCMeta) class ServiceManager(object, metaclass=abc.ABCMeta):
class ServiceManager(object):
@abc.abstractproperty @abc.abstractproperty
def service_name(self): def service_name(self):

View File

@@ -28,7 +28,6 @@ from oslo_config import cfg
from oslo_log import log from oslo_log import log
from oslo_utils import strutils from oslo_utils import strutils
from oslo_utils import uuidutils from oslo_utils import uuidutils
import six
from watcher.common import exception from watcher.common import exception
@@ -82,7 +81,7 @@ def safe_rstrip(value, chars=None):
:return: Stripped value. :return: Stripped value.
""" """
if not isinstance(value, six.string_types): if not isinstance(value, str):
LOG.warning( LOG.warning(
"Failed to remove trailing character. Returning original object." "Failed to remove trailing character. Returning original object."
"Supplied object is not a string: %s,", value) "Supplied object is not a string: %s,", value)
@@ -104,7 +103,7 @@ def is_hostname_safe(hostname):
""" """
m = r'^[a-z0-9]([a-z0-9\-]{0,61}[a-z0-9])?$' m = r'^[a-z0-9]([a-z0-9\-]{0,61}[a-z0-9])?$'
return (isinstance(hostname, six.string_types) and return (isinstance(hostname, str) and
(re.match(m, hostname) is not None)) (re.match(m, hostname) is not None))

View File

@@ -43,11 +43,20 @@ APPLIER_MANAGER_OPTS = [
help='Select the engine to use to execute the workflow'), help='Select the engine to use to execute the workflow'),
] ]
APPLIER_OPTS = [
cfg.BoolOpt('rollback_when_actionplan_failed',
default=False,
help='If set True, the failed actionplan will rollback '
'when executing. Defaule value is False.'),
]
def register_opts(conf): def register_opts(conf):
conf.register_group(watcher_applier) conf.register_group(watcher_applier)
conf.register_opts(APPLIER_MANAGER_OPTS, group=watcher_applier) conf.register_opts(APPLIER_MANAGER_OPTS, group=watcher_applier)
conf.register_opts(APPLIER_OPTS, group=watcher_applier)
def list_opts(): def list_opts():
return [(watcher_applier, APPLIER_MANAGER_OPTS)] return [(watcher_applier, APPLIER_MANAGER_OPTS),
(watcher_applier, APPLIER_OPTS)]

View File

@@ -18,7 +18,6 @@ Base classes for storage engines
import abc import abc
from oslo_config import cfg from oslo_config import cfg
from oslo_db import api as db_api from oslo_db import api as db_api
import six
_BACKEND_MAPPING = {'sqlalchemy': 'watcher.db.sqlalchemy.api'} _BACKEND_MAPPING = {'sqlalchemy': 'watcher.db.sqlalchemy.api'}
IMPL = db_api.DBAPI.from_config(cfg.CONF, backend_mapping=_BACKEND_MAPPING, IMPL = db_api.DBAPI.from_config(cfg.CONF, backend_mapping=_BACKEND_MAPPING,
@@ -30,8 +29,7 @@ def get_instance():
return IMPL return IMPL
@six.add_metaclass(abc.ABCMeta) class BaseConnection(object, metaclass=abc.ABCMeta):
class BaseConnection(object):
"""Base class for storage system connections.""" """Base class for storage system connections."""
@abc.abstractmethod @abc.abstractmethod

View File

@@ -15,8 +15,6 @@
# limitations under the License. # limitations under the License.
# #
from __future__ import print_function
import collections import collections
import datetime import datetime
import itertools import itertools
@@ -25,7 +23,6 @@ import sys
from oslo_log import log from oslo_log import log
from oslo_utils import strutils from oslo_utils import strutils
import prettytable as ptable import prettytable as ptable
from six.moves import input
from watcher._i18n import _ from watcher._i18n import _
from watcher._i18n import lazy_translation_enabled from watcher._i18n import lazy_translation_enabled

View File

@@ -6,6 +6,7 @@ Create Date: 2017-03-24 11:21:29.036532
""" """
from alembic import op from alembic import op
from sqlalchemy import inspect
import sqlalchemy as sa import sqlalchemy as sa
from watcher.db.sqlalchemy import models from watcher.db.sqlalchemy import models
@@ -14,8 +15,17 @@ from watcher.db.sqlalchemy import models
revision = '0f6042416884' revision = '0f6042416884'
down_revision = '001' down_revision = '001'
def _table_exists(table_name):
bind = op.get_context().bind
insp = inspect(bind)
names = insp.get_table_names()
return any(t == table_name for t in names)
def upgrade(): def upgrade():
if _table_exists('apscheduler_jobs'):
return
op.create_table( op.create_table(
'apscheduler_jobs', 'apscheduler_jobs',
sa.Column('id', sa.Unicode(191, _warn_on_bytestring=False), sa.Column('id', sa.Unicode(191, _warn_on_bytestring=False),

View File

@@ -44,7 +44,11 @@ _FACADE = None
def _create_facade_lazily(): def _create_facade_lazily():
global _FACADE global _FACADE
if _FACADE is None: if _FACADE is None:
_FACADE = db_session.EngineFacade.from_config(CONF) # FIXME(amoralej): Remove autocommit=True (and ideally use of
# LegacyEngineFacade) asap since it's not compatible with SQLAlchemy
# 2.0.
_FACADE = db_session.EngineFacade.from_config(CONF,
autocommit=True)
return _FACADE return _FACADE
@@ -278,7 +282,7 @@ class Connection(api.BaseConnection):
query = model_query(model, session=session) query = model_query(model, session=session)
query = add_identity_filter(query, id_) query = add_identity_filter(query, id_)
try: try:
ref = query.with_lockmode('update').one() ref = query.with_for_update().one()
except exc.NoResultFound: except exc.NoResultFound:
raise exception.ResourceNotFound(name=model.__name__, id=id_) raise exception.ResourceNotFound(name=model.__name__, id=id_)
@@ -815,7 +819,7 @@ class Connection(api.BaseConnection):
query = model_query(models.Action, session=session) query = model_query(models.Action, session=session)
query = add_identity_filter(query, action_id) query = add_identity_filter(query, action_id)
try: try:
ref = query.with_lockmode('update').one() ref = query.with_for_update().one()
except exc.NoResultFound: except exc.NoResultFound:
raise exception.ActionNotFound(action=action_id) raise exception.ActionNotFound(action=action_id)
@@ -900,7 +904,7 @@ class Connection(api.BaseConnection):
query = model_query(models.ActionPlan, session=session) query = model_query(models.ActionPlan, session=session)
query = add_identity_filter(query, action_plan_id) query = add_identity_filter(query, action_plan_id)
try: try:
ref = query.with_lockmode('update').one() ref = query.with_for_update().one()
except exc.NoResultFound: except exc.NoResultFound:
raise exception.ActionPlanNotFound(action_plan=action_plan_id) raise exception.ActionPlanNotFound(action_plan=action_plan_id)

View File

@@ -18,7 +18,6 @@ SQLAlchemy models for watcher service
from oslo_db.sqlalchemy import models from oslo_db.sqlalchemy import models
from oslo_serialization import jsonutils from oslo_serialization import jsonutils
import six.moves.urllib.parse as urlparse
from sqlalchemy import Boolean from sqlalchemy import Boolean
from sqlalchemy import Column from sqlalchemy import Column
from sqlalchemy import DateTime from sqlalchemy import DateTime
@@ -33,7 +32,7 @@ from sqlalchemy import String
from sqlalchemy import Text from sqlalchemy import Text
from sqlalchemy.types import TypeDecorator, TEXT from sqlalchemy.types import TypeDecorator, TEXT
from sqlalchemy import UniqueConstraint from sqlalchemy import UniqueConstraint
import urllib.parse as urlparse
from watcher import conf from watcher import conf
CONF = conf.CONF CONF = conf.CONF

View File

@@ -18,7 +18,6 @@
# limitations under the License. # limitations under the License.
# #
import abc import abc
import six
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log from oslo_log import log
@@ -36,9 +35,11 @@ CONF = cfg.CONF
LOG = log.getLogger(__name__) LOG = log.getLogger(__name__)
@six.add_metaclass(abc.ABCMeta) class BaseMetaClass(service.Singleton, abc.ABCMeta):
@six.add_metaclass(service.Singleton) pass
class BaseAuditHandler(object):
class BaseAuditHandler(object, metaclass=BaseMetaClass):
@abc.abstractmethod @abc.abstractmethod
def execute(self, audit, request_context): def execute(self, audit, request_context):
@@ -57,8 +58,7 @@ class BaseAuditHandler(object):
raise NotImplementedError() raise NotImplementedError()
@six.add_metaclass(abc.ABCMeta) class AuditHandler(BaseAuditHandler, metaclass=abc.ABCMeta):
class AuditHandler(BaseAuditHandler):
def __init__(self): def __init__(self):
super(AuditHandler, self).__init__() super(AuditHandler, self).__init__()

View File

@@ -19,6 +19,8 @@ import time
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log from oslo_log import log
from watcher.common import exception
CONF = cfg.CONF CONF = cfg.CONF
LOG = log.getLogger(__name__) LOG = log.getLogger(__name__)
@@ -54,6 +56,13 @@ class DataSourceBase(object):
instance_root_disk_size=None, instance_root_disk_size=None,
) )
def _get_meter(self, meter_name):
"""Retrieve the meter from the metric map or raise error"""
meter = self.METRIC_MAP.get(meter_name)
if meter is None:
raise exception.MetricNotAvailable(metric=meter_name)
return meter
def query_retry(self, f, *args, **kwargs): def query_retry(self, f, *args, **kwargs):
"""Attempts to retrieve metrics from the external service """Attempts to retrieve metrics from the external service
@@ -122,6 +131,30 @@ class DataSourceBase(object):
pass pass
@abc.abstractmethod
def statistic_series(self, resource=None, resource_type=None,
meter_name=None, start_time=None, end_time=None,
granularity=300):
"""Retrieves metrics based on the specified parameters over a period
:param resource: Resource object as defined in watcher models such as
ComputeNode and Instance
:param resource_type: Indicates which type of object is supplied
to the resource parameter
:param meter_name: The desired metric to retrieve as key from
METRIC_MAP
:param start_time: The datetime to start retrieving metrics for
:type start_time: datetime.datetime
:param end_time: The datetime to limit the retrieval of metrics to
:type end_time: datetime.datetime
:param granularity: Interval between samples in measurements in
seconds
:return: Dictionary of key value pairs with timestamps and metric
values
"""
pass
@abc.abstractmethod @abc.abstractmethod
def get_host_cpu_usage(self, resource, period, aggregate, def get_host_cpu_usage(self, resource, period, aggregate,
granularity=None): granularity=None):

View File

@@ -161,9 +161,7 @@ class CeilometerHelper(base.DataSourceBase):
end_time = datetime.datetime.utcnow() end_time = datetime.datetime.utcnow()
start_time = end_time - datetime.timedelta(seconds=int(period)) start_time = end_time - datetime.timedelta(seconds=int(period))
meter = self.METRIC_MAP.get(meter_name) meter = self._get_meter(meter_name)
if meter is None:
raise exception.MetricNotAvailable(metric=meter_name)
if aggregate == 'mean': if aggregate == 'mean':
aggregate = 'avg' aggregate = 'avg'
@@ -194,6 +192,12 @@ class CeilometerHelper(base.DataSourceBase):
item_value *= 10 item_value *= 10
return item_value return item_value
def statistic_series(self, resource=None, resource_type=None,
meter_name=None, start_time=None, end_time=None,
granularity=300):
raise NotImplementedError(
_('Ceilometer helper does not support statistic series method'))
def get_host_cpu_usage(self, resource, period, def get_host_cpu_usage(self, resource, period,
aggregate, granularity=None): aggregate, granularity=None):

View File

@@ -23,7 +23,6 @@ from oslo_config import cfg
from oslo_log import log from oslo_log import log
from watcher.common import clients from watcher.common import clients
from watcher.common import exception
from watcher.decision_engine.datasources import base from watcher.decision_engine.datasources import base
CONF = cfg.CONF CONF = cfg.CONF
@@ -72,9 +71,7 @@ class GnocchiHelper(base.DataSourceBase):
stop_time = datetime.utcnow() stop_time = datetime.utcnow()
start_time = stop_time - timedelta(seconds=(int(period))) start_time = stop_time - timedelta(seconds=(int(period)))
meter = self.METRIC_MAP.get(meter_name) meter = self._get_meter(meter_name)
if meter is None:
raise exception.MetricNotAvailable(metric=meter_name)
if aggregate == 'count': if aggregate == 'count':
aggregate = 'mean' aggregate = 'mean'
@@ -123,6 +120,52 @@ class GnocchiHelper(base.DataSourceBase):
return return_value return return_value
def statistic_series(self, resource=None, resource_type=None,
meter_name=None, start_time=None, end_time=None,
granularity=300):
meter = self._get_meter(meter_name)
resource_id = resource.uuid
if resource_type == 'compute_node':
resource_id = "%s_%s" % (resource.hostname, resource.hostname)
kwargs = dict(query={"=": {"original_resource_id": resource_id}},
limit=1)
resources = self.query_retry(
f=self.gnocchi.resource.search, **kwargs)
if not resources:
LOG.warning("The {0} resource {1} could not be "
"found".format(self.NAME, resource_id))
return
resource_id = resources[0]['id']
raw_kwargs = dict(
metric=meter,
start=start_time,
stop=end_time,
resource_id=resource_id,
granularity=granularity,
)
kwargs = {k: v for k, v in raw_kwargs.items() if k and v}
statistics = self.query_retry(
f=self.gnocchi.metric.get_measures, **kwargs)
return_value = None
if statistics:
# measure has structure [time, granularity, value]
if meter_name == 'host_airflow':
# Airflow from hardware.ipmi.node.airflow is reported as
# 1/10 th of actual CFM
return_value = {s[0]: s[2]*10 for s in statistics}
else:
return_value = {s[0]: s[2] for s in statistics}
return return_value
def get_host_cpu_usage(self, resource, period, aggregate, def get_host_cpu_usage(self, resource, period, aggregate,
granularity=300): granularity=300):

View File

@@ -16,10 +16,13 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from urllib import parse as urlparse
from http import HTTPStatus
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log from oslo_log import log
import six.moves.urllib.parse as urlparse
from watcher._i18n import _
from watcher.common import clients from watcher.common import clients
from watcher.common import exception from watcher.common import exception
from watcher.decision_engine.datasources import base from watcher.decision_engine.datasources import base
@@ -136,11 +139,11 @@ class GrafanaHelper(base.DataSourceBase):
resp = requests.get(self._base_url + str(project_id) + '/query', resp = requests.get(self._base_url + str(project_id) + '/query',
params=params, headers=self._headers) params=params, headers=self._headers)
if resp.status_code == 200: if resp.status_code == HTTPStatus.OK:
return resp return resp
elif resp.status_code == 400: elif resp.status_code == HTTPStatus.BAD_REQUEST:
LOG.error("Query for metric is invalid") LOG.error("Query for metric is invalid")
elif resp.status_code == 401: elif resp.status_code == HTTPStatus.UNAUTHORIZED:
LOG.error("Authorization token is invalid") LOG.error("Authorization token is invalid")
raise exception.DataSourceNotAvailable(self.NAME) raise exception.DataSourceNotAvailable(self.NAME)
@@ -187,6 +190,12 @@ class GrafanaHelper(base.DataSourceBase):
return result return result
def statistic_series(self, resource=None, resource_type=None,
meter_name=None, start_time=None, end_time=None,
granularity=300):
raise NotImplementedError(
_('Grafana helper does not support statistic series method'))
def get_host_cpu_usage(self, resource, period=300, def get_host_cpu_usage(self, resource, period=300,
aggregate="mean", granularity=None): aggregate="mean", granularity=None):
return self.statistic_aggregation( return self.statistic_aggregation(

View File

@@ -21,7 +21,6 @@ import datetime
from monascaclient import exc from monascaclient import exc
from watcher.common import clients from watcher.common import clients
from watcher.common import exception
from watcher.decision_engine.datasources import base from watcher.decision_engine.datasources import base
@@ -90,9 +89,7 @@ class MonascaHelper(base.DataSourceBase):
stop_time = datetime.datetime.utcnow() stop_time = datetime.datetime.utcnow()
start_time = stop_time - datetime.timedelta(seconds=(int(period))) start_time = stop_time - datetime.timedelta(seconds=(int(period)))
meter = self.METRIC_MAP.get(meter_name) meter = self._get_meter(meter_name)
if meter is None:
raise exception.MetricNotAvailable(metric=meter_name)
if aggregate == 'mean': if aggregate == 'mean':
aggregate = 'avg' aggregate = 'avg'
@@ -121,6 +118,34 @@ class MonascaHelper(base.DataSourceBase):
return cpu_usage return cpu_usage
def statistic_series(self, resource=None, resource_type=None,
meter_name=None, start_time=None, end_time=None,
granularity=300):
meter = self._get_meter(meter_name)
raw_kwargs = dict(
name=meter,
start_time=start_time.isoformat(),
end_time=end_time.isoformat(),
dimensions={'hostname': resource.uuid},
statistics='avg',
group_by='*',
)
kwargs = {k: v for k, v in raw_kwargs.items() if k and v}
statistics = self.query_retry(
f=self.monasca.metrics.list_statistics, **kwargs)
result = {}
for stat in statistics:
v_index = stat['columns'].index('avg')
t_index = stat['columns'].index('timestamp')
result.update({r[t_index]: r[v_index] for r in stat['statistics']})
return result
def get_host_cpu_usage(self, resource, period, def get_host_cpu_usage(self, resource, period,
aggregate, granularity=None): aggregate, granularity=None):
return self.statistic_aggregation( return self.statistic_aggregation(

View File

@@ -15,13 +15,11 @@
# limitations under the License. # limitations under the License.
import abc import abc
import six
from watcher.common.loader import loadable from watcher.common.loader import loadable
@six.add_metaclass(abc.ABCMeta) class Goal(loadable.Loadable, metaclass=abc.ABCMeta):
class Goal(loadable.Loadable):
def __init__(self, config): def __init__(self, config):
super(Goal, self).__init__(config) super(Goal, self).__init__(config)

View File

@@ -27,11 +27,8 @@ import abc
import jsonschema import jsonschema
from oslo_serialization import jsonutils from oslo_serialization import jsonutils
import six
class EfficacySpecification(object, metaclass=abc.ABCMeta):
@six.add_metaclass(abc.ABCMeta)
class EfficacySpecification(object):
def __init__(self): def __init__(self):
self._indicators_specs = self.get_indicators_specifications() self._indicators_specs = self.get_indicators_specifications()

View File

@@ -18,7 +18,6 @@ import abc
import jsonschema import jsonschema
from jsonschema import SchemaError from jsonschema import SchemaError
from jsonschema import ValidationError from jsonschema import ValidationError
import six
from oslo_log import log from oslo_log import log
from oslo_serialization import jsonutils from oslo_serialization import jsonutils
@@ -29,8 +28,7 @@ from watcher.common import exception
LOG = log.getLogger(__name__) LOG = log.getLogger(__name__)
@six.add_metaclass(abc.ABCMeta) class IndicatorSpecification(object, metaclass=abc.ABCMeta):
class IndicatorSpecification(object):
def __init__(self, name=None, description=None, unit=None, required=True): def __init__(self, name=None, description=None, unit=None, required=True):
self.name = name self.name = name

View File

@@ -19,9 +19,6 @@
# limitations under the License. # limitations under the License.
# #
from __future__ import unicode_literals
from watcher.common.loader import default from watcher.common.loader import default

View File

@@ -25,11 +25,9 @@ See: :doc:`../architecture` for more details on this component.
""" """
import abc import abc
import six
@six.add_metaclass(abc.ABCMeta) class Model(object, metaclass=abc.ABCMeta):
class Model(object):
@abc.abstractmethod @abc.abstractmethod
def to_string(self): def to_string(self):

View File

@@ -110,7 +110,6 @@ import time
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log from oslo_log import log
import six
from watcher.common import clients from watcher.common import clients
from watcher.common.loader import loadable from watcher.common.loader import loadable
@@ -120,8 +119,8 @@ LOG = log.getLogger(__name__)
CONF = cfg.CONF CONF = cfg.CONF
@six.add_metaclass(abc.ABCMeta) class BaseClusterDataModelCollector(loadable.LoadableSingleton,
class BaseClusterDataModelCollector(loadable.LoadableSingleton): metaclass=abc.ABCMeta):
STALE_MODEL = model_root.ModelRoot(stale=True) STALE_MODEL = model_root.ModelRoot(stale=True)

View File

@@ -13,8 +13,6 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import six
from oslo_log import log from oslo_log import log
from watcher.common import cinder_helper from watcher.common import cinder_helper
@@ -152,6 +150,9 @@ class CinderClusterDataModelCollector(base.BaseClusterDataModelCollector):
if self._audit_scope_handler is None: if self._audit_scope_handler is None:
LOG.debug("No audit, Don't Build storage data model") LOG.debug("No audit, Don't Build storage data model")
return return
if self._data_model_scope is None:
LOG.debug("No audit scope, Don't Build storage data model")
return
builder = CinderModelBuilder(self.osc) builder = CinderModelBuilder(self.osc)
return builder.execute(self._data_model_scope) return builder.execute(self._data_model_scope)
@@ -204,7 +205,7 @@ class CinderModelBuilder(base.BaseModelBuilder):
"""Build a storage node from a Cinder storage node """Build a storage node from a Cinder storage node
:param node: A storage node :param node: A storage node
:type node: :py:class:`~cinderclient.v2.services.Service` :type node: :py:class:`~cinderclient.v3.services.Service`
""" """
# node.host is formatted as host@backendname since ocata, # node.host is formatted as host@backendname since ocata,
# or may be only host as of ocata # or may be only host as of ocata
@@ -232,7 +233,7 @@ class CinderModelBuilder(base.BaseModelBuilder):
"""Build a storage pool from a Cinder storage pool """Build a storage pool from a Cinder storage pool
:param pool: A storage pool :param pool: A storage pool
:type pool: :py:class:`~cinderclient.v2.pools.Pool` :type pool: :py:class:`~cinderclient.v3.pools.Pool`
:raises: exception.InvalidPoolAttributeValue :raises: exception.InvalidPoolAttributeValue
""" """
# build up the storage pool. # build up the storage pool.
@@ -286,7 +287,7 @@ class CinderModelBuilder(base.BaseModelBuilder):
:param instance: Cinder Volume object. :param instance: Cinder Volume object.
:return: A volume node for the graph. :return: A volume node for the graph.
""" """
attachments = [{k: v for k, v in six.iteritems(d) if k in ( attachments = [{k: v for k, v in iter(d.items()) if k in (
'server_id', 'attachment_id')} for d in volume.attachments] 'server_id', 'attachment_id')} for d in volume.attachments]
volume_attributes = { volume_attributes = {

View File

@@ -63,6 +63,9 @@ class BaremetalClusterDataModelCollector(base.BaseClusterDataModelCollector):
if self._audit_scope_handler is None: if self._audit_scope_handler is None:
LOG.debug("No audit, Don't Build Baremetal data model") LOG.debug("No audit, Don't Build Baremetal data model")
return return
if self._data_model_scope is None:
LOG.debug("No audit scope, Don't Build Baremetal data model")
return
builder = BareMetalModelBuilder(self.osc) builder = BareMetalModelBuilder(self.osc)
return builder.execute(self._data_model_scope) return builder.execute(self._data_model_scope)

View File

@@ -184,6 +184,9 @@ class NovaClusterDataModelCollector(base.BaseClusterDataModelCollector):
if self._audit_scope_handler is None: if self._audit_scope_handler is None:
LOG.debug("No audit, Don't Build compute data model") LOG.debug("No audit, Don't Build compute data model")
return return
if self._data_model_scope is None:
LOG.debug("No audit scope, Don't Build compute data model")
return
builder = NovaModelBuilder(self.osc) builder = NovaModelBuilder(self.osc)
return builder.execute(self._data_model_scope) return builder.execute(self._data_model_scope)

View File

@@ -16,14 +16,12 @@
import abc import abc
import six
from watcher.decision_engine.model.element import base from watcher.decision_engine.model.element import base
from watcher.objects import fields as wfields from watcher.objects import fields as wfields
@six.add_metaclass(abc.ABCMeta) class BaremetalResource(base.Element, metaclass=abc.ABCMeta):
class BaremetalResource(base.Element):
VERSION = '1.0' VERSION = '1.0'

View File

@@ -21,7 +21,6 @@ import collections
from lxml import etree from lxml import etree
from oslo_log import log from oslo_log import log
import six
from watcher.objects import base from watcher.objects import base
from watcher.objects import fields as wfields from watcher.objects import fields as wfields
@@ -29,9 +28,8 @@ from watcher.objects import fields as wfields
LOG = log.getLogger(__name__) LOG = log.getLogger(__name__)
@six.add_metaclass(abc.ABCMeta)
class Element(base.WatcherObject, base.WatcherObjectDictCompat, class Element(base.WatcherObject, base.WatcherObjectDictCompat,
base.WatcherComparableObject): base.WatcherComparableObject, metaclass=abc.ABCMeta):
# Initial version # Initial version
VERSION = '1.0' VERSION = '1.0'

View File

@@ -16,14 +16,12 @@
import abc import abc
import six
from watcher.decision_engine.model.element import base from watcher.decision_engine.model.element import base
from watcher.objects import fields as wfields from watcher.objects import fields as wfields
@six.add_metaclass(abc.ABCMeta) class ComputeResource(base.Element, metaclass=abc.ABCMeta):
class ComputeResource(base.Element):
VERSION = '1.0' VERSION = '1.0'

View File

@@ -16,14 +16,12 @@
import abc import abc
import six
from watcher.decision_engine.model.element import base from watcher.decision_engine.model.element import base
from watcher.objects import fields as wfields from watcher.objects import fields as wfields
@six.add_metaclass(abc.ABCMeta) class StorageResource(base.Element, metaclass=abc.ABCMeta):
class StorageResource(base.Element):
VERSION = '1.0' VERSION = '1.0'

View File

@@ -21,7 +21,6 @@ from lxml import etree
import networkx as nx import networkx as nx
from oslo_concurrency import lockutils from oslo_concurrency import lockutils
from oslo_log import log from oslo_log import log
import six
from watcher._i18n import _ from watcher._i18n import _
from watcher.common import exception from watcher.common import exception
@@ -93,9 +92,9 @@ class ModelRoot(nx.DiGraph, base.Model):
:param node: :py:class:`~.node.ComputeNode` object or node UUID :param node: :py:class:`~.node.ComputeNode` object or node UUID
:type node: str or :py:class:`~.instance.Instance` :type node: str or :py:class:`~.instance.Instance`
""" """
if isinstance(instance, six.string_types): if isinstance(instance, str):
instance = self.get_instance_by_uuid(instance) instance = self.get_instance_by_uuid(instance)
if isinstance(node, six.string_types): if isinstance(node, str):
node = self.get_node_by_uuid(node) node = self.get_node_by_uuid(node)
self.assert_node(node) self.assert_node(node)
self.assert_instance(instance) self.assert_instance(instance)
@@ -104,9 +103,9 @@ class ModelRoot(nx.DiGraph, base.Model):
@lockutils.synchronized("model_root") @lockutils.synchronized("model_root")
def unmap_instance(self, instance, node): def unmap_instance(self, instance, node):
if isinstance(instance, six.string_types): if isinstance(instance, str):
instance = self.get_instance_by_uuid(instance) instance = self.get_instance_by_uuid(instance)
if isinstance(node, six.string_types): if isinstance(node, str):
node = self.get_node_by_uuid(node) node = self.get_node_by_uuid(node)
self.remove_edge(instance.uuid, node.uuid) self.remove_edge(instance.uuid, node.uuid)
@@ -367,9 +366,9 @@ class StorageModelRoot(nx.DiGraph, base.Model):
:param pool: :py:class:`~.node.Pool` object or pool name :param pool: :py:class:`~.node.Pool` object or pool name
:param node: :py:class:`~.node.StorageNode` object or node host :param node: :py:class:`~.node.StorageNode` object or node host
""" """
if isinstance(pool, six.string_types): if isinstance(pool, str):
pool = self.get_pool_by_pool_name(pool) pool = self.get_pool_by_pool_name(pool)
if isinstance(node, six.string_types): if isinstance(node, str):
node = self.get_node_by_name(node) node = self.get_node_by_name(node)
self.assert_node(node) self.assert_node(node)
self.assert_pool(pool) self.assert_pool(pool)
@@ -383,9 +382,9 @@ class StorageModelRoot(nx.DiGraph, base.Model):
:param pool: :py:class:`~.node.Pool` object or pool name :param pool: :py:class:`~.node.Pool` object or pool name
:param node: :py:class:`~.node.StorageNode` object or node name :param node: :py:class:`~.node.StorageNode` object or node name
""" """
if isinstance(pool, six.string_types): if isinstance(pool, str):
pool = self.get_pool_by_pool_name(pool) pool = self.get_pool_by_pool_name(pool)
if isinstance(node, six.string_types): if isinstance(node, str):
node = self.get_node_by_name(node) node = self.get_node_by_name(node)
self.remove_edge(pool.name, node.host) self.remove_edge(pool.name, node.host)
@@ -411,9 +410,9 @@ class StorageModelRoot(nx.DiGraph, base.Model):
:param volume: :py:class:`~.volume.Volume` object or volume UUID :param volume: :py:class:`~.volume.Volume` object or volume UUID
:param pool: :py:class:`~.node.Pool` object or pool name :param pool: :py:class:`~.node.Pool` object or pool name
""" """
if isinstance(volume, six.string_types): if isinstance(volume, str):
volume = self.get_volume_by_uuid(volume) volume = self.get_volume_by_uuid(volume)
if isinstance(pool, six.string_types): if isinstance(pool, str):
pool = self.get_pool_by_pool_name(pool) pool = self.get_pool_by_pool_name(pool)
self.assert_pool(pool) self.assert_pool(pool)
self.assert_volume(volume) self.assert_volume(volume)
@@ -427,9 +426,9 @@ class StorageModelRoot(nx.DiGraph, base.Model):
:param volume: :py:class:`~.volume.Volume` object or volume UUID :param volume: :py:class:`~.volume.Volume` object or volume UUID
:param pool: :py:class:`~.node.Pool` object or pool name :param pool: :py:class:`~.node.Pool` object or pool name
""" """
if isinstance(volume, six.string_types): if isinstance(volume, str):
volume = self.get_volume_by_uuid(volume) volume = self.get_volume_by_uuid(volume)
if isinstance(pool, six.string_types): if isinstance(pool, str):
pool = self.get_pool_by_pool_name(pool) pool = self.get_pool_by_pool_name(pool)
self.remove_edge(volume.uuid, pool.name) self.remove_edge(volume.uuid, pool.name)
@@ -632,7 +631,7 @@ class BaremetalModelRoot(nx.DiGraph, base.Model):
super(BaremetalModelRoot, self).remove_node(node.uuid) super(BaremetalModelRoot, self).remove_node(node.uuid)
except nx.NetworkXError as exc: except nx.NetworkXError as exc:
LOG.exception(exc) LOG.exception(exc)
raise exception.IronicNodeNotFound(name=node.uuid) raise exception.IronicNodeNotFound(uuid=node.uuid)
@lockutils.synchronized("baremetal_model") @lockutils.synchronized("baremetal_model")
def get_all_ironic_nodes(self): def get_all_ironic_nodes(self):
@@ -644,7 +643,7 @@ class BaremetalModelRoot(nx.DiGraph, base.Model):
try: try:
return self._get_by_uuid(uuid) return self._get_by_uuid(uuid)
except exception.BaremetalResourceNotFound: except exception.BaremetalResourceNotFound:
raise exception.IronicNodeNotFound(name=uuid) raise exception.IronicNodeNotFound(uuid=uuid)
def _get_by_uuid(self, uuid): def _get_by_uuid(self, uuid):
try: try:

View File

@@ -17,11 +17,9 @@
# limitations under the License. # limitations under the License.
import abc import abc
import six
@six.add_metaclass(abc.ABCMeta) class NotificationEndpoint(object, metaclass=abc.ABCMeta):
class NotificationEndpoint(object):
def __init__(self, collector): def __init__(self, collector):
super(NotificationEndpoint, self).__init__() super(NotificationEndpoint, self).__init__()

View File

@@ -14,8 +14,6 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import six
from oslo_log import log from oslo_log import log
from watcher.common import cinder_helper from watcher.common import cinder_helper
from watcher.common import exception from watcher.common import exception
@@ -161,7 +159,7 @@ class CinderNotification(base.NotificationEndpoint):
return 'attachment_id' return 'attachment_id'
attachments = [ attachments = [
{_keyReplace(k): v for k, v in six.iteritems(d) {_keyReplace(k): v for k, v in iter(d.items())
if k in ('instance_uuid', 'id')} if k in ('instance_uuid', 'id')}
for d in data['volume_attachment'] for d in data['volume_attachment']
] ]

View File

@@ -19,7 +19,6 @@
import re import re
import oslo_messaging as om import oslo_messaging as om
import six
class NotificationFilter(om.NotificationFilter): class NotificationFilter(om.NotificationFilter):
@@ -81,7 +80,7 @@ class NotificationFilter(om.NotificationFilter):
elif regex is not None and data is None: elif regex is not None and data is None:
return True return True
elif (regex is not None and elif (regex is not None and
isinstance(data, six.string_types) and isinstance(data, str) and
not regex.match(data)): not regex.match(data)):
return True return True

View File

@@ -45,13 +45,11 @@ See :doc:`../architecture` for more details on this component.
""" """
import abc import abc
import six
from watcher.common.loader import loadable from watcher.common.loader import loadable
@six.add_metaclass(abc.ABCMeta) class BasePlanner(loadable.Loadable, metaclass=abc.ABCMeta):
class BasePlanner(loadable.Loadable):
@classmethod @classmethod
def get_config_opts(cls): def get_config_opts(cls):

View File

@@ -16,13 +16,11 @@
# #
import abc import abc
import six
from watcher.common import context from watcher.common import context
@six.add_metaclass(abc.ABCMeta) class BaseScope(object, metaclass=abc.ABCMeta):
class BaseScope(object):
"""A base class for Scope mechanism """A base class for Scope mechanism
Child of this class is called when audit launches strategy. This strategy Child of this class is called when audit launches strategy. This strategy

View File

@@ -17,13 +17,11 @@
# limitations under the License. # limitations under the License.
import abc import abc
import six
from watcher.common.loader import loadable from watcher.common.loader import loadable
@six.add_metaclass(abc.ABCMeta) class ScoringEngine(loadable.Loadable, metaclass=abc.ABCMeta):
class ScoringEngine(loadable.Loadable):
"""A base class for all the Scoring Engines. """A base class for all the Scoring Engines.
A Scoring Engine is an instance of a data model, to which the learning A Scoring Engine is an instance of a data model, to which the learning
@@ -97,8 +95,7 @@ class ScoringEngine(loadable.Loadable):
return [] return []
@six.add_metaclass(abc.ABCMeta) class ScoringEngineContainer(loadable.Loadable, metaclass=abc.ABCMeta):
class ScoringEngineContainer(loadable.Loadable):
"""A base class for all the Scoring Engines Containers. """A base class for all the Scoring Engines Containers.
A Scoring Engine Container is an abstraction which allows to plugin A Scoring Engine Container is an abstraction which allows to plugin

View File

@@ -56,13 +56,11 @@ Two approaches to dealing with this can be envisaged:
""" """
import abc import abc
import six
from watcher.decision_engine.solution import efficacy from watcher.decision_engine.solution import efficacy
@six.add_metaclass(abc.ABCMeta) class BaseSolution(object, metaclass=abc.ABCMeta):
class BaseSolution(object):
def __init__(self, goal, strategy): def __init__(self, goal, strategy):
"""Base Solution constructor """Base Solution constructor

View File

@@ -17,11 +17,9 @@
# limitations under the License. # limitations under the License.
# #
import abc import abc
import six
@six.add_metaclass(abc.ABCMeta) class BaseSolutionComparator(object, metaclass=abc.ABCMeta):
class BaseSolutionComparator(object):
@abc.abstractmethod @abc.abstractmethod
def compare(self, sol1, sol2): def compare(self, sol1, sol2):
raise NotImplementedError() raise NotImplementedError()

View File

@@ -17,11 +17,9 @@
# limitations under the License. # limitations under the License.
# #
import abc import abc
import six
@six.add_metaclass(abc.ABCMeta) class BaseSolutionEvaluator(object, metaclass=abc.ABCMeta):
class BaseSolutionEvaluator(object):
@abc.abstractmethod @abc.abstractmethod
def evaluate(self, solution): def evaluate(self, solution):
raise NotImplementedError() raise NotImplementedError()

View File

@@ -18,14 +18,12 @@
# limitations under the License. # limitations under the License.
import abc import abc
import six
from watcher import notifications from watcher import notifications
from watcher.objects import fields from watcher.objects import fields
@six.add_metaclass(abc.ABCMeta) class StrategyContext(object, metaclass=abc.ABCMeta):
class StrategyContext(object):
def execute_strategy(self, audit, request_context): def execute_strategy(self, audit, request_context):
"""Execute the strategy for the given an audit """Execute the strategy for the given an audit

View File

@@ -17,11 +17,9 @@
# limitations under the License. # limitations under the License.
# #
import abc import abc
import six
@six.add_metaclass(abc.ABCMeta) class BaseSelector(object, metaclass=abc.ABCMeta):
class BaseSelector(object):
@abc.abstractmethod @abc.abstractmethod
def select(self): def select(self):

View File

@@ -37,7 +37,6 @@ which are dynamically loaded by Watcher at launch time.
""" """
import abc import abc
import six
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log from oslo_log import log
@@ -121,8 +120,7 @@ class StrategyEndpoint(object):
return [available_datasource, available_metrics, available_cdm] return [available_datasource, available_metrics, available_cdm]
@six.add_metaclass(abc.ABCMeta) class BaseStrategy(loadable.Loadable, metaclass=abc.ABCMeta):
class BaseStrategy(loadable.Loadable):
"""A base class for all the strategies """A base class for all the strategies
A Strategy is an algorithm implementation which is able to find a A Strategy is an algorithm implementation which is able to find a
@@ -471,8 +469,7 @@ class BaseStrategy(loadable.Loadable):
input_parameters=parameters) input_parameters=parameters)
@six.add_metaclass(abc.ABCMeta) class DummyBaseStrategy(BaseStrategy, metaclass=abc.ABCMeta):
class DummyBaseStrategy(BaseStrategy):
@classmethod @classmethod
def get_goal_name(cls): def get_goal_name(cls):
@@ -485,8 +482,7 @@ class DummyBaseStrategy(BaseStrategy):
return [] return []
@six.add_metaclass(abc.ABCMeta) class UnclassifiedStrategy(BaseStrategy, metaclass=abc.ABCMeta):
class UnclassifiedStrategy(BaseStrategy):
"""This base class is used to ease the development of new strategies """This base class is used to ease the development of new strategies
The goal defined within this strategy can be used to simplify the The goal defined within this strategy can be used to simplify the
@@ -500,8 +496,7 @@ class UnclassifiedStrategy(BaseStrategy):
return "unclassified" return "unclassified"
@six.add_metaclass(abc.ABCMeta) class ServerConsolidationBaseStrategy(BaseStrategy, metaclass=abc.ABCMeta):
class ServerConsolidationBaseStrategy(BaseStrategy):
REASON_FOR_DISABLE = 'watcher_disabled' REASON_FOR_DISABLE = 'watcher_disabled'
@@ -510,16 +505,14 @@ class ServerConsolidationBaseStrategy(BaseStrategy):
return "server_consolidation" return "server_consolidation"
@six.add_metaclass(abc.ABCMeta) class ThermalOptimizationBaseStrategy(BaseStrategy, metaclass=abc.ABCMeta):
class ThermalOptimizationBaseStrategy(BaseStrategy):
@classmethod @classmethod
def get_goal_name(cls): def get_goal_name(cls):
return "thermal_optimization" return "thermal_optimization"
@six.add_metaclass(abc.ABCMeta) class WorkloadStabilizationBaseStrategy(BaseStrategy, metaclass=abc.ABCMeta):
class WorkloadStabilizationBaseStrategy(BaseStrategy):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(WorkloadStabilizationBaseStrategy, self super(WorkloadStabilizationBaseStrategy, self
@@ -531,16 +524,14 @@ class WorkloadStabilizationBaseStrategy(BaseStrategy):
return "workload_balancing" return "workload_balancing"
@six.add_metaclass(abc.ABCMeta) class NoisyNeighborBaseStrategy(BaseStrategy, metaclass=abc.ABCMeta):
class NoisyNeighborBaseStrategy(BaseStrategy):
@classmethod @classmethod
def get_goal_name(cls): def get_goal_name(cls):
return "noisy_neighbor" return "noisy_neighbor"
@six.add_metaclass(abc.ABCMeta) class SavingEnergyBaseStrategy(BaseStrategy, metaclass=abc.ABCMeta):
class SavingEnergyBaseStrategy(BaseStrategy):
@classmethod @classmethod
def get_goal_name(cls): def get_goal_name(cls):
@@ -553,8 +544,7 @@ class SavingEnergyBaseStrategy(BaseStrategy):
return [] return []
@six.add_metaclass(abc.ABCMeta) class ZoneMigrationBaseStrategy(BaseStrategy, metaclass=abc.ABCMeta):
class ZoneMigrationBaseStrategy(BaseStrategy):
@classmethod @classmethod
def get_goal_name(cls): def get_goal_name(cls):
@@ -567,8 +557,7 @@ class ZoneMigrationBaseStrategy(BaseStrategy):
return [] return []
@six.add_metaclass(abc.ABCMeta) class HostMaintenanceBaseStrategy(BaseStrategy, metaclass=abc.ABCMeta):
class HostMaintenanceBaseStrategy(BaseStrategy):
REASON_FOR_MAINTAINING = 'watcher_maintaining' REASON_FOR_MAINTAINING = 'watcher_maintaining'

View File

@@ -18,8 +18,6 @@
# #
from oslo_log import log from oslo_log import log
import six
from watcher._i18n import _ from watcher._i18n import _
from watcher.common import exception from watcher.common import exception
from watcher.decision_engine.model import element from watcher.decision_engine.model import element
@@ -103,7 +101,7 @@ class HostMaintenance(base.HostMaintenanceBaseStrategy):
def get_instance_state_str(self, instance): def get_instance_state_str(self, instance):
"""Get instance state in string format""" """Get instance state in string format"""
if isinstance(instance.state, six.string_types): if isinstance(instance.state, str):
return instance.state return instance.state
elif isinstance(instance.state, element.InstanceState): elif isinstance(instance.state, element.InstanceState):
return instance.state.value return instance.state.value
@@ -116,7 +114,7 @@ class HostMaintenance(base.HostMaintenanceBaseStrategy):
def get_node_status_str(self, node): def get_node_status_str(self, node):
"""Get node status in string format""" """Get node status in string format"""
if isinstance(node.status, six.string_types): if isinstance(node.status, str):
return node.status return node.status
elif isinstance(node.status, element.ServiceState): elif isinstance(node.status, element.ServiceState):
return node.status.value return node.status.value

View File

@@ -197,9 +197,9 @@ class SavingEnergy(base.SavingEnergyBaseStrategy):
def save_energy(self): def save_energy(self):
need_poweron = max( need_poweron = int(max(
(len(self.with_vms_node_pool) * self.free_used_percent / 100), ( (len(self.with_vms_node_pool) * self.free_used_percent / 100), (
self.min_free_hosts_num)) self.min_free_hosts_num)))
len_poweron = len(self.free_poweron_node_pool) len_poweron = len(self.free_poweron_node_pool)
len_poweroff = len(self.free_poweroff_node_pool) len_poweroff = len(self.free_poweroff_node_pool)
if len_poweron > need_poweron: if len_poweron > need_poweron:

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