Compare commits

..

393 Commits

Author SHA1 Message Date
3597c6a7bd Update .gitreview for unmaintained/zed
Change-Id: I69857afcd5c6a52899c121e1939f01a602d758c4
2024-05-08 11:00:00 +00:00
e7b9945933 Update TOX_CONSTRAINTS_FILE for stable/zed
Update the URL to the upper-constraints file to point to the redirect
rule on releases.openstack.org so that anyone working on this branch
will switch to the correct upper-constraints list automatically when
the requirements repository branches.

Until the requirements repository has as stable/zed branch, tests will
continue to use the upper-constraints list on master.

Change-Id: I4a4e652d6d7fabe5ce7b6fc5b0b6391957a7cbc5
2022-09-19 11:20:17 +00:00
a08c0fde6f Update .gitreview for stable/zed
Change-Id: I6b03383455ec1b2d83323056e55bc6dedfa2d162
2022-09-19 11:20:13 +00:00
Thierry Carrez
e227f82fd6 Update to zed cycle testing runtime
Fix Zed gate for python-watcherclient by updating to Zed testing
runtime.

Change-Id: I49f1156065a9a405691383af755634be7d29af31
2022-09-16 05:26:06 +00:00
765701da39 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: I5c6406f03a18dc49522bc6caeece0855709a4768
2021-09-10 14:32:22 +00:00
Zuul
dc9b5cb347 Merge "remove unicode from code" 2021-07-13 08:42:38 +00:00
wu.shiming
cf18f56c6f 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: Ie426b70156f777654d78bb3a3dada05f733abdc5
2021-07-06 16:16:01 +08:00
XinxinShen
f2f882e297 Switch testing to Xena testing runtime
Updating the tetsing template to Xena testing runtime:
https://governance.openstack.org/tc/reference/runtimes/xena.html

Change-Id: I7eaad18c98a1850e6d429b52e1e8782d4274ee9b
2021-07-05 15:11:46 +02:00
XinxinShen
add4254a3f Replace deprecated UPPER_CONSTRAINTS_FILE variable
UPPER_CONSTRAINTS_FILE is old name and deprecated

[1] https://zuul-ci.org/docs/zuul-jobs/python-roles.html#rolevar-tox.tox_constraints_file

Change-Id: Ie0cbc9e5e0375b70f28fc9e0b2e64f72f6721717
2021-07-05 15:11:15 +02:00
Zuul
983a347341 Merge "setup.cfg: Replace dashes with underscores" 2021-07-05 13:09:46 +00:00
maaoyu
6a4937d18d 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: Ib952d51523684ba21b1247a0cef59ea5552ecdca
2021-07-05 12:05:43 +00:00
zhangboye
d0f41996ff 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.

Change-Id: I0385351f6bb08b1938568f0a69d7384556c8d78e
2021-07-05 12:04:46 +00:00
Dantali0n
52a3fd062d Drop lower constraints testing
Change-Id: If01998ae7422e5e066241f6fe42d08399cd6478f
2021-07-03 07:01:33 +00:00
zhangboye
c97e16fd01 remove unicode from code
Change-Id: I42166c2db7c305c816bc1934e954d5d4acca659e
2021-01-03 16:31:39 +08:00
Zuul
6a33b44d7f Merge "Remove install unnecessary packages" 2020-10-14 01:52:37 +00:00
maaoyu
41feafc420 Remove install unnecessary packages
The docs requirements migrated to doc/requirements.txt
we need not install things from requirements.txt.

Change-Id: I31972595411d814700b6b51113827f438085170a
2020-09-24 17:28:12 +08:00
e1bcc5f758 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: Iae7748124e2ab374637bc7a30a77433b5981e8b5
2020-09-09 17:40:22 +00:00
Ghanshyam Mann
80f728b14f [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.

Story: #2007865
Task: #40227

Closes-Bug: #1886298

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

Change-Id: I56837a6877a22020048b095b9eb528700c786c66
2020-08-16 23:39:29 +00:00
licanwei
2e97950670 remove mox3
Change-Id: I4a1de074db42854871a43ba49dbaa9dc2dfc6621
2020-06-19 09:52:37 +08:00
Andreas Jaeger
21b106dc15 Switch to newer openstackdocstheme version
Switch to openstackdocstheme 2.2.0. Using
the version 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.

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.

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.

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

Change-Id: I58edf52ff891328b14edecc9e6e990b34cb730b7
2020-05-21 09:31:12 +02:00
Ghanshyam Mann
7213f7195e 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: I794bcf026f8c30d81c84b8c26e8b982b0e7b5b17
2020-05-12 21:35:48 -05:00
Zuul
21f42884f1 Merge "Use unittest.mock instead of third party mock" 2020-05-07 06:59:31 +00:00
Zuul
4c57d61f8d Merge "Remove future imports" 2020-05-07 06:58:34 +00:00
qiufossen
e05b498a5f 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: I3cec266e4326b4f0749d70f6733023c73ca08d80
2020-05-07 10:15:07 +08:00
zhangbailin
8d3ce6c58d Remove future imports
These particular imports are no longer needed in a Python 3-only world.

Change-Id: Ifecdc3c35820977ad561cd2d78471d14b94ee65a
2020-04-30 09:58:27 +00:00
Zuul
bb7af48350 Merge "Bump default tox env from py37 to py38" 2020-04-30 03:10:21 +00:00
jacky06
92c15fa38a 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: Idac937dd704ef11dfc33e197f7539e3f7a5feb92
2020-04-29 23:50:12 +08:00
Sean McGinnis
d3cc035ff7 Bump default tox env from py37 to py38
Python 3.8 is now our highest level supported python runtime.
This updates the default tox target environments to swap out
py37 for py38 to make sure local development testing is
covering this version.

This does not impact zuul jobs in any way, nor prevent local
tests against py37. It just changes the default if none is
explicitly provided.

Change-Id: Iac6ba63153af308cd82f3d3a303ce4c3fead0a5f
Signed-off-by: Sean McGinnis <sean.mcginnis@gmail.com>
2020-04-24 10:25:59 -05:00
Sean McGinnis
fb22d3e1f8 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: Ia0db684e1c03231a93f71cab49cbbd4f23768dda
Signed-off-by: Sean McGinnis <sean.mcginnis@gmail.com>
2020-04-24 08:23:19 -05:00
ac0ccb67a6 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: I0ec7925e847386f9ea8e2976c0f99dc03904a922
2020-04-11 18:49:26 +00:00
Andreas Jaeger
5946fbb5b1 Cleanup py27 support
Make a few cleanups:
- Remove python 2.7 stanza from setup.py
- Add requires on python >= 3.6 to setup.cfg so that pypi and pip
  know about the requirement
- Remove obsolete sections from setup.cfg: Wheel is not needed for python
  3 only repo
- Update requirements, no need for python_version anymore
- Use modern sphinx-build for docs building, update openstackdocstheme,
  fix api-doc building.

Change-Id: I40b67f330ac850bf45cca742a8b967fd12480ce3
2020-04-04 14:27:51 +02:00
Andreas Jaeger
2830afdc75 Update hacking for Python3
The repo is Python 3 now, so update hacking to version 3.0 which
supports Python 3.

Fix problems found.

Change-Id: I6bd9fdee0ee275e4d9d3fcaf96c1512933ce35a6
2020-03-31 13:29:10 +02:00
Zuul
1912b9aa82 Merge "Support audit type event" 2020-01-10 01:56:48 +00:00
licanwei
1f9194ced5 Support audit type event
Add a new EVENT type to audit type and change the microversion
to 1.4

Partially Implements: blueprint event-driven-optimization-based

Change-Id: Ia9608534d12f6877f9b93e88fa75fe9457c29347
2020-01-07 15:57:11 +08:00
Zuul
9387369cd7 Merge "Drop python 2.7 support and testing" 2019-12-16 02:42:17 +00:00
licanwei
431319ee4d Watcherclient supports list data model API
Change-Id: I5527414b5e87253d87a4a26398ad5dcce1193e43
Related-Bug: #1854121
2019-12-02 14:41:32 +08:00
Ghanshyam Mann
e3c903cfce Drop python 2.7 support and testing
OpenStack is dropping the py2.7 support in ussuri cycle.

python-watcherclient is ready with python 3 and ok to drop the
python 2.7 support.

Complete discussion & schedule can be found in
- http://lists.openstack.org/pipermail/openstack-discuss/2019-October/010142.html
- https://etherpad.openstack.org/p/drop-python2-support

Ussuri Communtiy-wide goal - https://review.opendev.org/#/c/691178/

Change-Id: Id66df6c12e7b533381a354937e23e33f992adbfa
2019-10-30 04:34:43 +00:00
Zuul
e3f0a3d2b5 Merge "Fix details doc format error" 2019-10-26 07:23:01 +00:00
chenke
88351df1c2 Fix details doc format error
This error was caused because of rst format.

pls see:
https://github.com/openstack/python-watcherclient/blob/master/doc/source/cli/details.rst

This patch solved this error.

Change-Id: I756d2f6327349c36e4523513a2ac84ad91f7785f
2019-10-26 09:55:34 +08:00
Zuul
df3ec7849e Merge "Switch to Ussuri jobs" 2019-10-25 03:43:15 +00:00
Eric Fried
0c7e306642 Fix python-openstackclient plugin doc build
A help string in a plugin command argument help string contained (a typo
and) some invalid sphinx-isms causing autoprogram-cliff building from
python-openstackclient to fail with:

.../python-openstackclient/doc/source/cli/plugin-commands/watcher.rst:30:Inline emphasis start-string without end-string.
and
<CreateAuditTemplate>:1:Unexpected indentation.

This commit fixes the (typo and) help string formatting.

Change-Id: Ifb668b9ada94b679672f3bab562410bf12f4ca64
2019-10-24 01:34:12 +00:00
kangyufei
db70063cee Switch to Ussuri jobs
Change-Id: I13ae604be95e8b8ddd81a957900199a1113fc3f2
2019-10-22 15:13:55 +08:00
licanwei
1d1f28a256 Build pdf docs
Add a new pdf-docs environment to enable PDF build.

Change-Id: I59bdc7cf339b022458b3b0d1fa3b694b7998c20f
2019-09-17 00:20:25 -07:00
Zuul
62fdb73dae Merge "Implement watcher datamodel list in watcherclient" 2019-09-09 02:30:52 +00:00
chenke
297ca1dfc5 Implement watcher datamodel list in watcherclient
1. Add data_model.py and data_model_shell.py for accept and
process request.

2. Add relative unittest.

Partically Implements: blueprint show-datamodel-api

Change-Id: I5e080453acaedf7e20734d67922b64511dd5f7fd
2019-08-28 09:45:03 +08:00
chenke
a8f919e1f7 Add datamodel doc in watcherclient
Change-Id: I319d47dc66cb10e5ba5b6e0e318ecff0438b2d05
2019-08-26 20:28:47 +08:00
licanwei
ea74a22b49 Fix _make_connection_url
After support uWSGI[1], Watcher endpoint changed from http://ip:port
to http://ip/infra-optim. method _make_connection_url in HTTPClient
class can't return the correct url. This patch fixed it.
[1]: https://review.opendev.org/#/c/666779/

Change-Id: I77e610cd6781b252327a49aa5cd5bc63d395bf91
Closes-Bug: #1837186
2019-07-19 17:17:19 +08:00
licanwei
3caa385548 Add Python3 Train unit tests
This is one goal of Train Cycle.
See the Train python3-updates goal document for details:
https://governance.openstack.org/tc/goals/train/python3-updates.html

Change-Id: Id5a150cbfa658383f6ae7958a06ebe3a4f9047e6
2019-07-03 11:18:27 +08:00
chenke
0e9c827c76 Switch to the new canonical constraints URL on master
Reference:
1. http://lists.openstack.org/pipermail/openstack-discuss/2019-May/006478.html
2. https://review.opendev.org/#/c/601188

Change-Id: If04d918774d0254c7d386f80c5e8b1ce84b7eac1
2019-06-14 19:55:06 +08:00
licanwei
dbbe7df1e2 Remove unused readme file
Change-Id: I87c6e6ce1bb6e253014d844a3a67b51cd6b11135
2019-05-30 15:34:32 +08:00
Zuul
be479feef9 Merge "Add force option" 2019-05-30 02:06:14 +00:00
Zuul
02583f7469 Merge "remove unused cliutils.py file as osc_lib is used" 2019-05-25 06:22:08 +00:00
Dantali0n
1aebe93477 remove unused cliutils.py file as osc_lib is used
Removes old cliutils.py file that contains methods provided by osc_lib
and remove prettytable dependency that was only required by cliutils.py

Depends-on: I8bc3330a456f8bb76a17c4277a094a64fe9be449
Change-Id: Ib9eedafb211c205ff8b7dd18a9fc87e1f0b2739f
2019-05-23 09:34:30 +02:00
licanwei
cde518be31 Add force option
Partially Implements: blueprint add-force-field-to-audit
Depends-on: Ib2d221ea9c994dea396c54cc8d2d32237025a1d4

Change-Id: I235bbd298b7fa8ad9d8b01a94d68376c8ac27e8d
2019-05-23 07:17:00 +00:00
Matt Riedemann
573ca6ed59 Cleanup doc dependencies
This creates a dedicated doc/requirements.txt for doc-only
dependencies like sphinx packages so we can decouple those
from the test-requirements.txt.

As a result, the missing oslo.serialization runtime dependency
is added (I used the same version that python-novaclient uses).

Due to change If558f184c959e4b63b56dec3ca1571d1034cfe5c in the
openstack/requirements repo, in order to pass the
requirements-check job we have to specify both the py27 and py3
versions for sphinx.

Change-Id: I8bc3330a456f8bb76a17c4277a094a64fe9be449
2019-05-13 13:35:25 -04:00
Matt Riedemann
f062e60990 Remove --test-path option from stestr run
The .stestr.conf already defines the test path
so we don't need to specify it on the command line.

Change-Id: I66892fa0b17895207307bc15b5ef8b322a7a010e
2019-05-11 18:54:37 -04:00
Matt Riedemann
c0b2604e9b Whitelist rm external usage in tox.ini
This cleans up the error message from tox:

WARNING: test command found but not installed in testenv
  cmd: /bin/rm
  env: /home/osboxes/git/python-watcherclient/.tox/py27
Maybe you forgot to specify a dependency? See also the whitelist_externals envconfig setting.

DEPRECATION WARNING: this will be an error in tox 4 and above!

Change-Id: I854676b070720df496cb6c66f2fd1a92d232fa11
2019-05-11 18:53:00 -04:00
Matt Riedemann
2cab116e30 Use upper-constraints in tox runs
The upper-constraints file wasn't being enforced
when installing dependencies in tox runs which can
lead to failures like installing Sphinx>2.0 in py27
where it's not supported.

This is loosely based on novaclient change
I8be883215f27abb58d15b85e8542cbdf32000bac for the
same kind of issue.

Note there are other things that should be done
in here regarding requirements cleanup, like the
sphinx dependnecies should move to a
doc/requirements.txt file to separate them from
unit test runs, but that can be dealt with in a
follow up change.

Change-Id: I359a35af5b653299110a8d0faddb255da0b10118
Closes-Bug: #1828698
2019-05-11 18:45:44 -04:00
Zuul
bb5586b477 Merge "Add tempest voting" 2019-05-07 05:49:36 +00:00
licanwei
c30f095481 Add tempest voting
Change-Id: Ic104274f445869ebc18090f9adc17b94261822db
2019-04-30 16:20:01 +08:00
jacky06
ffb71506aa Replace git.openstack.org URLs with opendev.org URLs
Change-Id: Ib764e351a42de92b532f4c0b4ff51758bb47b6a2
2019-04-28 09:36:25 +00:00
Zuul
32a8799516 Merge "Remove py35" 2019-04-20 04:02:58 +00:00
OpenDev Sysadmins
b52df6899d OpenDev Migration Patch
This commit was bulk generated and pushed by the OpenDev sysadmins
as a part of the Git hosting and code review systems migration
detailed in these mailing list posts:

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

Attempts have been made to correct repository namespaces and
hostnames based on simple pattern matching, but it's possible some
were updated incorrectly or missed entirely. Please reach out to us
via the contact information listed at https://opendev.org/ with any
questions you may have.
2019-04-19 19:45:00 +00:00
licanwei
103bb38475 Remove py35
We just need python3.6 and python3.7

https://governance.openstack.org/tc/reference/runtimes/train.html

Change-Id: Id5d58a3b0973bd64b4655ebc8b85ec550bb39d4e
2019-04-16 16:41:41 +08:00
Zuul
76a01b0c7c Merge "Add marker option for strategy in watcher-client" 2019-03-22 02:05:44 +00:00
Zuul
939371d180 Merge "Increase actionplan_shell.py unittest coverage from 70% to 97%" 2019-03-21 03:11:45 +00:00
Zuul
c62757b093 Merge "Update .gitignore to ignore cover and .coverage*" 2019-03-20 01:47:32 +00:00
chenke
e2082907ff Increase actionplan_shell.py unittest coverage from 70% to 97%
Change-Id: Iaca67b517c2caf4938dbf861bee3add0a41c18a2
2019-03-19 16:10:25 +08:00
Zuul
16ff74f54c Merge "Add marker option for goal" 2019-03-19 03:42:33 +00:00
Zuul
de9b8d124b Merge "Increase the unit test coverage of action_plan.py from 79% to 95%" 2019-03-19 03:42:32 +00:00
chenke
a25cd66052 Update .gitignore to ignore cover and .coverage*
Change-Id: I8856741461611aac45a644e62470846824409219
2019-03-18 11:39:15 +08:00
chenke
9b1e234e36 Increase the unit test coverage of action_plan.py from 79% to 95%
Change-Id: Ie33b00d690746609663492c63b8f778048a689f2
2019-03-18 11:19:57 +08:00
licanwei
512e43eb32 Remove functional in tox.ini
Functional code was removed to watcher-tempest-plugin

Change-Id: I279e256940c44d3643f1cdd3000050674bcd6e95
2019-03-18 10:45:44 +08:00
chenke
d0f2f10f5d Add marker option for strategy in watcher-client
Change-Id: I40ab57889c5402fe5b69d28a3372e7a0a14592f8
2019-03-18 01:12:17 +00:00
zhurong
8342e64051 Remove the functional test
Depends-On: https://review.openstack.org/643247
Change-Id: I5723575d44dccf81779959c1cae43e2cab2abc9b
2019-03-15 03:50:20 +00:00
chenke
2c29c49f24 Add marker option for goal
Change-Id: I27f06019e731633349389781545fe8c3c036d723
2019-03-13 21:23:36 +08:00
Zuul
a70ebd8a41 Merge "Add openstack-cover-jobs for watcherclient" 2019-03-13 06:21:14 +00:00
chenke
4db175f342 Add openstack-cover-jobs for watcherclient
Change-Id: Idc5e67bc5bf61bd02147e52872a9fcf7d71eeae4
2019-03-12 14:05:46 +08:00
ZhongShengping
775199cb42 add python 3.7 unit test job
This is a mechanically generated patch to add a unit test job running
under Python 3.7.

See ML discussion here [1] for context.

[1] http://lists.openstack.org/pipermail/openstack-dev/2018-October/135626.html

Change-Id: I9cd0ea328ae6e88dc17c4a1c447e3d42d07bef3d
Story: #2004073
Task: #27462
2019-02-19 17:06:05 +08:00
Zuul
9d9c5fe3be Merge "DEFAULT_VER should be '1.latest'" 2019-02-01 09:30:20 +00:00
licanwei
e4ee4ff03c DEFAULT_VER should be '1.latest'
Change-Id: I359838db9ee8427812215833f379a84463c8dbfb
2019-01-26 14:10:20 +08:00
licanwei
ca6190c3a1 Use openstack common CLI
Change-Id: Ia013cafe7dfa3a54c86ff44e57f98d64b15b6a86
2019-01-25 09:40:38 +08:00
Zuul
74cbf1b17b Merge "[Doc] Fix OS_AUTH_URL value" 2019-01-24 06:59:15 +00:00
ZhijunWei
4a1b6eaf81 Update hacking version
1. update the hacking to latest, due to[1]
2. fix pep8 failed

[1]: https://github.com/openstack/python-watcherclient/blob/master/HACKING.rst

Change-Id: I02891ca17e2655b9567cc56b5c2c0b4fb6a96446
2019-01-17 14:20:33 +00:00
Zuul
1186c7c34f Merge "Add deletion of actionplan to osc plugin" 2019-01-14 11:38:15 +00:00
Alexander Chadin
02498f85f6 Add deletion of actionplan to osc plugin
Change-Id: I3674f6945adb9a7e9b1ffa9e8ea81ddeaa893c67
2019-01-14 13:26:10 +03:00
Zuul
9d1d5e2cae Merge "Pass API microversion to Client class" 2019-01-14 08:57:24 +00:00
Hidekazu Nakamura
b0ac926ee6 [Doc] Fix OS_AUTH_URL value
Since Keystone v2 was removed in Queens release, this patch set
updates keystone version from v2.0 to v3 in OS_AUTH_URL value.

Change-Id: I77e8b1519ea8241e3c5cdeaffd9be9046b6315ce
2019-01-09 14:01:59 +09:00
licanwei
3e734b177d update audit start/end time help
Change-Id: I47232f671eacd9a6b8923d4ee588c4413f65d015
2018-12-24 13:55:09 +08:00
Zuul
2cfe7f9afc Merge "Add Python 3.6 classifier to setup.cfg" 2018-12-20 10:40:28 +00:00
Alexander Chadin
df57eb800d Pass API microversion to Client class
Change-Id: If6ac21330cb6c8303f62eec6ee5082f523ff73a1
2018-12-17 17:30:01 +03:00
Zuul
abea1a8815 Merge "Change openstack-dev to openstack-discuss" 2018-12-14 14:08:40 +00:00
Zuul
ab22110f7b Merge "Revert "Pass actual API version to Client class"" 2018-12-14 12:13:20 +00:00
melissaml
ec7e8ca803 Change openstack-dev to openstack-discuss
Mailinglists have been updated. Openstack-discuss replaces openstack-dev.

Change-Id: I141558842442c165ea662ddd5a85914faef8ddb8
2018-12-14 20:09:07 +08:00
Alexander Chadin
bdd99d60f3 Revert "Pass actual API version to Client class"
This reverts commit e391d53c2f.

Change-Id: I87c18b2e0d2b291f1de446cc6d8fc39a63fba589
2018-12-14 10:47:49 +00:00
Zuul
25ff2811d5 Merge "add python 3.6 unit test job" 2018-12-10 09:53:15 +00:00
Zuul
8ce78f8c1f Merge "Fix obsolete version of osc" 2018-12-07 11:21:16 +00:00
Alexander Chadin
ffc50c5001 Fix obsolete version of osc
This patch set adds a link to actual API version for OSC.

Closes-Bug: #1807180
Change-Id: I622bfec99c2e6fd9f69293aaa04c3184215af0d3
2018-12-06 18:03:30 +03:00
Zuul
6c66276040 Merge "Add continuous audit functional test" 2018-12-06 14:43:31 +00:00
98k
c256ee2a21 Change openstack-dev to openstack-discuss
Mailinglists have been updated. Openstack-discuss replaces openstack-dev.

Change-Id: Icc4b0796a8944cc2f59779e6eab242e55cd00114
2018-12-04 04:13:18 +00:00
qingszhao
7abd55a823 Add Python 3.6 classifier to setup.cfg
Change-Id: Ia42baeea21d624437dc2fbe4769a2857ab460d38
2018-11-30 07:41:11 +00:00
licanwei
98e09044c1 Add continuous audit functional test
Change-Id: Ibee323f7c894ae9ead2ea872561e0e7e79320017
2018-11-30 10:11:33 +08:00
Vieri
6c8dfd366d add python 3.6 unit test job
This is a mechanically generated patch to add a unit test job running
under Python 3.6 as part of the python3-first goal.

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

Change-Id: I554919fa8eccd8bb9946b80415903e0bb128e85e
Story: #2002586
2018-11-28 08:12:25 +00:00
Zuul
112e372239 Merge "Pass actual API version to Client class" 2018-11-20 02:00:44 +00:00
Zuul
c5b4db7fc1 Merge "Refactor the getid method base.py" 2018-11-19 09:01:44 +00:00
Zuul
7c6b39eeba Merge "Replace latest with explicit version" 2018-11-19 08:59:01 +00:00
wanghui
94f6864bf0 Refactor the getid method base.py
Refer to a merged commit.
https://review.openstack.org/#/c/588983/

Change-Id: I9765543c288370cfcdaaa930b2839e28b51a9380
2018-11-09 20:11:16 +08:00
Alexander Chadin
e391d53c2f Pass actual API version to Client class
Change-Id: Ie5f563c6982239ad7a99af06f704e2d931d164be
2018-11-08 17:39:22 +03:00
licanwei
b7928eb155 Replace latest with explicit version
Change-Id: I8aae4595f7ca9dae7ed36705b1311070a531523f
Closes-Bug: #1802217
2018-11-08 16:59:38 +08:00
huang.zhiping
7b7d07fac1 Update min tox version to 2.0
The commands used by constraints need at least tox 2.0.  Update to
reflect reality, which should help with local running of constraints
targets.

Change-Id: Ie378b24c559c04f235890f7eaa2ba82161b0604d
Closes-Bug:  #1801660
2018-11-07 11:53:12 +00:00
Hidekazu Nakamura
946ef06dc6 Update watcher api command argument
This patch set updates watcher api command argument.
1. os_watcher_api_version to os_infra_optim_api_version
2. OS_WATCHER_API_VERSION to OS_INFRA_OPTIM_API_VERSION

This patch set also updated --os-infra-optim-api-version help message.

Change-Id: I2502377b350b8cabfeba80c68f0569d567d24b3a
2018-11-05 13:07:00 +09:00
licanwei
69f0493968 add start and end time for continuous audit
Add new start_time and end_time fields when audit create

Partially Implements: blueprint add-start-end-time-for-continuous-audit

Change-Id: I37d1bd13649dfb92ce7526f04b25054ed088c4f2
2018-11-01 12:01:07 +08:00
Zuul
8c89b3327b Merge "Prepare watcherclient for microversioning" 2018-10-31 12:42:22 +00:00
Alexander Chadin
2e9de6868b Prepare watcherclient for microversioning
Implements: blueprint bp/api-microversioning

Change-Id: I049f9aac84a5658efaccc9e9fdf6c9d4be677d29
2018-10-18 11:29:30 +03:00
Alexander Chadin
db7a5e4bc9 Allow CLI to pass goal and strategy names
This patch set removes additional type verification
for goal and strategy entities to let CLI pass goal
and strategy names straight to API.

Depends-On: I89a9c7661616f49639151869055d8f5ebe723d5f
Change-Id: I323a66dd5bdef6f33d5fd5c60c99e1b4dcd7a7e0
Closes-Bug: #1794233
2018-10-02 13:58:48 +03:00
Andreas Jaeger
825e5cb081 Use templates lower-constraints, remove cover
Use openstack-lower-constraints-jobs template

Remove jobs that are part of the templates.

Remove cover job, this one is not working at all and always fails. If
anybody wants to enable it again, they can add the openstack-cover-jobs
template and fix it - I couldn't find an easy way to fix it without
knowledge of this repo.

Change-Id: I3b50c8384507d22339ed11f556dbe32181fe0518
2018-09-08 15:40:46 +02:00
Zuul
a8185c7067 Merge "add python 3.6 unit test job" 2018-09-03 10:26:54 +00:00
Zuul
4a0b0e76b4 Merge "switch documentation job to new PTI" 2018-09-03 10:26:53 +00:00
Zuul
1918d3f26b Merge "import zuul job settings from project-config" 2018-08-28 07:52:55 +00:00
Zuul
2ca6b6b421 Merge "Switch to stestr" 2018-08-28 02:42:24 +00:00
zhangyangyang
1086b23454 Switch to stestr
According to Openstack summit session [1],
stestr is maintained project to which all Openstack projects should migrate.
Let's switch to stestr as other projects have already moved to it.

[1] https://etherpad.openstack.org/p/YVR-python-pti

Change-Id: Ie5133b8e627f762402df38969aee15f48d192520
2018-08-20 11:08:43 +08:00
Nguyen Hai
535b9da7d2 add python 3.6 unit test job
This is a mechanically generated patch to add a unit test job running
under Python 3.6 as part of the python3-first goal.

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

Change-Id: I5f1f5655c5a4ea9dfbfba1397ad0207fbdf53c58
Story: #2002586
Task: #24344
2018-08-19 00:58:24 +09:00
Nguyen Hai
34a4ad3041 switch documentation job to new PTI
This is a mechanically generated patch to switch the documentation
jobs to use the new PTI versions of the jobs as part of the
python3-first goal.

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

Change-Id: Ia23c18578c4fa2854ed706a96b79f700bd751c43
Story: #2002586
Task: #24344
2018-08-19 00:58:23 +09:00
Nguyen Hai
39d4c1e944 import zuul job settings from project-config
This is a mechanically generated patch to complete step 1 of moving
the zuul job settings out of project-config and into each project
repository.

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

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

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

Change-Id: I05e014be3cdc08d35d3a1efef6fae418bd4511c8
Story: #2002586
Task: #24344
2018-08-19 00:57:31 +09:00
Alexander Chadin
c1fd569b76 fix watcher actionplan show command
This patch set is intended for Python 3.x support and replace
itervalues() method with values().

Change-Id: I6852239d2d6634a4304c87a1694e64479f560de1
Closes-Bug: #1786784
2018-08-13 17:31:02 +03:00
Zuul
eed22ea2bb Merge "Add audit name to CLI help doc" 2018-08-03 08:03:15 +00:00
Zuul
47241e0462 Merge "Add --marker help info" 2018-08-03 01:47:22 +00:00
Zuul
88d122a21f Merge "Update watcher strategy state in CLI" 2018-08-03 01:46:51 +00:00
Yumeng Bao
5e928b80be Update watcher strategy state in CLI
Change-Id: Ie77336207c9affcf2c9a0ef0247cf5adef38c87f
2018-08-02 05:40:55 +00:00
Yumeng Bao
723ad12afa Add --marker help info
Change-Id: Ia132e45d7f9665a386d1e40360a75c4234aecc7d
2018-08-02 11:12:33 +08:00
chenke
3926dcc541 Organize the use of 'log' and replace 'log' with LOG
Change-Id: I42ddf63dd73559e43efce401f3912c4b9413a6d4
2018-07-31 11:25:25 +08:00
Zuul
c557e45ae2 Merge "Add --marker help info" 2018-07-30 07:34:55 +00:00
Zuul
0b8dba2cb9 Merge "Fix watherclient error in py3" 2018-07-27 09:27:56 +00:00
licanwei
496f4c1365 Add audit name to CLI help doc
Change-Id: I9749bb679d66a65de3d4abe3564109bf4a8f8ccd
2018-07-26 18:36:09 -07:00
Zuul
6681724daa Merge "Add hostname field to support HA" 2018-07-26 13:45:54 +00:00
zhurong
2551ff0934 Fix watherclient error in py3
watchercliet will raise error:
Recoverable error: sequence item 0: expected str instance, bytes found

This patch fix this.

Change-Id: I6fe21766f320b0a09a14202203a5d0451175e1d3
2018-07-26 11:37:35 +08:00
licanwei
adc812746c Add --marker help info
Change-Id: I34c1a83f49b101d5ef85e1a19858b9d2b59c921d
2018-07-22 23:20:29 -07:00
Alexander Chadin
8d62995cf4 Add hostname field to support HA
Change-Id: Ic099070f93edbea738e58f7686d10f354df69532
2018-07-17 18:01:39 +03:00
Dao Cong Tien
d82be4c8c4 Invalid doc for Client exceptions
There is no BaseException any more.

Change-Id: I9bf4613fa27cfc6d62a466afe703d907e8aa737a
2018-07-11 14:54:17 +07:00
Andreas Jaeger
152804168d Don't run voting jobs in gate
Non-voting jobs should not be in gate queue at all, remove them.
They are wasting needlessly our resources since they get ignored.

Mark the job explictely as non-voting, since another change will make
the job voting by default - which allows to make it easily voting here.

See also https://review.openstack.org/580110

Change-Id: I73fd45772ba9c793dad3221c852af4e9606362e1
2018-07-04 11:46:11 +02:00
Doug Hellmann
4a4add3dcc fix tox python3 overrides
We want to default to running all tox environments under python 3, so
set the basepython value in each environment.

We do not want to specify a minor version number, because we do not
want to have to update the file every time we upgrade python.

We do not want to set the override once in testenv, because that
breaks the more specific versions used in default environments like
py35 and py36.

Change-Id: Ie9d1d45811450e3feadd0dd3d027d3a20370f206
Signed-off-by: Doug Hellmann <doug@doughellmann.com>
2018-06-06 17:58:20 -04:00
Zuul
db012f1f8f Merge "Modify Watcher start actionplan command" 2018-05-24 08:08:21 +00:00
deepak_mourya
a4c020c19f Modify Watcher start actionplan command
Currently, watcher start actionplan command uses update request
to start the action plan.
PATCH /v1/action_plans

This Patch Set will send the request to new API for action plan start
POST /v1/action_plans/action_plan_uuid/start

Depends-on: I5353e4aa58d1675d8afb94bea35d9b953514129a
Change-Id: I15291efa994daf719342d764f6179ca7699d8b08
Related-Bug: #1756274
2018-05-08 15:40:27 +05:30
rajat29
8ef72f18c4 Remove 'actionplan create' command
Actionplan create command can create new
audit which looks ambiguous as audit should only
be created by audit command.

Change-Id: I6d8116b4520be5cbb4289de7caf9cc99251e1f9f
Closes-bug: #1764654
2018-04-26 10:26:09 +05:30
Zuul
673905fead Merge "Update links in README" 2018-04-02 08:09:51 +00:00
Zuul
d886672fb5 Merge "add lower-constraints job" 2018-03-29 10:01:43 +00:00
Alexander Chadin
83ccfbb177 [WiP] functional jobs fix
Change-Id: If92660ad48b19fce47dd7a88ed33796427f70a80
2018-03-28 09:11:18 +00:00
Zuul
4c47c7364c Merge "ZuulV3 support for watcherclient" 2018-03-27 16:48:01 +00:00
Alexander Chadin
8acf01859c ZuulV3 support for watcherclient
Change-Id: I0efc302dae72d18f86dbdae1d22a6ea798cfb8f5
2018-03-27 18:38:55 +03:00
Zuul
d4af8d8834 Merge "Delete the unnecessary '-'" 2018-03-26 09:30:30 +00:00
Doug Hellmann
40d8df21c8 add lower-constraints job
Create a tox environment for running the unit tests against the lower
bounds of the dependencies.

Create a lower-constraints.txt to be used to enforce the lower bounds
in those tests.

Add openstack-tox-lower-constraints job to the zuul configuration.

See http://lists.openstack.org/pipermail/openstack-dev/2018-March/128352.html
for more details.

Change-Id: I11c8526b413e6dfc6e2457026ccc2f35e38d1699
Depends-On: https://review.openstack.org/555034
Signed-off-by: Doug Hellmann <doug@doughellmann.com>
2018-03-25 11:32:15 -04:00
Zuul
b87399cb2c Merge "Add tempest plugin" 2018-03-23 12:56:05 +00:00
Alexander Chadin
9bfefbf9ab Add tempest plugin
This patch set adds tempest plugin to register existing tempest
tests of watcherclient. It is also required to let devstack-tempest
job to launch watcherclient functional tests.

Change-Id: I4d906fd597048bb37803a2bb42f8357502cf1b76
2018-03-23 14:36:38 +03:00
huang.zhiping
b84039d7d4 Delete the unnecessary '-'
Change-Id: I6f36a4114026368d854fac37dcd003d3f4236455
2018-03-23 11:29:03 +08:00
OpenStack Proposal Bot
f8ead12481 Updated from global requirements
Change-Id: I35f49cea5915272e21ac1351dfb190c2b55be335
2018-03-15 08:06:52 +00:00
OpenStack Proposal Bot
85e4e364b7 Updated from global requirements
Change-Id: I46b763854d736e74523106240e1faf06150a3139
2018-03-13 07:30:46 +00:00
melissaml
ed9ce5b952 Update links in README
Change the outdated links to the latest links in README

Change-Id: I0a0781d4a86bb860bb8c85923e7be8b803f91ae2
2018-03-11 03:01:04 +08:00
Zuul
731e019bc1 Merge "Fix global efficacy format" 2018-02-23 09:09:47 +00:00
OpenStack Proposal Bot
a22dab5f88 Updated from global requirements
Change-Id: Ib45b0cc6fefd94b3c3a8181bd10b0d85f8044800
2018-02-17 10:20:48 +00:00
Alexander Chadin
0d7233055d Fix global efficacy format
Closes-Bug: #1749463
Change-Id: I0496f0d82bbf72dbbc8b808feb3a529ad6d49402
2018-02-14 17:06:15 +03:00
Zuul
2777a9bba8 Merge "Zuul: Remove project name" 2018-02-07 08:23:00 +00:00
James E. Blair
e359488cde Zuul: Remove project name
Zuul no longer requires the project-name for in-repo configuration.
Omitting it makes forking or renaming projects easier.

Change-Id: I884a00879ac30b504833951303578de42174ba09
2018-02-02 10:11:34 -08:00
Zuul
a1b6eed54c Merge "Add strategy state command" 2018-01-25 20:34:01 +00:00
Alexander Chadin
a907c2d0cd Add strategy state command
This patch set adds command "strategy state"
that allows to request strategy requirements to run.

Partially-Implements: blueprint check-strategy-requirements
Change-Id: I327cc4f5a887f62af700bd646576caa036faaf75
2018-01-24 14:55:01 +00:00
Zuul
d38bb255ed Merge "Updated from global requirements" 2018-01-24 14:03:31 +00:00
Zuul
30e2aad126 Merge "Audit Template Help Message" 2018-01-24 12:37:57 +00:00
OpenStack Proposal Bot
bc0fb4f051 Updated from global requirements
Change-Id: I420d547482d84c9cf8e39e2e2069c46f6d86e993
2018-01-24 01:34:14 +00:00
Zuul
ef533eb151 Merge "Updated from global requirements" 2018-01-22 11:24:34 +00:00
OpenStack Proposal Bot
3c160af376 Updated from global requirements
Change-Id: I65f25febf490e24d2bea4182890400191ce3a16a
I08b68c15c3906885ce3ca6fb410d227c3e585978
2018-01-19 13:50:22 +00:00
OpenStack Proposal Bot
186029ac87 Updated from global requirements
Change-Id: I08b68c15c3906885ce3ca6fb410d227c3e585978
I65f25febf490e24d2bea4182890400191ce3a16a
2018-01-19 12:01:23 +00:00
aditi
b9112a1199 Audit Template Help Message
This patch updates help message of "watcher audittemplate create"
It updates help about storage scoper.

Change-Id: I46be98c2819c2dfb2a7ef3fe1aa98caa90ececfd
Implements: blueprint audit-scoper-for-storage-data-model
2018-01-19 11:16:44 +00:00
Alexander Chadin
9d301fa14a Fix test_action_plan functional tests
Change-Id: Ie5b5bd330c68b696dce48e2475baf77a81f2e8c4
Closes-Bug: #1744262
2018-01-19 13:36:19 +03:00
Zuul
15d7d78b8b Merge "Fix watcher actionplan list command" 2018-01-05 09:25:24 +00:00
OpenStack Proposal Bot
81b84bcff5 Updated from global requirements
Change-Id: I8dcbe4616e7618c783097baecd62f67ef6501e30
2017-12-21 00:47:51 +00:00
Alexander Chadin
79880c2dff Fix watcher actionplan list command
This patch set replaces itervalues() method with values()
to get py3.* compatibility.

Closes-Bug: #1738772
Change-Id: Ie13d15d6f407b08ba087168ac647669c0df2c30a
2017-12-18 15:45:33 +03:00
Zuul
32259fe287 Merge "Fix unnecessary retries during conflict" 2017-12-13 14:24:13 +00:00
Zuul
d36ba79e77 Merge "marker when retrive audit" 2017-12-13 11:43:17 +00:00
Zuul
4f5487b5e1 Merge "Update audit_template create help message" 2017-12-13 10:06:17 +00:00
Zuul
7bf192a981 Merge "marker when retrive action" 2017-12-13 08:36:22 +00:00
Zuul
f8b341c0f3 Merge "marker when retrive audit template" 2017-12-13 05:39:09 +00:00
Zuul
abd6d8a0cb Merge "Updated from global requirements" 2017-12-08 00:51:31 +00:00
Alexander Chadin
147e4cd383 Migrate to Zuul v3
This patch does step 1 in the docs: Move Legacy Jobs to Projects.

Partial-Implements: blueprint migrate-to-zuulv3
Change-Id: I2344ac5b711ba5d723887d225d72a133fa06555c
2017-12-06 12:25:14 +00:00
OpenStack Proposal Bot
3988e9e7a8 Updated from global requirements
Change-Id: I6459fb19ee9b306aa4dde19816318ae2dc71669a
2017-12-05 03:35:50 +00:00
Zuul
88131d19fd Merge "Updated from global requirements" 2017-11-30 14:00:45 +00:00
Zuul
c1668fff44 Merge "Add --marker for 'watcher actionplan list'" 2017-11-30 13:54:39 +00:00
Yumeng Bao
1a6703266f Update audit_template create help message
'id' should be an integer, not string.
Closes-Bug: #1734056
Change-Id: I4275127e7f76ba6ad05f478278204c3de535cf5c
2017-11-28 10:04:16 +08:00
suzhengwei
fada471714 marker when retrive audit
Change-Id: I72078850152e0ccf2abc0d35b06a5142df35c312
2017-11-27 06:56:01 +00:00
suzhengwei
1cd8c38d95 marker when retrive action
Change-Id: Ic733c3e79a31c7cd99226e6e49dfbbc8c3b58902
2017-11-27 06:54:42 +00:00
suzhengwei
0257aa9116 marker when retrive audit template
Change-Id: Ia2cd0598770359c2727ec569dd7f2531f7b5f40a
2017-11-22 13:34:18 +00:00
licanwei
aa9d1a65f6 Add --marker for 'watcher actionplan list'
Change-Id: I88bb986d484198add967cdd953f46e341bf6f9ac
Closes-Bug: #1731826
2017-11-21 18:42:44 -08:00
OpenStack Proposal Bot
b5f584dafa Updated from global requirements
Change-Id: If01512e04786c99347abaaf30715bf1e205d5f55
2017-11-16 11:27:22 +00:00
Zuul
bf706365ea Merge "Updated from global requirements" 2017-11-15 09:59:44 +00:00
Zuul
7898268426 Merge "Multiple global efficacy" 2017-11-15 01:36:32 +00:00
OpenStack Proposal Bot
1eecf8fd63 Updated from global requirements
Change-Id: I489ee3ce735d775108c676342c7ca9239099d5b8
2017-11-15 00:44:21 +00:00
aditi
e6f361804f Multiple global efficacy
This patch adds changes for python-watcherclient for
multiple global efficacy indicator.

Change-Id: I8a7b283f4f79dc5e412fc0addfc4302ae49425ae
Implements: blueprint multiple-global-efficacy-indicator
2017-11-13 10:04:37 +00:00
suzhengwei
f5b2e7e4f5 add name for audit, changes for python-watcherclient
Change-Id: I9000018459913cd3107814e34977525eb3da10f4
Implements:blueprint add-name-for-audit
2017-11-01 02:42:15 +00:00
Zuul
0a29b296ae Merge "Use generic user for both zuul v2 and v3" 2017-10-30 14:26:12 +00:00
Zuul
4789e22e4a Merge "Update audit_template create help message" 2017-10-25 13:40:05 +00:00
aditi
5378102cd6 Fix unnecessary retries during conflict
This patch removes retries from python-watcherclient in case
watcher-api responded with conflict case.

Change-Id: I830abe0a3cd67484e165a0a42d5a57b75ed4dac6
Closes-Bug: #1725088
2017-10-20 02:27:13 +00:00
Nam Nguyen Hoai
42cab67124 Use generic user for both zuul v2 and v3
Zuul v2 uses 'jenkins' as user, but Zuul v3 uses 'zuul'.
Using $USER solves it for both cases.

Change-Id: I42c3328bf7ce5dbb745eb21954bc5528a6befed5
2017-10-17 07:33:36 +00:00
OpenStack Proposal Bot
0fd1b11f6d Updated from global requirements
Change-Id: I2cee86f0b7a9b7630322d1364463a97dbbe60b35
2017-10-10 12:36:58 +00:00
Hidekazu Nakamura
74773a60b2 Update audit_template create help message
Since scoping file format has changed by implementing cdm-scoping,
this patch updates audit_template create help message
about scoping file example.

Partially-Implements blueprint cdm-scoping

Change-Id: Ia9c4c23b5f6c4d99d59305297ea3c7aa9dcfbc94
2017-10-10 11:55:20 +00:00
Alexander Chadin
e92dd4db20 Fix gate-watcherclient-dsvm-functional-ubuntu-xenial job
Closes-Bug: #1722212
Change-Id: I8d5cb2fd1a17beb6049fb5d2a560fc31ba77fe3d
2017-10-09 15:45:03 +03:00
OpenStack Proposal Bot
ad0a32886d Updated from global requirements
Change-Id: I83a8ff2c92353500dd10da5a4c5e17c3c6be1b8e
2017-09-16 23:24:29 +00:00
OpenStack Proposal Bot
84f05d8e40 Updated from global requirements
Change-Id: Iabc543ea5aef45e3751629ba9be55a7e8fcd97c6
2017-09-13 13:03:41 +00:00
Jenkins
b33a444e90 Merge "Fix to use "." to source script files" 2017-09-06 07:59:28 +00:00
OpenStack Proposal Bot
27d1e4c85a Updated from global requirements
Change-Id: I9bfc8466e06767001cd0a2ff5eedde2572c165a4
2017-09-02 11:51:57 +00:00
Jenkins
77eb8f677f Merge "import content from cli-reference in openstack-manuals" 2017-09-02 09:24:51 +00:00
melissaml
320bb4c14f Fix to use "." to source script files
Adhering to coding conventions. Refer to ``Code conventions`` at
https://docs.openstack.org/contributor-guide/ for details.

Change-Id: Ie6b7d00e63acba0ffd8b27acd791fdb0b08417fe
2017-08-29 02:42:07 +08:00
Hidekazu Nakamura
7b5908b390 import content from cli-reference in openstack-manuals
This patch addes details.rst generated automatically by
openstack-doc-tools.

Change-Id: Ia9cd77f7fe5841d9b5bc2c81e3c1974ec3a744dd
2017-08-28 12:13:36 +09:00
OpenStack Proposal Bot
1d69f6a72f Updated from global requirements
Change-Id: I12c059b5ee28a43d5f8cdd6f5f0a4fff5fd9a6bd
2017-08-18 04:52:50 +00:00
OpenStack Proposal Bot
0e080e7294 Updated from global requirements
Change-Id: I04b7b0dc0816b976ec4097503b7f6797a9c838cd
2017-08-01 03:05:22 +00:00
Jenkins
c09ad28c9a Merge "Fix Audit Update functional test" 2017-08-01 02:16:37 +00:00
zte-hanrong
08fbccc684 Add the filed of description to shell command for action.
blueprint dynamic-action-description

Change-Id: I927cf966530059d9c7af1e6e60a8d75dd3e6b812
2017-07-27 16:07:11 +08:00
Jenkins
2f2d05d657 Merge "Update .gitignore because of doc migration" 2017-07-26 12:26:18 +00:00
Alexander Chadin
c02f584b33 Update .gitignore because of doc migration
This patch set updates .gitignore and fixes autodoc_exclude_modules

Change-Id: If0e8a28c541b7e0711cc5a76ef93513c51080974
2017-07-26 11:58:58 +03:00
Alexander Chadin
d6b68dc819 Fix Audit Update functional test
Change-Id: Iffd70302d0b1d7a919db3e6e44bd3bbebcb1e7ce
2017-07-26 11:09:18 +03:00
Jenkins
a70d587803 Merge "Update the documentation link for doc migration" 2017-07-25 13:36:51 +00:00
Hangdong Zhang
2e47d77f86 Update the documentation link for doc migration
Change-Id: Ia7119776f3d173af71561b1263e021dafc5c010d
BTW: Do some optimization as well (http -> https)
2017-07-24 13:55:17 +08:00
OpenStack Proposal Bot
a9405f5c2d Updated from global requirements
Change-Id: Iecde214cf1d386bb0a170f1456814a349a3c3f7d
2017-07-23 13:53:11 +00:00
Jenkins
4bb678f7a5 Merge "Add support for cron syntax" 2017-07-21 09:10:08 +00:00
Jenkins
baadbe3dca Merge "Update URLs in documents according to document migration" 2017-07-19 14:04:41 +00:00
Jenkins
24b089c057 Merge "Update permissions for post_test_hook.sh" 2017-07-19 13:42:36 +00:00
Alexander Chadin
c8acc20e82 Update permissions for post_test_hook.sh
This patch updates permissions up to 755 for post_test_hook.sh
to let it be executed using jenkins jobs.

Change-Id: I0224d10089df05729b8d479d6d910a2a2105c3f8
2017-07-19 14:45:56 +03:00
melissaml
fa91740b47 Update URLs in documents according to document migration
Change-Id: Ic1f137214fc16cdaab2e0da8fd5761a0ed153ad8
2017-07-14 11:38:36 +08:00
OpenStack Proposal Bot
504ca86b78 Updated from global requirements
Change-Id: Iee0f3a7ccade75a51bed40d08521306dd710732b
2017-07-13 14:25:08 +00:00
Jenkins
2b155f9505 Merge "Move existing content into the new standard structure" 2017-07-12 15:01:40 +00:00
Alexander Chadin
c8df16da8f Add support for cron syntax
Implements: blueprint cron-based-continuous-audits

Change-Id: Ib281964fbf9c160791d30eafe94fd83937cac23e
2017-07-10 07:30:38 +00:00
OpenStack Proposal Bot
0de3f627c5 Updated from global requirements
Change-Id: Ifd99e023666c7cfccff15cc4e7d2ffe06811dfa4
2017-07-06 01:45:35 +00:00
Jenkins
9c46ee00bb Merge "Add post_test_hook" 2017-07-06 00:22:40 +00:00
Jenkins
48703e19e4 Merge "Fix for README.rst of tests" 2017-07-06 00:21:33 +00:00
Jenkins
799084d3d1 Merge "Fixed wrap from taking negative values" 2017-07-06 00:17:15 +00:00
kavithahr
ee087b85d5 Fixed wrap from taking negative values
Now for wrap input it will take only postive integers as an input and
if any negative numbers are give it will give output as "Wrap argument
should be a positive integer".

Change-Id: I375dab0bdd53ee464f5634162472000119f247cb
2017-07-05 18:06:10 +05:30
Alexander Chadin
8524016170 Add post_test_hook
This patch set adds post_test_hook.sh which allows to
set jenkins job to execute functional jobs.

Change-Id: Icc4cdf8680da3ae83f36b3455fb32aecae2fb57f
2017-07-05 12:11:50 +03:00
Yumeng Bao
ed5e1b86c3 Move existing content into the new standard structure
This patch rearranges and reformats existing content.

Change-Id: I05088140504ba55abc724115828a7a977bd5c087
2017-07-05 16:10:09 +08:00
Alexander Chadin
42bf82c22c Fix for README.rst of tests
This patch set fixes one of steps to prepare functional env.

Change-Id: Ibb2536e61f847cda2590674e50d34d68726926a8
2017-07-05 11:07:38 +03:00
Yumeng Bao
0d0192c472 switch to openstackdocstheme
Depends-On: Ia750cb049c0f53a234ea70ce1f2bbbb7a2aa9454
Change-Id: I93dfcbd516810c41a1d64e872a28a539ec4f3155
2017-07-04 09:56:28 +08:00
Jenkins
641cd44adb Merge "Updated from global requirements" 2017-06-28 12:44:55 +00:00
Jenkins
da715f8e70 Merge "Enable some off-by-default checks" 2017-06-28 12:44:43 +00:00
OpenStack Proposal Bot
abe14a14d4 Updated from global requirements
Change-Id: Iffc25e19f78014db1d50b7778bf550f900f24a35
2017-06-27 12:23:00 +00:00
Yumeng Bao
984601ecfa Turn on warning-is-error in sphinx build
Turn on the flag to ensure that future warnings in the doc build
trigger a build failure.

Change-Id: I6f93e229cfd9bc56208750d1ddfe88404f89ab8e
2017-06-26 20:17:57 +08:00
blue55
f32956493b Enable some off-by-default checks
Some of the available checks are disabled by default, like:
[H106] Don’t put vim configuration in source files
[H203] Use assertIs(Not)None to check for None

Change-Id: I2809ab2cce76dd31a04d3cca0e97cdad26c14cb4
2017-06-23 10:13:40 +08:00
Jenkins
1e2a13fe1a Merge "Add CLI for Action Plan Cancel" 2017-06-19 09:17:59 +00:00
OpenStack Proposal Bot
417b3a2669 Updated from global requirements
Change-Id: Ie3692b21a749dec23583f302a42a822c5922bff5
2017-06-10 11:48:35 +00:00
aditi
3f25b6b223 Add CLI for Action Plan Cancel
This patch CLI for for action plan cancel
watcher action plan cancel <action-plan-uuid>

Change-Id: I9c8d53107b1926d6ce4532d7c696dc36c84c6cf8
Partially-Implements: blueprint cancel-action-plan
2017-05-31 11:19:20 +00:00
OpenStack Proposal Bot
5cbce9fb20 Updated from global requirements
Change-Id: I7e4668bd04f9a439296644f6d9dd181ba0b2ae9d
2017-05-23 12:00:31 +00:00
OpenStack Proposal Bot
f379b1544c Updated from global requirements
Change-Id: I02ae2ad14f93141e3aaadc873d43fec076480686
2017-05-17 03:58:59 +00:00
OpenStack Proposal Bot
30f49c9f70 Updated from global requirements
Change-Id: Ia162a2106be6cb4982c694d5a37d9c2ed845f143
2017-05-03 12:23:47 +00:00
Jenkins
af13d9cdd1 Merge "Updated from global requirements" 2017-05-03 12:21:47 +00:00
OpenStack Proposal Bot
8952b2fbd2 Updated from global requirements
Change-Id: I14c857805f9156640e9c0fd57233ca4cf2b5d99f
2017-05-01 14:08:23 +00:00
M V P Nitesh
66681ef9c9 Add 'rm -f .testrepository/times.dbm' command in testenv
Running py2* post py3* tests results in error. Add
'rm -f .testrepository/times.dbm' command in testenv to
resolve this.

Change-Id: Ie704b12c413c9e8cc0b2649c1d2bbc03a3b61a11
2017-04-25 12:55:27 +05:30
Jenkins
4285b388ca Merge "Updated from global requirements" 2017-04-12 12:23:36 +00:00
OpenStack Proposal Bot
723d39cd65 Updated from global requirements
Change-Id: I32bd693211fe91f86f1f2e1f5921ad56fbeaf1e5
2017-04-12 04:22:27 +00:00
M V P Nitesh
156d660cd3 Optimize the link address
Use https instead of http to ensure the safety

Change-Id: Ieeea614ce26b99b007a89cb12a8e83f120b64d32
2017-04-10 16:15:11 +05:30
Jenkins
07b19ede3f Merge "Remove log translations" 2017-03-29 12:57:12 +00:00
daohanli
94c317250e Remove log translations
Log messages are no longer being translated. This removes all use of
the _LE, _LI, and _LW translation markers to simplify logging and to
avoid confusion with new contributions.

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

Change-Id: Icfe6ab464fd9fbbbfb9c9a05dba2220aa9e0bace
2017-03-23 10:43:15 +08:00
Luong Anh Tuan
7250886d14 Indicating the location tests directory in oslo_debug_helper
According to [1], we can passing a "-t" argument to
oslo_debug_helper to indicate the directory where tests
are located. This will solves ImportError exception.

[1] https://docs.openstack.org/developer/oslotest/features.html

Change-Id: Id72596a8c3d9e2e344ef492f2d60b89bc0422aec
Closes-Bug: #1666560
2017-03-22 10:14:22 +00:00
Jenkins
03ac32b1be Merge "Using assert methods instead of assertTrue" 2017-03-08 09:35:39 +00:00
Jenkins
89390ac0a9 Merge "Updated from global requirements" 2017-03-03 08:28:09 +00:00
zhuzeyu
69c10379af Using assert methods instead of assertTrue
It will print a nicer error message if it fails.

Change-Id: I6fb9054e3285db76057db373fe87964e510de516
2017-03-03 06:33:21 +00:00
Jenkins
0ea4020d98 Merge "Remove support for py34" 2017-03-03 05:44:14 +00:00
Jenkins
cbcc990383 Merge "update help description about actionplan create" 2017-03-03 03:19:08 +00:00
OpenStack Proposal Bot
15f519f827 Updated from global requirements
Change-Id: I6055fa04daf29ae76845af307e844d94ba030117
2017-03-03 03:09:00 +00:00
ricolin
1ccf0588f9 [Fix gate]Update test requirement
Since pbr already landed and the old version of hacking seems not
work very well with pbr>=2, we should update it to match global
requirement.
Partial-Bug: #1668848

Change-Id: I21616cbbd11d2ccab60155ea78ed261ee12db5d4
2017-03-02 20:14:13 +08:00
Chris Spencer
cd267c9fa4 Remove RST files located in doc/source/api.
Change-Id: Ib9600297b6b65a44a72090cfb0c7d8f80dcfd34a
Closes-Bug: 1640811
2017-02-14 10:06:50 -07:00
gengchc2
ce477baa1f Remove support for py34
The gating on python 3.4 is restricted to <= Mitaka. This is due
to the change from Ubuntu Trusty to Xenial, where only python3.5
is available. There is no need to continue to keep these settings.

Change-Id: I66b76645b7799c6550583c675bc968310d5e0d1c
2017-02-08 16:33:34 +08:00
licanwei
cd918fe086 update help description about actionplan create
help=_("ActionPlan type.")
=>
help=_("Audit type. It must be ONESHOT or CONTINUOUS. "
       "Default is ONESHOT."))

Change-Id: Ic79b5d1d0cb5ed459aaa290269219ff0e00065d5
2017-02-07 09:56:47 +08:00
Jenkins
1f7df3d53d Merge "Using jsonutils instead of json" 2017-02-03 08:47:00 +00:00
zhuzeyu
dfe9d31ee4 Using jsonutils instead of json
TrivialFix

Change-Id: I1d17994f4cf854f6ba62c75ed18ebee3c7f5fa47
2017-02-03 15:48:12 +08:00
Jenkins
2ea26be247 Merge "Add functional env to tox" 2017-02-02 08:40:25 +00:00
OpenStack Proposal Bot
15b5fb791e Updated from global requirements
Change-Id: I487004e11fc37040601562bc2cf807d5d853335a
2017-01-25 09:37:23 +00:00
zhuzeyu
eafb6b21f7 Remove useless utf-8 coding
TrivialFix

Change-Id: I37d77df21349f3c113582a0a6e51a84be297cc73
2017-01-25 15:20:48 +08:00
Alexander Chadin
08cf7d99d3 Add functional env to tox
This patch set adds functional environment to tox
to be able to create post_hook file for functional gate.

Change-Id: I8e918fe47f6008b9570e39c2d0e9159d0d223362
2017-01-23 18:58:43 +03:00
Jenkins
cec8ee4f15 Merge "Add functional tests to watcherclient" 2017-01-19 14:54:54 +00:00
Jenkins
4713a69a18 Merge "Support parents field along with planner changes" 2017-01-19 14:19:12 +00:00
Jenkins
22bc9a97c9 Merge "Updated from global requirements" 2017-01-17 16:12:11 +00:00
licanwei
11e3568d66 update '--detail' help in goal list
help=_("Show detailed information about metric collectors."))
==>
help=_("Show detailed information about each goal."))

Change-Id: If6bf750a6a7941524dd144430abcc48b9f44a9d3
2017-01-17 16:49:19 +08:00
OpenStack Proposal Bot
96ef016b81 Updated from global requirements
Change-Id: I6239c242d4ab23ec885556daddc45d0f97b8234c
2017-01-16 17:28:36 +00:00
Alexander Chadin
c0f6ea54f6 Add functional tests to watcherclient
This Patch Set implements functional tests for
watcherclient to cover all use cases of watcher objects.

Implements : blueprint tempest-cli-test
Change-Id: I920d5b1ae25c62a72d3474538f866a5415c2e119
2017-01-16 17:08:27 +00:00
Alexander Chadin
b8666d511e Support parents field along with planner changes
This patch set allows python-watcherclient to show
parents field instead of next_uuid field.

Partially Implements: blueprint planner-storage-action-plan
Change-Id: I00cefd2ba6dad5daa6470c851c2fdfb7c22d7a63
Depends-On: Ide2c8fc521488e486eac8f9f89d3f808ccf4b4d7
2017-01-16 20:05:10 +03:00
Jenkins
4a093e168d Merge "Enable coverage report in console output" 2017-01-16 11:09:11 +00:00
Jenkins
1fa93eeb8f Merge "Add auto_trigger support" 2017-01-16 10:18:55 +00:00
Jenkins
d36f2de07e Merge "Add param 'goal' and 'strategy' in list()" 2017-01-13 16:38:00 +00:00
Jenkins
d17bc25fef Merge "Use keystoneauth instead of keystoneclient" 2017-01-13 15:06:21 +00:00
Lucky samadhiya
075b32efe2 changes to make consistent with other openstack component
Change-Id: I4a530ff7912f129823783c742f906d769965872e
2017-01-13 10:10:01 +00:00
Jeremy Liu
a2cbb8d4b2 Use keystoneauth instead of keystoneclient
keystoneauth was extracted from keystoneclient, this CR replaces usage
of keystoneclient in favor of keystoneauth.

Implements: blueprint use-keystoneauth-instead-of-keystoneclient
Change-Id: Iada0f8b45ae30a89908a4ae9e5f55a33e3744e17
2017-01-13 16:14:33 +08:00
Jeremy Liu
ecfa35ecc2 Remove unused files
`MANIFEST.in` was used to handle git files but now pbr can do it instead.
`openstack-common.conf` was used to copy files from oslo-incubator, but
oslo-incubator is no longer maintained. So delete the two files from repo.

Change-Id: I976434e8283c588191d7bfb9321f46cea724406a
2017-01-13 14:39:04 +08:00
Jeremy Liu
546d03c3aa Enable coverage report in console output
Change-Id: I861dbe49eb888e9c51a0c649dffde4479f19ee67
2017-01-13 10:51:12 +08:00
licanwei
3a04f9fb9a Add param 'goal' and 'strategy' in list()
watcher  audit list --goal dummy
list() got an unexpected keyword argument 'goal'

watcher  audit list --strategy dummy
list() got an unexpected keyword argument 'strategy'

Change-Id: Iba4b89da1669f07002718c885107ee3813ca676a
Closes-Bug: #1654962
2017-01-12 11:54:56 +08:00
DeepaJon
17a144e2f8 Removes unnecessary utf-8 encoding
This patches removes unnecessary utf-8 encoding in the
watcherclient/*
doc/source/conf.py

Change-Id: Ic74c9c57f52f7bf021dfa25d4de069b57e5cb474
2017-01-11 14:23:40 +05:30
licanwei
658fd038f3 update audit create '--interval' description
update audit create '--interval' description

Change-Id: I03779a8fe446c051397f02cfb2d73bda804706fe
2017-01-10 18:02:55 +01:00
Jenkins
d2aede7151 Merge "Fix a typo in audittemplate help" 2017-01-10 16:29:41 +00:00
Jenkins
de54d5b8ba Merge "Add unit for continuous audit's interval." 2017-01-10 16:27:10 +00:00
Jenkins
ae003b7e76 Merge "use 'auto' instead of None" 2017-01-10 16:27:01 +00:00
ericxiett
d08c0e3ef1 Add unit for continuous audit's interval.
End user does not get the unit of 'interval' when use command
``watcher audit create -h``. This patch adds unit for the option
'interval'. Aslo use single quotes.

Change-Id: I9e3df031822f2f2704a3c661c6a5953d7e0caae5
Closes-Bug: #1653322
2017-01-03 08:07:10 +08:00
licanwei
c68120edcd Fix a typo in audittemplate help
'Descrition'->'Description'

Change-Id: Ie1f06f14a06e27c52b41b1d8c7da1f160212288d
2016-12-26 10:29:02 +08:00
licanwei
bf7085fabd use 'auto' instead of None
In cli cmds:watcher audit create,
the Strategy is None if no --strategy
It's better to use default instead of None
watcher audit create -g thermal_optimization
+-------------+--------------------------------------+
| Field       | Value                                |
+-------------+--------------------------------------+
| UUID        | 2bc3001d-683a-48ee-b2f2-766cb8d6329e |
| Created At  | 2016-12-22T08:41:21.173601+00:00     |
| Updated At  | None                                 |
| Deleted At  | None                                 |
| State       | PENDING                              |
| Audit Type  | ONESHOT                              |
| Parameters  | {}                                   |
| Interval    | None                                 |
| Goal        | thermal_optimization                 |
| Strategy    | None                                 |
| Audit Scope | []                                   |
+-------------+--------------------------------------+

Change-Id: I5798df81303c425ed0e26e401589e6680b945bf6
2016-12-22 17:52:29 +08:00
Jenkins
ef93a57b46 Merge "too many digits after the decimal point" 2016-12-19 11:03:17 +00:00
Alexander Chadin
6e291f0f13 Add auto_trigger support
This patch set adds support of auto-triggering for action plans.
You can use it by adding new attribute '--auto-trigger' to
watcher audit create command.

Change-Id: I2e4ee53f9f639cb3248c0e4dcc7b9716ff1fc352
Partially-Implements: blueprint automatic-triggering-audit
Depends-On: I36b7dff8eab5f6ebb18f6f4e752cf4b263456293
2016-12-16 17:01:46 +00:00
Jenkins
73dcf25b63 Merge "Replace six.iteritems() with .items()" 2016-12-16 16:34:15 +00:00
zhangguoqing
0ecafcd6a0 Fix TOKENID format which should without dashed
[1] is wrong amendment which had change the TOKENID's format.
Since [2] had been merged, this patch fix the format without dashed.

[1] https://review.openstack.org/#/c/399359/1/watcherclient/tests/keystone_client_fixtures.py
[2] https://review.openstack.org/#/c/398788

Change-Id: I80b953cbf31e2b09160f0b55ffe48eea845c2dd4
2016-12-15 14:40:21 +00:00
licanwei
529f406075 too many digits after the decimal point
'global_efficacy' field print too many digits
 after the decimal point.
 for example 14.2857142857 %
 two digits are enough
 for example 14.29%

Closes-Bug: #1650159

Change-Id: I4af3ef5b250d7e0b921269cc91ec46978d090c10
2016-12-15 09:08:34 +00:00
Antoine Cabot
b66834506a Remove readme reference because of sphinx error
Change-Id: Ide4b84131fd516ae4784dab9673354c5bab0968a
Closes-Bug: #1650173
2016-12-15 09:42:46 +01:00
gengchc2
5b8e3d4d6c Replace six.iteritems() with .items()
1.As mentioned in [1], we should avoid using
six.iteritems to achieve iterators. We can
use dict.items instead, as it will return
iterators in PY3 as well. And dict.items/keys
will more readable. 2.In py2, the performance
about list should be negligible, see the link [2].
[1] https://wiki.openstack.org/wiki/Python3
[2] http://lists.openstack.org/pipermail/openstack-dev/2015-June/066391.html

Change-Id: Ic6af69d5b4b36f3dd02aab0f9c446aa54970f388
2016-12-09 11:31:24 +08:00
OpenStack Proposal Bot
fce4e7e10c Updated from global requirements
Change-Id: Ifc867f3be4b569c6ec9a5fce1149d949bce09685
2016-12-02 17:18:38 +00:00
Flavio Percoco
8004b4ec0b Show team and repo badges on README
This patch adds the team's and repository's badges to the README file.
The motivation behind this is to communicate the project status and
features at first glance.

For more information about this effort, please read this email thread:

http://lists.openstack.org/pipermail/openstack-dev/2016-October/105562.html

To see an example of how this would look like check:

https://gist.github.com/f8cdc5cce16393ddd9885f99ad05a610

Change-Id: I58f89eb319919a824fea21961b4338e2d1132f6e
2016-11-25 17:23:24 +01:00
OpenStack Proposal Bot
0584350663 Updated from global requirements
Change-Id: I98b97ab69a726f1634f6c96274d02cde60b064c2
2016-11-18 21:33:33 +00:00
qinchunhua
ccef7be62c Use uuidutils instead of uuid.uuid4()
Openstack common has a wrapper for generating uuids.
We should only use that function when generating
uuids for consistency.

Change-Id: Ic36426c6ab4228826b66a926e74e3331e9a9abdc
Closes-Bug: #1082248
2016-11-18 11:27:48 +08:00
Jenkins
d960977c96 Merge "Remove unnecessary ')'" 2016-11-16 21:15:25 +00:00
OpenStack Proposal Bot
51b295c21c Updated from global requirements
Change-Id: Ib24775ef8844c56b64d1b8b2fea30eb69f252135
2016-11-14 15:13:17 +00:00
Jenkins
e3478de41d Merge "Fix a typo error in a help message in the client" 2016-11-14 13:54:30 +00:00
David.T
c8bf47d72d Remove obsolete object attributes
As we are about to version the Watcher objects, we need to make sure
that upcoming model/object modifications are additive in order to
avoid having to bump the major version of the API. Therefore,
this changeset removes 2 unused DB fields: extra in Audit Template
object and deadline in Audit object.

Change-Id: Ib9750d2dee8b565bd837341f826999b64c4e2cc3
Partially-Implements: blueprint watcher-versioned-objects
2016-11-14 10:03:37 +00:00
Tin Lam
c83499e85f Fix a typo error in a help message in the client
In the class UpdateAuditTemplate, there is a help message with an extra
')'.  This patch set removes that extra ')'.

Change-Id: I1463144e38ebb5db59f49a94406ff884f0e2450b
Closes-Bug: #1639681
2016-11-10 12:45:04 -06:00
Jenkins
28acfe1535 Merge "Updated from global requirements" 2016-11-08 12:55:57 +00:00
OpenStack Proposal Bot
9edd6afa28 Updated from global requirements
Change-Id: I330f1fe0daa0431d47719268cf2c4c92e89387e1
2016-11-06 02:07:40 +00:00
caihui
9923b51944 Remove unnecessary ')'
Change-Id: Ia16cfe517cbd4511fb29b32e4ce9f2cc42151dc4
2016-11-04 14:27:03 +08:00
Tony Xu
7dfcdba21e Add Python 3.5 classifier and venv
Now that there is a passing gate job, we can claim
support for Python 3.5 in the classifier.
This patch also adds the convenience py35 venv.

Change-Id: I2ed2d7c62c32df6593ae7b1e00da92fb56d391c6
2016-10-26 10:36:54 +08:00
gecong1973
dfdee212cc Add __ne__ built-in function
In Python 3 __ne__ by default delegates to __eq__ and inverts the
result, but in Python 2 they urge you to define __ne__ when you
define __eq__ for it to work properly [1].There are no implied
relationships among the comparison operators. The truth of x==y
does not imply that x!=y is false. Accordingly, when defining __eq__(),
one should also define __ne__() so that the operators will behave as
expected.
[1]https://docs.python.org/2/reference/datamodel.html#object.__ne__

Change-Id: I6b43b9ac33b4f6e6331b390366e68f2a5bbb997c
2016-10-17 09:02:05 +08:00
Jenkins
50af3b6bb8 Merge "Add support for Audit Scope" 2016-10-14 14:59:55 +00:00
OpenStack Proposal Bot
494b2ecc88 Updated from global requirements
Change-Id: I13491acd6fe8a7c2c9dcf4211769daaf58190ff3
2016-10-13 05:28:46 +00:00
Jenkins
d109e9d9a0 Merge "Add service support" 2016-10-12 12:48:46 +00:00
Alexander Chadin
c185f32ebb Add support for Audit Scope
This patch set adds audit scope support in python-watcherclient.

Change-Id: I2a94320bec0fd7051a38bee1c872148e39f69d0c
Partially-Implements: blueprint define-the-audit-scope
2016-10-07 12:30:44 +03:00
Jenkins
11056302b4 Merge "Add parameters in Audit creation attributes list" 2016-10-06 09:07:34 +00:00
David.T
466131e788 Add parameters in Audit creation attributes list
Change-Id: Ib4371223af76d20de2f6d019b73164058f1b4e89
Closes-Bug: #1617320
2016-10-05 17:18:20 +02:00
OpenStack Proposal Bot
c88551435d Updated from global requirements
Change-Id: I5e9d875b0049ae3d9fc0d2dde6943db0c2d84730
2016-10-04 14:02:54 +00:00
Jenkins
77d282e452 Merge "Added support for Client creation from KS session" 2016-10-04 08:08:06 +00:00
Vincent Francoise
940a7093e6 Added support for Client creation from KS session
In this changeset, I refactored some of the code to now support
the creation of a watcher client using a Keystone session as it was
already possible in most other OS projects.

Change-Id: I3462daeaac9103138366a0fcaa2fc46729bbd8ce
Related-Bug: #1625643
Closes-Bug: #1623070
2016-09-28 17:54:29 +02:00
OpenStack Proposal Bot
0c0f6cb079 Updated from global requirements
Change-Id: I5c16b623d05241e2744d89160322c5e4c3d08c2d
2016-09-27 10:08:00 +00:00
Jenkins
9c3440df44 Merge "Add constraint target to tox.ini and remove 1 dep" 2016-09-26 09:39:54 +00:00
Tony Xu
f50df0dc74 Add fixtures to test-requirements
Closes-Bug: #1626372
Change-Id: I671a925f36e3d177f55036766e6792bc87ab58a0
2016-09-22 17:38:14 +08:00
David.T
abf3257e1c Add constraint target to tox.ini and remove 1 dep
This adds a pip install command to tox.ini that is only used when the
tox env is passed with the 'constraints' factor appended onto it.
As such this will not effect developer workflows or current unit tests.

The initial use of this will be in a non-voting job, to verify that the
constrained checks with tox are stable.  DevStack is already running
constrained jobs, as such problems are no expected.

To run a tox with pip using constraints on a developer system a
developer should run the desired tox environment with -constraints.
For example: $(tox -epy27-constraints)
Pip will pull the current version of the upper-constraints.txt file down
from the git.openstack.org, however this method can be overriden to use
a local file setting the environment variable "UPPER_CONSTRAINTS_FILE"
to the local path or a different URL, it is passed directly to pip.

This is currently not enabled in the default tox run, however it is
possible to enable it as a default by adding it to 'envlist' in tox.ini

This also removes requirements.txt from tox.ini deps
This is redundant, per lifeless email:
http://lists.openstack.org/pipermail/openstack-dev/2015-July/069663.html

Change-Id: Id953a99cf2f83533a38a03f9934f4ec818bec03f
2016-09-21 12:15:05 +02:00
Alexander Chadin
4e86151f81 Add service support
This patch set adds service support to watcherclient.
There is two new commands:
1. service list
2. service show

Change-Id: I669fd69ca7e854f8f576a017447ef003c6cf3d3b
Partially-Implements: blueprint watcher-service-list
2016-09-21 10:31:15 +03:00
David.T
a48a9213f0 python-openstackclient ClientManager interface changed
I update the watcher client plugin to correctly used ClientManager
auth parameters

Change-Id: Ie2e4db3b63ea1671147a407480ce0d2569d5b057
Closes-bug: #1625643
2016-09-20 16:17:49 +02:00
avnish
ad4ee3fcc7 Update home page link in cfg file
Change-Id: I4630862bc2e7cd64f158173fdf05af5a054afd92
2016-09-20 08:30:18 +05:30
Cao Xuan Hoang
4df180fc1f Clean imports in code
This patch set modifies lines which are importing objects
instead of modules. As per openstack import guide lines, user should
import modules in a file not objects.

http://docs.openstack.org/developer/hacking/#imports

Change-Id: I17e692108c058ba393eb2a81b8814f879956a991
2016-09-06 10:58:04 +07:00
Jenkins
465d0d46a3 Merge "Add again parameters as Audit creation attributes" 2016-08-26 16:24:31 +00:00
David.T
6e858233dc Add again parameters as Audit creation attributes
'parameters' option for audit creation was removed due to
a bad merge conflict resolution.

Change-Id: I37848ca7c1e8d6cd03996a5a81471edd9802b673
Closes-Bug: #1617320
2016-08-26 16:02:42 +02:00
Jenkins
522bc4374a Merge "Add strategy name in action plan fields" 2016-08-26 09:53:58 +00:00
OpenStack Proposal Bot
c2b5eea3fb Updated from global requirements
Change-Id: I586e71238ca36d93f882acf7757208a26b094e8a
2016-08-25 01:11:54 +00:00
David.T
824017fa1f Add strategy name in action plan fields
Command 'actionplan show' will display associated strategy
name of the action plan.

Depends-On: I95d2739eb552d4a7a02c822b11844591008f648e
Partially Implements: blueprint efficacy-indicator

Change-Id: Ic1674a53373909bcae06e017fc5e2c53aa8df14a
2016-08-19 12:03:51 +02:00
OpenStack Proposal Bot
545f153bba Updated from global requirements
Change-Id: I219ac296553f8134fb69cf280f5c5523994760da
2016-08-18 12:40:48 +00:00
licanwei
008b50ea67 remove redundant ')'
There is more one ')' in the class UpdateAudit
help=_("Operation: 'add'), 'replace', or 'remove'."))

Change-Id: Ifdce30981fd63f3fb95520c49740b4bf67c23778
2016-08-15 15:29:05 +08:00
Jenkins
b836d83bc2 Merge "Add goal_id, strategy_id and host_aggregate CLI options to audit" 2016-08-04 16:07:40 +00:00
Prashanth Hari
6fbcfc794a Add goal_id, strategy_id and host_aggregate CLI options to audit
Add goal_id, strategy_id and host_aggregate CLI options to audit
so that an audit doesn't lose important information when an audit
template is deleted. Also, user can input a specific strategy to
accomplish a goal for an audit.

Partially-Implements: blueprint persistent-audit-parameters
Depends-On: I7b3eae4d0752a11208f5f92ee13ab1018d8521ad
Change-Id: Ied1da980f358343316ee726b0781188107bfba8d
2016-08-04 14:09:44 +00:00
zte-hanrong
aa90c536b3 Optimiz the help information for audit type parameter.
I want to create a audit from audit template, I don't know correct
audit type value I can use. So I optimize the help information for
audit create shell command.

Change-Id: Idee3bb2e62c9cdb9bf70cced4acbc4df4f8a968c
2016-08-04 16:41:51 +08:00
OpenStack Proposal Bot
9c32e6e6dc Updated from global requirements
Change-Id: I87e27feb5e84a5676f4316f655ebdae74e4f4542
2016-08-03 09:07:50 +00:00
Tomasz Kaczynski
7b55f92e11 Add scoring engine commands
Scoring Module is exposing information about scoring engines
through API. Additional commands make them available in CLI as well.

Partially-Implements: blueprint scoring-module
Change-Id: I6dae5617fdbd6917ce35741e62a2217e19dce510
Depends-On: I32168adeaf34fd12a731204c5b58fe68434ad087
2016-08-01 14:22:34 +00:00
Swapnil Kulkarni (coolsvap)
daa4a88447 Remove discover from test-requirements
It's only needed for python < 2.7 which is not supported

Change-Id: I4675fbf6eebc35dc2ea8dd0134dbca3a19af6ba5
2016-07-21 15:38:09 +00:00
OpenStack Proposal Bot
776a251d98 Updated from global requirements
Change-Id: Ife71cebe2866b55874c123366773871a78b9a67c
2016-07-21 04:10:51 +00:00
OpenStack Proposal Bot
613810e43c Updated from global requirements
Change-Id: I0b9abd912e1aa4e5afc0cf7bc842e5d2334e3366
2016-07-19 21:14:40 +00:00
Jenkins
df8997129e Merge "Updated from global requirements" 2016-07-19 19:40:48 +00:00
Alexandr Stavitskiy
e2586130e1 Fix for importing osc-lib instead openstackclient
This patch set stop importing from the python-openstackclient and
start importing from osc-lib.

Change-Id: I6e4000565e48467f3e32a9cc408ab8a04b9c5f8a
Closes-Bug: #1604047
2016-07-19 18:52:42 +03:00
OpenStack Proposal Bot
ea455477a0 Updated from global requirements
Change-Id: I716998ec31b06f3907140f464664a80f4fad6753
2016-07-13 17:22:48 +00:00
Alexandr Stavitskiy
5b914e8877 Fix for error importing of exception class
This patch set fixes error while importing of ConnectionRefused
exception class.

Change-Id: I4aee677ccc25334ba9bd12633b1c487db2b1dd3e
Closes-Bug: #1602214
2016-07-12 16:12:04 +03:00
Vladimir Ostroverkhov
918d2f0bbd Add support continuously-optimization
This patch set adds support for interval
field to python-watcherclient

Depends-On: I5f4ec97b2082c8a6b3ccebe36b2a343fa4a67d19
Implements: blueprint continuously-optimization

Change-Id: I1152c9c6d9379e250ba46adbc58789d8b13bfd5a
2016-07-12 07:20:28 +00:00
hongzhezheng
91d1d8b0e1 Remove the blank space between the function name and the parenthesis.
TrivialFix

Change-Id: I73e659d2cf30a2878767a9362d3671bdd06c0513
2016-07-12 15:23:37 +08:00
PanFengyun
3ffe4869f3 Prints '-' instead of 'None' when data is None
Client prints 'None' when data is None , and client also prints
'None' when data is a string 'None'. But string 'None' is  different
to None. To clear the confusion, Client should print '-' instead of
'None' when data is None. Nova Client and Cinder Client has cleared
the confusion.

Change-Id: I6a8908fcb2df39d7f2c5fc4055cc41779d668d6c
2016-07-10 19:29:01 +08:00
Edwin Zhai
bde259e38c Enable strategy parameter
Print strategy parameter spec and add new cmd line for parameters
input

Partially-implements: optimization-threshold

Change-Id: If2b8976c6d504754d9db46bb77d3c4ce04b1e2cf
2016-07-07 11:14:56 +02:00
digambar
75dd8dc561 Fix field type to audit_type
There's a number of places where a field of an object is named "type",
which isn't good thing. Actually type is keyword in python, so wherever
I found type used in models/api/object/test, I have fixed it to
audit_type in the audit files

Change-Id: Ic09458b455820787f5483e48aed940a2196b297e
Closes-Bug: #1533392
2016-07-06 21:55:53 +05:30
Daniel Pawlik
a6aed1772d Add license file
License file is the same as in Watcher project.

Change-Id: I4d20e5c269298b60ac9c169c996cd92b24fc502f
2016-07-04 18:04:10 +00:00
OpenStack Proposal Bot
63a1039fb2 Updated from global requirements
Change-Id: I499eefd614f64eb6bd167aa93ecbe892b78d297e
2016-06-30 18:50:11 +00:00
Chihiro Yokoyama
9d3a6c51b1 Remove tempest-lib
tempest-lib is still referenced in test-requirements.txt
although it is deprecated and also unused.

Change-Id: I13796eb7fc6360cac5f0898ebc8dbb8515dc6733
Closes-Bug: #1590867
2016-06-27 09:53:21 +00:00
OpenStack Proposal Bot
8bcdf13d7f Updated from global requirements
Change-Id: I0c1760cdfcea5c85031a08dd9631aaa54880842f
2016-06-23 15:38:14 +00:00
Edwin Zhai
f9fb0875e0 Revert "Add support continuously-optimization"
This reverts commit 888a58fd2a.
Will restore it once related changes in watcher get merged.

Change-Id: Icdde1678598867c5e1ce68c8bd4c189f7a37bedc
Closes-Bug: #1595368
2016-06-23 02:36:39 +00:00
Vladimir Ostroverkhov
d36d835d08 Replaced UUID of goal with name
This patch updated the CLI to display the name of the goal
associated to an strategy (instead UUID).
Related-Bug: #1590416.

Change-Id: Ia8bd0c18d63461da2336a690364f034d0f7f2343
2016-06-20 11:24:34 +03:00
Jenkins
20931e2ce7 Merge "Updated CLI to display efficacy related fields" 2016-06-15 08:59:32 +00:00
Jenkins
fb84ae9b25 Merge "Add support continuously-optimization" 2016-06-13 12:05:08 +00:00
Antoine Cabot
e64e597aa6 Remove useless index on root doc page
Change-Id: I37a882cd6725220d7fe99604f067030d50aed019
2016-06-10 10:47:22 +02:00
Vincent Francoise
f9aac4fc9f Updated CLI to display efficacy related fields
In this changeset, I updated the CLI as followed:

- The 'efficacy_specification' field is now shown by the
  'goal list --detail' and the 'goal show <goal>' subcommands.
- Both the 'global_efficacy' and the 'efficacy_indicators' fields
  are now displayed when issuing 'actionplan list --detail' or
  'actionplan show <action_plan_uuid>'.

Change-Id: I47462d0af92318773ec9284828180b62166ca936
Partially-Implements: blueprint efficacy-indicator
2016-06-08 15:03:17 +02:00
OpenStack Proposal Bot
0f276e483b Updated from global requirements
Change-Id: Ic2ef241b1026929ba8af14ca4b3a1322a9c4cdfd
2016-06-01 13:54:46 +00:00
Vladimir Ostroverkhov
888a58fd2a Add support continuously-optimization
This patch set adds support for period
field to python-watcherclient

Change-Id: I777429f9d2d596bea506664e8614da7e78a31904
Implements: blueprint continuously-optimization
2016-05-27 18:29:21 +03:00
David.T
89cfc55870 Update Watcher CLI documentation
I updated, in this patchset, some examples of wacher CLI, because
option format has changed (we have no more '-' character in
keywords)
I added a new page for the openstack client + our watcher plugin.

Change-Id: Ia2ae148e4357eb64c8e3df1f3036dc992e85714c
2016-05-27 08:19:17 +00:00
David.T
4c19084cb1 Use goal name as strategy list filter
In this changeset, I updated the CLI to be able to use now
the goal name as a filter parameter of the command
strategy list.

Change-Id: I507bb1c37c845f56db537735f00a6d82a696908e
Partial-Bug: #1573582
2016-05-27 10:04:07 +02:00
Vincent Francoise
bc572e70dc Replaced UUID of goal and strategy with name
In this changeset, I updated the CLI to now display the names of
the goal and strategy associated to an audit template
(instead of their UUIDs).

Change-Id: I57e83f23ed2240048d8ef07a629aec6ef13970e8
Closes-Bug: #1573582
2016-05-26 12:54:39 +02:00
Vincent Francoise
544db1951f Flatten the project structure
In this changeset, I flattened the project structure by removing
the 'osc' package as it is now shared by both the OSC plugin and by
the 'watcher' command.

Closes-Bug: #1570467
Partially Implements: blueprint openstackclient-plugin

Change-Id: I867fd23c3a27cfc925dcc28f8dd158cb690c5659
2016-05-24 17:47:47 +02:00
Vincent Francoise
1b14be868e Switch Watcher CLI to an OSC-compatible version
In this changeset, I switched the watcher command line to now use
the OpenStackClient code to avoid code duplication.

Partially Implements: blueprint openstackclient-plugin

Change-Id: I2e0df6a96f4c7c59d33b92c01962f65129bfc7cc
2016-05-24 15:50:11 +02:00
Vincent Francoise
e8236aaf65 OpenStackClient plugin for action
In this changeset, I implemented the 'action' commands.

Partially Implements: blueprint openstackclient-plugin

Change-Id: I3e454d4bb13a392a96787cce3eddcfa7aec4c9e8
2016-05-24 15:50:10 +02:00
Vincent Francoise
0260775f30 OpenStackClient plugin for action plan
In this changeset, I implemented the 'actionplan' commands.

Partially Implements: blueprint openstackclient-plugin

Change-Id: I932321b75981a35a20abd749cfdbe793a52416d7
2016-05-24 15:49:35 +02:00
Vincent Francoise
3b79b58f68 OpenStackClient plugin for audit
In this changeset, I implemented the 'audit' commands.

Partially Implements: blueprint openstackclient-plugin

Change-Id: I49693a8e5715952415b416815d9bec09cff22517
2016-05-24 15:49:12 +02:00
Vincent Francoise
d9c558107e OpenStackClient plugin for audit template
In this changeset, I implemented the 'audittemplate' commands.

Partially Implements: blueprint openstackclient-plugin

Change-Id: I2dc2963c21a6bb05d67122e0c1ba2f6fed9b401a
2016-05-24 15:48:14 +02:00
Vincent Francoise
0be6832e6b OpenStackClient plugin for strategy
In this changeset, I implemented the 'strategy' commands.

Partially Implements: blueprint openstackclient-plugin

Change-Id: I3b2db3d2820961ae9c946ec4c8088bf7c503a433
2016-05-24 15:47:46 +02:00
Vincent Francoise
5586bbdff3 OpenStackClient plugin for goal
In this changeset, I implemented the OpenStackClient plugin which
allows Watcher to be used via the "openstack" unified CLI.

Partially Implements: blueprint openstackclient-plugin

Change-Id: I1e0a3830eb15a9bd5014bbbf45962627d21fe7fa
2016-05-24 15:47:11 +02:00
Vincent Francoise
cbc578998a Tidy up
In this changeset, I do some tidy up so I can later on make it
easier to refactor the lot.

Partially Implements: blueprint openstackclient-plugin

Change-Id: I566101fb951b9489481a3e6c1a4008c80b14f6fd
2016-05-24 15:45:12 +02:00
Dougal Matthews
94af770a6d Use the correct capitalization of OpenStack
Change-Id: I97387a8fdfe3870e5a7548a027906e5a43dd353b
2016-05-18 11:47:56 +01:00
Vincent Francoise
d2c22f0353 Support for refactored /audit_templates endpoint
In this changeset, I updated the Watcher CLI to support the new
goal_uuid and strategy_uuid fields that were introduced.

Partially Implements: blueprint get-goal-from-strategy

Change-Id: I27b239361dd7df7e18d996e31da64d9477d172cc
2016-05-12 12:02:05 +00:00
Vincent Francoise
c5a5b7dad7 Added Strategy support in Watcher CLI
In this changeset, I add the support for the /strategies endpoint.

Partially Implements: blueprint get-goal-from-strategy

Change-Id: I63dbbaefee18e7ae6db180478aae89ac4c09d2cc
2016-05-12 12:01:41 +00:00
Vincent Francoise
e6ca4e54a7 Updated CLI for new /goals API
In this changeset I added the support for the refactored /goals API.

Partially Implements: blueprint get-goal-from-strategy

Change-Id: Idbf8ced7ad9fbe6246e27791890e9b6a3ec0dc9c
2016-05-12 10:03:20 +00:00
David.T
e0d1e5facf Add PrettyTable module
This package was previously imported by a keystoneclient package.
but that is no longer true.

Change-Id: I9b1933de3c57566596d780ce4f2fcb9adf05680b
2016-05-12 11:25:07 +02:00
Vincent Francoise
35c4e93a09 Fixed audit creation bug in CLI
This changeset fixes the issue with the audit creation.

Change-Id: Ic1fd34f1f1db0e45e205a2d19b5d3538efe89925
Closes-Bug: #1573686
2016-04-22 18:13:49 +02:00
Jenkins
567b74ad0a Merge "Add audit-template name checking in CLI" 2016-04-19 09:00:37 +00:00
Larry Rensing
f306a61ece Removed unused 'alarm' field
The 'alarm' field is currently unused, so it has been removed.

Change-Id: I5262dbf65f730ef6974f76186f26e26e3b69a677
Closes-Bug: #1550261
2016-04-18 15:16:00 +00:00
Alexander Chadin
0aaaf13278 Add audit-template name checking in CLI
This patch set allows to send audit_template_uuid as uuid type only.
If audit_template argument given as name, watcherclient will send request
to get audit template uuid.

Change-Id: Idf5f07ca08f2e5d871dc2163c32fbda9ed338a99
Related-Bug: #1532843
2016-04-14 16:13:07 +03:00
OpenStack Proposal Bot
e17dbab7c6 Updated from global requirements
Change-Id: Ib088ed427674d30d52ca1b28fc11647147beef78
2016-04-13 12:48:52 +00:00
160 changed files with 9438 additions and 4592 deletions

11
.coveragerc Normal file
View File

@@ -0,0 +1,11 @@
[run]
branch = True
source = watcherclient
omit =
watcherclient/tests/*
[report]
ignore_errors = True
exclude_lines =
@abc.abstract
raise NotImplementedError

14
.gitignore vendored
View File

@@ -6,6 +6,7 @@
# Packages
*.egg
*.egg-info
.eggs
dist
build
eggs
@@ -22,11 +23,12 @@ lib64
pip-log.txt
# Unit test / coverage reports
.coverage
.coverage*
.tox
nosetests.xml
.testrepository
.stestr/
.venv
.testrepository/
# Translations
*.mo
@@ -42,6 +44,7 @@ output/*/index.html
# Sphinx
doc/build
doc/source/reference/api
# pbr generates these
AUTHORS
@@ -54,3 +57,10 @@ ChangeLog
sftp-config.json
/.idea/
/cover/
# Desktop Service Store
*.DS_Store
# Atom
.remote-sync.json

View File

@@ -1,4 +1,5 @@
[gerrit]
host=review.openstack.org
host=review.opendev.org
port=29418
project=openstack/python-watcherclient.git
defaultbranch=unmaintained/zed

3
.stestr.conf Normal file
View File

@@ -0,0 +1,3 @@
[DEFAULT]
test_path=./watcherclient/tests/unit
top_dir=./

View File

@@ -1,7 +0,0 @@
[DEFAULT]
test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \
OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \
OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-10} \
${PYTHON:-python} -m subunit.run discover -t ./ . $LISTOPT $IDOPTION
test_id_option=--load-list $IDFILE
test_list_option=--list

10
.zuul.yaml Normal file
View File

@@ -0,0 +1,10 @@
- project:
templates:
- openstack-cover-jobs
- openstack-python3-zed-jobs
- publish-openstack-docs-pti
- check-requirements
- openstackclient-plugin-jobs
check:
jobs:
- watcherclient-tempest-functional

View File

@@ -1,13 +1,13 @@
If you would like to contribute to the development of OpenStack,
you must follow the steps in this page:
http://docs.openstack.org/infra/manual/developers.html
https://docs.openstack.org/infra/manual/developers.html
Once those steps have been completed, changes to OpenStack
should be submitted for review via the Gerrit tool, following
the workflow documented at:
http://docs.openstack.org/infra/manual/developers.html#development-workflow
https://docs.openstack.org/infra/manual/developers.html#development-workflow
Pull requests submitted through GitHub will be ignored.

View File

@@ -1,4 +1,4 @@
python-watcherclient Style Commandments
=======================================
Read the OpenStack Style Commandments http://docs.openstack.org/developer/hacking/
Read the OpenStack Style Commandments https://docs.openstack.org/hacking/latest/

176
LICENSE Normal file
View File

@@ -0,0 +1,176 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.

View File

@@ -1,6 +0,0 @@
include AUTHORS
include ChangeLog
exclude .gitignore
exclude .gitreview
global-exclude *.pyc

View File

@@ -1,3 +1,12 @@
========================
Team and repository tags
========================
.. image:: https://governance.openstack.org/tc/badges/python-watcherclient.svg
:target: https://governance.openstack.org/tc/reference/tags/index.html
.. Change things from this point on
====================
python-watcherclient
====================
@@ -11,12 +20,12 @@ metrics receiver, complex event processor and profiler, optimization processor
and an action plan applier. This provides a robust framework to realize a wide
range of cloud optimization goals, including the reduction of data center
operating costs, increased system performance via intelligent virtual machine
migration, increased energy efficiency-and more!
migration, increased energy efficiency and more!
* Free software: Apache license
* Wiki: http://wiki.openstack.org/wiki/Watcher
* Source: http://git.openstack.org/cgit/openstack/python-watcher
* Bugs: http://bugs.launchpad.net/watcher
* Wiki: https://wiki.openstack.org/wiki/Watcher
* Source: https://opendev.org/openstack/python-watcherclient
* Bugs: https://bugs.launchpad.net/watcher
Installation
============
@@ -49,13 +58,21 @@ You can install the Watcher CLI with the following command:
.. code::
pip install python-watcherclient
sudo pip install python-watcherclient
You can also use the `OpenStack client <https://docs.openstack.org/python-openstackclient/latest/>`_
with Watcher (our watcher plugin for OpenStack client is included in the
python-watcherclient package). To install it, you have just to run this command:
.. code::
sudo pip install python-openstackclient
Configuration
=============
Create a **creds** file containing your Openstack credentials:
Create a **creds** file containing your OpenStack credentials:
.. code::
@@ -73,31 +90,48 @@ Source these credentials into your current shell session:
# source creds
You should be able to launch the following command which gets the list of previously created Audit Templates:
You should be able to launch the following command which gets the list of
previously created Audit Templates:
.. code::
# watcher audit-template-list
+------+------+
| UUID | Name |
+------+------+
+------+------+
# watcher audittemplate list
You can view the entire list of available Watcher commands and options using this command:
or::
# openstack optimize audittemplate list
+--------------------------------+------+----------------------+----------+
| UUID | Name | Goal | Strategy |
+--------------------------------+------+----------------------+----------+
+--------------------------------+------+----------------------+----------+
You can view the entire list of available Watcher commands and options using
this command:
.. code::
# watcher help
or::
# openstack help optimize
Troubleshootings
================
If any watcher command fails, you can obtain more details with the **--debug** option :
If any watcher command fails, you can obtain more details with the **--debug**
option :
.. code::
# watcher --debug audit-template-list
# watcher --debug audittemplate list
or::
# openstack --debug optimize audittemplate list
Install the openstack CLI :
@@ -105,7 +139,8 @@ Install the openstack CLI :
# pip install python-openstackclient
Make sure that your Openstack credentials are correct. If so, you should be able to verify that the watcher user has been declared in your Openstack keystone :
Make sure that your Openstack credentials are correct. If so, you should be able
to verify that the watcher user has been declared in your Openstack keystone :
.. code::

View File

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

8
doc/requirements.txt Normal file
View File

@@ -0,0 +1,8 @@
# 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
# process, which may cause wedges in the gate later.
openstackdocstheme>=2.2.1 # Apache-2.0
sphinx>=2.0.0,!=2.1.0 # BSD
sphinxcontrib-apidoc>=0.2.0 # BSD

View File

@@ -1,48 +0,0 @@
.. toctree::
:maxdepth: 1
watcherclient.client.rst
watcherclient.common.apiclient.base.rst
watcherclient.common.apiclient.exceptions.rst
watcherclient.common.base.rst
watcherclient.common.cliutils.rst
watcherclient.common.http.rst
watcherclient.common.i18n.rst
watcherclient.common.utils.rst
watcherclient.exceptions.rst
watcherclient.shell.rst
watcherclient.tests.keystone_client_fixtures.rst
watcherclient.tests.test_client.rst
watcherclient.tests.test_http.rst
watcherclient.tests.test_import.rst
watcherclient.tests.test_shell.rst
watcherclient.tests.test_utils.rst
watcherclient.tests.utils.rst
watcherclient.tests.v1.test_action.rst
watcherclient.tests.v1.test_action_plan.rst
watcherclient.tests.v1.test_action_plan_shell.rst
watcherclient.tests.v1.test_action_shell.rst
watcherclient.tests.v1.test_audit.rst
watcherclient.tests.v1.test_audit_shell.rst
watcherclient.tests.v1.test_audit_template.rst
watcherclient.tests.v1.test_audit_template_shell.rst
watcherclient.tests.v1.test_goal.rst
watcherclient.tests.v1.test_goal_shell.rst
watcherclient.tests.v1.test_metric_collector.rst
watcherclient.tests.v1.test_metric_collector_shell.rst
watcherclient.v1.action.rst
watcherclient.v1.action_plan.rst
watcherclient.v1.action_plan_shell.rst
watcherclient.v1.action_shell.rst
watcherclient.v1.audit.rst
watcherclient.v1.audit_shell.rst
watcherclient.v1.audit_template.rst
watcherclient.v1.audit_template_shell.rst
watcherclient.v1.client.rst
watcherclient.v1.goal.rst
watcherclient.v1.goal_shell.rst
watcherclient.v1.metric_collector.rst
watcherclient.v1.metric_collector_shell.rst
watcherclient.v1.resource_fields.rst
watcherclient.v1.shell.rst
watcherclient.version.rst

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.client` Module
======================================
.. automodule:: watcherclient.client
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.common.apiclient.auth` Module
=====================================================
.. automodule:: watcherclient.common.apiclient.auth
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.common.apiclient.base` Module
=====================================================
.. automodule:: watcherclient.common.apiclient.base
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.common.apiclient.client` Module
=======================================================
.. automodule:: watcherclient.common.apiclient.client
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.common.apiclient.exceptions` Module
===========================================================
.. automodule:: watcherclient.common.apiclient.exceptions
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.common.apiclient.utils` Module
======================================================
.. automodule:: watcherclient.common.apiclient.utils
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.common.base` Module
===========================================
.. automodule:: watcherclient.common.base
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.common.cliutils` Module
===============================================
.. automodule:: watcherclient.common.cliutils
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.common.http` Module
===========================================
.. automodule:: watcherclient.common.http
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.common.i18n` Module
===========================================
.. automodule:: watcherclient.common.i18n
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.common.utils` Module
============================================
.. automodule:: watcherclient.common.utils
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.exceptions` Module
==========================================
.. automodule:: watcherclient.exceptions
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.shell` Module
=====================================
.. automodule:: watcherclient.shell
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.tests.keystone_client_fixtures` Module
==============================================================
.. automodule:: watcherclient.tests.keystone_client_fixtures
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.tests.test_client` Module
=================================================
.. automodule:: watcherclient.tests.test_client
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.tests.test_http` Module
===============================================
.. automodule:: watcherclient.tests.test_http
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.tests.test_import` Module
=================================================
.. automodule:: watcherclient.tests.test_import
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.tests.test_shell` Module
================================================
.. automodule:: watcherclient.tests.test_shell
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.tests.test_utils` Module
================================================
.. automodule:: watcherclient.tests.test_utils
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.tests.utils` Module
===========================================
.. automodule:: watcherclient.tests.utils
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.tests.v1.test_action` Module
====================================================
.. automodule:: watcherclient.tests.v1.test_action
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.tests.v1.test_action_plan` Module
=========================================================
.. automodule:: watcherclient.tests.v1.test_action_plan
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.tests.v1.test_action_plan_shell` Module
===============================================================
.. automodule:: watcherclient.tests.v1.test_action_plan_shell
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.tests.v1.test_action_shell` Module
==========================================================
.. automodule:: watcherclient.tests.v1.test_action_shell
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.tests.v1.test_audit` Module
===================================================
.. automodule:: watcherclient.tests.v1.test_audit
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.tests.v1.test_audit_shell` Module
=========================================================
.. automodule:: watcherclient.tests.v1.test_audit_shell
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.tests.v1.test_audit_template` Module
============================================================
.. automodule:: watcherclient.tests.v1.test_audit_template
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.tests.v1.test_audit_template_shell` Module
==================================================================
.. automodule:: watcherclient.tests.v1.test_audit_template_shell
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.tests.v1.test_goal` Module
==================================================
.. automodule:: watcherclient.tests.v1.test_goal
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.tests.v1.test_goal_shell` Module
========================================================
.. automodule:: watcherclient.tests.v1.test_goal_shell
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.tests.v1.test_metric_collector` Module
==============================================================
.. automodule:: watcherclient.tests.v1.test_metric_collector
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.tests.v1.test_metric_collector_shell` Module
====================================================================
.. automodule:: watcherclient.tests.v1.test_metric_collector_shell
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.v1.action` Module
=========================================
.. automodule:: watcherclient.v1.action
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.v1.action_plan` Module
==============================================
.. automodule:: watcherclient.v1.action_plan
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.v1.action_plan_shell` Module
====================================================
.. automodule:: watcherclient.v1.action_plan_shell
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.v1.action_shell` Module
===============================================
.. automodule:: watcherclient.v1.action_shell
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.v1.audit` Module
========================================
.. automodule:: watcherclient.v1.audit
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.v1.audit_shell` Module
==============================================
.. automodule:: watcherclient.v1.audit_shell
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.v1.audit_template` Module
=================================================
.. automodule:: watcherclient.v1.audit_template
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.v1.audit_template_shell` Module
=======================================================
.. automodule:: watcherclient.v1.audit_template_shell
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.v1.client` Module
=========================================
.. automodule:: watcherclient.v1.client
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.v1.goal` Module
=======================================
.. automodule:: watcherclient.v1.goal
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.v1.goal_shell` Module
=============================================
.. automodule:: watcherclient.v1.goal_shell
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.v1.metric_collector` Module
===================================================
.. automodule:: watcherclient.v1.metric_collector
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.v1.metric_collector_shell` Module
=========================================================
.. automodule:: watcherclient.v1.metric_collector_shell
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.v1.resource_fields` Module
==================================================
.. automodule:: watcherclient.v1.resource_fields
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.v1.shell` Module
========================================
.. automodule:: watcherclient.v1.shell
:members:
:undoc-members:
:show-inheritance:

View File

@@ -1,7 +0,0 @@
The :mod:`watcherclient.version` Module
=======================================
.. automodule:: watcherclient.version
:members:
:undoc-members:
:show-inheritance:

1102
doc/source/cli/details.rst Normal file

File diff suppressed because it is too large Load Diff

32
doc/source/cli/index.rst Normal file
View File

@@ -0,0 +1,32 @@
=============================
Command-line Tool Reference
=============================
In order to use the CLI, you must provide your OpenStack username,
password, tenant, and auth endpoint. Use the corresponding
configuration options (``--os-username``, ``--os-password``,
``--os-tenant-id``, and ``--os-auth-url``) or set them in environment
variables::
export OS_USERNAME=user
export OS_PASSWORD=pass
export OS_TENANT_ID=b363706f891f48019483f8bd6503c54b
export OS_AUTH_URL=http://auth.example.com:5000/v3/
The command line tool will attempt to reauthenticate using your
provided credentials for every request. You can override this behavior
by manually supplying an auth token using ``--os-watcher-url`` and
``--os-auth-token``. You can alternatively set these environment
variables::
export OS_WATCHER_URL=http://watcher.example.org:9322/
export OS_AUTH_TOKEN=3bcc3d3a03f44e3d8377f9247b0ad155
Once you've configured your authentication parameters, you can run
``watcher help`` to see a complete listing of available commands.
.. toctree::
watcher
openstack_cli
details

View File

@@ -0,0 +1,81 @@
=====================================================================
:program:`openstack` Command-Line Interface (CLI) with Watcher plugin
=====================================================================
.. program:: openstack
.. highlight:: bash
SYNOPSIS
========
:program:`openstack` [options] :program:`optimize` <command> [command-options]
:program:`openstack help optimize`
:program:`openstack help optimize` <command>
DESCRIPTION
===========
The :program:`openstack` command-line interface (CLI) can interact with the
OpenStack infra-optim Service (Watcher), by using our additional plugin
(included into the python-watcherclient package).
In order to use the CLI, you must provide your OpenStack username, password,
project (historically called tenant), and auth endpoint. You can use
configuration options :option:``--os-username``, :option:``--os-password``,
:option:``--os-tenant-id`` (or :option:``--os-tenant-name``),
and :option:``--os-auth-url``, or set the corresponding
environment variables::
$ export OS_USERNAME=user
$ export OS_PASSWORD=password
$ export OS_TENANT_ID=b363706f891f48019483f8bd6503c54b # or OS_TENANT_NAME
$ export OS_TENANT_NAME=project # or OS_TENANT_ID
$ export OS_AUTH_URL=http://auth.example.com:5000/v3/
The command-line tool will attempt to reauthenticate using the provided
credentials for every request. You can override this behavior by manually
supplying an auth token using :option:``--watcher-url`` and
:option:``--os-auth-token``, or by setting the corresponding environment variables::
export WATCHER_URL=http://watcher.example.org:9322/
export OS_AUTH_TOKEN=3bcc3d3a03f44e3d8377f9247b0ad155
Since Keystone can return multiple regions in the Service Catalog, you can
specify the one you want with :option:``--os-region-name`` or set the following
environment variable. (It defaults to the first in the list returned.)
::
$ export OS_REGION_NAME=region
OPTIONS
=======
To get a list of available (sub)commands and options, run::
$ openstack help optimize
To get usage and options of a command, run::
$ openstack help optimize <command>
EXAMPLES
========
Get information about the audit-create command::
$ openstack help optimize audit create
Get a list of available goal::
$ openstack optimize goal list
Get a list of audits::
$ openstack optimize audit list

View File

@@ -1,6 +1,6 @@
==============================================
===============================================
:program:`watcher` Command-Line Interface (CLI)
==============================================
===============================================
.. program:: watcher
.. highlight:: bash
@@ -19,43 +19,43 @@ DESCRIPTION
===========
The :program:`watcher` command-line interface (CLI) interacts with the
OpenStack TODEFINE Service (Watcher).
OpenStack infra-optim Service (Watcher).
In order to use the CLI, you must provide your OpenStack username, password,
project (historically called tenant), and auth endpoint. You can use
configuration options :option:`--os-username`, :option:`--os-password`,
:option:`--os-tenant-id` (or :option:`--os-tenant-name`),
and :option:`--os-auth-url`, or set the corresponding
configuration options :option:``--os-username``, :option:``--os-password``,
:option:``--os-tenant-id`` (or :option:``--os-tenant-name``),
and :option:``--os-auth-url``, or set the corresponding
environment variables::
export OS_USERNAME=user
export OS_PASSWORD=password
export OS_TENANT_ID=b363706f891f48019483f8bd6503c54b # or OS_TENANT_NAME
export OS_TENANT_NAME=project # or OS_TENANT_ID
export OS_AUTH_URL=http://auth.example.com:5000/v2.0
$ export OS_USERNAME=user
$ export OS_PASSWORD=password
$ export OS_TENANT_ID=b363706f891f48019483f8bd6503c54b # or OS_TENANT_NAME
$ export OS_TENANT_NAME=project # or OS_TENANT_ID
$ export OS_AUTH_URL=http://auth.example.com:5000/v3/
The command-line tool will attempt to reauthenticate using the provided
credentials for every request. You can override this behavior by manually
supplying an auth token using :option:`--watcher-url` and
:option:`--os-auth-token`, or by setting the corresponding environment variables::
supplying an auth token using :option:``--watcher-url`` and
:option:``--os-auth-token``, or by setting the corresponding environment variables::
export WATCHER_URL=http://watcher.example.org:9322/
export OS_AUTH_TOKEN=3bcc3d3a03f44e3d8377f9247b0ad155
$ export WATCHER_URL=http://watcher.example.org:9322/
$ export OS_AUTH_TOKEN=3bcc3d3a03f44e3d8377f9247b0ad155
Since Keystone can return multiple regions in the Service Catalog, you can
specify the one you want with :option:`--os-region-name` or set the following
specify the one you want with :option:``--os-region-name`` or set the following
environment variable. (It defaults to the first in the list returned.)
::
export OS_REGION_NAME=region
$ export OS_REGION_NAME=region
Watcher CLI supports bash completion. The command-line tool can automatically
fill partially typed commands. To use this feature, source the below file
(available at
https://git.openstack.org/cgit/openstack/python-watcherclient/tree/tools/watcher.bash_completion)
https://opendev.org/openstack/python-watcherclient/src/branch/master/tools/watcher.bash_completion)
to your terminal and then bash completion should work::
source watcher.bash_completion
$ . watcher.bash_completion
To avoid doing this every time, add this to your ``.bashrc`` or copy the
watcher.bash_completion file to the default bash completion scripts directory
@@ -66,11 +66,11 @@ OPTIONS
To get a list of available (sub)commands and options, run::
watcher help
$ watcher help
To get usage and options of a command, run::
watcher help <command>
$ watcher help <command>
EXAMPLES
@@ -78,12 +78,12 @@ EXAMPLES
Get information about the audit-create command::
watcher help audit-create
$ watcher help audit create
Get a list of available goal::
watcher goal-list
$ watcher goal list
Get a list of audits::
watcher audit-list
$ watcher audit list

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
@@ -12,7 +11,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from watcherclient import version as watcherclient_version
# -- General configuration ----------------------------------------------------
@@ -20,13 +18,20 @@ from watcherclient import version as watcherclient_version
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc',
'sphinx.ext.viewcode',
'oslosphinx',
]
'sphinxcontrib.apidoc',
'openstackdocstheme',
]
# autodoc generation is a bit aggressive and a nuisance when doing heavy
# text edit cycles.
# execute "export SPHINX_DEBUG=1" in your terminal to disable
# sphinxcontrib.apidoc options
apidoc_module_dir = '../../watcherclient'
apidoc_output_dir = 'reference/api'
apidoc_excluded_paths = [
'tests/*']
apidoc_separate_modules = True
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
@@ -37,18 +42,8 @@ source_suffix = '.rst'
master_doc = 'index'
# General information about the project.
project = u'python-watcherclient'
copyright = u'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 = watcherclient_version.version_info.release_string()
# The short X.Y version.
version = watcherclient_version.version_info.version_string()
project = 'python-watcherclient'
copyright = 'OpenStack Foundation'
# A list of ignored prefixes for module index sorting.
modindex_common_prefix = ['watcherclient.']
@@ -61,7 +56,7 @@ add_function_parentheses = True
add_module_names = True
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
pygments_style = 'native'
# -- Options for HTML output --------------------------------------------------
@@ -70,7 +65,8 @@ pygments_style = 'sphinx'
# html_theme_path = ["."]
# html_theme = '_theme'
# html_static_path = ['_static']
html_theme_options = {'incubating': True}
html_theme = 'openstackdocs'
# html_theme_path = [openstackdocstheme.get_html_theme_path()]
# Output file base name for HTML help builder.
htmlhelp_basename = '%sdoc' % project
@@ -83,7 +79,27 @@ latex_documents = [
(
'index',
'%s.tex' % project,
u'%s Documentation' % project,
u'OpenStack Foundation', 'manual'
'%s Documentation' % project,
'OpenStack Foundation', 'manual'
),
]
# Disable usage of xindy https://bugzilla.redhat.com/show_bug.cgi?id=1643664
latex_use_xindy = False
latex_domain_indices = False
latex_elements = {
'makeindex': '',
'printindex': '',
'preamble': r'\setcounter{tocdepth}{3}',
}
# openstackdocstheme options
openstackdocs_repo_name = 'openstack/python-watcherclient'
openstackdocs_pdf_link = True
openstackdocs_bug_project = 'python-watcherclient'
openstackdocs_bug_tag = ''
#html_theme_options = {"show_other_versions": "True"}

View File

@@ -1,8 +1,8 @@
.. _contributing:
===================================
====================================
Contributing to python-watcherclient
===================================
====================================
If you're interested in contributing to the python-watcherclient project,
the following will help get you started.
@@ -19,8 +19,8 @@ signed OpenStack's contributor's agreement.
.. seealso::
* http://docs.openstack.org/infra/manual/developers.html
* http://wiki.openstack.org/CLA
* https://docs.openstack.org/infra/manual/developers.html
* https://wiki.openstack.org/CLA
LaunchPad Project
-----------------
@@ -41,14 +41,14 @@ Project Hosting Details
-------------------------
Bug tracker
http://launchpad.net/python-watcherclient
https://launchpad.net/python-watcherclient
Mailing list (prefix subjects with ``[watcher]`` for faster responses)
http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev
http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-discuss
Code Hosting
https://git.openstack.org/cgit/openstack/python-watcherclient
https://opendev.org/openstack/python-watcherclient
Code Review
https://review.openstack.org/#/q/status:open+project:openstack/python-watcherclient,n,z
https://review.opendev.org/#/q/status:open+project:openstack/python-watcherclient,n,z

View File

@@ -1,50 +1,15 @@
Python bindings to the OpenStack Watcher API
============================================
This is a client for OpenStack Watcher API. There's :doc:`a Python API
<api_v1>` (the :mod:`watcherclient` modules), and a :doc:`command-line script
<cli>` (installed as :program:`watcher`). Each implements the entire
This is a client for OpenStack Watcher API. There's a Python API
(the :mod:`watcherclient` modules), and a command-line script
(installed as :program:`watcher`). Each implements the entire
OpenStack Watcher API.
You'll need credentials for an OpenStack cloud in order to use the watcher client.
Contents:
.. toctree::
:maxdepth: 1
:maxdepth: 2
readme
cli/index
reference/index
installation
api_v1
cli
contributing
Contributing
============
Code is hosted at `git.openstack.org`_. Submit bugs to the Watcher project on
`Launchpad`_. Submit code to the openstack/python-watcherclient project using
`Gerrit`_.
.. _git.openstack.org: https://git.openstack.org/cgit/openstack/python-watcherclient
.. _Launchpad: https://launchpad.net/watcher
.. _Gerrit: http://docs.openstack.org/infra/manual/developers.html#development-workflow
Testing
-------
The preferred way to run the unit tests is using ``tox``.
See `Consistent Testing Interface`_ for more details.
.. _Consistent Testing Interface: http://git.openstack.org/cgit/openstack/governance/tree/reference/project-testing-interface.rst
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
.. _Watcher: https://wiki.openstack.org/wiki/Watcher

View File

@@ -2,9 +2,9 @@
Installation
============
Or, if you have `virtualenvwrapper <https://virtualenvwrapper.readthedocs.org/en/latest/install.html>`_ installed::
If you have `virtualenvwrapper <https://virtualenvwrapper.readthedocs.org/en/latest/install.html>`_ installed::
$ mkvirtualenv python-watcherclient
$ git clone https://git.openstack.org/openstack/python-watcherclient
$ git clone https://opendev.org/openstack/python-watcherclient
$ cd python-watcherclient && python setup.py install
$ pip install -r ./requirements.txt

View File

@@ -1 +0,0 @@
.. include:: ../../README.rst

View File

@@ -68,11 +68,10 @@ Once you have an watcher `Client`_, you can perform various tasks::
>>> watcher.action.list() # list of actions
>>> watcher.action_plan.list() # list of action_plan
>>> watcher.audit.get(audit_uuid) # information about a particular audit
>>> watcher.audit.get(audit_uuid_or_name) # information about a particular audit
When the `Client`_ needs to propagate an exception, it will usually
raise an instance subclassed from
`watcherclient.exc.BaseException`_ or `watcherclient.exc.ClientException`_.
raise an instance listed in `watcherclient.exceptions`_.
Refer to the modules themselves, for more details.
@@ -80,15 +79,8 @@ Refer to the modules themselves, for more details.
watcherclient Modules
=====================
.. toctree::
:maxdepth: 1
modules <api/autoindex>
.. _watcherclient.v1.audit: api/watcherclient.v1.audit.html#watcherclient.v1.audit.Audit
.. _watcherclient.v1.client.Client: api/watcherclient.v1.client.html#watcherclient.v1.client.Client
.. _Client: api/watcherclient.v1.client.html#watcherclient.v1.client.Client
.. _watcherclient.client.get_client(): api/watcherclient.client.html#watcherclient.client.get_client
.. _watcherclient.exc.BaseException: api/watcherclient.exc.html#watcherclient.exc.BaseException
.. _watcherclient.exc.ClientException: api/watcherclient.exc.html#watcherclient.exc.ClientException
.. _watcherclient.exceptions: api/watcherclient.exceptions.html

View File

@@ -0,0 +1,14 @@
==========================
Python Library Reference
==========================
In order to use the python api directly, you must first obtain an auth
token and identify which endpoint you wish to speak to. Once you have
done so, you can use the API like so.
.. toctree::
:maxdepth: 2
api/modules
api_v1

82
lower-constraints.txt Normal file
View File

@@ -0,0 +1,82 @@
alabaster==0.7.10
appdirs==1.4.3
asn1crypto==0.23.0
certifi==2018.1.18
cffi==1.14.0
chardet==3.0.4
cliff==2.11.0
cmd2==0.8.2
coverage==4.0
cryptography==2.7
debtcollector==1.19.0
decorator==4.2.1
deprecation==2.0
docutils==0.11
dogpile.cache==0.6.5
dulwich==0.15.0
extras==1.0.0
fasteners==0.7.0
fixtures==3.0.0
flake8==2.5.5
hacking==0.12.0
idna==2.6
imagesize==0.7.1
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
linecache2==1.0.0
MarkupSafe==1.0
mccabe==0.2.1
monotonic==1.4
msgpack-python==0.4.0
munch==2.2.0
netaddr==0.7.19
netifaces==0.10.6
openstacksdk==0.12.0
os-client-config==1.29.0
os-service-types==1.2.0
os-testr==1.0.0
osc-lib==1.10.0
oslo.concurrency==3.25.0
oslo.config==5.2.0
oslo.context==2.19.2
oslo.i18n==3.20.0
oslo.log==3.36.0
oslo.serialization==2.18.0
oslo.utils==3.36.0
oslotest==3.2.0
packaging==17.1
paramiko==2.0.0
pbr==3.1.1
pep8==1.5.7
pyasn1==0.1.8
pycparser==2.18
pyflakes==0.8.1
Pygments==2.2.0
pyinotify==0.9.6
pyparsing==2.2.0
pyperclip==1.6.0
python-dateutil==2.5.3
python-mimeparse==1.6.0
python-subunit==1.0.0
pytz==2018.3
PyYAML==3.13
requests==2.18.4
requestsexceptions==1.4.0
rfc3986==0.3.1
simplejson==3.13.2
six==1.11.0
snowballstemmer==1.2.1
stestr==2.0.0
stevedore==1.28.0
tempest==17.1.0
testscenarios==0.4
testtools==2.2.0
traceback2==1.4.0
unittest2==1.1.0
urllib3==1.22
wrapt==1.10.11

View File

@@ -1,10 +0,0 @@
[DEFAULT]
# The list of modules to copy from oslo-incubator.git
module=apiclient
module=cliutils
module=_i18n
# The base module to hold the copy of openstack.common
base=watcherclient

View File

@@ -0,0 +1,6 @@
---
upgrade:
- |
Python 2.7 support has been dropped. Last release of python-watcherclient
to support py2.7 is OpenStack Train. The minimum version of Python now
supported by python-watcherclient is Python 3.6.

View File

@@ -2,9 +2,12 @@
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
Babel>=1.3 # BSD
oslo.i18n>=2.1.0 # Apache-2.0
oslo.utils>=3.5.0 # Apache-2.0
pbr>=1.6 # Apache-2.0
python-keystoneclient!=1.8.0,!=2.1.0,>=1.6.0 # Apache-2.0
six>=1.9.0 # MIT
cliff!=2.9.0,>=2.11.0 # Apache-2.0
osc-lib>=1.10.0 # Apache-2.0
oslo.i18n>=3.20.0 # Apache-2.0
oslo.serialization!=2.19.1,>=2.18.0 # Apache-2.0
oslo.utils>=3.36.0 # Apache-2.0
pbr!=2.1.0,>=3.1.1 # Apache-2.0
keystoneauth1>=3.4.0 # Apache-2.0
six>=1.11.0 # MIT
PyYAML>=3.13 # MIT

118
setup.cfg
View File

@@ -1,11 +1,12 @@
[metadata]
name = python-watcherclient
summary = Python client library for Watcher API
description-file =
description_file =
README.rst
author = OpenStack
author-email = openstack-dev@lists.openstack.org
home-page = http://www.openstack.org/
author_email = openstack-discuss@lists.openstack.org
home_page = https://docs.openstack.org/python-watcherclient/latest/
python_requires = >=3.8
classifier =
Environment :: OpenStack
Intended Audience :: Information Technology
@@ -13,10 +14,9 @@ classifier =
License :: OSI Approved :: Apache Software License
Operating System :: POSIX :: Linux
Programming Language :: Python
Programming Language :: Python :: 2
Programming Language :: Python :: 2.7
Programming Language :: Python :: 3
Programming Language :: Python :: 3.4
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
[files]
packages =
@@ -26,27 +26,89 @@ packages =
console_scripts =
watcher = watcherclient.shell:main
openstack.cli.extension =
infra_optim = watcherclient.osc.plugin
# Entry points for the 'openstack' command
openstack.infra_optim.v1 =
optimize_goal_show = watcherclient.v1.goal_shell:ShowGoal
optimize_goal_list = watcherclient.v1.goal_shell:ListGoal
optimize_strategy_show = watcherclient.v1.strategy_shell:ShowStrategy
optimize_strategy_list = watcherclient.v1.strategy_shell:ListStrategy
optimize_strategy_state = watcherclient.v1.strategy_shell:StateStrategy
optimize_audittemplate_show = watcherclient.v1.audit_template_shell:ShowAuditTemplate
optimize_audittemplate_list = watcherclient.v1.audit_template_shell:ListAuditTemplate
optimize_audittemplate_create = watcherclient.v1.audit_template_shell:CreateAuditTemplate
optimize_audittemplate_update = watcherclient.v1.audit_template_shell:UpdateAuditTemplate
optimize_audittemplate_delete = watcherclient.v1.audit_template_shell:DeleteAuditTemplate
optimize_audit_show = watcherclient.v1.audit_shell:ShowAudit
optimize_audit_list = watcherclient.v1.audit_shell:ListAudit
optimize_audit_create = watcherclient.v1.audit_shell:CreateAudit
optimize_audit_update = watcherclient.v1.audit_shell:UpdateAudit
optimize_audit_delete = watcherclient.v1.audit_shell:DeleteAudit
optimize_actionplan_show = watcherclient.v1.action_plan_shell:ShowActionPlan
optimize_actionplan_delete = watcherclient.v1.action_plan_shell:DeleteActionPlan
optimize_actionplan_list = watcherclient.v1.action_plan_shell:ListActionPlan
optimize_actionplan_update = watcherclient.v1.action_plan_shell:UpdateActionPlan
optimize_actionplan_start = watcherclient.v1.action_plan_shell:StartActionPlan
optimize_actionplan_cancel = watcherclient.v1.action_plan_shell:CancelActionPlan
optimize_action_show = watcherclient.v1.action_shell:ShowAction
optimize_action_list = watcherclient.v1.action_shell:ListAction
optimize_scoringengine_show = watcherclient.v1.scoring_engine_shell:ShowScoringEngine
optimize_scoringengine_list = watcherclient.v1.scoring_engine_shell:ListScoringEngine
optimize_service_show = watcherclient.v1.service_shell:ShowService
optimize_service_list = watcherclient.v1.service_shell:ListService
optimize_datamodel_list = watcherclient.v1.data_model_shell:ListDataModel
# The same as above but used by the 'watcher' command
watcherclient.v1 =
goal_show = watcherclient.v1.goal_shell:ShowGoal
goal_list = watcherclient.v1.goal_shell:ListGoal
strategy_show = watcherclient.v1.strategy_shell:ShowStrategy
strategy_list = watcherclient.v1.strategy_shell:ListStrategy
strategy_state = watcherclient.v1.strategy_shell:StateStrategy
audittemplate_show = watcherclient.v1.audit_template_shell:ShowAuditTemplate
audittemplate_list = watcherclient.v1.audit_template_shell:ListAuditTemplate
audittemplate_create = watcherclient.v1.audit_template_shell:CreateAuditTemplate
audittemplate_update = watcherclient.v1.audit_template_shell:UpdateAuditTemplate
audittemplate_delete = watcherclient.v1.audit_template_shell:DeleteAuditTemplate
audit_show = watcherclient.v1.audit_shell:ShowAudit
audit_list = watcherclient.v1.audit_shell:ListAudit
audit_create = watcherclient.v1.audit_shell:CreateAudit
audit_update = watcherclient.v1.audit_shell:UpdateAudit
audit_delete = watcherclient.v1.audit_shell:DeleteAudit
actionplan_show = watcherclient.v1.action_plan_shell:ShowActionPlan
actionplan_list = watcherclient.v1.action_plan_shell:ListActionPlan
actionplan_update = watcherclient.v1.action_plan_shell:UpdateActionPlan
actionplan_start = watcherclient.v1.action_plan_shell:StartActionPlan
actionplan_delete = watcherclient.v1.action_plan_shell:DeleteActionPlan
actionplan_cancel = watcherclient.v1.action_plan_shell:CancelActionPlan
action_show = watcherclient.v1.action_shell:ShowAction
action_list = watcherclient.v1.action_shell:ListAction
scoringengine_show = watcherclient.v1.scoring_engine_shell:ShowScoringEngine
scoringengine_list = watcherclient.v1.scoring_engine_shell:ListScoringEngine
service_show = watcherclient.v1.service_shell:ShowService
service_list = watcherclient.v1.service_shell:ListService
datamodel_list = watcherclient.v1.data_model_shell:ListDataModel
[pbr]
autodoc_index_modules = True
[build_sphinx]
source-dir = doc/source
build-dir = doc/build
all_files = 1
[bdist_wheel]
universal = 1
[compile_catalog]
directory = watcherclient/locale
domain = watcherclient
[update_catalog]
domain = watcherclient
output_dir = watcherclient/locale
input_file = watcherclient/locale/watcherclient.pot
[extract_messages]
keywords = _ gettext ngettext l_ lazy_gettext _LI _LW _LE _LC
mapping_file = babel.cfg
output_file = watcherclient/locale/watcherclient.pot
autodoc_exclude_modules =
watcherclient.tests.*
api_doc_dir = reference/api

View File

@@ -13,17 +13,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
import setuptools
# In python < 2.7.4, a lazy loading of package `pbr` will break
# setuptools if some other modules registered functions in `atexit`.
# solution from: http://bugs.python.org/issue15881#msg170215
try:
import multiprocessing # noqa
except ImportError:
pass
setuptools.setup(
setup_requires=['pbr>=1.8'],
setup_requires=['pbr>=2.0.0'],
pbr=True)

View File

@@ -2,17 +2,12 @@
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
coverage>=3.6 # Apache-2.0
discover # BSD
hacking<0.11,>=0.10.2
mock>=1.2 # BSD
oslosphinx!=3.4.0,>=2.5.0 # Apache-2.0
oslotest>=1.10.0 # Apache-2.0
python-subunit>=0.0.18 # Apache-2.0/BSD
sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2 # BSD
testrepository>=0.0.18 # Apache-2.0/BSD
coverage!=4.4,>=4.0 # Apache-2.0
fixtures>=3.0.0 # Apache-2.0/BSD
hacking>=3.0.1,<3.1.0 # Apache-2.0
oslotest>=3.2.0 # Apache-2.0
python-subunit>=1.0.0 # Apache-2.0/BSD
stestr>=2.0.0 # Apache-2.0
testscenarios>=0.4 # Apache-2.0/BSD
testtools>=1.4.0 # MIT
# Needed for pypi packaging
wheel # MIT
testtools>=2.2.0 # MIT
tempest>=17.1.0 # Apache-2.0

59
tox.ini
View File

@@ -1,40 +1,79 @@
[tox]
minversion = 1.6
envlist = py34,py27,pep8
minversion = 3.18.0
envlist = py3,pep8
skipsdist = True
[testenv]
usedevelop = True
install_command = pip install -U {opts} {packages}
passenv = ZUUL_CACHE_DIR
REQUIREMENTS_PIP_LOCATION
install_command = pip install {opts} {packages}
setenv =
VIRTUAL_ENV={envdir}
deps = -r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt
commands = python setup.py testr --slowest --testr-args='{posargs}'
deps =
-c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/zed}
-r{toxinidir}/test-requirements.txt
-r{toxinidir}/requirements.txt
allowlist_externals =
rm
commands = rm -f .testrepository/times.dbm
# The --test-path is defined in .stestr.conf
stestr run {posargs}
stestr slowest
[testenv:pep8]
basepython = python3
commands = flake8
[testenv:venv]
basepython = python3
commands = {posargs}
[testenv:cover]
commands = python setup.py testr --coverage --testr-args='{posargs}'
basepython = python3
setenv =
PYTHON=coverage run --source watcherclient --parallel-mode
commands =
stestr run {posargs}
coverage combine
coverage html -d cover
coverage xml -o cover/coverage.xml
coverage report
[testenv:docs]
commands = python setup.py build_sphinx
basepython = python3
deps =
-c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/zed}
-r{toxinidir}/doc/requirements.txt
commands = sphinx-build -W -b html doc/source doc/build/html
[testenv:pdf-docs]
basepython = python3
envdir = {toxworkdir}/docs
deps = {[testenv:docs]deps}
allowlist_externals =
rm
make
commands =
rm -rf doc/build/pdf
sphinx-build -W -b latex doc/source doc/build/pdf
make -C doc/build/pdf
[testenv:debug]
commands = oslo_debug_helper {posargs}
basepython = python3
commands = oslo_debug_helper -t watcherclient/tests/unit {posargs}
[flake8]
# E123, E125 skipped as they are invalid PEP-8.
show-source = True
ignore = E123,E125
enable-extensions = H203,H106
ignore = E123,E125,W504
builtins = _
exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build
[testenv:wheel]
basepython = python3
commands = python setup.py bdist_wheel
[hacking]

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
#
# Copyright 2013 Hewlett-Packard Development Company, L.P.
# All Rights Reserved.
@@ -18,6 +17,7 @@
import pbr.version
from watcherclient import client
from watcherclient.common import api_versioning
from watcherclient import exceptions
@@ -25,3 +25,11 @@ __version__ = pbr.version.VersionInfo(
'python-watcherclient').version_string()
__all__ = ['client', 'exceptions', ]
API_MIN_VERSION = api_versioning.APIVersion("1.0")
# The max version should be the latest version that is supported in the client,
# not necessarily the latest that the server can provide. This is only bumped
# when client supported the max version, and bumped sequentially, otherwise
# the client may break due to server side new version may include some
# backward incompatible change.
API_MAX_VERSION = api_versioning.APIVersion("1.1")

View File

@@ -30,16 +30,6 @@ _C = _translators.contextual_form
# requires oslo.i18n >=2.1.0
_P = _translators.plural_form
# Translators for log levels.
#
# The abbreviated names are meant to reflect the usual use of a short
# name like '_'. The "L" is for "log" and the other letter comes from
# the level.
_LI = _translators.log_info
_LW = _translators.log_warning
_LE = _translators.log_error
_LC = _translators.log_critical
def get_available_languages():
return oslo_i18n.get_available_languages(DOMAIN)

View File

@@ -1,5 +1,3 @@
# -*- coding: utf-8 -*-
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
@@ -12,112 +10,183 @@
# License for the specific language governing permissions and limitations
# under the License.
from keystoneclient.v2_0 import client as ksclient
import oslo_i18n
from keystoneauth1 import loading as kaloading
from oslo_utils import importutils
from watcherclient._i18n import _
from watcherclient.common import utils
from watcherclient import exceptions as exc
oslo_i18n.install('watcherclient')
from watcherclient.common import api_versioning
from watcherclient import exceptions
def _get_ksclient(**kwargs):
"""Get an endpoint and auth token from Keystone.
:param kwargs: keyword args containing credentials:
* username: name of user
* password: user's password
* auth_url: endpoint to authenticate against
* insecure: allow insecure SSL (no cert verification)
* tenant_{name|id}: name or ID of tenant
"""
return ksclient.Client(username=kwargs.get('username'),
password=kwargs.get('password'),
tenant_id=kwargs.get('tenant_id'),
tenant_name=kwargs.get('tenant_name'),
auth_url=kwargs.get('auth_url'),
insecure=kwargs.get('insecure'))
def _get_endpoint(client, **kwargs):
"""Get an endpoint using the provided keystone client."""
attr = None
filter_value = None
if kwargs.get('region_name'):
attr = 'region'
filter_value = kwargs.get('region_name')
return client.service_catalog.url_for(
service_type=kwargs.get('service_type') or 'infra-optim',
attr=attr,
filter_value=filter_value,
endpoint_type=kwargs.get('endpoint_type') or 'publicURL')
def get_client(api_version, **kwargs):
"""Get an authenticated client, based on the credentials in args.
def get_client(api_version, os_auth_token=None, watcher_url=None,
os_username=None, os_password=None, os_auth_url=None,
os_project_id=None, os_project_name=None, os_tenant_id=None,
os_tenant_name=None, os_region_name=None,
os_user_domain_id=None, os_user_domain_name=None,
os_project_domain_id=None, os_project_domain_name=None,
os_service_type=None, os_endpoint_type=None,
insecure=None, timeout=None, os_cacert=None, ca_file=None,
os_cert=None, cert_file=None, os_key=None, key_file=None,
os_infra_optim_api_version=None, max_retries=None,
retry_interval=None, session=None, os_endpoint_override=None,
**ignored_kwargs):
"""Get an authenticated client, based on the credentials.
:param api_version: the API version to use. Valid value: '1'.
:param kwargs: keyword args containing credentials, either:
* os_auth_token: pre-existing token to re-use
* watcher_url: watcher API endpoint
or:
* os_username: name of user
* os_password: user's password
* os_auth_url: endpoint to authenticate against
* insecure: allow insecure SSL (no cert verification)
* os_tenant_{name|id}: name or ID of tenant
:param os_auth_token: pre-existing token to re-use
:param watcher_url: watcher API endpoint
:param os_username: name of a user
:param os_password: user's password
:param os_auth_url: endpoint to authenticate against
:param os_project_id: ID of a project
:param os_project_name: name of a project
:param os_tenant_id: ID of a tenant (deprecated in favour of
os_project_id)
:param os_tenant_name: name of a tenant (deprecated in favour of
os_project_name)
:param os_region_name: name of a keystone region
:param os_user_domain_id: ID of a domain the user belongs to
:param os_user_domain_name: name of a domain the user belongs to
:param os_project_domain_id: ID of a domain the project belongs to
:param os_project_domain_name: name of a domain the project belongs to
:param os_service_type: the type of service to lookup the endpoint for
:param os_endpoint_type: the type (exposure) of the endpoint
:param insecure: allow insecure SSL (no cert verification)
:param timeout: allows customization of the timeout for client HTTP
requests
:param os_cacert: path to cacert file
:param ca_file: path to cacert file, deprecated in favour of os_cacert
:param os_cert: path to cert file
:param cert_file: path to cert file, deprecated in favour of os_cert
:param os_key: path to key file
:param key_file: path to key file, deprecated in favour of os_key
:param os_infra_optim_api_version: watcher API version to use
:param max_retries: Maximum number of retries in case of conflict error
:param retry_interval: Amount of time (in seconds) between retries in case
of conflict error
:param session: Keystone session to use
:param os_endpoint_override: watcher API endpoint
:param ignored_kwargs: all the other params that are passed. Left for
backwards compatibility. They are ignored.
"""
if kwargs.get('os_auth_token') and kwargs.get('watcher_url'):
token = kwargs.get('os_auth_token')
endpoint = kwargs.get('watcher_url')
auth_ref = None
elif (kwargs.get('os_username') and
kwargs.get('os_password') and
kwargs.get('os_auth_url') and
(kwargs.get('os_tenant_id') or kwargs.get('os_tenant_name'))):
ks_kwargs = {
'username': kwargs.get('os_username'),
'password': kwargs.get('os_password'),
'tenant_id': kwargs.get('os_tenant_id'),
'tenant_name': kwargs.get('os_tenant_name'),
'auth_url': kwargs.get('os_auth_url'),
'service_type': kwargs.get('os_service_type'),
'endpoint_type': kwargs.get('os_endpoint_type'),
'insecure': kwargs.get('insecure'),
}
_ksclient = _get_ksclient(**ks_kwargs)
token = (kwargs.get('os_auth_token')
if kwargs.get('os_auth_token')
else _ksclient.auth_token)
ks_kwargs['region_name'] = kwargs.get('os_region_name')
endpoint = (kwargs.get('watcher_url') or
_get_endpoint(_ksclient, **ks_kwargs))
auth_ref = _ksclient.auth_ref
else:
e = (_('Must provide Keystone credentials or user-defined endpoint '
'and token'))
raise exc.AmbiguousAuthSystem(e)
cli_kwargs = {
'token': token,
'insecure': kwargs.get('insecure'),
'timeout': kwargs.get('timeout'),
'ca_file': kwargs.get('ca_file'),
'cert_file': kwargs.get('cert_file'),
'key_file': kwargs.get('key_file'),
'auth_ref': auth_ref,
os_service_type = os_service_type or 'infra-optim'
os_endpoint_type = os_endpoint_type or 'publicURL'
project_id = (os_project_id or os_tenant_id)
project_name = (os_project_name or os_tenant_name)
kwargs = {
'os_infra_optim_api_version': os_infra_optim_api_version,
'max_retries': max_retries,
'retry_interval': retry_interval,
}
endpoint = watcher_url or os_endpoint_override
cacert = os_cacert or ca_file
cert = os_cert or cert_file
key = os_key or key_file
if os_auth_token and endpoint:
kwargs.update({
'token': os_auth_token,
'insecure': insecure,
'ca_file': cacert,
'cert_file': cert,
'key_file': key,
'timeout': timeout,
})
elif os_auth_url:
auth_type = 'password'
auth_kwargs = {
'auth_url': os_auth_url,
'project_id': project_id,
'project_name': project_name,
'user_domain_id': os_user_domain_id,
'user_domain_name': os_user_domain_name,
'project_domain_id': os_project_domain_id,
'project_domain_name': os_project_domain_name,
}
if os_username and os_password:
auth_kwargs.update({
'username': os_username,
'password': os_password,
})
elif os_auth_token:
auth_type = 'token'
auth_kwargs.update({
'token': os_auth_token,
})
# Create new session only if it was not passed in
if not session:
loader = kaloading.get_plugin_loader(auth_type)
auth_plugin = loader.load_from_options(**auth_kwargs)
# Let keystoneauth do the necessary parameter conversions
session = kaloading.session.Session().load_from_options(
auth=auth_plugin, insecure=insecure, cacert=cacert,
cert=cert, key=key, timeout=timeout,
)
return Client(api_version, endpoint, **cli_kwargs)
exception_msg = _('Must provide Keystone credentials or user-defined '
'endpoint and token')
if not endpoint:
if session:
try:
# Pass the endpoint, it will be used to get hostname
# and port that will be used for API version caching. It will
# be also set as endpoint_override.
endpoint = session.get_endpoint(
service_type=os_service_type,
interface=os_endpoint_type,
region_name=os_region_name
)
except Exception as e:
raise exceptions.AmbiguousAuthSystem(
exception_msg + _(', error was: %s') % e)
else:
# Neither session, nor valid auth parameters provided
raise exceptions.AmbiguousAuthSystem(exception_msg)
# Always pass the session
kwargs['session'] = session
return Client(api_version, endpoint, **kwargs)
def _get_client_class_and_version(version):
if not isinstance(version, api_versioning.APIVersion):
version = api_versioning.get_api_version(version)
else:
api_versioning.check_major_version(version)
if version.is_latest():
raise exceptions.UnsupportedVersion(
_("The version should be explicit, not latest."))
return version, importutils.import_class(
"watcherclient.v%s.client.Client" % version.ver_major)
def Client(version, *args, **kwargs):
module = utils.import_versioned_module(version, 'client')
client_class = getattr(module, 'Client')
"""Initialize client object based on given version.
HOW-TO:
The simplest way to create a client instance is initialization with your
credentials::
>>> from watcherclient import client
>>> watcher = client.Client(VERSION, USERNAME, PASSWORD,
... PROJECT_ID, AUTH_URL)
Here ``VERSION`` can be a string or
``watcherclient.api_versions.APIVersion`` obj. If you prefer string value,
you can use ``1`` or ``1.X`` (where X is a microversion).
Alternatively, you can create a client instance using the keystoneauth
session API. See "The watcherclient Python API" page at
python-watcherclient's doc.
"""
api_version, client_class = _get_client_class_and_version(version)
kw_api = kwargs.get('os_infra_optim_api_version')
endpoint = kwargs.get('endpoint')
# If both os_infra_optim_api_version and endpoint are not provided, get
# API version from arg.
if not kw_api and not endpoint:
kwargs['os_infra_optim_api_version'] = api_version.get_string()
return client_class(*args, **kwargs)

View File

@@ -0,0 +1,235 @@
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import logging
import os
import pkgutil
import re
from oslo_utils import strutils
from watcherclient._i18n import _
from watcherclient import exceptions
LOG = logging.getLogger(__name__)
if not LOG.handlers:
LOG.addHandler(logging.StreamHandler())
MINOR_1_START_END_TIMING = '1.1'
MINOR_2_FORCE_AUDIT = '1.2'
HEADER_NAME = "OpenStack-API-Version"
# key is a deprecated version and value is an alternative version.
DEPRECATED_VERSIONS = {}
_type_error_msg = _("'%(other)s' should be an instance of '%(cls)s'")
def allow_start_end_audit_time(requested_version):
"""Check if we should support optional start/end attributes for Audit.
Version 1.1 of the API added support for start and end time of continuous
audits.
"""
return (APIVersion(requested_version) >=
APIVersion(MINOR_1_START_END_TIMING))
def launch_audit_forced(requested_version):
"""Check if we should support force option for Audit.
Version 1.2 of the API added support for force option.
"""
return (APIVersion(requested_version) >=
APIVersion(MINOR_2_FORCE_AUDIT))
class APIVersion(object):
"""This class represents an API Version Request.
This class provides convenience methods for manipulation
and comparison of version numbers that we need to do to
implement microversions.
"""
def __init__(self, version_str=None):
"""Create an API version object.
:param version_str: String representation of APIVersionRequest.
Correct format is 'X.Y', where 'X' and 'Y'
are int values. None value should be used
to create Null APIVersionRequest, which is
equal to 0.0
"""
self.ver_major = 0
self.ver_minor = 0
if version_str is not None:
match = re.match(r"^([1-9]\d*)\.([1-9]\d*|0|latest)$", version_str)
if match:
self.ver_major = int(match.group(1))
if match.group(2) == "latest":
# NOTE(andreykurilin): Infinity allows to easily determine
# latest version and doesn't require any additional checks
# in comparison methods.
self.ver_minor = float("inf")
else:
self.ver_minor = int(match.group(2))
else:
msg = _("Invalid format of client version '%s'. "
"Expected format 'X.Y', where X is a major part and Y "
"is a minor part of version.") % version_str
raise exceptions.UnsupportedVersion(msg)
def __str__(self):
"""Debug/Logging representation of object."""
if self.is_latest():
return "Latest API Version Major: %s" % self.ver_major
return ("API Version Major: %s, Minor: %s"
% (self.ver_major, self.ver_minor))
def __repr__(self):
if self.is_null():
return "<APIVersion: null>"
else:
return "<APIVersion: %s>" % self.get_string()
def is_null(self):
return self.ver_major == 0 and self.ver_minor == 0
def is_latest(self):
return self.ver_minor == float("inf")
def __lt__(self, other):
if not isinstance(other, APIVersion):
raise TypeError(_type_error_msg % {"other": other,
"cls": self.__class__})
return ((self.ver_major, self.ver_minor) <
(other.ver_major, other.ver_minor))
def __eq__(self, other):
if not isinstance(other, APIVersion):
raise TypeError(_type_error_msg % {"other": other,
"cls": self.__class__})
return ((self.ver_major, self.ver_minor) ==
(other.ver_major, other.ver_minor))
def __gt__(self, other):
if not isinstance(other, APIVersion):
raise TypeError(_type_error_msg % {"other": other,
"cls": self.__class__})
return ((self.ver_major, self.ver_minor) >
(other.ver_major, other.ver_minor))
def __le__(self, other):
return self < other or self == other
def __ne__(self, other):
return not self.__eq__(other)
def __ge__(self, other):
return self > other or self == other
def matches(self, min_version, max_version):
"""Matches the version object.
Returns whether the version object represents a version
greater than or equal to the minimum version and less than
or equal to the maximum version.
:param min_version: Minimum acceptable version.
:param max_version: Maximum acceptable version.
:returns: boolean
If min_version is null then there is no minimum limit.
If max_version is null then there is no maximum limit.
If self is null then raise ValueError
"""
if self.is_null():
raise ValueError(_("Null APIVersion doesn't support 'matches'."))
if max_version.is_null() and min_version.is_null():
return True
elif max_version.is_null():
return min_version <= self
elif min_version.is_null():
return self <= max_version
else:
return min_version <= self <= max_version
def get_string(self):
"""Version string representation.
Converts object to string representation which if used to create
an APIVersion object results in the same version.
"""
if self.is_null():
raise ValueError(
_("Null APIVersion cannot be converted to string."))
elif self.is_latest():
return "%s.%s" % (self.ver_major, "latest")
return "%s.%s" % (self.ver_major, self.ver_minor)
def get_available_major_versions():
# NOTE(andreykurilin): available clients version should not be
# hardcoded, so let's discover them.
matcher = re.compile(r"v[0-9]*$")
submodules = pkgutil.iter_modules(
[os.path.dirname(os.path.dirname(__file__))])
available_versions = [name[1:] for loader, name, ispkg in submodules
if matcher.search(name)]
return available_versions
def check_major_version(api_version):
"""Checks major part of ``APIVersion`` obj is supported.
:raises watcherclient.exceptions.UnsupportedVersion: if major part is not
supported
"""
available_versions = get_available_major_versions()
if (not api_version.is_null() and
str(api_version.ver_major) not in available_versions):
if len(available_versions) == 1:
msg = _("Invalid client version '%(version)s'. "
"Major part should be '%(major)s'") % {
"version": api_version.get_string(),
"major": available_versions[0]}
else:
msg = _("Invalid client version '%(version)s'. "
"Major part must be one of: '%(major)s'") % {
"version": api_version.get_string(),
"major": ", ".join(available_versions)}
raise exceptions.UnsupportedVersion(msg)
def get_api_version(version_string):
"""Returns checked APIVersion object"""
version_string = str(version_string)
if version_string in DEPRECATED_VERSIONS:
LOG.warning(
"Version %(deprecated_version)s is deprecated, using "
"alternative version %(alternative)s instead.",
{"deprecated_version": version_string,
"alternative": DEPRECATED_VERSIONS[version_string]})
version_string = DEPRECATED_VERSIONS[version_string]
if strutils.is_int_like(version_string):
version_string = "%s.0" % version_string
api_version = APIVersion(version_string)
check_major_version(api_version)
return api_version

View File

@@ -317,7 +317,7 @@ class CrudManager(BaseManager):
def _filter_kwargs(self, kwargs):
"""Drop null values and handle ids."""
for key, ref in six.iteritems(kwargs.copy()):
for key, ref in kwargs.copy().items():
if ref is None:
kwargs.pop(key)
else:
@@ -475,7 +475,7 @@ class Resource(object):
return None
def _add_details(self, info):
for (k, v) in six.iteritems(info):
for (k, v) in info.items():
try:
setattr(self, k, v)
self._info[k] = v
@@ -497,7 +497,7 @@ class Resource(object):
def get(self):
"""Support for lazy loading details.
Some clients, such as novaclient have the option to lazy load the
Some clients, such as watcherclient have the option to lazy load the
details, details which can be loaded with this function.
"""
# set_loaded() first ... so if we have to bail, we know we tried.
@@ -521,6 +521,9 @@ class Resource(object):
return self.id == other.id
return self._info == other._info
def __ne__(self, other):
return not self.__eq__(other)
def is_loaded(self):
return self._loaded

View File

@@ -421,7 +421,7 @@ class HttpVersionNotSupported(HttpServerError):
# _code_map contains all the classes that have http_status attribute.
_code_map = dict(
(getattr(obj, 'http_status', None), obj)
for name, obj in six.iteritems(vars(sys.modules[__name__]))
for name, obj in vars(sys.modules[__name__]).items()
if inspect.isclass(obj) and getattr(obj, 'http_status', False)
)
@@ -433,11 +433,7 @@ def from_response(response, method, url):
:param method: HTTP method used for request
:param url: URL used for request
"""
req_id = response.headers.get("x-openstack-request-id")
# NOTE(hdd) true for older versions of nova and cinder
if not req_id:
req_id = response.headers.get("x-compute-request-id")
kwargs = {
"http_status": response.status_code,
"response": response,

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
#
# Copyright 2012 OpenStack LLC.
# All Rights Reserved.
@@ -32,10 +31,7 @@ def getid(obj):
Abstracts the common pattern of allowing both an object or an
object's ID (UUID) as a parameter when dealing with relationships.
"""
try:
return obj.id
except AttributeError:
return obj
return getattr(obj, 'id', obj)
class Manager(object):
@@ -135,6 +131,11 @@ class Manager(object):
def _delete(self, url):
self.api.raw_request('DELETE', url)
def _start(self, url, body=None, method='POST'):
resp, body = self.api.json_request(method, url, body={})
if body:
return self.resource_class(self, body)
class Resource(base.Resource):
"""Represents a particular instance of an object (tenant, user, etc).

View File

@@ -1,271 +0,0 @@
# Copyright 2012 Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
# W0603: Using the global statement
# W0621: Redefining name %s from outer scope
# pylint: disable=W0603,W0621
from __future__ import print_function
import getpass
import inspect
import os
import sys
import textwrap
from oslo_utils import encodeutils
from oslo_utils import strutils
import prettytable
import six
from six import moves
from watcherclient._i18n import _
class MissingArgs(Exception):
"""Supplied arguments are not sufficient for calling a function."""
def __init__(self, missing):
self.missing = missing
msg = _("Missing arguments: %s") % ", ".join(missing)
super(MissingArgs, self).__init__(msg)
def validate_args(fn, *args, **kwargs):
"""Check that the supplied args are sufficient for calling a function.
>>> validate_args(lambda a: None)
Traceback (most recent call last):
...
MissingArgs: Missing argument(s): a
>>> validate_args(lambda a, b, c, d: None, 0, c=1)
Traceback (most recent call last):
...
MissingArgs: Missing argument(s): b, d
:param fn: the function to check
:param arg: the positional arguments supplied
:param kwargs: the keyword arguments supplied
"""
argspec = inspect.getargspec(fn)
num_defaults = len(argspec.defaults or [])
required_args = argspec.args[:len(argspec.args) - num_defaults]
def isbound(method):
return getattr(method, '__self__', None) is not None
if isbound(fn):
required_args.pop(0)
missing = [arg for arg in required_args if arg not in kwargs]
missing = missing[len(args):]
if missing:
raise MissingArgs(missing)
def arg(*args, **kwargs):
"""Decorator for CLI args.
Example:
>>> @arg("name", help="Name of the new entity")
... def entity_create(args):
... pass
"""
def _decorator(func):
add_arg(func, *args, **kwargs)
return func
return _decorator
def env(*args, **kwargs):
"""Returns the first environment variable set.
If all are empty, defaults to '' or keyword arg `default`.
"""
for arg in args:
value = os.environ.get(arg)
if value:
return value
return kwargs.get('default', '')
def add_arg(func, *args, **kwargs):
"""Bind CLI arguments to a shell.py `do_foo` function."""
if not hasattr(func, 'arguments'):
func.arguments = []
# NOTE(sirp): avoid dups that can occur when the module is shared across
# tests.
if (args, kwargs) not in func.arguments:
# Because of the semantics of decorator composition if we just append
# to the options list positional options will appear to be backwards.
func.arguments.insert(0, (args, kwargs))
def unauthenticated(func):
"""Adds 'unauthenticated' attribute to decorated function.
Usage:
>>> @unauthenticated
... def mymethod(f):
... pass
"""
func.unauthenticated = True
return func
def isunauthenticated(func):
"""Checks if the function does not require authentication.
Mark such functions with the `@unauthenticated` decorator.
:returns: bool
"""
return getattr(func, 'unauthenticated', False)
def print_list(objs, fields, formatters=None, sortby_index=0,
mixed_case_fields=None, field_labels=None):
"""Print a list or objects as a table, one row per object.
:param objs: iterable of :class:`Resource`
:param fields: attributes that correspond to columns, in order
:param formatters: `dict` of callables for field formatting
:param sortby_index: index of the field for sorting table rows
:param mixed_case_fields: fields corresponding to object attributes that
have mixed case names (e.g., 'serverId')
:param field_labels: Labels to use in the heading of the table, default to
fields.
"""
formatters = formatters or {}
mixed_case_fields = mixed_case_fields or []
field_labels = field_labels or fields
if len(field_labels) != len(fields):
raise ValueError(_("Field labels list %(labels)s has different number "
"of elements than fields list %(fields)s"),
{'labels': field_labels, 'fields': fields})
if sortby_index is None:
kwargs = {}
else:
kwargs = {'sortby': field_labels[sortby_index]}
pt = prettytable.PrettyTable(field_labels)
pt.align = 'l'
for o in objs:
row = []
for field in fields:
if field in formatters:
row.append(formatters[field](o))
else:
if field in mixed_case_fields:
field_name = field.replace(' ', '_')
else:
field_name = field.lower().replace(' ', '_')
data = getattr(o, field_name, '')
row.append(data)
pt.add_row(row)
if six.PY3:
print(encodeutils.safe_encode(pt.get_string(**kwargs)).decode())
else:
print(encodeutils.safe_encode(pt.get_string(**kwargs)))
def print_dict(dct, dict_property="Property", wrap=0):
"""Print a `dict` as a table of two columns.
:param dct: `dict` to print
:param dict_property: name of the first column
:param wrap: wrapping for the second column
"""
pt = prettytable.PrettyTable([dict_property, 'Value'])
pt.align = 'l'
for k, v in six.iteritems(dct):
# convert dict to str to check length
if isinstance(v, dict):
v = six.text_type(v)
if wrap > 0:
v = textwrap.fill(six.text_type(v), wrap)
# if value has a newline, add in multiple rows
# e.g. fault with stacktrace
if v and isinstance(v, six.string_types) and r'\n' in v:
lines = v.strip().split(r'\n')
col1 = k
for line in lines:
pt.add_row([col1, line])
col1 = ''
else:
pt.add_row([k, v])
if six.PY3:
print(encodeutils.safe_encode(pt.get_string()).decode())
else:
print(encodeutils.safe_encode(pt.get_string()))
def get_password(max_password_prompts=3):
"""Read password from TTY."""
verify = strutils.bool_from_string(env("OS_VERIFY_PASSWORD"))
pw = None
if hasattr(sys.stdin, "isatty") and sys.stdin.isatty():
# Check for Ctrl-D
try:
for __ in moves.range(max_password_prompts):
pw1 = getpass.getpass("OS Password: ")
if verify:
pw2 = getpass.getpass("Please verify: ")
else:
pw2 = pw1
if pw1 == pw2 and pw1:
pw = pw1
break
except EOFError:
pass
return pw
def service_type(stype):
"""Adds 'service_type' attribute to decorated function.
Usage:
.. code-block:: python
@service_type('volume')
def mymethod(f):
...
"""
def inner(f):
f.service_type = stype
return f
return inner
def get_service_type(f):
"""Retrieves service type from function."""
return getattr(f, 'service_type', None)
def pretty_choice_list(l):
return ', '.join("'%s'" % i for i in l)
def exit(msg=''):
if msg:
print (msg, file=sys.stderr)
sys.exit(1)

View File

@@ -0,0 +1,50 @@
# Copyright 2016 NEC Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import abc
import logging
from cliff import command
from cliff import lister
from cliff import show
import six
class CommandMeta(abc.ABCMeta):
def __new__(mcs, name, bases, cls_dict):
if 'log' not in cls_dict:
cls_dict['log'] = logging.getLogger(
cls_dict['__module__'] + '.' + name)
return super(CommandMeta, mcs).__new__(mcs, name, bases, cls_dict)
@six.add_metaclass(CommandMeta)
class Command(command.Command):
def run(self, parsed_args):
self.log.debug('run(%s)', parsed_args)
return super(Command, self).run(parsed_args)
class Lister(Command, lister.Lister):
pass
class ShowOne(Command, show.ShowOne):
def get_parser(self, prog_name, formatter_class=None):
parser = super(ShowOne, self).get_parser(prog_name)
if formatter_class:
parser.formatter_class = formatter_class
return parser

View File

@@ -1,384 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright 2012 OpenStack LLC.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import copy
import json
import logging
import os
import socket
import ssl
from keystoneclient import adapter
import six
import six.moves.urllib.parse as urlparse
from watcherclient._i18n import _, _LW, _LE
from watcherclient import exceptions as exc
LOG = logging.getLogger(__name__)
USER_AGENT = 'python-watcherclient'
CHUNKSIZE = 1024 * 64 # 64kB
API_VERSION = '/v1'
def _trim_endpoint_api_version(url):
"""Trim API version and trailing slash from endpoint."""
return url.rstrip('/').rstrip(API_VERSION)
def _extract_error_json(body):
"""Return error_message from the HTTP response body."""
error_json = {}
try:
body_json = json.loads(body)
if 'error_message' in body_json:
raw_msg = body_json['error_message']
error_json = json.loads(raw_msg)
except ValueError:
pass
return error_json
class HTTPClient(object):
def __init__(self, endpoint, **kwargs):
self.endpoint = endpoint
self.endpoint_trimmed = _trim_endpoint_api_version(endpoint)
self.auth_token = kwargs.get('token')
self.auth_ref = kwargs.get('auth_ref')
self.connection_params = self.get_connection_params(endpoint, **kwargs)
@staticmethod
def get_connection_params(endpoint, **kwargs):
parts = urlparse.urlparse(endpoint)
path = _trim_endpoint_api_version(parts.path)
_args = (parts.hostname, parts.port, path)
_kwargs = {'timeout': (float(kwargs.get('timeout'))
if kwargs.get('timeout') else 600)}
if parts.scheme == 'https':
_class = VerifiedHTTPSConnection
_kwargs['ca_file'] = kwargs.get('ca_file', None)
_kwargs['cert_file'] = kwargs.get('cert_file', None)
_kwargs['key_file'] = kwargs.get('key_file', None)
_kwargs['insecure'] = kwargs.get('insecure', False)
elif parts.scheme == 'http':
_class = six.moves.http_client.HTTPConnection
else:
raise exc.EndpointException(
_('Unsupported scheme: %s'), parts.scheme)
return (_class, _args, _kwargs)
def get_connection(self):
_class = self.connection_params[0]
try:
return _class(*self.connection_params[1][0:2],
**self.connection_params[2])
except six.moves.http_client.InvalidURL:
raise exc.EndpointException()
def log_curl_request(self, method, url, kwargs):
curl = ['curl -i -X %s' % method]
for (key, value) in kwargs['headers'].items():
header = '-H \'%s: %s\'' % (key, value)
curl.append(header)
conn_params_fmt = [
('key_file', '--key %s'),
('cert_file', '--cert %s'),
('ca_file', '--cacert %s'),
]
for (key, fmt) in conn_params_fmt:
value = self.connection_params[2].get(key)
if value:
curl.append(fmt % value)
if self.connection_params[2].get('insecure'):
curl.append('-k')
if 'body' in kwargs:
curl.append('-d \'%s\'' % kwargs['body'])
curl.append(urlparse.urljoin(self.endpoint_trimmed, url))
LOG.debug(' '.join(curl))
@staticmethod
def log_http_response(resp, body=None):
status = (resp.version / 10.0, resp.status, resp.reason)
dump = ['\nHTTP/%.1f %s %s' % status]
dump.extend(['%s: %s' % (k, v) for k, v in resp.getheaders()])
dump.append('')
if body:
dump.extend([body, ''])
LOG.debug('\n'.join(dump))
def _make_connection_url(self, url):
(_class, _args, _kwargs) = self.connection_params
base_url = _args[2]
return '%s/%s' % (base_url, url.lstrip('/'))
def _http_request(self, url, method, **kwargs):
"""Send an http request with the specified characteristics.
Wrapper around httplib.HTTP(S)Connection.request to handle tasks such
as setting headers and error handling.
"""
# Copy the kwargs so we can reuse the original in case of redirects
kwargs['headers'] = copy.deepcopy(kwargs.get('headers', {}))
kwargs['headers'].setdefault('User-Agent', USER_AGENT)
if self.auth_token:
kwargs['headers'].setdefault('X-Auth-Token', self.auth_token)
self.log_curl_request(method, url, kwargs)
conn = self.get_connection()
try:
conn_url = self._make_connection_url(url)
conn.request(method, conn_url, **kwargs)
resp = conn.getresponse()
except socket.gaierror as e:
raise exc.EndpointNotFound(
_("Error finding address for %(url)s: %(e)s"),
url=url, e=e)
except (socket.error, socket.timeout) as e:
endpoint = self.endpoint
raise exc.ConnectionRefused(
_("Error communicating with %(endpoint)s %(e)s"),
endpoint=endpoint, e=e)
body_iter = ResponseBodyIterator(resp)
# Read body into string if it isn't obviously image data
body_str = None
if resp.getheader('content-type', None) != 'application/octet-stream':
body_str = ''.join([chunk for chunk in body_iter])
self.log_http_response(resp, body_str)
body_iter = six.StringIO(body_str)
else:
self.log_http_response(resp)
if 400 <= resp.status < 600:
LOG.warning(_LW("Request returned failure status."))
error_json = _extract_error_json(body_str)
raise exc.from_response(
resp, error_json.get('faultstring'),
error_json.get('debuginfo'), method, url)
elif resp.status in (301, 302, 305):
# Redirected. Reissue the request to the new location.
return self._http_request(resp['location'], method, **kwargs)
elif resp.status == 300:
raise exc.from_response(resp, method=method, url=url)
return resp, body_iter
def json_request(self, method, url, **kwargs):
kwargs.setdefault('headers', {})
kwargs['headers'].setdefault('Content-Type', 'application/json')
kwargs['headers'].setdefault('Accept', 'application/json')
if 'body' in kwargs:
kwargs['body'] = json.dumps(kwargs['body'])
resp, body_iter = self._http_request(url, method, **kwargs)
content_type = resp.getheader('content-type', None)
if resp.status == 204 or resp.status == 205 or content_type is None:
return resp, list()
if 'application/json' in content_type:
body = ''.join([chunk for chunk in body_iter])
try:
body = json.loads(body)
except ValueError:
LOG.error(_LE('Could not decode response body as JSON'))
else:
body = None
return resp, body
def raw_request(self, method, url, **kwargs):
kwargs.setdefault('headers', {})
kwargs['headers'].setdefault('Content-Type',
'application/octet-stream')
return self._http_request(url, method, **kwargs)
class VerifiedHTTPSConnection(six.moves.http_client.HTTPSConnection):
"""httplib-compatibile connection using client-side SSL authentication
:see http://code.activestate.com/recipes/
577548-https-httplib-client-connection-with-certificate-v/
"""
def __init__(self, host, port, key_file=None, cert_file=None,
ca_file=None, timeout=None, insecure=False):
six.moves.http_client.HTTPSConnection.__init__(
self, host, port,
key_file=key_file,
cert_file=cert_file)
self.key_file = key_file
self.cert_file = cert_file
if ca_file is not None:
self.ca_file = ca_file
else:
self.ca_file = self.get_system_ca_file()
self.timeout = timeout
self.insecure = insecure
def connect(self):
"""Connect to a host on a given (SSL) port.
If ca_file is pointing somewhere, use it to check Server Certificate.
Redefined/copied and extended from httplib.py:1105 (Python 2.6.x).
This is needed to pass cert_reqs=ssl.CERT_REQUIRED as parameter to
ssl.wrap_socket(), which forces SSL to check server certificate against
our client certificate.
"""
sock = socket.create_connection((self.host, self.port), self.timeout)
if self._tunnel_host:
self.sock = sock
self._tunnel()
if self.insecure is True:
kwargs = {'cert_reqs': ssl.CERT_NONE}
else:
kwargs = {'cert_reqs': ssl.CERT_REQUIRED, 'ca_certs': self.ca_file}
if self.cert_file:
kwargs['certfile'] = self.cert_file
if self.key_file:
kwargs['keyfile'] = self.key_file
self.sock = ssl.wrap_socket(sock, **kwargs)
@staticmethod
def get_system_ca_file():
"""Return path to system default CA file."""
# Standard CA file locations for Debian/Ubuntu, RedHat/Fedora,
# Suse, FreeBSD/OpenBSD
ca_path = ['/etc/ssl/certs/ca-certificates.crt',
'/etc/pki/tls/certs/ca-bundle.crt',
'/etc/ssl/ca-bundle.pem',
'/etc/ssl/cert.pem']
for ca in ca_path:
if os.path.exists(ca):
return ca
return None
class SessionClient(adapter.LegacyJsonAdapter):
"""HTTP client based on Keystone client session."""
def _http_request(self, url, method, **kwargs):
kwargs.setdefault('user_agent', USER_AGENT)
kwargs.setdefault('auth', self.auth)
endpoint_filter = kwargs.setdefault('endpoint_filter', {})
endpoint_filter.setdefault('interface', self.interface)
endpoint_filter.setdefault('service_type', self.service_type)
endpoint_filter.setdefault('region_name', self.region_name)
resp = self.session.request(url, method,
raise_exc=False, **kwargs)
if 400 <= resp.status_code < 600:
error_json = _extract_error_json(resp.content)
raise exc.from_response(resp, error_json.get(
'faultstring'),
error_json.get('debuginfo'), method, url)
elif resp.status_code in (301, 302, 305):
# Redirected. Reissue the request to the new location.
location = resp.headers.get('location')
resp = self._http_request(location, method, **kwargs)
elif resp.status_code == 300:
raise exc.from_response(resp, method=method, url=url)
return resp
def json_request(self, method, url, **kwargs):
kwargs.setdefault('headers', {})
kwargs['headers'].setdefault('Content-Type', 'application/json')
kwargs['headers'].setdefault('Accept', 'application/json')
if 'body' in kwargs:
kwargs['data'] = json.dumps(kwargs.pop('body'))
resp = self._http_request(url, method, **kwargs)
body = resp.content
content_type = resp.headers.get('content-type', None)
status = resp.status_code
if status == 204 or status == 205 or content_type is None:
return resp, list()
if 'application/json' in content_type:
try:
body = resp.json()
except ValueError:
LOG.error(_LE('Could not decode response body as JSON'))
else:
body = None
return resp, body
def raw_request(self, method, url, **kwargs):
kwargs.setdefault('headers', {})
kwargs['headers'].setdefault('Content-Type',
'application/octet-stream')
return self._http_request(url, method, **kwargs)
class ResponseBodyIterator(object):
"""A class that acts as an iterator over an HTTP response."""
def __init__(self, resp):
self.resp = resp
def __iter__(self):
while True:
yield self.next()
def next(self):
chunk = self.resp.read(CHUNKSIZE)
if chunk:
return chunk
else:
raise StopIteration()
def _construct_http_client(*args, **kwargs):
session = kwargs.pop('session', None)
auth = kwargs.pop('auth', None)
if session:
service_type = kwargs.pop('service_type', 'infra-optim')
interface = kwargs.pop('endpoint_type', None)
region_name = kwargs.pop('region_name', None)
return SessionClient(session=session,
auth=auth,
interface=interface,
service_type=service_type,
region_name=region_name,
service_name=None,
user_agent='python-watcherclient')
else:
return HTTPClient(*args, **kwargs)

View File

@@ -0,0 +1,641 @@
# Copyright 2012 OpenStack LLC.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import copy
from distutils import version
import functools
import hashlib
import logging
import os
import socket
import ssl
import textwrap
import time
from keystoneauth1 import adapter
from keystoneauth1 import exceptions as kexceptions
from oslo_serialization import jsonutils
from oslo_utils import strutils
import requests
import six
from six.moves import http_client
import six.moves.urllib.parse as urlparse
from watcherclient._i18n import _
from watcherclient.common import api_versioning
from watcherclient import exceptions
# Record the latest version that this client was tested with.
DEFAULT_VER = '1.latest'
# Minor version 4 for adding webhook API
LAST_KNOWN_API_VERSION = 4
LATEST_VERSION = '1.{}'.format(LAST_KNOWN_API_VERSION)
LOG = logging.getLogger(__name__)
USER_AGENT = 'python-watcherclient'
CHUNKSIZE = 1024 * 64 # 64kB
API_VERSION = '/v1'
API_VERSION_SELECTED_STATES = ('user', 'negotiated', 'cached', 'default')
DEFAULT_MAX_RETRIES = 5
DEFAULT_RETRY_INTERVAL = 2
SENSITIVE_HEADERS = ('X-Auth-Token',)
SUPPORTED_ENDPOINT_SCHEME = ('http', 'https')
def _trim_endpoint_api_version(url):
"""Trim API version and trailing slash from endpoint."""
return url.rstrip('/').rstrip(API_VERSION)
def _extract_error_json(body):
"""Return error_message from the HTTP response body."""
error_json = {}
try:
body_json = jsonutils.loads(body)
if 'error_message' in body_json:
raw_msg = body_json['error_message']
error_json = jsonutils.loads(raw_msg)
except ValueError:
pass
return error_json
def get_server(endpoint):
"""Extract and return the server & port that we're connecting to."""
if endpoint is None:
return None, None
parts = urlparse.urlparse(endpoint)
return parts.hostname, str(parts.port)
class VersionNegotiationMixin(object):
def negotiate_version(self, conn, resp):
"""Negotiate the server version
Assumption: Called after receiving a 406 error when doing a request.
param conn: A connection object
param resp: The response object from http request
"""
if self.api_version_select_state not in API_VERSION_SELECTED_STATES:
raise RuntimeError(
_('Error: self.api_version_select_state should be one of the '
'values in: "%(valid)s" but had the value: "%(value)s"') %
{'valid': ', '.join(API_VERSION_SELECTED_STATES),
'value': self.api_version_select_state})
min_ver, max_ver = self._parse_version_headers(resp)
# If the user requested an explicit version or we have negotiated a
# version and still failing then error now. The server could
# support the version requested but the requested operation may not
# be supported by the requested version.
if self.api_version_select_state == 'user':
raise exceptions.UnsupportedVersion(textwrap.fill(
_("Requested API version %(req)s is not supported by the "
"server or the requested operation is not supported by the "
"requested version. Supported version range is %(min)s to "
"%(max)s")
% {'req': self.os_infra_optim_api_version,
'min': min_ver, 'max': max_ver}))
if self.api_version_select_state == 'negotiated':
raise exceptions.UnsupportedVersion(textwrap.fill(
_("No API version was specified and the requested operation "
"was not supported by the client's negotiated API version "
"%(req)s. Supported version range is: %(min)s to %(max)s")
% {'req': self.os_infra_optim_api_version,
'min': min_ver, 'max': max_ver}))
negotiated_ver = str(
min(version.StrictVersion(self.os_infra_optim_api_version),
version.StrictVersion(max_ver)))
if negotiated_ver < min_ver:
negotiated_ver = min_ver
# server handles microversions, but doesn't support
# the requested version, so try a negotiated version
self.api_version_select_state = 'negotiated'
self.os_infra_optim_api_version = negotiated_ver
LOG.debug('Negotiated API version is %s', negotiated_ver)
return negotiated_ver
def _generic_parse_version_headers(self, accessor_func):
min_ver = accessor_func('OpenStack-API-Minimum-Version',
None)
max_ver = accessor_func('OpenStack-API-Maximum-Version',
None)
return min_ver, max_ver
def _parse_version_headers(self, accessor_func):
# NOTE(jlvillal): Declared for unit testing purposes
raise NotImplementedError()
def _make_simple_request(self, conn, method, url):
# NOTE(jlvillal): Declared for unit testing purposes
raise NotImplementedError()
_RETRY_EXCEPTIONS = (exceptions.ServiceUnavailable,
exceptions.ConnectionRefused,
kexceptions.RetriableConnectionFailure)
def with_retries(func):
"""Wrapper for _http_request adding support for retries."""
@functools.wraps(func)
def wrapper(self, url, method, **kwargs):
if self.conflict_max_retries is None:
self.conflict_max_retries = DEFAULT_MAX_RETRIES
if self.conflict_retry_interval is None:
self.conflict_retry_interval = DEFAULT_RETRY_INTERVAL
num_attempts = self.conflict_max_retries + 1
for attempt in range(1, num_attempts + 1):
try:
return func(self, url, method, **kwargs)
except _RETRY_EXCEPTIONS as error:
msg = ("Error contacting Watcher server: %(error)s. "
"Attempt %(attempt)d of %(total)d" %
{'attempt': attempt,
'total': num_attempts,
'error': error})
if attempt == num_attempts:
LOG.error(msg)
raise
else:
LOG.debug(msg)
time.sleep(self.conflict_retry_interval)
return wrapper
class HTTPClient(VersionNegotiationMixin):
def __init__(self, endpoint, **kwargs):
self.endpoint = endpoint
self.endpoint_trimmed = _trim_endpoint_api_version(endpoint)
self.auth_token = kwargs.get('token')
self.auth_ref = kwargs.get('auth_ref')
self.os_infra_optim_api_version = kwargs.get(
'os_infra_optim_api_version', DEFAULT_VER)
self.api_version_select_state = kwargs.get(
'api_version_select_state', 'default')
self.conflict_max_retries = kwargs.pop('max_retries',
DEFAULT_MAX_RETRIES)
self.conflict_retry_interval = kwargs.pop('retry_interval',
DEFAULT_RETRY_INTERVAL)
self.session = requests.Session()
parts = urlparse.urlparse(endpoint)
if parts.scheme not in SUPPORTED_ENDPOINT_SCHEME:
msg = _('Unsupported scheme: %s') % parts.scheme
raise exceptions.EndpointException(msg)
if parts.scheme == 'https':
if kwargs.get('insecure') is True:
self.session.verify = False
elif kwargs.get('ca_file'):
self.session.verify = kwargs['ca_file']
self.session.cert = (kwargs.get('cert_file'),
kwargs.get('key_file'))
def _process_header(self, name, value):
"""Redacts any sensitive header
Redact a header that contains sensitive information, by returning an
updated header with the sha1 hash of that value. The redacted value is
prefixed by '{SHA1}' because that's the convention used within
OpenStack.
:returns: A tuple of (name, value)
name: the safe encoding format of name
value: the redacted value if name is x-auth-token,
or the safe encoding format of name
"""
if name in SENSITIVE_HEADERS:
v = value.encode('utf-8')
h = hashlib.sha1(v)
d = h.hexdigest()
return (name, "{SHA1}%s" % d)
else:
return (name, value)
def log_curl_request(self, method, url, kwargs):
curl = ['curl -i -X %s' % method]
for (key, value) in kwargs['headers'].items():
header = '-H \'%s: %s\'' % self._process_header(key, value)
curl.append(header)
if not self.session.verify:
curl.append('-k')
elif isinstance(self.session.verify, six.string_types):
curl.append('--cacert %s' % self.session.verify)
if self.session.cert:
curl.append('--cert %s' % self.session.cert[0])
curl.append('--key %s' % self.session.cert[1])
if 'body' in kwargs:
body = strutils.mask_password(kwargs['body'])
curl.append('-d \'%s\'' % body)
curl.append(urlparse.urljoin(self.endpoint_trimmed, url))
LOG.debug(' '.join(curl))
@staticmethod
def log_http_response(resp, body=None):
# NOTE(aarefiev): resp.raw is urllib3 response object, it's used
# only to get 'version', response from request with 'stream = True'
# should be used for raw reading.
status = (resp.raw.version / 10.0, resp.status_code, resp.reason)
dump = ['\nHTTP/%.1f %s %s' % status]
dump.extend(['%s: %s' % (k, v) for k, v in resp.headers.items()])
dump.append('')
if body:
body = strutils.mask_password(body)
dump.extend([body, ''])
LOG.debug('\n'.join(dump))
def _make_connection_url(self, url):
return '%s/%s' % (self.endpoint_trimmed.rstrip('/'), url.lstrip('/'))
def _parse_version_headers(self, resp):
return self._generic_parse_version_headers(resp.headers.get)
def _make_simple_request(self, conn, method, url):
return conn.request(method, self._make_connection_url(url))
@with_retries
def _http_request(self, url, method, **kwargs):
"""Send an http request with the specified characteristics.
Wrapper around request.Session.request to handle tasks such
as setting headers and error handling.
"""
# Copy the kwargs so we can reuse the original in case of redirects
kwargs['headers'] = copy.deepcopy(kwargs.get('headers', {}))
kwargs['headers'].setdefault('User-Agent', USER_AGENT)
if self.os_infra_optim_api_version:
api_version = api_versioning.get_api_version(
self.os_infra_optim_api_version)
if api_version.is_latest():
api_version = api_versioning.get_api_version(
LATEST_VERSION)
kwargs['headers'].setdefault(
'OpenStack-API-Version',
' '.join(['infra-optim', api_version.get_string()]))
if self.auth_token:
kwargs['headers'].setdefault('X-Auth-Token', self.auth_token)
self.log_curl_request(method, url, kwargs)
# NOTE(aarefiev): This is for backwards compatibility, request
# expected body in 'data' field, previously we used httplib,
# which expected 'body' field.
body = kwargs.pop('body', None)
if body:
kwargs['data'] = body
conn_url = self._make_connection_url(url)
try:
resp = self.session.request(method,
conn_url,
**kwargs)
# TODO(deva): implement graceful client downgrade when connecting
# to servers that did not support microversions. Details here:
# http://specs.openstack.org/openstack/watcher-specs/specs/kilo/api-microversions.html#use-case-3b-new-client-communicating-with-a-old-watcher-user-specified # noqa
if resp.status_code == http_client.NOT_ACCEPTABLE:
negotiated_ver = self.negotiate_version(self.session, resp)
kwargs['headers']['OpenStack-API-Version'] = (
' '.join(['infra-optim', negotiated_ver]))
return self._http_request(url, method, **kwargs)
except requests.exceptions.RequestException as e:
message = (_("Error has occurred while handling "
"request for %(url)s: %(e)s") %
dict(url=conn_url, e=e))
# NOTE(aarefiev): not valid request(invalid url, missing schema,
# and so on), retrying is not needed.
if isinstance(e, ValueError):
raise exceptions.ValidationError(message)
raise exceptions.ConnectionRefused(message)
body_iter = resp.iter_content(chunk_size=CHUNKSIZE)
# Read body into string if it isn't obviously image data
body_str = None
if resp.headers.get('Content-Type') != 'application/octet-stream':
# decoding byte to string is necessary for Python 3 compatibility
# this issues has not been found with Python 3 unit tests
# because the test creates a fake http response of type str
# the if statement satisfies test (str) and real (bytes) behavior
body_list = [
chunk.decode("utf-8") if isinstance(chunk, bytes)
else chunk for chunk in body_iter
]
body_str = ''.join(body_list)
self.log_http_response(resp, body_str)
body_iter = six.StringIO(body_str)
else:
self.log_http_response(resp)
if resp.status_code >= http_client.BAD_REQUEST:
error_json = _extract_error_json(body_str)
raise exceptions.from_response(
resp, error_json.get('faultstring'),
error_json.get('debuginfo'), method, url)
elif resp.status_code in (http_client.MOVED_PERMANENTLY,
http_client.FOUND,
http_client.USE_PROXY):
# Redirected. Reissue the request to the new location.
return self._http_request(resp['location'], method, **kwargs)
elif resp.status_code == http_client.MULTIPLE_CHOICES:
raise exceptions.from_response(resp, method=method, url=url)
return resp, body_iter
def json_request(self, method, url, **kwargs):
kwargs.setdefault('headers', {})
kwargs['headers'].setdefault('Content-Type', 'application/json')
kwargs['headers'].setdefault('Accept', 'application/json')
if 'body' in kwargs:
kwargs['body'] = jsonutils.dumps(kwargs['body'])
resp, body_iter = self._http_request(url, method, **kwargs)
content_type = resp.headers.get('Content-Type')
if (resp.status_code in (http_client.NO_CONTENT,
http_client.RESET_CONTENT) or
content_type is None):
return resp, list()
if 'application/json' in content_type:
body = ''.join([chunk for chunk in body_iter])
try:
body = jsonutils.loads(body)
except ValueError:
LOG.error('Could not decode response body as JSON')
else:
body = None
return resp, body
def raw_request(self, method, url, **kwargs):
kwargs.setdefault('headers', {})
kwargs['headers'].setdefault('Content-Type',
'application/octet-stream')
return self._http_request(url, method, **kwargs)
class VerifiedHTTPSConnection(six.moves.http_client.HTTPSConnection):
"""httplib-compatible connection using client-side SSL authentication
:see http://code.activestate.com/recipes/
577548-https-httplib-client-connection-with-certificate-v/
"""
def __init__(self, host, port, key_file=None, cert_file=None,
ca_file=None, timeout=None, insecure=False):
six.moves.http_client.HTTPSConnection.__init__(self, host, port,
key_file=key_file,
cert_file=cert_file)
self.key_file = key_file
self.cert_file = cert_file
if ca_file is not None:
self.ca_file = ca_file
else:
self.ca_file = self.get_system_ca_file()
self.timeout = timeout
self.insecure = insecure
def connect(self):
"""Connect to a host on a given (SSL) port.
If ca_file is pointing somewhere, use it to check Server Certificate.
Redefined/copied and extended from httplib.py:1105 (Python 2.6.x).
This is needed to pass cert_reqs=ssl.CERT_REQUIRED as parameter to
ssl.wrap_socket(), which forces SSL to check server certificate against
our client certificate.
"""
sock = socket.create_connection((self.host, self.port), self.timeout)
if self._tunnel_host:
self.sock = sock
self._tunnel()
if self.insecure is True:
kwargs = {'cert_reqs': ssl.CERT_NONE}
else:
kwargs = {'cert_reqs': ssl.CERT_REQUIRED, 'ca_certs': self.ca_file}
if self.cert_file:
kwargs['certfile'] = self.cert_file
if self.key_file:
kwargs['keyfile'] = self.key_file
self.sock = ssl.wrap_socket(sock, **kwargs)
@staticmethod
def get_system_ca_file():
"""Return path to system default CA file."""
# Standard CA file locations for Debian/Ubuntu, RedHat/Fedora,
# Suse, FreeBSD/OpenBSD
ca_path = ['/etc/ssl/certs/ca-certificates.crt',
'/etc/pki/tls/certs/ca-bundle.crt',
'/etc/ssl/ca-bundle.pem',
'/etc/ssl/cert.pem']
for ca in ca_path:
if os.path.exists(ca):
return ca
return None
class SessionClient(VersionNegotiationMixin, adapter.LegacyJsonAdapter):
"""HTTP client based on Keystone client session."""
def __init__(self,
os_infra_optim_api_version,
api_version_select_state,
max_retries,
retry_interval,
endpoint,
**kwargs):
self.os_infra_optim_api_version = os_infra_optim_api_version
self.api_version_select_state = api_version_select_state
self.conflict_max_retries = max_retries
self.conflict_retry_interval = retry_interval
self.endpoint = endpoint
super(SessionClient, self).__init__(**kwargs)
def _parse_version_headers(self, resp):
return self._generic_parse_version_headers(resp.headers.get)
def _make_simple_request(self, conn, method, url):
# NOTE: conn is self.session for this class
return conn.request(url, method, raise_exc=False)
@with_retries
def _http_request(self, url, method, **kwargs):
kwargs.setdefault('user_agent', USER_AGENT)
kwargs.setdefault('auth', self.auth)
if isinstance(self.endpoint_override, six.string_types):
kwargs.setdefault(
'endpoint_override',
_trim_endpoint_api_version(self.endpoint_override)
)
if getattr(self, 'os_infra_optim_api_version', None):
api_version = api_versioning.get_api_version(
self.os_infra_optim_api_version)
if api_version.is_latest():
api_version = api_versioning.get_api_version(
LATEST_VERSION)
kwargs['headers'].setdefault(
'OpenStack-API-Version',
' '.join(['infra-optim',
api_version.get_string()]))
endpoint_filter = kwargs.setdefault('endpoint_filter', {})
endpoint_filter.setdefault('interface', self.interface)
endpoint_filter.setdefault('service_type', self.service_type)
endpoint_filter.setdefault('region_name', self.region_name)
resp = self.session.request(url, method,
raise_exc=False, **kwargs)
if resp.status_code == http_client.NOT_ACCEPTABLE:
negotiated_ver = self.negotiate_version(self.session, resp)
kwargs['headers']['OpenStack-API-Version'] = (
' '.join(['infra-optim', negotiated_ver]))
return self._http_request(url, method, **kwargs)
if resp.status_code >= http_client.BAD_REQUEST:
error_json = _extract_error_json(resp.content)
raise exceptions.from_response(
resp, error_json.get('faultstring'),
error_json.get('debuginfo'), method, url)
elif resp.status_code in (http_client.MOVED_PERMANENTLY,
http_client.FOUND, http_client.USE_PROXY):
# Redirected. Reissue the request to the new location.
location = resp.headers.get('location')
resp = self._http_request(location, method, **kwargs)
elif resp.status_code == http_client.MULTIPLE_CHOICES:
raise exceptions.from_response(resp, method=method, url=url)
return resp
def json_request(self, method, url, **kwargs):
kwargs.setdefault('headers', {})
kwargs['headers'].setdefault('Content-Type', 'application/json')
kwargs['headers'].setdefault('Accept', 'application/json')
if 'body' in kwargs:
kwargs['data'] = jsonutils.dumps(kwargs.pop('body'))
resp = self._http_request(url, method, **kwargs)
body = resp.content
content_type = resp.headers.get('content-type', None)
status = resp.status_code
if (status in (http_client.NO_CONTENT, http_client.RESET_CONTENT) or
content_type is None):
return resp, list()
if 'application/json' in content_type:
try:
body = resp.json()
except ValueError:
LOG.error('Could not decode response body as JSON')
else:
body = None
return resp, body
def raw_request(self, method, url, **kwargs):
kwargs.setdefault('headers', {})
kwargs['headers'].setdefault('Content-Type',
'application/octet-stream')
return self._http_request(url, method, **kwargs)
def _construct_http_client(endpoint=None,
session=None,
token=None,
auth_ref=None,
os_infra_optim_api_version=DEFAULT_VER,
api_version_select_state='default',
max_retries=DEFAULT_MAX_RETRIES,
retry_interval=DEFAULT_RETRY_INTERVAL,
timeout=600,
ca_file=None,
cert_file=None,
key_file=None,
insecure=None,
**kwargs):
if session:
kwargs.setdefault('service_type', 'infra-optim')
kwargs.setdefault('user_agent', 'python-watcherclient')
kwargs.setdefault('interface', kwargs.pop('endpoint_type', None))
kwargs.setdefault('endpoint_override', endpoint)
ignored = {'token': token,
'auth_ref': auth_ref,
'timeout': timeout != 600,
'ca_file': ca_file,
'cert_file': cert_file,
'key_file': key_file,
'insecure': insecure}
dvars = [k for k, v in ignored.items() if v]
if dvars:
LOG.warning('The following arguments are ignored when using '
'the session to construct a client: %s',
', '.join(dvars))
return SessionClient(
session=session,
os_infra_optim_api_version=os_infra_optim_api_version,
api_version_select_state=api_version_select_state,
max_retries=max_retries,
retry_interval=retry_interval,
endpoint=endpoint,
**kwargs)
else:
if kwargs:
LOG.warning('The following arguments are being ignored when '
'constructing the client: %s', ', '.join(kwargs))
return HTTPClient(
endpoint=endpoint,
token=token,
auth_ref=auth_ref,
os_infra_optim_api_version=os_infra_optim_api_version,
api_version_select_state=api_version_select_state,
max_retries=max_retries,
retry_interval=retry_interval,
timeout=timeout,
ca_file=ca_file,
cert_file=cert_file,
key_file=key_file,
insecure=insecure)

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
#
# Copyright 2012 OpenStack LLC.
# All Rights Reserved.
@@ -15,11 +14,12 @@
# License for the specific language governing permissions and limitations
# under the License.
from __future__ import print_function
import argparse
import json
import os
import uuid
import yaml
from oslo_serialization import jsonutils
from oslo_utils import importutils
from watcherclient._i18n import _
@@ -73,7 +73,7 @@ def import_versioned_module(version, submodule=None):
return importutils.import_module(module)
def split_and_deserialize(string):
def split_and_deserialize(string, exclude_fields=[]):
"""Split and try to JSON deserialize a string.
Gets a string with the KEY=VALUE format, split it (using '=' as the
@@ -86,10 +86,11 @@ def split_and_deserialize(string):
except ValueError:
raise exc.CommandError(_('Attributes must be a list of '
'PATH=VALUE not "%s"') % string)
try:
value = json.loads(value)
except ValueError:
pass
if key not in exclude_fields:
try:
value = jsonutils.loads(value)
except ValueError:
pass
return (key, value)
@@ -102,7 +103,7 @@ def args_array_to_dict(kwargs, key_to_convert):
return kwargs
def args_array_to_patch(op, attributes):
def args_array_to_patch(op, attributes, exclude_fields=[]):
patch = []
for attr in attributes:
# Sanitize
@@ -110,7 +111,8 @@ def args_array_to_patch(op, attributes):
attr = '/' + attr
if op in ['add', 'replace']:
path, value = split_and_deserialize(attr)
path, value = split_and_deserialize(attr,
exclude_fields=exclude_fields)
patch.append({'op': op, 'path': path, 'value': value})
elif op == "remove":
@@ -157,17 +159,21 @@ def common_params_for_list(args, fields, field_labels):
args.sort_dir)
params['sort_dir'] = args.sort_dir
marker = getattr(args, 'marker', None)
if marker is not None:
params['marker'] = marker
params['detail'] = args.detail
return params
def common_filters(limit=None, sort_key=None, sort_dir=None):
def common_filters(limit=None, sort_key=None, sort_dir=None, marker=None):
"""Generate common filters for any list request.
:param limit: maximum number of entities to return.
:param sort_key: field to use for sorting.
:param sort_dir: direction of sorting: 'asc' or 'desc'.
:param marker: The last actionplan UUID of the previous page.
:returns: list of string filters.
"""
filters = []
@@ -177,4 +183,26 @@ def common_filters(limit=None, sort_key=None, sort_dir=None):
filters.append('sort_key=%s' % sort_key)
if sort_dir is not None:
filters.append('sort_dir=%s' % sort_dir)
if marker is not None:
filters.append('marker=%s' % marker)
return filters
def is_uuid_like(val):
"""Returns validation of a value as a UUID.
For our purposes, a UUID is a canonical form string:
aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa
"""
try:
return str(uuid.UUID(val)) == val
except (TypeError, ValueError, AttributeError):
return False
def serialize_file_to_dict(filename):
filename = os.path.expanduser(filename)
with open(filename, "rb") as stream:
scope = yaml.safe_load(stream.read())
return scope

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
@@ -53,11 +52,26 @@ A generic error message, given when no more specific message is suitable.
An alias of :py:exc:`watcherclient.common.apiclient.ValidationError`
"""
Conflict = exceptions.Conflict
ConnectionRefused = exceptions.ConnectionRefused
EndpointException = exceptions.EndpointException
EndpointNotFound = exceptions.EndpointNotFound
ServiceUnavailable = exceptions.ServiceUnavailable
class UnsupportedVersion(Exception):
"""Unsupported API Version
Indicates that the user is trying to use an unsupported version of the API.
"""
pass
class AmbiguousAuthSystem(exceptions.ClientException):
"""Could not obtain token and endpoint using provided credentials."""
pass
# Alias for backwards compatibility
AmbigiousAuthSystem = AmbiguousAuthSystem
@@ -86,11 +100,10 @@ def from_response(response, message=None, traceback=None, method=None,
'Content-Type': response.getheader('content-type', "")}
if hasattr(response, 'status_code'):
# NOTE(jiangfei): These modifications allow SessionClient
# to handle faultstring.
# NOTE(hongbin): This allows SessionClient to handle faultstring.
response.json = lambda: {'error': error_body}
if (response.headers['Content-Type'].startswith('text/') and
if (response.headers.get('Content-Type', '').startswith('text/') and
not hasattr(response, 'text')):
# NOTE(clif_h): There seems to be a case in the
# common.apiclient.exceptions module where if the
@@ -100,4 +113,4 @@ def from_response(response, message=None, traceback=None, method=None,
# This is to work around that problem.
response.text = ''
return exceptions.from_response(response, message, url)
return exceptions.from_response(response, method, url)

View File

@@ -0,0 +1,90 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import logging
from osc_lib import utils
import watcherclient
from watcherclient.common import api_versioning
from watcherclient.common import httpclient
from watcherclient import exceptions
LOG = logging.getLogger(__name__)
DEFAULT_API_VERSION = httpclient.LATEST_VERSION
API_VERSION_OPTION = 'os_infra_optim_api_version'
API_NAME = 'infra-optim'
API_VERSIONS = {
'1': 'watcherclient.v1.client.Client',
}
def make_client(instance):
"""Returns an infra-optim service client."""
version = api_versioning.APIVersion(instance._api_version[API_NAME])
infraoptim_client_class = utils.get_client_class(
API_NAME,
version.ver_major,
API_VERSIONS)
LOG.debug('Instantiating infraoptim client: %s', infraoptim_client_class)
client = infraoptim_client_class(
os_infra_optim_api_version=instance._api_version[API_NAME],
session=instance.session,
region_name=instance._region_name,
)
return client
def build_option_parser(parser):
"""Hook to add global options."""
parser.add_argument('--os-infra-optim-api-version',
metavar='<infra-optim-api-version>',
default=utils.env(
'OS_INFRA_OPTIM_API_VERSION',
default=DEFAULT_API_VERSION),
help=('Watcher API version, default=' +
DEFAULT_API_VERSION +
' (Env: OS_INFRA_OPTIM_API_VERSION)'))
return parser
def check_api_version(check_version):
"""Validate version supplied by user
Returns:
* True if version is OK
* False if the version has not been checked and the previous plugin
check should be performed
* throws an exception if the version is no good
"""
infra_api_version = api_versioning.get_api_version(check_version)
# Bypass X.latest format microversion
if not infra_api_version.is_latest():
if infra_api_version > api_versioning.APIVersion("2.0"):
if not infra_api_version.matches(
watcherclient.API_MIN_VERSION,
watcherclient.API_MAX_VERSION,
):
msg = "versions supported by client: %(min)s - %(max)s" % {
"min": watcherclient.API_MIN_VERSION.get_string(),
"max": watcherclient.API_MAX_VERSION.get_string(),
}
raise exceptions.CommandError(msg)
return True

View File

@@ -1,507 +1,212 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2013 Rackspace, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Command-line interface to the Watcher API.
"""
from __future__ import print_function
import argparse
import getpass
from collections import namedtuple
import logging
import sys
from keystoneclient.auth.identity import v2 as v2_auth
from keystoneclient.auth.identity import v3 as v3_auth
from keystoneclient import discover
from keystoneclient import exceptions as ks_exc
from keystoneclient import session as kssession
import six.moves.urllib.parse as urlparse
from cliff import app
from cliff import command
from cliff import commandmanager
from cliff import complete
from cliff import help as cli_help
from keystoneauth1 import loading
from osc_lib import logs
from osc_lib import utils
import watcherclient
from watcherclient._i18n import _
from watcherclient import client as watcher_client
from watcherclient.common import cliutils
from watcherclient.common import utils
from watcherclient import exceptions as exc
from watcherclient import client as watcherclient
from watcherclient import version
LOG = logging.getLogger(__name__)
class WatcherShell(object):
API_NAME = 'infra-optim'
API_VERSIONS = {
'1': 'watcherclient.v1.client.Client',
}
DEFAULT_OS_INFRA_OPTIM_API_VERSION = '1.latest'
_DEFAULT_IDENTITY_API_VERSION = '3'
_IDENTITY_API_VERSION_2 = ['2', '2.0']
_IDENTITY_API_VERSION_3 = ['3']
def _append_global_identity_args(self, parser):
# FIXME(dhu): these are global identity (Keystone) arguments which
# should be consistent and shared by all service clients. Therefore,
# they should be provided by python-keystoneclient. We will need to
# refactor this code once this functionality is avaible in
# python-keystoneclient.
# Register arguments needed for a Session
kssession.Session.register_cli_options(parser)
class WatcherShell(app.App):
"""Watcher command line interface."""
def __init__(self, **kwargs):
self.client = None
# Patch command.Command to add a default auth_required = True
command.Command.auth_required = True
# Some commands do not need authentication
cli_help.HelpCommand.auth_required = False
complete.CompleteCommand.auth_required = False
super(WatcherShell, self).__init__(
description=__doc__.strip(),
version=version.__version__,
command_manager=commandmanager.CommandManager(
'watcherclient.v1'),
deferred_help=True,
**kwargs
)
def create_client(self, args):
client = watcherclient.get_client('1', **args.__dict__)
return client
def build_option_parser(self, description, version, argparse_kwargs=None):
"""Introduces global arguments for the application.
This is inherited from the framework.
"""
parser = super(WatcherShell, self).build_option_parser(
description, version, argparse_kwargs)
parser.add_argument('--no-auth', '-N', action='store_true',
help='Do not use authentication.')
parser.add_argument('--os-identity-api-version',
metavar='<identity-api-version>',
default=utils.env('OS_IDENTITY_API_VERSION'),
help='Specify Identity API version to use. '
'Defaults to env[OS_IDENTITY_API_VERSION]'
' or 3.')
parser.add_argument('--os-auth-url', '-A',
metavar='<auth-url>',
default=utils.env('OS_AUTH_URL'),
help='Defaults to env[OS_AUTH_URL].')
parser.add_argument('--os-region-name', '-R',
metavar='<region-name>',
default=utils.env('OS_REGION_NAME'),
help='Defaults to env[OS_REGION_NAME].')
parser.add_argument('--os-username', '-U',
metavar='<auth-user-name>',
default=utils.env('OS_USERNAME'),
help='Defaults to env[OS_USERNAME].')
parser.add_argument('--os-user-id',
metavar='<auth-user-id>',
default=utils.env('OS_USER_ID'),
help='Defaults to env[OS_USER_ID].')
parser.add_argument('--os-password', '-P',
metavar='<auth-password>',
default=utils.env('OS_PASSWORD'),
help='Defaults to env[OS_PASSWORD].')
parser.add_argument('--os-user-domain-id',
default=cliutils.env('OS_USER_DOMAIN_ID'),
metavar='<auth-user-domain-id>',
default=utils.env('OS_USER_DOMAIN_ID'),
help='Defaults to env[OS_USER_DOMAIN_ID].')
parser.add_argument('--os-user-domain-name',
default=cliutils.env('OS_USER_DOMAIN_NAME'),
metavar='<auth-user-domain-name>',
default=utils.env('OS_USER_DOMAIN_NAME'),
help='Defaults to env[OS_USER_DOMAIN_NAME].')
parser.add_argument('--os-tenant-name', '-T',
metavar='<auth-tenant-name>',
default=utils.env('OS_TENANT_NAME'),
help='Defaults to env[OS_TENANT_NAME].')
parser.add_argument('--os-tenant-id', '-I',
metavar='<tenant-id>',
default=utils.env('OS_TENANT_ID'),
help='Defaults to env[OS_TENANT_ID].')
parser.add_argument('--os-project-id',
default=cliutils.env('OS_PROJECT_ID'),
metavar='<auth-project-id>',
default=utils.env('OS_PROJECT_ID'),
help='Another way to specify tenant ID. '
'This option is mutually exclusive with '
' --os-tenant-id. '
'Defaults to env[OS_PROJECT_ID].')
'Defaults to env[OS_PROJECT_ID].')
parser.add_argument('--os-project-name',
default=cliutils.env('OS_PROJECT_NAME'),
metavar='<auth-project-name>',
default=utils.env('OS_PROJECT_NAME'),
help='Another way to specify tenant name. '
'This option is mutually exclusive with '
' --os-tenant-name. '
'Defaults to env[OS_PROJECT_NAME].')
parser.add_argument('--os-project-domain-id',
default=cliutils.env('OS_PROJECT_DOMAIN_ID'),
metavar='<auth-project-domain-id>',
default=utils.env('OS_PROJECT_DOMAIN_ID'),
help='Defaults to env[OS_PROJECT_DOMAIN_ID].')
parser.add_argument('--os-project-domain-name',
default=cliutils.env('OS_PROJECT_DOMAIN_NAME'),
metavar='<auth-project-domain-name>',
default=utils.env('OS_PROJECT_DOMAIN_NAME'),
help='Defaults to env[OS_PROJECT_DOMAIN_NAME].')
def get_base_parser(self):
parser = argparse.ArgumentParser(
prog='watcher',
description=__doc__.strip(),
epilog='See "watcher help COMMAND" '
'for help on a specific command.',
add_help=False,
formatter_class=HelpFormatter,
)
# Global arguments
parser.add_argument('-h', '--help',
action='store_true',
help=argparse.SUPPRESS,
)
parser.add_argument('--version',
action='version',
version=watcherclient.__version__)
parser.add_argument('--debug',
default=bool(cliutils.env('WATCHERCLIENT_DEBUG')),
action='store_true',
help='Defaults to env[WATCHERCLIENT_DEBUG]')
parser.add_argument('-v', '--verbose',
default=False, action="store_true",
help="Print more verbose output")
# for backward compatibility only
parser.add_argument('--cert-file',
dest='os_cert',
help='DEPRECATED! Use --os-cert.')
# for backward compatibility only
parser.add_argument('--key-file',
dest='os_key',
help='DEPRECATED! Use --os-key.')
# for backward compatibility only
parser.add_argument('--ca-file',
dest='os_cacert',
help='DEPRECATED! Use --os-cacert.')
parser.add_argument('--os-username',
default=cliutils.env('OS_USERNAME'),
help='Defaults to env[OS_USERNAME]')
parser.add_argument('--os_username',
help=argparse.SUPPRESS)
parser.add_argument('--os-password',
default=cliutils.env('OS_PASSWORD'),
help='Defaults to env[OS_PASSWORD]')
parser.add_argument('--os_password',
help=argparse.SUPPRESS)
parser.add_argument('--os-tenant-id',
default=cliutils.env('OS_TENANT_ID'),
help='Defaults to env[OS_TENANT_ID]')
parser.add_argument('--os_tenant_id',
help=argparse.SUPPRESS)
parser.add_argument('--os-tenant-name',
default=cliutils.env('OS_TENANT_NAME'),
help='Defaults to env[OS_TENANT_NAME]')
parser.add_argument('--os_tenant_name',
help=argparse.SUPPRESS)
parser.add_argument('--os-auth-url',
default=cliutils.env('OS_AUTH_URL'),
help='Defaults to env[OS_AUTH_URL]')
parser.add_argument('--os_auth_url',
help=argparse.SUPPRESS)
parser.add_argument('--os-region-name',
default=cliutils.env('OS_REGION_NAME'),
help='Defaults to env[OS_REGION_NAME]')
parser.add_argument('--os_region_name',
help=argparse.SUPPRESS)
parser.add_argument('--os-auth-token',
default=cliutils.env('OS_AUTH_TOKEN'),
help='Defaults to env[OS_AUTH_TOKEN]')
parser.add_argument('--os_auth_token',
help=argparse.SUPPRESS)
parser.add_argument('--watcher-url',
default=cliutils.env('WATCHER_URL'),
help='Defaults to env[WATCHER_URL]')
parser.add_argument('--watcher_url',
help=argparse.SUPPRESS)
parser.add_argument('--watcher-api-version',
default=cliutils.env(
'WATCHER_API_VERSION', default='1'),
help='Defaults to env[WATCHER_API_VERSION] '
'or 1')
parser.add_argument('--watcher_api_version',
help=argparse.SUPPRESS)
parser.add_argument('--os-service-type',
default=cliutils.env('OS_SERVICE_TYPE'),
help='Defaults to env[OS_SERVICE_TYPE] or '
'"watcher"')
parser.add_argument('--os_service_type',
help=argparse.SUPPRESS)
parser.add_argument('--os-endpoint',
default=cliutils.env('OS_SERVICE_ENDPOINT'),
help='Specify an endpoint to use instead of '
'retrieving one from the service catalog '
'(via authentication). '
'Defaults to env[OS_SERVICE_ENDPOINT].')
parser.add_argument('--os_endpoint',
help=argparse.SUPPRESS)
metavar='<auth-token>',
default=utils.env('OS_AUTH_TOKEN'),
help='Defaults to env[OS_AUTH_TOKEN].')
parser.add_argument(
'--os-infra-optim-api-version',
metavar='<infra-optim-api-version>',
default=utils.env('OS_INFRA_OPTIM_API_VERSION',
default=DEFAULT_OS_INFRA_OPTIM_API_VERSION),
help='Accepts X, X.Y (where X is major and Y is minor part) or '
'"X.latest", defaults to env[OS_INFRA_OPTIM_API_VERSION].')
parser.add_argument('--os-endpoint-type',
default=cliutils.env('OS_ENDPOINT_TYPE'),
default=utils.env('OS_ENDPOINT_TYPE'),
help='Defaults to env[OS_ENDPOINT_TYPE] or '
'"publicURL"')
parser.add_argument('--os_endpoint_type',
help=argparse.SUPPRESS)
# FIXME(gyee): this method should come from python-keystoneclient.
# Will refactor this code once it is available.
# https://bugs.launchpad.net/python-keystoneclient/+bug/1332337
self._append_global_identity_args(parser)
parser.add_argument('--os-endpoint-override',
metavar='<endpoint-override>',
default=utils.env('OS_ENDPOINT_OVERRIDE'),
help="Use this API endpoint instead of the "
"Service Catalog.")
parser.epilog = ('See "watcher help COMMAND" for help '
'on a specific command.')
loading.register_session_argparse_arguments(parser)
return parser
def get_subcommand_parser(self, version):
parser = self.get_base_parser()
def configure_logging(self):
"""Configure logging for the app."""
self.log_configurator = logs.LogConfigurator(self.options)
self.dump_stack_trace = self.log_configurator.dump_trace
self.subcommands = {}
subparsers = parser.add_subparsers(metavar='<subcommand>')
submodule = utils.import_versioned_module(version, 'shell')
submodule.enhance_parser(parser, subparsers, self.subcommands)
utils.define_commands_from_module(subparsers, self, self.subcommands)
return parser
def prepare_to_run_command(self, cmd):
"""Prepares to run the command
def _setup_debugging(self, debug):
if debug:
logging.basicConfig(
format="%(levelname)s (%(module)s:%(lineno)d) %(message)s",
level=logging.DEBUG)
else:
logging.basicConfig(
format="%(levelname)s %(message)s",
level=logging.CRITICAL)
Checks if the minimal parameters are provided and creates the
client interface.
This is inherited from the framework.
"""
self.client_manager = namedtuple('ClientManager', 'infra_optim')
if cmd.auth_required:
client = self.create_client(self.options)
setattr(self.client_manager, 'infra-optim', client)
def do_bash_completion(self):
"""Prints all of the commands and options for bash-completion."""
commands = set()
options = set()
for sc_str, sc in self.subcommands.items():
commands.add(sc_str)
for option in sc._optionals._option_string_actions.keys():
options.add(option)
commands.remove('bash-completion')
print(' '.join(commands | options))
def _discover_auth_versions(self, session, auth_url):
# discover the API versions the server is supporting base on the
# given URL
v2_auth_url = None
v3_auth_url = None
def run(self, argv):
ret_val = 1
self.command_options = argv
try:
ks_discover = discover.Discover(session=session, auth_url=auth_url)
v2_auth_url = ks_discover.url_for('2.0')
v3_auth_url = ks_discover.url_for('3.0')
except ks_exc.ClientException:
# Identity service may not support discover API version.
# Let's try to figure out the API version from the original URL.
url_parts = urlparse.urlparse(auth_url)
(scheme, netloc, path, params, query, fragment) = url_parts
path = path.lower()
if path.startswith('/v3'):
v3_auth_url = auth_url
elif path.startswith('/v2'):
v2_auth_url = auth_url
else:
# not enough information to determine the auth version
msg = _('Unable to determine the Keystone version '
'to authenticate with using the given '
'auth_url. Identity service may not support API '
'version discovery. Please provide a versioned '
'auth_url instead. %s') % auth_url
raise exc.CommandError(msg)
ret_val = super(WatcherShell, self).run(argv)
return ret_val
except Exception as e:
if not logging.getLogger('').handlers:
logging.basicConfig()
LOG.error('Exception raised: %s', str(e))
return (v2_auth_url, v3_auth_url)
return ret_val
def _get_keystone_v3_auth(self, v3_auth_url, **kwargs):
auth_token = kwargs.pop('auth_token', None)
if auth_token:
return v3_auth.Token(v3_auth_url, auth_token)
else:
return v3_auth.Password(v3_auth_url, **kwargs)
def _get_keystone_v2_auth(self, v2_auth_url, **kwargs):
auth_token = kwargs.pop('auth_token', None)
if auth_token:
return v2_auth.Token(
v2_auth_url,
auth_token,
tenant_id=kwargs.pop('project_id', None),
tenant_name=kwargs.pop('project_name', None))
else:
return v2_auth.Password(
v2_auth_url,
username=kwargs.pop('username', None),
password=kwargs.pop('password', None),
tenant_id=kwargs.pop('project_id', None),
tenant_name=kwargs.pop('project_name', None))
def _get_keystone_auth(self, session, auth_url, **kwargs):
# FIXME(dhu): this code should come from keystoneclient
# discover the supported keystone versions using the given url
(v2_auth_url, v3_auth_url) = self._discover_auth_versions(
session=session,
auth_url=auth_url)
# Determine which authentication plugin to use. First inspect the
# auth_url to see the supported version. If both v3 and v2 are
# supported, then use the highest version if possible.
auth = None
if v3_auth_url and v2_auth_url:
user_domain_name = kwargs.get('user_domain_name', None)
user_domain_id = kwargs.get('user_domain_id', None)
project_domain_name = kwargs.get('project_domain_name', None)
project_domain_id = kwargs.get('project_domain_id', None)
# support both v2 and v3 auth. Use v3 if domain information is
# provided.
if (user_domain_name or user_domain_id or project_domain_name or
project_domain_id):
auth = self._get_keystone_v3_auth(v3_auth_url, **kwargs)
else:
auth = self._get_keystone_v2_auth(v2_auth_url, **kwargs)
elif v3_auth_url:
# support only v3
auth = self._get_keystone_v3_auth(v3_auth_url, **kwargs)
elif v2_auth_url:
# support only v2
auth = self._get_keystone_v2_auth(v2_auth_url, **kwargs)
else:
raise exc.CommandError(
_('Unable to determine the Keystone version '
'to authenticate with using the given '
'auth_url.'))
return auth
def main(self, argv):
# Parse args once to find version
parser = self.get_base_parser()
(options, args) = parser.parse_known_args(argv)
self._setup_debugging(options.debug)
# build available subcommands based on version
api_version = options.watcher_api_version
subcommand_parser = self.get_subcommand_parser(api_version)
self.parser = subcommand_parser
# Handle top-level --help/-h before attempting to parse
# a command off the command line
if options.help or not argv:
self.do_help(options)
return 0
# Parse args again and call whatever callback was selected
args = subcommand_parser.parse_args(argv)
# Short-circuit and deal with these commands right away.
if args.func == self.do_help:
self.do_help(args)
return 0
elif args.func == self.do_bash_completion:
self.do_bash_completion()
return 0
if not (args.os_auth_token and (args.watcher_url or args.os_endpoint)):
if not args.os_username:
raise exc.CommandError(_("You must provide a username via "
"either --os-username or via "
"env[OS_USERNAME]"))
if not args.os_password:
# No password, If we've got a tty, try prompting for it
if hasattr(sys.stdin, 'isatty') and sys.stdin.isatty():
# Check for Ctl-D
try:
args.os_password = getpass.getpass(
'OpenStack Password: ')
except EOFError:
pass
# No password because we didn't have a tty or the
# user Ctl-D when prompted.
if not args.os_password:
raise exc.CommandError(_("You must provide a password via "
"either --os-password, "
"env[OS_PASSWORD], "
"or prompted response"))
if not (args.os_tenant_id or args.os_tenant_name or
args.os_project_id or args.os_project_name):
raise exc.CommandError(_(
"You must provide a project name or"
" project id via --os-project-name, --os-project-id,"
" env[OS_PROJECT_ID] or env[OS_PROJECT_NAME]. You may"
" use os-project and os-tenant interchangeably."))
if not args.os_auth_url:
raise exc.CommandError(_("You must provide an auth url via "
"either --os-auth-url or via "
"env[OS_AUTH_URL]"))
endpoint = args.watcher_url or args.os_endpoint
service_type = args.os_service_type or 'infra-optim'
project_id = args.os_project_id or args.os_tenant_id
project_name = args.os_project_name or args.os_tenant_name
if (args.os_auth_token and (args.watcher_url or args.os_endpoint)):
kwargs = {
'token': args.os_auth_token,
'insecure': args.insecure,
'timeout': args.timeout,
'ca_file': args.os_cacert,
'cert_file': args.os_cert,
'key_file': args.os_key,
'auth_ref': None,
}
elif (args.os_username and
args.os_password and
args.os_auth_url and
(project_id or project_name)):
keystone_session = kssession.Session.load_from_cli_options(args)
kwargs = {
'username': args.os_username,
'user_domain_id': args.os_user_domain_id,
'user_domain_name': args.os_user_domain_name,
'password': args.os_password,
'auth_token': args.os_auth_token,
'project_id': project_id,
'project_name': project_name,
'project_domain_id': args.os_project_domain_id,
'project_domain_name': args.os_project_domain_name,
}
keystone_auth = self._get_keystone_auth(keystone_session,
args.os_auth_url,
**kwargs)
if not endpoint:
svc_type = args.os_service_type
region_name = args.os_region_name
endpoint = keystone_auth.get_endpoint(keystone_session,
service_type=svc_type,
region_name=region_name)
endpoint_type = args.os_endpoint_type or 'publicURL'
kwargs = {
'auth_url': args.os_auth_url,
'session': keystone_session,
'auth': keystone_auth,
'service_type': service_type,
'endpoint_type': endpoint_type,
'region_name': args.os_region_name,
'username': args.os_username,
'password': args.os_password,
}
client = watcher_client.Client(api_version, endpoint, **kwargs)
try:
args.func(client, args)
except exc.Unauthorized:
raise exc.CommandError(_("Invalid OpenStack Identity credentials"))
@cliutils.arg('command', metavar='<subcommand>', nargs='?',
help='Display help for <subcommand>')
def do_help(self, args):
"""Display help about this program or one of its subcommands."""
if getattr(args, 'command', None):
if args.command in self.subcommands:
self.subcommands[args.command].print_help()
else:
raise exc.CommandError(_("'%s' is not a valid subcommand") %
args.command)
else:
self.parser.print_help()
finally:
LOG.info("END return value: %s", ret_val)
class HelpFormatter(argparse.HelpFormatter):
def start_section(self, heading):
# Title-case the headings
heading = '%s%s' % (heading[0].upper(), heading[1:])
super(HelpFormatter, self).start_section(heading)
def main(argv=sys.argv[1:]):
watcher_app = WatcherShell()
return watcher_app.run(argv)
def main():
try:
WatcherShell().main(sys.argv[1:])
except KeyboardInterrupt:
print("... terminating watcher client", file=sys.stderr)
sys.exit(130)
except Exception as e:
print(str(e), file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
main()
if __name__ == '__main__': # pragma: no cover
sys.exit(main(sys.argv[1:]))

View File

@@ -1,142 +0,0 @@
# -*- coding: utf-8 -*-
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import fixtures
from watcherclient.client import get_client
from watcherclient import exceptions as exc
from watcherclient.tests import utils
def fake_get_ksclient(**kwargs):
return utils.FakeKeystone('KSCLIENT_AUTH_TOKEN')
class ClientTest(utils.BaseTestCase):
def test_get_client_with_auth_token_watcher_url(self):
self.useFixture(fixtures.MonkeyPatch(
'watcherclient.client._get_ksclient', fake_get_ksclient))
kwargs = {
'watcher_url': 'http://watcher.example.org:6385/',
'os_auth_token': 'USER_AUTH_TOKEN',
}
client = get_client('1', **kwargs)
self.assertEqual('USER_AUTH_TOKEN', client.http_client.auth_token)
self.assertEqual('http://watcher.example.org:6385/',
client.http_client.endpoint)
def test_get_client_no_auth_token(self):
self.useFixture(fixtures.MonkeyPatch(
'watcherclient.client._get_ksclient', fake_get_ksclient))
kwargs = {
'os_tenant_name': 'TENANT_NAME',
'os_username': 'USERNAME',
'os_password': 'PASSWORD',
'os_auth_url': 'http://localhost:35357/v2.0',
'os_auth_token': '',
}
client = get_client('1', **kwargs)
self.assertEqual('KSCLIENT_AUTH_TOKEN', client.http_client.auth_token)
self.assertEqual('http://localhost:6385/v1/f14b41234',
client.http_client.endpoint)
self.assertEqual(fake_get_ksclient().auth_ref,
client.http_client.auth_ref)
def test_get_client_with_region_no_auth_token(self):
self.useFixture(fixtures.MonkeyPatch(
'watcherclient.client._get_ksclient', fake_get_ksclient))
kwargs = {
'os_tenant_name': 'TENANT_NAME',
'os_username': 'USERNAME',
'os_password': 'PASSWORD',
'os_region_name': 'REGIONONE',
'os_auth_url': 'http://localhost:35357/v2.0',
'os_auth_token': '',
}
client = get_client('1', **kwargs)
self.assertEqual('KSCLIENT_AUTH_TOKEN', client.http_client.auth_token)
self.assertEqual('http://regionhost:6385/v1/f14b41234',
client.http_client.endpoint)
self.assertEqual(fake_get_ksclient().auth_ref,
client.http_client.auth_ref)
def test_get_client_with_auth_token(self):
self.useFixture(fixtures.MonkeyPatch(
'watcherclient.client._get_ksclient', fake_get_ksclient))
kwargs = {
'os_tenant_name': 'TENANT_NAME',
'os_username': 'USERNAME',
'os_password': 'PASSWORD',
'os_auth_url': 'http://localhost:35357/v2.0',
'os_auth_token': 'USER_AUTH_TOKEN',
}
client = get_client('1', **kwargs)
self.assertEqual('USER_AUTH_TOKEN', client.http_client.auth_token)
self.assertEqual('http://localhost:6385/v1/f14b41234',
client.http_client.endpoint)
self.assertEqual(fake_get_ksclient().auth_ref,
client.http_client.auth_ref)
def test_get_client_with_region_name_auth_token(self):
self.useFixture(fixtures.MonkeyPatch(
'watcherclient.client._get_ksclient', fake_get_ksclient))
kwargs = {
'os_tenant_name': 'TENANT_NAME',
'os_username': 'USERNAME',
'os_password': 'PASSWORD',
'os_auth_url': 'http://localhost:35357/v2.0',
'os_region_name': 'REGIONONE',
'os_auth_token': 'USER_AUTH_TOKEN',
}
client = get_client('1', **kwargs)
self.assertEqual('USER_AUTH_TOKEN', client.http_client.auth_token)
self.assertEqual('http://regionhost:6385/v1/f14b41234',
client.http_client.endpoint)
self.assertEqual(fake_get_ksclient().auth_ref,
client.http_client.auth_ref)
def test_get_client_no_url_and_no_token(self):
self.useFixture(fixtures.MonkeyPatch(
'watcherclient.client._get_ksclient', fake_get_ksclient))
kwargs = {
'os_tenant_name': 'TENANT_NAME',
'os_username': 'USERNAME',
'os_password': 'PASSWORD',
'os_auth_url': '',
'os_auth_token': '',
}
self.assertRaises(exc.AmbiguousAuthSystem, get_client, '1', **kwargs)
# test the alias as well to ensure backwards compatibility
self.assertRaises(exc.AmbigiousAuthSystem, get_client, '1', **kwargs)
def test_ensure_auth_ref_propagated(self):
ksclient = fake_get_ksclient
self.useFixture(fixtures.MonkeyPatch(
'watcherclient.client._get_ksclient', ksclient))
kwargs = {
'os_tenant_name': 'TENANT_NAME',
'os_username': 'USERNAME',
'os_password': 'PASSWORD',
'os_auth_url': 'http://localhost:35357/v2.0',
'os_auth_token': '',
}
client = get_client('1', **kwargs)
self.assertEqual(ksclient().auth_ref, client.http_client.auth_ref)

View File

@@ -1,283 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright 2012 OpenStack LLC.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import json
import six
from watcherclient.common import http
from watcherclient import exceptions as exc
from watcherclient.tests import utils
HTTP_CLASS = six.moves.http_client.HTTPConnection
HTTPS_CLASS = http.VerifiedHTTPSConnection
DEFAULT_TIMEOUT = 600
def _get_error_body(faultstring=None, debuginfo=None):
error_body = {
'faultstring': faultstring,
'debuginfo': debuginfo
}
raw_error_body = json.dumps(error_body)
body = {'error_message': raw_error_body}
raw_body = json.dumps(body)
return raw_body
class HttpClientTest(utils.BaseTestCase):
def test_url_generation_trailing_slash_in_base(self):
client = http.HTTPClient('http://localhost/')
url = client._make_connection_url('/v1/resources')
self.assertEqual('/v1/resources', url)
def test_url_generation_without_trailing_slash_in_base(self):
client = http.HTTPClient('http://localhost')
url = client._make_connection_url('/v1/resources')
self.assertEqual('/v1/resources', url)
def test_url_generation_prefix_slash_in_path(self):
client = http.HTTPClient('http://localhost/')
url = client._make_connection_url('/v1/resources')
self.assertEqual('/v1/resources', url)
def test_url_generation_without_prefix_slash_in_path(self):
client = http.HTTPClient('http://localhost')
url = client._make_connection_url('v1/resources')
self.assertEqual('/v1/resources', url)
def test_server_exception_empty_body(self):
error_body = _get_error_body()
fake_resp = utils.FakeResponse({'content-type': 'application/json'},
six.StringIO(error_body),
version=1,
status=500)
client = http.HTTPClient('http://localhost/')
client.get_connection = (
lambda *a, **kw: utils.FakeConnection(fake_resp))
error = self.assertRaises(exc.InternalServerError,
client.json_request,
'GET', '/v1/resources')
self.assertEqual('Internal Server Error (HTTP 500)', str(error))
def test_server_exception_msg_only(self):
error_msg = 'test error msg'
error_body = _get_error_body(error_msg)
fake_resp = utils.FakeResponse({'content-type': 'application/json'},
six.StringIO(error_body),
version=1,
status=500)
client = http.HTTPClient('http://localhost/')
client.get_connection = (
lambda *a, **kw: utils.FakeConnection(fake_resp))
error = self.assertRaises(exc.InternalServerError,
client.json_request,
'GET', '/v1/resources')
self.assertEqual(error_msg + ' (HTTP 500)', str(error))
def test_server_exception_msg_and_traceback(self):
error_msg = 'another test error'
error_trace = ("\"Traceback (most recent call last):\\n\\n "
"File \\\"/usr/local/lib/python2.7/...")
error_body = _get_error_body(error_msg, error_trace)
fake_resp = utils.FakeResponse({'content-type': 'application/json'},
six.StringIO(error_body),
version=1,
status=500)
client = http.HTTPClient('http://localhost/')
client.get_connection = (
lambda *a, **kw: utils.FakeConnection(fake_resp))
error = self.assertRaises(exc.InternalServerError,
client.json_request,
'GET', '/v1/resources')
self.assertEqual(
'%(error)s (HTTP 500)\n%(trace)s' % {'error': error_msg,
'trace': error_trace},
"%(error)s\n%(details)s" % {'error': str(error),
'details': str(error.details)})
def test_get_connection_params(self):
endpoint = 'http://watcher-host:6385'
expected = (HTTP_CLASS,
('watcher-host', 6385, ''),
{'timeout': DEFAULT_TIMEOUT})
params = http.HTTPClient.get_connection_params(endpoint)
self.assertEqual(expected, params)
def test_get_connection_params_with_trailing_slash(self):
endpoint = 'http://watcher-host:6385/'
expected = (HTTP_CLASS,
('watcher-host', 6385, ''),
{'timeout': DEFAULT_TIMEOUT})
params = http.HTTPClient.get_connection_params(endpoint)
self.assertEqual(expected, params)
def test_get_connection_params_with_ssl(self):
endpoint = 'https://watcher-host:6385'
expected = (HTTPS_CLASS,
('watcher-host', 6385, ''),
{
'timeout': DEFAULT_TIMEOUT,
'ca_file': None,
'cert_file': None,
'key_file': None,
'insecure': False,
})
params = http.HTTPClient.get_connection_params(endpoint)
self.assertEqual(expected, params)
def test_get_connection_params_with_ssl_params(self):
endpoint = 'https://watcher-host:6385'
ssl_args = {
'ca_file': '/path/to/ca_file',
'cert_file': '/path/to/cert_file',
'key_file': '/path/to/key_file',
'insecure': True,
}
expected_kwargs = {'timeout': DEFAULT_TIMEOUT}
expected_kwargs.update(ssl_args)
expected = (HTTPS_CLASS,
('watcher-host', 6385, ''),
expected_kwargs)
params = http.HTTPClient.get_connection_params(endpoint, **ssl_args)
self.assertEqual(expected, params)
def test_get_connection_params_with_timeout(self):
endpoint = 'http://watcher-host:6385'
expected = (HTTP_CLASS,
('watcher-host', 6385, ''),
{'timeout': 300.0})
params = http.HTTPClient.get_connection_params(endpoint, timeout=300)
self.assertEqual(expected, params)
def test_get_connection_params_with_version(self):
endpoint = 'http://watcher-host:6385/v1'
expected = (HTTP_CLASS,
('watcher-host', 6385, ''),
{'timeout': DEFAULT_TIMEOUT})
params = http.HTTPClient.get_connection_params(endpoint)
self.assertEqual(expected, params)
def test_get_connection_params_with_version_trailing_slash(self):
endpoint = 'http://watcher-host:6385/v1/'
expected = (HTTP_CLASS,
('watcher-host', 6385, ''),
{'timeout': DEFAULT_TIMEOUT})
params = http.HTTPClient.get_connection_params(endpoint)
self.assertEqual(expected, params)
def test_get_connection_params_with_subpath(self):
endpoint = 'http://watcher-host:6385/watcher'
expected = (HTTP_CLASS,
('watcher-host', 6385, '/watcher'),
{'timeout': DEFAULT_TIMEOUT})
params = http.HTTPClient.get_connection_params(endpoint)
self.assertEqual(expected, params)
def test_get_connection_params_with_subpath_trailing_slash(self):
endpoint = 'http://watcher-host:6385/watcher/'
expected = (HTTP_CLASS,
('watcher-host', 6385, '/watcher'),
{'timeout': DEFAULT_TIMEOUT})
params = http.HTTPClient.get_connection_params(endpoint)
self.assertEqual(expected, params)
def test_get_connection_params_with_subpath_version(self):
endpoint = 'http://watcher-host:6385/watcher/v1'
expected = (HTTP_CLASS,
('watcher-host', 6385, '/watcher'),
{'timeout': DEFAULT_TIMEOUT})
params = http.HTTPClient.get_connection_params(endpoint)
self.assertEqual(expected, params)
def test_get_connection_params_with_subpath_version_trailing_slash(self):
endpoint = 'http://watcher-host:6385/watcher/v1/'
expected = (HTTP_CLASS,
('watcher-host', 6385, '/watcher'),
{'timeout': DEFAULT_TIMEOUT})
params = http.HTTPClient.get_connection_params(endpoint)
self.assertEqual(expected, params)
def test_401_unauthorized_exception(self):
error_body = _get_error_body()
fake_resp = utils.FakeResponse({'content-type': 'text/plain'},
six.StringIO(error_body),
version=1,
status=401)
client = http.HTTPClient('http://localhost/')
client.get_connection = (
lambda *a, **kw: utils.FakeConnection(fake_resp))
self.assertRaises(exc.Unauthorized, client.json_request,
'GET', '/v1/resources')
class SessionClientTest(utils.BaseTestCase):
def test_server_exception_msg_and_traceback(self):
error_msg = 'another test error'
error_trace = ("\"Traceback (most recent call last):\\n\\n "
"File \\\"/usr/local/lib/python2.7/...")
error_body = _get_error_body(error_msg, error_trace)
fake_session = utils.FakeSession({'Content-Type': 'application/json'},
error_body,
500)
client = http.SessionClient(session=fake_session,
auth=None,
interface=None,
service_type='publicURL',
region_name='',
service_name=None)
error = self.assertRaises(exc.InternalServerError,
client.json_request,
'GET', '/v1/resources')
self.assertEqual(
'%(error)s (HTTP 500)\n%(trace)s' % {'error': error_msg,
'trace': error_trace},
"%(error)s\n%(details)s" % {'error': str(error),
'details': str(error.details)})
def test_server_exception_empty_body(self):
error_body = _get_error_body()
fake_session = utils.FakeSession({'Content-Type': 'application/json'},
error_body,
500)
client = http.SessionClient(session=fake_session,
auth=None,
interface=None,
service_type='publicURL',
region_name='',
service_name=None)
error = self.assertRaises(exc.InternalServerError,
client.json_request,
'GET', '/v1/resources')
self.assertEqual('Internal Server Error (HTTP 500)', str(error))

View File

@@ -1,154 +0,0 @@
# -*- coding: utf-8 -*-
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import re
import sys
import fixtures
from keystoneclient import exceptions as keystone_exc
import mock
import six
from testtools import matchers
from watcherclient import exceptions as exc
from watcherclient import shell as watcher_shell
from watcherclient.tests import utils
FAKE_ENV = {'OS_USERNAME': 'username',
'OS_PASSWORD': 'password',
'OS_TENANT_NAME': 'tenant_name',
'OS_AUTH_URL': 'http://no.where/v2.0/'}
class ShellTest(utils.BaseTestCase):
re_options = re.DOTALL | re.MULTILINE
# Patch os.environ to avoid required auth info.
def make_env(self, exclude=None):
env = dict((k, v) for k, v in FAKE_ENV.items() if k != exclude)
self.useFixture(fixtures.MonkeyPatch('os.environ', env))
def setUp(self):
super(ShellTest, self).setUp()
def shell(self, argstr):
orig = sys.stdout
try:
sys.stdout = six.StringIO()
_shell = watcher_shell.WatcherShell()
_shell.main(argstr.split())
except SystemExit:
exc_type, exc_value, exc_traceback = sys.exc_info()
self.assertEqual(0, exc_value.code)
finally:
out = sys.stdout.getvalue()
sys.stdout.close()
sys.stdout = orig
return out
def test_help_unknown_command(self):
self.assertRaises(exc.CommandError, self.shell, 'help foofoo')
def test_help(self):
required = [
'.*?^usage: watcher',
'.*?^ +bash-completion',
'.*?^See "watcher help COMMAND" '
'for help on a specific command',
]
for argstr in ['--help', 'help']:
help_text = self.shell(argstr)
for r in required:
self.assertThat(help_text,
matchers.MatchesRegex(r,
self.re_options))
def test_help_on_subcommand(self):
required = [
'.*?^usage: watcher action-show',
".*?^Show detailed information about an action",
]
argstrings = [
'help action-show',
]
for argstr in argstrings:
help_text = self.shell(argstr)
for r in required:
self.assertThat(help_text,
matchers.MatchesRegex(r, self.re_options))
def test_auth_param(self):
self.make_env(exclude='OS_USERNAME')
self.test_help()
@mock.patch('sys.stdin', side_effect=mock.MagicMock)
@mock.patch('getpass.getpass', return_value='password')
def test_password_prompted(self, mock_getpass, mock_stdin):
self.make_env(exclude='OS_PASSWORD')
# We will get a Connection Refused because there is no keystone.
self.assertRaises(keystone_exc.ConnectionRefused,
self.shell, 'action-list')
# Make sure we are actually prompted.
mock_getpass.assert_called_with('OpenStack Password: ')
@mock.patch('sys.stdin', side_effect=mock.MagicMock)
@mock.patch('getpass.getpass', side_effect=EOFError)
def test_password_prompted_ctrlD(self, mock_getpass, mock_stdin):
self.make_env(exclude='OS_PASSWORD')
# We should get Command Error because we mock Ctl-D.
self.assertRaises(exc.CommandError,
self.shell, 'action-list')
# Make sure we are actually prompted.
mock_getpass.assert_called_with('OpenStack Password: ')
@mock.patch('sys.stdin')
def test_no_password_no_tty(self, mock_stdin):
# delete the isatty attribute so that we do not get
# prompted when manually running the tests
del mock_stdin.isatty
required = ('You must provide a password'
' via either --os-password, env[OS_PASSWORD],'
' or prompted response',)
self.make_env(exclude='OS_PASSWORD')
try:
self.shell('action-list')
except exc.CommandError as message:
self.assertEqual(required, message.args)
else:
self.fail('CommandError not raised')
def test_bash_completion(self):
stdout = self.shell('bash-completion')
# just check we have some output
required = [
'.*help',
'.*audit-list',
'.*audit-show',
'.*audit-delete',
'.*audit-update',
'.*audit-template-create',
'.*audit-template-update',
'.*audit-template-list',
'.*audit-template-show',
'.*audit-template-delete',
'.*action-list',
'.*action-show',
'.*action-update',
'.*action-plan-list',
'.*action-plan-show',
'.*action-plan-update',
]
for r in required:
self.assertThat(stdout,
matchers.MatchesRegex(r, self.re_options))

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