Compare commits
83 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a1b6eed54c | ||
|
|
a907c2d0cd | ||
|
|
d38bb255ed | ||
|
|
30e2aad126 | ||
|
|
bc0fb4f051 | ||
|
|
ef533eb151 | ||
|
|
3c160af376 | ||
|
|
186029ac87 | ||
|
|
b9112a1199 | ||
|
|
9d301fa14a | ||
|
|
15d7d78b8b | ||
|
|
81b84bcff5 | ||
|
|
79880c2dff | ||
|
|
32259fe287 | ||
|
|
d36ba79e77 | ||
|
|
4f5487b5e1 | ||
|
|
7bf192a981 | ||
|
|
f8b341c0f3 | ||
|
|
abd6d8a0cb | ||
|
|
147e4cd383 | ||
|
|
3988e9e7a8 | ||
|
|
88131d19fd | ||
|
|
c1668fff44 | ||
|
|
1a6703266f | ||
|
|
fada471714 | ||
|
|
1cd8c38d95 | ||
|
|
0257aa9116 | ||
|
|
aa9d1a65f6 | ||
|
|
b5f584dafa | ||
|
|
bf706365ea | ||
|
|
7898268426 | ||
|
|
1eecf8fd63 | ||
|
|
e6f361804f | ||
|
|
f5b2e7e4f5 | ||
|
|
0a29b296ae | ||
|
|
4789e22e4a | ||
|
|
5378102cd6 | ||
|
|
42cab67124 | ||
|
|
0fd1b11f6d | ||
|
|
74773a60b2 | ||
|
|
e92dd4db20 | ||
|
|
ad0a32886d | ||
|
|
84f05d8e40 | ||
|
|
b33a444e90 | ||
|
|
27d1e4c85a | ||
|
|
77eb8f677f | ||
|
|
320bb4c14f | ||
|
|
7b5908b390 | ||
|
|
1d69f6a72f | ||
|
|
0e080e7294 | ||
|
|
c09ad28c9a | ||
|
|
08fbccc684 | ||
|
|
2f2d05d657 | ||
|
|
c02f584b33 | ||
|
|
d6b68dc819 | ||
|
|
a70d587803 | ||
|
|
2e47d77f86 | ||
|
|
a9405f5c2d | ||
|
|
4bb678f7a5 | ||
|
|
baadbe3dca | ||
|
|
24b089c057 | ||
|
|
c8acc20e82 | ||
|
|
fa91740b47 | ||
|
|
504ca86b78 | ||
|
|
2b155f9505 | ||
|
|
c8df16da8f | ||
|
|
0de3f627c5 | ||
|
|
9c46ee00bb | ||
|
|
48703e19e4 | ||
|
|
799084d3d1 | ||
|
|
ee087b85d5 | ||
|
|
8524016170 | ||
|
|
ed5e1b86c3 | ||
|
|
42bf82c22c | ||
|
|
0d0192c472 | ||
|
|
641cd44adb | ||
|
|
da715f8e70 | ||
|
|
abe14a14d4 | ||
|
|
984601ecfa | ||
|
|
f32956493b | ||
|
|
1e2a13fe1a | ||
|
|
417b3a2669 | ||
|
|
3f25b6b223 |
6
.gitignore
vendored
6
.gitignore
vendored
@@ -6,6 +6,7 @@
|
||||
# Packages
|
||||
*.egg
|
||||
*.egg-info
|
||||
.eggs
|
||||
dist
|
||||
build
|
||||
eggs
|
||||
@@ -42,7 +43,7 @@ output/*/index.html
|
||||
|
||||
# Sphinx
|
||||
doc/build
|
||||
doc/source/api
|
||||
doc/source/reference/api
|
||||
|
||||
# pbr generates these
|
||||
AUTHORS
|
||||
@@ -55,3 +56,6 @@ ChangeLog
|
||||
|
||||
sftp-config.json
|
||||
/.idea/
|
||||
|
||||
# Desktop Service Store
|
||||
*.DS_Store
|
||||
|
||||
8
.zuul.yaml
Normal file
8
.zuul.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
- project:
|
||||
name: openstack/python-watcherclient
|
||||
check:
|
||||
jobs:
|
||||
- watcherclient-tempest-functional
|
||||
gate:
|
||||
jobs:
|
||||
- watcherclient-tempest-functional
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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/
|
||||
|
||||
@@ -23,9 +23,9 @@ operating costs, increased system performance via intelligent virtual machine
|
||||
migration, increased energy efficiency-and more!
|
||||
|
||||
* Free software: Apache license
|
||||
* Wiki: http://wiki.openstack.org/wiki/Watcher
|
||||
* Source: http://git.openstack.org/cgit/openstack/python-watcher
|
||||
* Bugs: http://bugs.launchpad.net/watcher
|
||||
* Wiki: https://wiki.openstack.org/wiki/Watcher
|
||||
* Source: https://git.openstack.org/cgit/openstack/python-watcher
|
||||
* Bugs: https://bugs.launchpad.net/watcher
|
||||
|
||||
Installation
|
||||
============
|
||||
@@ -61,7 +61,7 @@ You can install the Watcher CLI with the following command:
|
||||
sudo pip install python-watcherclient
|
||||
|
||||
|
||||
You can also use the `OpenStack client <http://docs.openstack.org/cli-reference/overview.html>`_
|
||||
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:
|
||||
|
||||
|
||||
1012
doc/source/cli/details.rst
Normal file
1012
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
32
doc/source/cli/index.rst
Normal 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/v2.0
|
||||
|
||||
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
|
||||
@@ -24,9 +24,9 @@ OpenStack infra-optim Service (Watcher), by using our additional plugin
|
||||
|
||||
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
|
||||
@@ -37,14 +37,14 @@ environment variables::
|
||||
|
||||
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
|
||||
|
||||
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.)
|
||||
::
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
==============================================
|
||||
===============================================
|
||||
:program:`watcher` Command-Line Interface (CLI)
|
||||
==============================================
|
||||
===============================================
|
||||
|
||||
.. program:: watcher
|
||||
.. highlight:: bash
|
||||
@@ -23,9 +23,9 @@ 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
|
||||
@@ -36,14 +36,14 @@ environment variables::
|
||||
|
||||
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
|
||||
|
||||
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.)
|
||||
::
|
||||
|
||||
@@ -55,7 +55,7 @@ fill partially typed commands. To use this feature, source the below file
|
||||
https://git.openstack.org/cgit/openstack/python-watcherclient/tree/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
|
||||
@@ -11,6 +11,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
from watcherclient import version as watcherclient_version
|
||||
|
||||
# -- General configuration ----------------------------------------------------
|
||||
@@ -19,9 +20,8 @@ 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',
|
||||
]
|
||||
|
||||
'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
|
||||
@@ -69,7 +69,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
|
||||
@@ -86,3 +87,13 @@ latex_documents = [
|
||||
u'OpenStack Foundation', 'manual'
|
||||
),
|
||||
]
|
||||
|
||||
# openstackdocstheme options
|
||||
repository_name = 'openstack/python-watcherclient'
|
||||
bug_project = 'python-watcherclient'
|
||||
bug_tag = ''
|
||||
|
||||
# Must set this variable to include year, month, day, hours, and minutes.
|
||||
html_last_updated_fmt = '%Y-%m-%d %H:%M'
|
||||
|
||||
#html_theme_options = {"show_other_versions": "True"}
|
||||
|
||||
@@ -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,7 +41,7 @@ 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
|
||||
|
||||
@@ -1,42 +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
|
||||
|
||||
cli/index
|
||||
reference/index
|
||||
installation
|
||||
api_v1
|
||||
cli
|
||||
openstack_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
|
||||
.. _Watcher: https://wiki.openstack.org/wiki/Watcher
|
||||
|
||||
8
doc/source/reference/api/index.rst
Normal file
8
doc/source/reference/api/index.rst
Normal file
@@ -0,0 +1,8 @@
|
||||
======================
|
||||
Python API Reference
|
||||
======================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
autoindex
|
||||
@@ -68,7 +68,7 @@ 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
|
||||
@@ -80,12 +80,6 @@ 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
|
||||
14
doc/source/reference/index.rst
Normal file
14
doc/source/reference/index.rst
Normal 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/index
|
||||
api_v1
|
||||
@@ -3,12 +3,12 @@
|
||||
# process, which may cause wedges in the gate later.
|
||||
|
||||
Babel!=2.4.0,>=2.3.4 # BSD
|
||||
cliff>=2.6.0 # Apache-2.0
|
||||
osc-lib>=1.5.1 # Apache-2.0
|
||||
oslo.i18n!=3.15.2,>=2.1.0 # Apache-2.0
|
||||
oslo.utils>=3.20.0 # Apache-2.0
|
||||
cliff!=2.9.0,>=2.8.0 # Apache-2.0
|
||||
osc-lib>=1.8.0 # Apache-2.0
|
||||
oslo.i18n>=3.15.3 # Apache-2.0
|
||||
oslo.utils>=3.33.0 # Apache-2.0
|
||||
pbr!=2.1.0,>=2.0.0 # Apache-2.0
|
||||
PrettyTable<0.8,>=0.7.1 # BSD
|
||||
keystoneauth1>=2.20.0 # Apache-2.0
|
||||
six>=1.9.0 # MIT
|
||||
PyYAML>=3.10.0 # MIT
|
||||
keystoneauth1>=3.3.0 # Apache-2.0
|
||||
six>=1.10.0 # MIT
|
||||
PyYAML>=3.10 # MIT
|
||||
|
||||
10
setup.cfg
10
setup.cfg
@@ -5,7 +5,7 @@ description-file =
|
||||
README.rst
|
||||
author = OpenStack
|
||||
author-email = openstack-dev@lists.openstack.org
|
||||
home-page = http://docs.openstack.org/developer/python-watcherclient
|
||||
home-page = https://docs.openstack.org/python-watcherclient/latest/
|
||||
classifier =
|
||||
Environment :: OpenStack
|
||||
Intended Audience :: Information Technology
|
||||
@@ -36,6 +36,7 @@ openstack.infra_optim.v1 =
|
||||
|
||||
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
|
||||
@@ -54,6 +55,7 @@ openstack.infra_optim.v1 =
|
||||
optimize_actionplan_create = watcherclient.v1.action_plan_shell:CreateActionPlan
|
||||
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
|
||||
@@ -71,6 +73,7 @@ watcherclient.v1 =
|
||||
|
||||
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
|
||||
@@ -90,6 +93,7 @@ watcherclient.v1 =
|
||||
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
|
||||
@@ -102,11 +106,15 @@ watcherclient.v1 =
|
||||
|
||||
[pbr]
|
||||
autodoc_index_modules = True
|
||||
autodoc_exclude_modules =
|
||||
watcherclient.tests.*
|
||||
api_doc_dir = reference/api
|
||||
|
||||
[build_sphinx]
|
||||
source-dir = doc/source
|
||||
build-dir = doc/build
|
||||
all_files = 1
|
||||
warning-is-error = 1
|
||||
|
||||
[bdist_wheel]
|
||||
universal = 1
|
||||
|
||||
@@ -5,15 +5,15 @@
|
||||
coverage!=4.4,>=4.0 # Apache-2.0
|
||||
fixtures>=3.0.0 # Apache-2.0/BSD
|
||||
hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0
|
||||
mock>=2.0 # BSD
|
||||
oslosphinx>=4.7.0 # Apache-2.0
|
||||
oslotest>=1.10.0 # Apache-2.0
|
||||
python-subunit>=0.0.18 # Apache-2.0/BSD
|
||||
sphinx!=1.6.1,>=1.5.1 # BSD
|
||||
mock>=2.0.0 # BSD
|
||||
openstackdocstheme>=1.18.1 # Apache-2.0
|
||||
oslotest>=3.2.0 # Apache-2.0
|
||||
python-subunit>=1.0.0 # Apache-2.0/BSD
|
||||
sphinx!=1.6.6,>=1.6.2 # BSD
|
||||
testrepository>=0.0.18 # Apache-2.0/BSD
|
||||
testscenarios>=0.4 # Apache-2.0/BSD
|
||||
testtools>=1.4.0 # MIT
|
||||
tempest>=14.0.0 # Apache-2.0
|
||||
testtools>=2.2.0 # MIT
|
||||
tempest>=17.1.0 # Apache-2.0
|
||||
|
||||
# Needed for pypi packaging
|
||||
wheel # MIT
|
||||
wheel>=0.24.0 # MIT
|
||||
|
||||
1
tox.ini
1
tox.ini
@@ -50,6 +50,7 @@ commands = python setup.py testr --slowest --testr-args='--concurrency=1 {posarg
|
||||
[flake8]
|
||||
# E123, E125 skipped as they are invalid PEP-8.
|
||||
show-source = True
|
||||
enable-extensions = H203,H106
|
||||
ignore = E123,E125
|
||||
builtins = _
|
||||
exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build
|
||||
|
||||
@@ -204,6 +204,8 @@ def print_dict(dct, dict_property="Property", wrap=0):
|
||||
v = six.text_type(v)
|
||||
if wrap > 0:
|
||||
v = textwrap.fill(six.text_type(v), wrap)
|
||||
elif wrap < 0:
|
||||
raise ValueError(_("Wrap argument should be a positive integer"))
|
||||
# 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:
|
||||
|
||||
@@ -165,8 +165,7 @@ class VersionNegotiationMixin(object):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
_RETRY_EXCEPTIONS = (exceptions.Conflict,
|
||||
exceptions.ServiceUnavailable,
|
||||
_RETRY_EXCEPTIONS = (exceptions.ServiceUnavailable,
|
||||
exceptions.ConnectionRefused,
|
||||
kexceptions.RetriableConnectionFailure)
|
||||
|
||||
|
||||
@@ -75,7 +75,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
|
||||
@@ -88,10 +88,11 @@ def split_and_deserialize(string):
|
||||
except ValueError:
|
||||
raise exc.CommandError(_('Attributes must be a list of '
|
||||
'PATH=VALUE not "%s"') % string)
|
||||
try:
|
||||
value = jsonutils.loads(value)
|
||||
except ValueError:
|
||||
pass
|
||||
if key not in exclude_fields:
|
||||
try:
|
||||
value = jsonutils.loads(value)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
return (key, value)
|
||||
|
||||
@@ -104,7 +105,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
|
||||
@@ -112,7 +113,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":
|
||||
@@ -159,17 +161,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 = []
|
||||
@@ -179,6 +185,8 @@ 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
|
||||
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ Functional tests
|
||||
The following procedure gets you started with Tempest testing but you can also
|
||||
refer to the `Tempest documentation`_ for more details.
|
||||
|
||||
.. _Tempest documentation: http://docs.openstack.org/developer/tempest/
|
||||
.. _Tempest documentation: https://docs.openstack.org/tempest/latest/
|
||||
|
||||
|
||||
Tempest installation
|
||||
@@ -26,7 +26,7 @@ You need to install virtualenv, create a virtual environment and activate it::
|
||||
|
||||
$ pip install virtualenv
|
||||
$ virtualenv watcher-env
|
||||
$ source watcher-env/bin/activate
|
||||
$ . watcher-env/bin/activate
|
||||
|
||||
Then, to install Tempest you can issue the following commands::
|
||||
|
||||
@@ -52,7 +52,7 @@ variables.
|
||||
To run functional tests you need to go to python-watcherclient folder, install
|
||||
all requirements and execute ``tempest run`` command::
|
||||
|
||||
$ pip install -r requirements.txt test-requirements.txt
|
||||
$ pip install -r requirements.txt -r test-requirements.txt
|
||||
$ pip install .
|
||||
$ tempest run --regex watcherclient.tests.functional
|
||||
|
||||
|
||||
53
watcherclient/tests/functional/hooks/post_test_hook.sh
Executable file
53
watcherclient/tests/functional/hooks/post_test_hook.sh
Executable file
@@ -0,0 +1,53 @@
|
||||
#!/bin/bash -xe
|
||||
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
# This script is executed inside post_test_hook function in devstack gate.
|
||||
|
||||
# Default gate uses /opt/stack/new... but some of us may install differently
|
||||
STACK_DIR=$BASE/new/devstack
|
||||
|
||||
function generate_testr_results {
|
||||
if [ -f .testrepository/0 ]; then
|
||||
sudo .tox/functional/bin/testr last --subunit > $WORKSPACE/testrepository.subunit
|
||||
sudo mv $WORKSPACE/testrepository.subunit $BASE/logs/testrepository.subunit
|
||||
sudo /usr/os-testr-env/bin/subunit2html $BASE/logs/testrepository.subunit $BASE/logs/testr_results.html
|
||||
sudo gzip -9 $BASE/logs/testrepository.subunit
|
||||
sudo gzip -9 $BASE/logs/testr_results.html
|
||||
sudo chown $USER:$USER $BASE/logs/testrepository.subunit.gz $BASE/logs/testr_results.html.gz
|
||||
sudo chmod a+r $BASE/logs/testrepository.subunit.gz $BASE/logs/testr_results.html.gz
|
||||
fi
|
||||
}
|
||||
|
||||
export WATCHERCLIENT_DIR="$BASE/new/python-watcherclient"
|
||||
|
||||
sudo chown -R $USER:stack $WATCHERCLIENT_DIR
|
||||
|
||||
# Get admin credentials
|
||||
cd $STACK_DIR
|
||||
source openrc admin admin
|
||||
|
||||
# Go to the watcherclient dir
|
||||
cd $WATCHERCLIENT_DIR
|
||||
|
||||
# Run tests
|
||||
echo "Running watcherclient functional test suite"
|
||||
set +e
|
||||
# Preserve env for OS_ credentials
|
||||
sudo -E -H -u $USER tox -efunctional
|
||||
EXIT_CODE=$?
|
||||
set -e
|
||||
|
||||
# Collect and parse result
|
||||
generate_testr_results
|
||||
exit $EXIT_CODE
|
||||
@@ -10,6 +10,8 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import os
|
||||
|
||||
import re
|
||||
import shlex
|
||||
import subprocess
|
||||
@@ -20,9 +22,24 @@ from tempest.lib.cli import output_parser
|
||||
from tempest.lib import exceptions
|
||||
|
||||
|
||||
def credentials():
|
||||
creds = {
|
||||
'--os-username': os.environ.get('OS_USERNAME', 'admin'),
|
||||
'--os-password': os.environ.get('OS_PASSWORD', 'secretadmin'),
|
||||
'--os-project-name': os.environ.get('OS_PROJECT_NAME', 'admin'),
|
||||
'--os-auth-url': os.environ.get('OS_AUTH_URL',
|
||||
'http://10.0.1.94/identity'),
|
||||
'--os-project-domain-id': os.environ.get('OS_PROJECT_DOMAIN_ID',
|
||||
'default'),
|
||||
'--os-user-domain-id': os.environ.get('OS_USER_DOMAIN_ID', 'default'),
|
||||
}
|
||||
return [x for sub in creds.items() for x in sub]
|
||||
|
||||
|
||||
def execute(cmd, fail_ok=False, merge_stderr=False):
|
||||
"""Executes specified command for the given action."""
|
||||
cmdlist = shlex.split(cmd)
|
||||
cmdlist.extend(credentials())
|
||||
stdout = subprocess.PIPE
|
||||
stderr = subprocess.STDOUT if merge_stderr else subprocess.PIPE
|
||||
proc = subprocess.Popen(cmdlist, stdout=stdout, stderr=stderr)
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import time
|
||||
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from watcherclient.tests.functional.v1 import base
|
||||
@@ -44,6 +46,15 @@ class ActionPlanTests(base.TestCase):
|
||||
output = cls.parse_show(
|
||||
cls.watcher('actionplan list --audit %s' % cls.audit_uuid))
|
||||
action_plan_uuid = output[0].keys()[0]
|
||||
retry = 10
|
||||
while retry > 0:
|
||||
output = cls.parse_show(
|
||||
cls.watcher('actionplan show %s' % action_plan_uuid))
|
||||
state = [x for x in output if x.keys()[0] == 'State'][0]['State']
|
||||
if state == 'SUCCEEDED':
|
||||
break
|
||||
time.sleep(1)
|
||||
retry -= 1
|
||||
raw_output = cls.watcher('actionplan delete %s' % action_plan_uuid)
|
||||
cls.assertOutput('', raw_output)
|
||||
# Delete audit
|
||||
|
||||
@@ -22,10 +22,11 @@ class AuditTests(base.TestCase):
|
||||
"""Functional tests for audit."""
|
||||
|
||||
dummy_name = 'dummy'
|
||||
list_fields = ['UUID', 'Audit Type', 'State', 'Goal', 'Strategy']
|
||||
list_fields = ['UUID', 'Name', 'Audit Type', 'State', 'Goal', 'Strategy']
|
||||
detailed_list_fields = list_fields + ['Created At', 'Updated At',
|
||||
'Deleted At', 'Parameters',
|
||||
'Interval', 'Audit Scope']
|
||||
'Interval', 'Audit Scope',
|
||||
'Next Run Time']
|
||||
audit_template_name = 'a' + uuidutils.generate_uuid()
|
||||
audit_uuid = None
|
||||
|
||||
@@ -70,7 +71,7 @@ class AuditTests(base.TestCase):
|
||||
|
||||
class AuditActiveTests(base.TestCase):
|
||||
|
||||
list_fields = ['UUID', 'Audit Type', 'State', 'Goal', 'Strategy']
|
||||
list_fields = ['UUID', 'Name', 'Audit Type', 'State', 'Goal', 'Strategy']
|
||||
detailed_list_fields = list_fields + ['Created At', 'Updated At',
|
||||
'Deleted At', 'Parameters',
|
||||
'Interval', 'Audit Scope']
|
||||
|
||||
@@ -20,7 +20,9 @@ class StrategyTests(base.TestCase):
|
||||
"""Functional tests for strategy."""
|
||||
|
||||
dummy_name = 'dummy'
|
||||
basic_strategy = 'basic'
|
||||
list_fields = ['UUID', 'Name', 'Display name', 'Goal']
|
||||
state_fields = ['Datasource', 'Metrics', 'CDM', 'Name']
|
||||
|
||||
def test_strategy_list(self):
|
||||
raw_output = self.watcher('strategy list')
|
||||
@@ -39,3 +41,8 @@ class StrategyTests(base.TestCase):
|
||||
self.assert_table_structure([raw_output],
|
||||
self.list_fields + ['Parameters spec'])
|
||||
self.assertNotIn('basic', raw_output)
|
||||
|
||||
def test_strategy_state(self):
|
||||
raw_output = self.watcher('strategy state %s' % self.basic_strategy)
|
||||
self.assertIn(self.basic_strategy, raw_output)
|
||||
self.assert_table_structure([raw_output], self.state_fields)
|
||||
|
||||
@@ -97,7 +97,8 @@ class UtilsTest(test_utils.BaseTestCase):
|
||||
class CommonParamsForListTest(test_utils.BaseTestCase):
|
||||
def setUp(self):
|
||||
super(CommonParamsForListTest, self).setUp()
|
||||
self.args = mock.Mock(limit=None, sort_key=None, sort_dir=None)
|
||||
self.args = mock.Mock(limit=None, marker=None,
|
||||
sort_key=None, sort_dir=None)
|
||||
self.args.detail = False
|
||||
self.expected_params = {'detail': False}
|
||||
|
||||
@@ -117,6 +118,13 @@ class CommonParamsForListTest(test_utils.BaseTestCase):
|
||||
utils.common_params_for_list,
|
||||
self.args, [], [])
|
||||
|
||||
def test_marker(self):
|
||||
self.args.marker = 'e420a881-d7df-4de2-bbf3-378cc13d9b3a'
|
||||
self.expected_params.update(
|
||||
{'marker': 'e420a881-d7df-4de2-bbf3-378cc13d9b3a'})
|
||||
self.assertEqual(self.expected_params,
|
||||
utils.common_params_for_list(self.args, [], []))
|
||||
|
||||
def test_sort_key_and_sort_dir(self):
|
||||
self.args.sort_key = 'field'
|
||||
self.args.sort_dir = 'desc'
|
||||
|
||||
@@ -144,6 +144,16 @@ fake_responses_sorting = {
|
||||
},
|
||||
}
|
||||
|
||||
fake_responses_marker = {
|
||||
'/v1/actions/?marker=770ef053-ecb3-48b0-85b5-d55a2dbc6588':
|
||||
{
|
||||
'GET': (
|
||||
{},
|
||||
{"actions": [ACTION2, ACTION3]}
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class ActionManagerTest(testtools.TestCase):
|
||||
|
||||
@@ -231,6 +241,20 @@ class ActionManagerTest(testtools.TestCase):
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(3, len(actions))
|
||||
|
||||
def test_actions_list_marker(self):
|
||||
self.api = utils.FakeAPI(fake_responses_marker)
|
||||
self.mgr = watcherclient.v1.action.ActionManager(self.api)
|
||||
actions = self.mgr.list(
|
||||
marker='770ef053-ecb3-48b0-85b5-d55a2dbc6588')
|
||||
expect = [
|
||||
('GET',
|
||||
'/v1/actions/?marker=770ef053-ecb3-48b0-85b5-d55a2dbc6588',
|
||||
{},
|
||||
None)
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(2, len(actions))
|
||||
|
||||
def test_actions_show(self):
|
||||
action = self.mgr.get(ACTION1['uuid'])
|
||||
expect = [
|
||||
|
||||
@@ -94,6 +94,13 @@ fake_responses_pagination = {
|
||||
{"action_plans": [ACTION_PLAN2]}
|
||||
),
|
||||
},
|
||||
'/v1/action_plans/?marker=f8e47706-efcf-49a4-a5c4-af604eb492f2':
|
||||
{
|
||||
'GET': (
|
||||
{},
|
||||
{"action_plans": [ACTION_PLAN2]}
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
fake_responses_sorting = {
|
||||
@@ -158,6 +165,19 @@ class ActionPlanManagerTest(testtools.TestCase):
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertThat(action_plans, matchers.HasLength(2))
|
||||
|
||||
def test_action_plans_list_marker(self):
|
||||
self.api = utils.FakeAPI(fake_responses_pagination)
|
||||
self.mgr = watcherclient.v1.action_plan.ActionPlanManager(self.api)
|
||||
action_plans = self.mgr.list(
|
||||
marker='f8e47706-efcf-49a4-a5c4-af604eb492f2')
|
||||
expect = [
|
||||
('GET', '/v1/action_plans/?'
|
||||
'marker=f8e47706-efcf-49a4-a5c4-af604eb492f2',
|
||||
{}, None),
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertThat(action_plans, matchers.HasLength(1))
|
||||
|
||||
def test_action_plans_list_sort_key(self):
|
||||
self.api = utils.FakeAPI(fake_responses_sorting)
|
||||
self.mgr = watcherclient.v1.action_plan.ActionPlanManager(self.api)
|
||||
|
||||
@@ -33,12 +33,16 @@ ACTION_PLAN_1 = {
|
||||
'unit': '%'}],
|
||||
'created_at': datetime.datetime.now().isoformat(),
|
||||
'updated_at': None,
|
||||
'global_efficacy': {
|
||||
"value": 99,
|
||||
"unit": "%",
|
||||
"name": "dummy_global_efficacy",
|
||||
"description": "Dummy Global Efficacy",
|
||||
},
|
||||
'global_efficacy': [
|
||||
{"value": 99,
|
||||
"unit": "%",
|
||||
"name": "dummy_global_efficacy",
|
||||
"description": "Dummy Global Efficacy"},
|
||||
{"value": 75,
|
||||
"unit": "%",
|
||||
"name": "dummy_global_efficacy2",
|
||||
"description": "Dummy Global Efficacy2"}
|
||||
],
|
||||
'deleted_at': None,
|
||||
}
|
||||
|
||||
@@ -52,12 +56,12 @@ ACTION_PLAN_2 = {
|
||||
'name': 'indicator2',
|
||||
'unit': '%'}],
|
||||
'updated_at': None,
|
||||
'global_efficacy': {
|
||||
'global_efficacy': [{
|
||||
"value": 87,
|
||||
"unit": "%",
|
||||
"name": "dummy_global_efficacy",
|
||||
"description": "Dummy Global Efficacy",
|
||||
},
|
||||
}],
|
||||
'deleted_at': None,
|
||||
}
|
||||
|
||||
@@ -69,6 +73,7 @@ class ActionPlanShellTest(base.CommandTestCase):
|
||||
resource_fields.ACTION_PLAN_SHORT_LIST_FIELD_LABELS)
|
||||
FIELDS = resource_fields.ACTION_PLAN_FIELDS
|
||||
FIELD_LABELS = resource_fields.ACTION_PLAN_FIELD_LABELS
|
||||
GLOBAL_EFFICACY_FIELDS = resource_fields.GLOBAL_EFFICACY_FIELDS
|
||||
|
||||
def setUp(self):
|
||||
super(self.__class__, self).setUp()
|
||||
@@ -114,6 +119,11 @@ class ActionPlanShellTest(base.CommandTestCase):
|
||||
self.SHORT_LIST_FIELD_LABELS)],
|
||||
results)
|
||||
|
||||
self.assertEqual(action_plan1.global_efficacy,
|
||||
results[0]['Global efficacy'])
|
||||
self.assertEqual(action_plan2.global_efficacy,
|
||||
results[1]['Global efficacy'])
|
||||
|
||||
self.m_action_plan_mgr.list.assert_called_once_with(detail=False)
|
||||
|
||||
def test_do_action_plan_list_detail(self):
|
||||
@@ -131,6 +141,10 @@ class ActionPlanShellTest(base.CommandTestCase):
|
||||
self.resource_as_dict(action_plan2, self.FIELDS,
|
||||
self.FIELD_LABELS)],
|
||||
results)
|
||||
self.assertEqual(action_plan1.global_efficacy,
|
||||
results[0]['Global efficacy'])
|
||||
self.assertEqual(action_plan2.global_efficacy,
|
||||
results[1]['Global efficacy'])
|
||||
|
||||
self.m_action_plan_mgr.list.assert_called_once_with(detail=True)
|
||||
|
||||
@@ -165,6 +179,8 @@ class ActionPlanShellTest(base.CommandTestCase):
|
||||
self.resource_as_dict(
|
||||
action_plan, self.FIELDS, self.FIELD_LABELS),
|
||||
result)
|
||||
self.assertEqual(action_plan.global_efficacy,
|
||||
result['Global efficacy'])
|
||||
self.m_action_plan_mgr.get.assert_called_once_with(
|
||||
'd9d9978e-6db5-4a05-8eab-1531795d7004')
|
||||
|
||||
@@ -257,3 +273,25 @@ class ActionPlanShellTest(base.CommandTestCase):
|
||||
|
||||
self.assertEqual(1, exit_code)
|
||||
self.assertEqual('', result)
|
||||
|
||||
def test_do_action_plan_cancel(self):
|
||||
action_plan = resource.ActionPlan(mock.Mock(), ACTION_PLAN_1)
|
||||
self.m_action_plan_mgr.cancel.return_value = action_plan
|
||||
|
||||
exit_code, result = self.run_cmd(
|
||||
'actionplan cancel 5869da81-4876-4687-a1ed-12cd64cf53d9')
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(
|
||||
self.resource_as_dict(action_plan, self.FIELDS, self.FIELD_LABELS),
|
||||
result)
|
||||
self.m_action_plan_mgr.cancel.assert_called_once_with(
|
||||
'5869da81-4876-4687-a1ed-12cd64cf53d9')
|
||||
|
||||
def test_do_action_plan_cancel_not_uuid(self):
|
||||
exit_code, result = self.run_cmd(
|
||||
'actionplan cancel not_uuid',
|
||||
formatting=None)
|
||||
|
||||
self.assertEqual(1, exit_code)
|
||||
self.assertEqual('', result)
|
||||
|
||||
@@ -30,6 +30,7 @@ ACTION_1 = {
|
||||
'action_type': 'migrate',
|
||||
'parents': ['239f02a5-9649-4e14-9d33-ac2bf67cb755'],
|
||||
'input_parameters': {"test": 1},
|
||||
'description': 'test',
|
||||
'created_at': datetime.datetime.now().isoformat(),
|
||||
'updated_at': None,
|
||||
'deleted_at': None,
|
||||
@@ -42,6 +43,7 @@ ACTION_2 = {
|
||||
'action_type': 'migrate',
|
||||
'parents': ['67653274-eb24-c7ba-70f6-a84e73d80843'],
|
||||
'input_parameters': {"test": 2},
|
||||
'description': 'test',
|
||||
'created_at': datetime.datetime.now().isoformat(),
|
||||
'updated_at': None,
|
||||
'deleted_at': None,
|
||||
@@ -53,6 +55,7 @@ ACTION_3 = {
|
||||
'parents': [],
|
||||
'state': 'PENDING',
|
||||
'action_type': 'sleep',
|
||||
'description': 'test',
|
||||
'created_at': datetime.datetime.now().isoformat(),
|
||||
'updated_at': None,
|
||||
'deleted_at': None,
|
||||
@@ -129,6 +132,27 @@ class ActionShellTest(base.CommandTestCase):
|
||||
|
||||
self.m_action_mgr.list.assert_called_once_with(detail=True)
|
||||
|
||||
def test_do_action_list_marker(self):
|
||||
action2 = resource.Action(mock.Mock(), ACTION_2)
|
||||
action3 = resource.Action(mock.Mock(), ACTION_3)
|
||||
self.m_action_mgr.list.return_value = [
|
||||
action2, action3]
|
||||
|
||||
exit_code, results = self.run_cmd(
|
||||
'action list --marker 770ef053-ecb3-48b0-85b5-d55a2dbc6588')
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(
|
||||
[self.resource_as_dict(action2, self.SHORT_LIST_FIELDS,
|
||||
self.SHORT_LIST_FIELD_LABELS),
|
||||
self.resource_as_dict(action3, self.SHORT_LIST_FIELDS,
|
||||
self.SHORT_LIST_FIELD_LABELS)],
|
||||
results)
|
||||
|
||||
self.m_action_mgr.list.assert_called_once_with(
|
||||
detail=False,
|
||||
marker='770ef053-ecb3-48b0-85b5-d55a2dbc6588')
|
||||
|
||||
def test_do_action_show_by_uuid(self):
|
||||
action = resource.Action(mock.Mock(), ACTION_1)
|
||||
self.m_action_mgr.get.return_value = action
|
||||
|
||||
@@ -145,6 +145,16 @@ fake_responses_strategy = {
|
||||
},
|
||||
}
|
||||
|
||||
fake_responses_marker = {
|
||||
'/v1/audits/?marker=5869da81-4876-4687-a1ed-12cd64cf53d9':
|
||||
{
|
||||
'GET': (
|
||||
{},
|
||||
{"audits": [AUDIT2]}
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class AuditManagerTest(testtools.TestCase):
|
||||
def setUp(self):
|
||||
@@ -229,6 +239,17 @@ class AuditManagerTest(testtools.TestCase):
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(1, len(audits))
|
||||
|
||||
def test_audits_list_marker(self):
|
||||
self.api = utils.FakeAPI(fake_responses_marker)
|
||||
self.mgr = watcherclient.v1.audit.AuditManager(self.api)
|
||||
audits = self.mgr.list(marker=AUDIT1['uuid'])
|
||||
expect = [
|
||||
('GET', '/v1/audits/?marker=5869da81-4876-4687-a1ed-12cd64cf53d9',
|
||||
{}, None),
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(1, len(audits))
|
||||
|
||||
def test_audits_show(self):
|
||||
audit = self.mgr.get(AUDIT1['uuid'])
|
||||
expect = [
|
||||
|
||||
114
watcherclient/tests/unit/v1/test_audit_shell.py
Normal file → Executable file
114
watcherclient/tests/unit/v1/test_audit_shell.py
Normal file → Executable file
@@ -17,7 +17,6 @@ import datetime
|
||||
import mock
|
||||
import six
|
||||
|
||||
from watcherclient import exceptions
|
||||
from watcherclient import shell
|
||||
from watcherclient.tests.unit.v1 import base
|
||||
from watcherclient import v1 as resource
|
||||
@@ -68,6 +67,8 @@ AUDIT_1 = {
|
||||
'interval': None,
|
||||
'scope': '',
|
||||
'auto_trigger': False,
|
||||
'next_run_time': None,
|
||||
'name': 'my_audit1',
|
||||
}
|
||||
|
||||
AUDIT_2 = {
|
||||
@@ -85,6 +86,8 @@ AUDIT_2 = {
|
||||
'interval': None,
|
||||
'scope': '',
|
||||
'auto_trigger': False,
|
||||
'next_run_time': None,
|
||||
'name': 'my_audit2',
|
||||
}
|
||||
|
||||
AUDIT_3 = {
|
||||
@@ -102,6 +105,8 @@ AUDIT_3 = {
|
||||
'interval': 3600,
|
||||
'scope': '',
|
||||
'auto_trigger': True,
|
||||
'next_run_time': None,
|
||||
'name': 'my_audit3',
|
||||
}
|
||||
|
||||
|
||||
@@ -167,6 +172,23 @@ class AuditShellTest(base.CommandTestCase):
|
||||
|
||||
self.m_audit_mgr.list.assert_called_once_with(detail=False)
|
||||
|
||||
def test_do_audit_list_marker(self):
|
||||
audit2 = resource.Audit(mock.Mock(), AUDIT_2)
|
||||
self.m_audit_mgr.list.return_value = [audit2]
|
||||
|
||||
exit_code, results = self.run_cmd(
|
||||
'audit list --marker 5869da81-4876-4687-a1ed-12cd64cf53d9')
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(
|
||||
[self.resource_as_dict(audit2, self.SHORT_LIST_FIELDS,
|
||||
self.SHORT_LIST_FIELD_LABELS)],
|
||||
results)
|
||||
|
||||
self.m_audit_mgr.list.assert_called_once_with(
|
||||
detail=False,
|
||||
marker='5869da81-4876-4687-a1ed-12cd64cf53d9')
|
||||
|
||||
def test_do_audit_list_detail(self):
|
||||
audit1 = resource.Audit(mock.Mock(), AUDIT_1)
|
||||
audit2 = resource.Audit(mock.Mock(), AUDIT_2)
|
||||
@@ -199,14 +221,19 @@ class AuditShellTest(base.CommandTestCase):
|
||||
self.m_audit_mgr.get.assert_called_once_with(
|
||||
'5869da81-4876-4687-a1ed-12cd64cf53d9')
|
||||
|
||||
def test_do_audit_show_by_not_uuid(self):
|
||||
self.m_audit_mgr.get.side_effect = exceptions.HTTPNotFound
|
||||
def test_do_audit_show_by_name(self):
|
||||
audit = resource.Audit(mock.Mock(), AUDIT_1)
|
||||
self.m_audit_mgr.get.return_value = audit
|
||||
|
||||
exit_code, result = self.run_cmd(
|
||||
'audit show not_uuid', formatting=None)
|
||||
'audit show my_audit')
|
||||
|
||||
self.assertEqual(1, exit_code)
|
||||
self.assertEqual('', result)
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(
|
||||
self.resource_as_dict(audit, self.FIELDS, self.FIELD_LABELS),
|
||||
result)
|
||||
self.m_audit_mgr.get.assert_called_once_with(
|
||||
'my_audit')
|
||||
|
||||
def test_do_audit_delete(self):
|
||||
self.m_audit_mgr.delete.return_value = ''
|
||||
@@ -220,6 +247,18 @@ class AuditShellTest(base.CommandTestCase):
|
||||
self.m_audit_mgr.delete.assert_called_once_with(
|
||||
'5869da81-4876-4687-a1ed-12cd64cf53d9')
|
||||
|
||||
def test_do_audit_delete_by_name(self):
|
||||
self.m_audit_mgr.delete.return_value = ''
|
||||
|
||||
exit_code, result = self.run_cmd(
|
||||
'audit delete my_audit',
|
||||
formatting=None)
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual('', result)
|
||||
self.m_audit_mgr.delete.assert_called_once_with(
|
||||
'my_audit')
|
||||
|
||||
def test_do_audit_delete_multiple(self):
|
||||
self.m_audit_mgr.delete.return_value = ''
|
||||
|
||||
@@ -235,16 +274,6 @@ class AuditShellTest(base.CommandTestCase):
|
||||
self.m_audit_mgr.delete.assert_any_call(
|
||||
'5b157edd-5a7e-4aaa-b511-f7b33ec86e9f')
|
||||
|
||||
def test_do_audit_delete_with_not_uuid(self):
|
||||
self.m_audit_mgr.delete.return_value = ''
|
||||
|
||||
exit_code, result = self.run_cmd(
|
||||
'audit delete not_uuid',
|
||||
formatting=None)
|
||||
|
||||
self.assertEqual(1, exit_code)
|
||||
self.assertEqual('', result)
|
||||
|
||||
def test_do_audit_update(self):
|
||||
audit = resource.Audit(mock.Mock(), AUDIT_1)
|
||||
self.m_audit_mgr.update.return_value = audit
|
||||
@@ -261,14 +290,20 @@ class AuditShellTest(base.CommandTestCase):
|
||||
'5869da81-4876-4687-a1ed-12cd64cf53d9',
|
||||
[{'op': 'replace', 'path': '/state', 'value': 'PENDING'}])
|
||||
|
||||
def test_do_audit_update_with_not_uuid(self):
|
||||
self.m_audit_mgr.update.return_value = ''
|
||||
def test_do_audit_update_by_name(self):
|
||||
audit = resource.Audit(mock.Mock(), AUDIT_1)
|
||||
self.m_audit_mgr.update.return_value = audit
|
||||
|
||||
exit_code, result = self.run_cmd(
|
||||
'audit update not_uuid replace state=PENDING', formatting=None)
|
||||
'audit update my_audit replace state=PENDING')
|
||||
|
||||
self.assertEqual(1, exit_code)
|
||||
self.assertEqual('', result)
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(
|
||||
self.resource_as_dict(audit, self.FIELDS, self.FIELD_LABELS),
|
||||
result)
|
||||
self.m_audit_mgr.update.assert_called_once_with(
|
||||
'my_audit',
|
||||
[{'op': 'replace', 'path': '/state', 'value': 'PENDING'}])
|
||||
|
||||
def test_do_audit_create_with_audit_template_uuid(self):
|
||||
audit = resource.Audit(mock.Mock(), AUDIT_3)
|
||||
@@ -285,7 +320,9 @@ class AuditShellTest(base.CommandTestCase):
|
||||
result)
|
||||
self.m_audit_mgr.create.assert_called_once_with(
|
||||
audit_template_uuid='f8e47706-efcf-49a4-a5c4-af604eb492f2',
|
||||
audit_type='ONESHOT', auto_trigger=False)
|
||||
audit_type='ONESHOT',
|
||||
auto_trigger=False
|
||||
)
|
||||
|
||||
def test_do_audit_create_with_audit_template_name(self):
|
||||
audit = resource.Audit(mock.Mock(), AUDIT_3)
|
||||
@@ -302,7 +339,8 @@ class AuditShellTest(base.CommandTestCase):
|
||||
self.m_audit_mgr.create.assert_called_once_with(
|
||||
audit_template_uuid='f8e47706-efcf-49a4-a5c4-af604eb492f2',
|
||||
auto_trigger=False,
|
||||
audit_type='ONESHOT')
|
||||
audit_type='ONESHOT'
|
||||
)
|
||||
|
||||
def test_do_audit_create_with_goal(self):
|
||||
audit = resource.Audit(mock.Mock(), AUDIT_1)
|
||||
@@ -353,7 +391,9 @@ class AuditShellTest(base.CommandTestCase):
|
||||
result)
|
||||
self.m_audit_mgr.create.assert_called_once_with(
|
||||
goal='fc087747-61be-4aad-8126-b701731ae836',
|
||||
auto_trigger=False, audit_type='ONESHOT')
|
||||
auto_trigger=False,
|
||||
audit_type='ONESHOT'
|
||||
)
|
||||
|
||||
def test_do_audit_create_with_parameter(self):
|
||||
audit = resource.Audit(mock.Mock(), AUDIT_1)
|
||||
@@ -371,7 +411,8 @@ class AuditShellTest(base.CommandTestCase):
|
||||
goal='fc087747-61be-4aad-8126-b701731ae836',
|
||||
audit_type='ONESHOT',
|
||||
auto_trigger=False,
|
||||
parameters={'para1': 10, 'para2': 20})
|
||||
parameters={'para1': 10, 'para2': 20}
|
||||
)
|
||||
|
||||
def test_do_audit_create_with_type_continuous(self):
|
||||
audit = resource.Audit(mock.Mock(), AUDIT_1)
|
||||
@@ -389,4 +430,25 @@ class AuditShellTest(base.CommandTestCase):
|
||||
goal='fc087747-61be-4aad-8126-b701731ae836',
|
||||
audit_type='CONTINUOUS',
|
||||
auto_trigger=False,
|
||||
interval='3600')
|
||||
interval='3600'
|
||||
)
|
||||
|
||||
def test_do_audit_create_with_name(self):
|
||||
audit = resource.Audit(mock.Mock(), AUDIT_1)
|
||||
self.m_audit_mgr.create.return_value = audit
|
||||
|
||||
exit_code, result = self.run_cmd(
|
||||
'audit create -g fc087747-61be-4aad-8126-b701731ae836 '
|
||||
'-t CONTINUOUS -i 3600 --name my_audit')
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(
|
||||
self.resource_as_dict(audit, self.FIELDS, self.FIELD_LABELS),
|
||||
result)
|
||||
self.m_audit_mgr.create.assert_called_once_with(
|
||||
goal='fc087747-61be-4aad-8126-b701731ae836',
|
||||
audit_type='CONTINUOUS',
|
||||
auto_trigger=False,
|
||||
interval='3600',
|
||||
name='my_audit'
|
||||
)
|
||||
|
||||
@@ -178,6 +178,16 @@ fake_responses_sorting = {
|
||||
},
|
||||
}
|
||||
|
||||
fake_responses_marker = {
|
||||
'/v1/audit_templates/?marker=f8e47706-efcf-49a4-a5c4-af604eb492f2':
|
||||
{
|
||||
'GET': (
|
||||
{},
|
||||
{"audit_templates": [AUDIT_TMPL2, AUDIT_TMPL3]}
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
fake_responses_filter_by_goal_uuid = {
|
||||
'/v1/audit_templates/?goal=e75ee410-b32b-465f-88b5-4397705f9473':
|
||||
{
|
||||
@@ -389,6 +399,18 @@ class AuditTemplateManagerTest(utils.BaseTestCase):
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(3, len(audit_templates))
|
||||
|
||||
def test_audit_templates_list_marker(self):
|
||||
self.api = utils.FakeAPI(fake_responses_marker)
|
||||
self.mgr = watcherclient.v1.audit_template.AuditTemplateManager(
|
||||
self.api)
|
||||
audit_templates = self.mgr.list(marker=AUDIT_TMPL1['uuid'])
|
||||
expect_url = '/v1/audit_templates/?marker=%s' % AUDIT_TMPL1['uuid']
|
||||
expect = [
|
||||
('GET', expect_url, {}, None)
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(2, len(audit_templates))
|
||||
|
||||
def test_audit_templates_show(self):
|
||||
audit_template = self.mgr.get(AUDIT_TMPL1['uuid'])
|
||||
expect = [
|
||||
|
||||
@@ -128,6 +128,24 @@ class AuditTemplateShellTest(base.CommandTestCase):
|
||||
|
||||
self.m_audit_template_mgr.list.assert_called_once_with(detail=False)
|
||||
|
||||
def test_do_audit_template_list_marker(self):
|
||||
audit_template2 = resource.AuditTemplate(mock.Mock(), AUDIT_TEMPLATE_2)
|
||||
self.m_audit_template_mgr.list.return_value = [audit_template2]
|
||||
|
||||
exit_code, results = self.run_cmd(
|
||||
'audittemplate list --marker '
|
||||
'f8e47706-efcf-49a4-a5c4-af604eb492f2')
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(
|
||||
[self.resource_as_dict(audit_template2, self.SHORT_LIST_FIELDS,
|
||||
self.SHORT_LIST_FIELD_LABELS)],
|
||||
results)
|
||||
|
||||
self.m_audit_template_mgr.list.assert_called_once_with(
|
||||
detail=False,
|
||||
marker='f8e47706-efcf-49a4-a5c4-af604eb492f2')
|
||||
|
||||
def test_do_audit_template_list_detail(self):
|
||||
audit_template1 = resource.AuditTemplate(mock.Mock(), AUDIT_TEMPLATE_1)
|
||||
audit_template2 = resource.AuditTemplate(mock.Mock(), AUDIT_TEMPLATE_2)
|
||||
|
||||
@@ -63,6 +63,13 @@ fake_responses = {
|
||||
STRATEGY1,
|
||||
),
|
||||
},
|
||||
'/v1/strategies/%s/state' % STRATEGY1['name']:
|
||||
{
|
||||
'GET': (
|
||||
{},
|
||||
STRATEGY1,
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
fake_responses_pagination = {
|
||||
@@ -180,3 +187,10 @@ class StrategyManagerTest(testtools.TestCase):
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(STRATEGY1['name'], strategy.name)
|
||||
|
||||
def test_strategies_state(self):
|
||||
self.mgr.state(STRATEGY1['name'])
|
||||
expect = [
|
||||
('GET', '/v1/strategies/%s/state' % STRATEGY1['name'], {}, None),
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
|
||||
@@ -17,6 +17,8 @@ import datetime
|
||||
import mock
|
||||
import six
|
||||
|
||||
from oslo_serialization import jsonutils
|
||||
|
||||
from watcherclient import shell
|
||||
from watcherclient.tests.unit.v1 import base
|
||||
from watcherclient import v1 as resource
|
||||
@@ -54,6 +56,8 @@ class StrategyShellTest(base.CommandTestCase):
|
||||
resource_fields.STRATEGY_SHORT_LIST_FIELD_LABELS)
|
||||
FIELDS = resource_fields.STRATEGY_FIELDS
|
||||
FIELD_LABELS = resource_fields.STRATEGY_FIELD_LABELS
|
||||
STATE_FIELDS = resource_fields.STRATEGY_STATE_FIELDS
|
||||
STATE_FIELD_LABELS = resource_fields.STRATEGY_STATE_FIELD_LABELS
|
||||
|
||||
def setUp(self):
|
||||
super(self.__class__, self).setUp()
|
||||
@@ -155,3 +159,33 @@ class StrategyShellTest(base.CommandTestCase):
|
||||
result)
|
||||
self.m_strategy_mgr.get.assert_called_once_with(
|
||||
'f8e47706-efcf-49a4-a5c4-af604eb492f2')
|
||||
|
||||
def test_do_strategy_state(self):
|
||||
strategy1 = resource.Strategy(mock.Mock(), STRATEGY_1)
|
||||
strategy_req = [
|
||||
{'type': 'Datasource', 'mandatory': True,
|
||||
'comment': '', 'state': 'gnocchi: True'},
|
||||
{'type': 'Metrics', 'mandatory': False,
|
||||
'comment': '', 'state': jsonutils.dumps([
|
||||
{'compute.node.cpu.percent': 'available'},
|
||||
{'cpu_util': 'available'},
|
||||
{'memory.resident': 'available'},
|
||||
{'hardware.memory.used': 'not available'}])},
|
||||
{'type': 'CDM', 'mandatory': True,
|
||||
'comment': '',
|
||||
'state': jsonutils.dumps([{'compute_model': 'available'},
|
||||
{'storage_model': 'not available'}])},
|
||||
{'type': 'Name', 'mandatory': '', 'comment': '',
|
||||
'state': strategy1.name}]
|
||||
requirements = [resource.Strategy(mock.Mock(), req)
|
||||
for req in strategy_req]
|
||||
self.m_strategy_mgr.state.return_value = requirements
|
||||
|
||||
exit_code, results = self.run_cmd('strategy state basic')
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(
|
||||
[self.resource_as_dict(req, self.STATE_FIELDS,
|
||||
self.STATE_FIELD_LABELS)
|
||||
for req in requirements],
|
||||
results)
|
||||
|
||||
@@ -30,7 +30,7 @@ class ActionManager(base.Manager):
|
||||
return '/v1/actions/%s' % id if id else '/v1/actions'
|
||||
|
||||
def list(self, action_plan=None, audit=None, limit=None, sort_key=None,
|
||||
sort_dir=None, detail=False):
|
||||
sort_dir=None, detail=False, marker=None):
|
||||
"""Retrieve a list of action.
|
||||
|
||||
:param action_plan: UUID of the action plan
|
||||
@@ -52,13 +52,15 @@ class ActionManager(base.Manager):
|
||||
:param detail: Optional, boolean whether to return detailed information
|
||||
about actions.
|
||||
|
||||
:param marker: Optional, UUID of the last action in the previous page.
|
||||
|
||||
:returns: A list of actions.
|
||||
|
||||
"""
|
||||
if limit is not None:
|
||||
limit = int(limit)
|
||||
|
||||
filters = utils.common_filters(limit, sort_key, sort_dir)
|
||||
filters = utils.common_filters(limit, sort_key, sort_dir, marker)
|
||||
if action_plan is not None:
|
||||
filters.append('action_plan_uuid=%s' % action_plan)
|
||||
if audit is not None:
|
||||
|
||||
@@ -31,7 +31,7 @@ class ActionPlanManager(base.Manager):
|
||||
return '/v1/action_plans/%s' % id if id else '/v1/action_plans'
|
||||
|
||||
def list(self, audit=None, limit=None, sort_key=None,
|
||||
sort_dir=None, detail=False):
|
||||
sort_dir=None, detail=False, marker=None):
|
||||
"""Retrieve a list of action plan.
|
||||
|
||||
:param audit: Name of the audit
|
||||
@@ -52,13 +52,16 @@ class ActionPlanManager(base.Manager):
|
||||
:param detail: Optional, boolean whether to return detailed information
|
||||
about action plans.
|
||||
|
||||
:param marker: The last actionplan UUID of the previous page;
|
||||
displays list of actionplans after "marker".
|
||||
|
||||
:returns: A list of action plans.
|
||||
|
||||
"""
|
||||
if limit is not None:
|
||||
limit = int(limit)
|
||||
|
||||
filters = utils.common_filters(limit, sort_key, sort_dir)
|
||||
filters = utils.common_filters(limit, sort_key, sort_dir, marker)
|
||||
if audit is not None:
|
||||
filters.append('audit_uuid=%s' % audit)
|
||||
|
||||
@@ -89,3 +92,12 @@ class ActionPlanManager(base.Manager):
|
||||
def start(self, action_plan_id):
|
||||
patch = [{'op': 'replace', 'value': 'PENDING', 'path': '/state'}]
|
||||
return self._update(self._path(action_plan_id), patch)
|
||||
|
||||
def cancel(self, action_plan_id):
|
||||
action_plan = self.get(action_plan_id)
|
||||
if action_plan.state == "ONGOING":
|
||||
patch = [{'op': 'replace', 'value': 'CANCELLING',
|
||||
'path': '/state'}]
|
||||
else:
|
||||
patch = [{'op': 'replace', 'value': 'CANCELLED', 'path': '/state'}]
|
||||
return self._update(self._path(action_plan_id), patch)
|
||||
|
||||
@@ -26,16 +26,16 @@ from watcherclient.v1 import resource_fields as res_fields
|
||||
|
||||
|
||||
def format_global_efficacy(global_efficacy):
|
||||
formatted_global_efficacy = None
|
||||
if (global_efficacy.get('value') is not None and
|
||||
global_efficacy.get('unit')):
|
||||
formatted_global_efficacy = "%(value).2f %(unit)s" % dict(
|
||||
unit=global_efficacy.get('unit'),
|
||||
value=global_efficacy.get('value'))
|
||||
elif global_efficacy.get('value') is not None:
|
||||
formatted_global_efficacy = global_efficacy.get('value')
|
||||
|
||||
return formatted_global_efficacy
|
||||
formatted_global_eff = {}
|
||||
for eff in global_efficacy:
|
||||
if (eff.get('value') is not None and eff.get('unit')):
|
||||
eff_name = eff.get('name')
|
||||
formatted_global_eff[eff_name] = "%(value).2f %(unit)s" % dict(
|
||||
unit=eff.get('unit'),
|
||||
value=eff.get('value'))
|
||||
elif eff.get('value') is not None:
|
||||
formatted_global_eff[eff_name] = eff.get('value')
|
||||
return formatted_global_eff
|
||||
|
||||
|
||||
class ShowActionPlan(command.ShowOne):
|
||||
@@ -64,6 +64,18 @@ class ShowActionPlan(command.ShowOne):
|
||||
)
|
||||
return out.getvalue() or ''
|
||||
|
||||
def _format_global_efficacy(self, global_efficacy, parsed_args):
|
||||
formatted_global_efficacy = format_global_efficacy(global_efficacy)
|
||||
out = six.StringIO()
|
||||
yaml_format.YAMLFormatter().emit_one(
|
||||
column_names=list(resource.capitalize()
|
||||
for resource in formatted_global_efficacy),
|
||||
data=[value for value in formatted_global_efficacy.itervalues()],
|
||||
stdout=out,
|
||||
parsed_args=parsed_args,
|
||||
)
|
||||
return out.getvalue() or ''
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = getattr(self.app.client_manager, "infra-optim")
|
||||
|
||||
@@ -83,8 +95,8 @@ class ShowActionPlan(command.ShowOne):
|
||||
self._format_indicators(action_plan, parsed_args))
|
||||
|
||||
# Update the raw global efficacy with the formatted one
|
||||
action_plan.global_efficacy = format_global_efficacy(
|
||||
action_plan.global_efficacy)
|
||||
action_plan.global_efficacy = self._format_global_efficacy(
|
||||
action_plan.global_efficacy, parsed_args)
|
||||
|
||||
columns = res_fields.ACTION_PLAN_FIELDS
|
||||
column_headers = res_fields.ACTION_PLAN_FIELD_LABELS
|
||||
@@ -113,6 +125,11 @@ class ListActionPlan(command.Lister):
|
||||
help=_('Maximum number of action plans to return per request, '
|
||||
'0 for no limit. Default is the maximum number used '
|
||||
'by the Watcher API Service.'))
|
||||
parser.add_argument(
|
||||
'--marker',
|
||||
metavar='<actionplan>',
|
||||
help=_('The last actionplan UUID of the previous page; '
|
||||
'displays list of actionplans after "marker".'))
|
||||
parser.add_argument(
|
||||
'--sort-key',
|
||||
metavar='<field>',
|
||||
@@ -139,6 +156,18 @@ class ListActionPlan(command.Lister):
|
||||
)
|
||||
return out.getvalue() or ''
|
||||
|
||||
def _format_global_efficacy(self, global_efficacy, parsed_args):
|
||||
formatted_global_efficacy = format_global_efficacy(global_efficacy)
|
||||
out = six.StringIO()
|
||||
yaml_format.YAMLFormatter().emit_one(
|
||||
column_names=list(resource.capitalize()
|
||||
for resource in formatted_global_efficacy),
|
||||
data=[value for value in formatted_global_efficacy.values()],
|
||||
stdout=out,
|
||||
parsed_args=parsed_args,
|
||||
)
|
||||
return out.getvalue() or ''
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = getattr(self.app.client_manager, "infra-optim")
|
||||
|
||||
@@ -164,8 +193,8 @@ class ListActionPlan(command.Lister):
|
||||
self._format_indicators(action_plan, parsed_args))
|
||||
|
||||
# Update the raw global efficacy with the formatted one
|
||||
action_plan.global_efficacy = format_global_efficacy(
|
||||
action_plan.global_efficacy)
|
||||
action_plan.global_efficacy = self._format_global_efficacy(
|
||||
action_plan.global_efficacy, parsed_args)
|
||||
|
||||
return (field_labels,
|
||||
(utils.get_item_properties(item, fields) for item in data))
|
||||
@@ -301,3 +330,29 @@ class DeleteActionPlan(command.Command):
|
||||
raise exceptions.ValidationError()
|
||||
|
||||
client.action_plan.delete(action_plan)
|
||||
|
||||
|
||||
class CancelActionPlan(command.ShowOne):
|
||||
"""Cancel action plan command."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CancelActionPlan, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'action_plan',
|
||||
metavar='<action-plan>',
|
||||
help=_("UUID of the action_plan."))
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = getattr(self.app.client_manager, "infra-optim")
|
||||
|
||||
if not uuidutils.is_uuid_like(parsed_args.action_plan):
|
||||
raise exceptions.ValidationError()
|
||||
|
||||
action_plan = client.action_plan.cancel(parsed_args.action_plan)
|
||||
|
||||
columns = res_fields.ACTION_PLAN_FIELDS
|
||||
column_headers = res_fields.ACTION_PLAN_FIELD_LABELS
|
||||
|
||||
return column_headers, utils.get_item_properties(action_plan, columns)
|
||||
|
||||
@@ -83,6 +83,13 @@ class ListAction(command.Lister):
|
||||
metavar='<direction>',
|
||||
choices=['asc', 'desc'],
|
||||
help=_('Sort direction: "asc" (the default) or "desc".'))
|
||||
parser.add_argument(
|
||||
'--marker',
|
||||
dest='marker',
|
||||
metavar='<marker>',
|
||||
default=None,
|
||||
help=_('UUID of the last action in the previous page; '
|
||||
'displays list of actions after "marker".'))
|
||||
|
||||
return parser
|
||||
|
||||
|
||||
@@ -19,7 +19,8 @@ from watcherclient import exceptions as exc
|
||||
|
||||
|
||||
CREATION_ATTRIBUTES = ['audit_template_uuid', 'audit_type', 'interval',
|
||||
'parameters', 'goal', 'strategy', 'auto_trigger']
|
||||
'parameters', 'goal', 'strategy', 'auto_trigger',
|
||||
'name']
|
||||
|
||||
|
||||
class Audit(base.Resource):
|
||||
@@ -35,11 +36,11 @@ class AuditManager(base.Manager):
|
||||
return '/v1/audits/%s' % id if id else '/v1/audits'
|
||||
|
||||
def list(self, audit_template=None, limit=None, sort_key=None,
|
||||
sort_dir=None, detail=False, goal=None, strategy=None):
|
||||
sort_dir=None, detail=False, goal=None, strategy=None,
|
||||
marker=None):
|
||||
"""Retrieve a list of audit.
|
||||
|
||||
:param audit_template: Name of the audit
|
||||
:param name: Name of the audit
|
||||
:param audit_template: Name of the audit template
|
||||
:param limit: The maximum number of results to return per
|
||||
request, if:
|
||||
|
||||
@@ -57,13 +58,15 @@ class AuditManager(base.Manager):
|
||||
:param detail: Optional, boolean whether to return detailed information
|
||||
about audits.
|
||||
|
||||
:param marker: Optional, UUID of the last audit in the previous page.
|
||||
|
||||
:returns: A list of audits.
|
||||
|
||||
"""
|
||||
if limit is not None:
|
||||
limit = int(limit)
|
||||
|
||||
filters = utils.common_filters(limit, sort_key, sort_dir)
|
||||
filters = utils.common_filters(limit, sort_key, sort_dir, marker)
|
||||
if audit_template is not None:
|
||||
filters.append('audit_template=%s' % audit_template)
|
||||
if goal is not None:
|
||||
@@ -92,14 +95,14 @@ class AuditManager(base.Manager):
|
||||
raise exc.InvalidAttribute()
|
||||
return self._create(self._path(), new)
|
||||
|
||||
def get(self, audit_id):
|
||||
def get(self, audit):
|
||||
try:
|
||||
return self._list(self._path(audit_id))[0]
|
||||
return self._list(self._path(audit))[0]
|
||||
except IndexError:
|
||||
return None
|
||||
|
||||
def delete(self, audit_id):
|
||||
return self._delete(self._path(audit_id))
|
||||
def delete(self, audit):
|
||||
return self._delete(self._path(audit))
|
||||
|
||||
def update(self, audit_id, patch):
|
||||
return self._update(self._path(audit_id), patch)
|
||||
def update(self, audit, patch):
|
||||
return self._update(self._path(audit), patch)
|
||||
|
||||
@@ -31,7 +31,7 @@ class ShowAudit(command.ShowOne):
|
||||
parser.add_argument(
|
||||
'audit',
|
||||
metavar='<audit>',
|
||||
help=_('UUID of the audit'),
|
||||
help=_('UUID or name of the audit'),
|
||||
)
|
||||
return parser
|
||||
|
||||
@@ -88,6 +88,13 @@ class ListAudit(command.Lister):
|
||||
metavar='<direction>',
|
||||
choices=['asc', 'desc'],
|
||||
help=_('Sort direction: "asc" (the default) or "desc".'))
|
||||
parser.add_argument(
|
||||
'--marker',
|
||||
dest='marker',
|
||||
metavar='<marker>',
|
||||
default=None,
|
||||
help=_('UUID of the last audit in the previous page; '
|
||||
'displays list of audits after "marker".'))
|
||||
|
||||
return parser
|
||||
|
||||
@@ -150,8 +157,9 @@ class CreateAudit(command.ShowOne):
|
||||
'-i', '--interval',
|
||||
dest='interval',
|
||||
metavar='<interval>',
|
||||
help=_('Audit interval (in seconds). '
|
||||
"Only used if the audit is CONTINUOUS."))
|
||||
help=_('Audit interval (in seconds or cron format). '
|
||||
'Cron inteval can be used like: "*/5 * * * *". '
|
||||
'Only used if the audit is CONTINUOUS.'))
|
||||
parser.add_argument(
|
||||
'-g', '--goal',
|
||||
dest='goal',
|
||||
@@ -174,13 +182,19 @@ class CreateAudit(command.ShowOne):
|
||||
default=False,
|
||||
help=_('Trigger automatically action plan '
|
||||
'once audit is succeeded.'))
|
||||
parser.add_argument(
|
||||
'--name',
|
||||
dest='name',
|
||||
metavar='<name>',
|
||||
help=_('Name for this audit.'))
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = getattr(self.app.client_manager, "infra-optim")
|
||||
|
||||
field_list = ['audit_template_uuid', 'audit_type', 'parameters',
|
||||
'interval', 'goal', 'strategy', 'auto_trigger']
|
||||
'interval', 'goal', 'strategy', 'auto_trigger', 'name']
|
||||
|
||||
fields = dict((k, v) for (k, v) in vars(parsed_args).items()
|
||||
if k in field_list and v is not None)
|
||||
@@ -218,7 +232,7 @@ class UpdateAudit(command.ShowOne):
|
||||
parser.add_argument(
|
||||
'audit',
|
||||
metavar='<audit>',
|
||||
help=_("UUID of the audit."))
|
||||
help=_("UUID or name of the audit."))
|
||||
parser.add_argument(
|
||||
'op',
|
||||
metavar='<op>',
|
||||
@@ -238,11 +252,9 @@ class UpdateAudit(command.ShowOne):
|
||||
def take_action(self, parsed_args):
|
||||
client = getattr(self.app.client_manager, "infra-optim")
|
||||
|
||||
if not uuidutils.is_uuid_like(parsed_args.audit):
|
||||
raise exceptions.ValidationError()
|
||||
|
||||
patch = common_utils.args_array_to_patch(
|
||||
parsed_args.op, parsed_args.attributes[0])
|
||||
parsed_args.op, parsed_args.attributes[0],
|
||||
exclude_fields=['/interval'])
|
||||
|
||||
audit = client.audit.update(parsed_args.audit, patch)
|
||||
|
||||
@@ -261,7 +273,7 @@ class DeleteAudit(command.Command):
|
||||
'audits',
|
||||
metavar='<audit>',
|
||||
nargs='+',
|
||||
help=_('UUID of the audit'),
|
||||
help=_('UUID or name of the audit'),
|
||||
)
|
||||
return parser
|
||||
|
||||
@@ -269,7 +281,4 @@ class DeleteAudit(command.Command):
|
||||
client = getattr(self.app.client_manager, "infra-optim")
|
||||
|
||||
for audit in parsed_args.audits:
|
||||
if not uuidutils.is_uuid_like(audit):
|
||||
raise exceptions.ValidationError()
|
||||
|
||||
client.audit.delete(audit)
|
||||
|
||||
@@ -33,7 +33,7 @@ class AuditTemplateManager(base.Manager):
|
||||
return '/v1/audit_templates/%s' % id_ if id_ else '/v1/audit_templates'
|
||||
|
||||
def list(self, name=None, goal=None, strategy=None, limit=None,
|
||||
sort_key=None, sort_dir=None, detail=False):
|
||||
sort_key=None, sort_dir=None, detail=False, marker=None):
|
||||
"""Retrieve a list of audit template.
|
||||
|
||||
:param name: Name of the audit template
|
||||
@@ -54,13 +54,16 @@ class AuditTemplateManager(base.Manager):
|
||||
:param detail: Optional, boolean whether to return detailed information
|
||||
about audit_templates.
|
||||
|
||||
:param marker: Optional, UUID of the last audit template of
|
||||
the previous page.
|
||||
|
||||
:returns: A list of audit templates.
|
||||
|
||||
"""
|
||||
if limit is not None:
|
||||
limit = int(limit)
|
||||
|
||||
filters = utils.common_filters(limit, sort_key, sort_dir)
|
||||
filters = utils.common_filters(limit, sort_key, sort_dir, marker)
|
||||
if name is not None:
|
||||
filters.append('name=%s' % name)
|
||||
if goal is not None:
|
||||
|
||||
@@ -91,6 +91,13 @@ class ListAuditTemplate(command.Lister):
|
||||
metavar='<direction>',
|
||||
choices=['asc', 'desc'],
|
||||
help=_('Sort direction: "asc" (the default) or "desc".'))
|
||||
parser.add_argument(
|
||||
'--marker',
|
||||
dest='marker',
|
||||
metavar='<marker>',
|
||||
default=None,
|
||||
help=_('UUID of the last audit template of the previous page; '
|
||||
'displays list of audit templates after "marker".'))
|
||||
|
||||
return parser
|
||||
|
||||
@@ -162,37 +169,81 @@ class CreateAuditTemplate(command.ShowOne):
|
||||
"Can be provided either in yaml or json file.\n"
|
||||
"YAML example:\n"
|
||||
"---\n"
|
||||
" - host_aggregates:\n"
|
||||
" - id: 1\n"
|
||||
" - id: 2\n"
|
||||
" - id: 3\n"
|
||||
" - availability_zones:\n"
|
||||
" - name: AZ1\n"
|
||||
" - name: AZ2\n"
|
||||
" - exclude:\n"
|
||||
" - instances:\n"
|
||||
" - uuid: UUID1\n"
|
||||
" - uuid: UUID2\n"
|
||||
" - compute_nodes:\n"
|
||||
" - name: compute1\n"
|
||||
" - compute:\n"
|
||||
" - host_aggregates:\n"
|
||||
" - id: 1\n"
|
||||
" - id: 2\n"
|
||||
" - id: 3\n"
|
||||
" - availability_zones:\n"
|
||||
" - name: AZ1\n"
|
||||
" - name: AZ2\n"
|
||||
" - exclude:\n"
|
||||
" - instances:\n"
|
||||
" - uuid: UUID1\n"
|
||||
" - uuid: UUID2\n"
|
||||
" - compute_nodes:\n"
|
||||
" - name: compute1\n"
|
||||
" - storage: \n"
|
||||
" - availability_zones:\n"
|
||||
" - name: AZ1\n"
|
||||
" - name: AZ2\n"
|
||||
" - volume_types:\n"
|
||||
" - name: lvm1\n"
|
||||
" - name: lvm2\n"
|
||||
" - exclude:\n"
|
||||
" - storage_pools:\n"
|
||||
" - name: host0@backend0#pool0\n"
|
||||
" - name: host1@backend1#pool1\n"
|
||||
" - volumes:\n"
|
||||
" - uuid: UUID1\n"
|
||||
" - uuid: UUID2\n"
|
||||
" - projects:\n"
|
||||
" - uuid: UUID1\n"
|
||||
" - uuid: UUID2\n"
|
||||
"\n"
|
||||
"JSON example:\n"
|
||||
"[{'host_aggregates': [\n"
|
||||
" {'id': 1},\n"
|
||||
" {'id': 2},\n"
|
||||
" {'id': 3}]},\n"
|
||||
" {'availability_zones': [\n"
|
||||
" {'name': 'AZ1'},\n"
|
||||
" {'name': 'AZ2'}]},\n"
|
||||
" {'exclude': [\n"
|
||||
" {'instances': [\n"
|
||||
" {'uuid': 'UUID1'},\n"
|
||||
" {'uuid': 'UUID2'}\n"
|
||||
" ]},\n"
|
||||
" {'compute_nodes': [\n"
|
||||
" {'name': 'compute1'}\n"
|
||||
" ]}\n"
|
||||
"]}]\n"
|
||||
"[\n"
|
||||
" {\"compute\":\n"
|
||||
" [{\"host_aggregates\": [\n"
|
||||
" {\"id\": 1},\n"
|
||||
" {\"id\": 2},\n"
|
||||
" {\"id\": 3}]},\n"
|
||||
" {\"availability_zones\": [\n"
|
||||
" {\"name\": \"AZ1\"},\n"
|
||||
" {\"name\": \"AZ2\"}]},\n"
|
||||
" {\"exclude\": [\n"
|
||||
" {\"instances\": [\n"
|
||||
" {\"uuid\": \"UUID1\"},\n"
|
||||
" {\"uuid\": \"UUID2\"}\n"
|
||||
" ]},\n"
|
||||
" {\"compute_nodes\": [\n"
|
||||
" {\"name\": \"compute1\"}\n"
|
||||
" ]}\n"
|
||||
" ]}]\n"
|
||||
" },\n"
|
||||
" {\"storage\":\n"
|
||||
" [{\"availability_zones\": [\n"
|
||||
" {\"name\": \"AZ1\"},\n"
|
||||
" {\"name\": \"AZ2\"}]},\n"
|
||||
" {\"volume_types\": [\n"
|
||||
" {\"name\": \"lvm1\"},\n"
|
||||
" {\"name\": \"lvm2\"}]},\n"
|
||||
" {\"exclude\": [\n"
|
||||
" {\"storage_pools\": [\n"
|
||||
" {\"name\": \"host0@backend0#pool0\"},\n"
|
||||
" {\"name\": \"host1@backend1#pool1\"}\n"
|
||||
" ]},\n"
|
||||
" {\"volumes\": [\n"
|
||||
" {\"uuid\": \"UUID1\"},\n"
|
||||
" {\"uuid\": \"UUID2\"}\n"
|
||||
" ]},\n"
|
||||
" {\"projects\": [\n"
|
||||
" {\"uuid\": \"UUID1\"},\n"
|
||||
" {\"uuid\": \"UUID2\"}\n"
|
||||
" ]},\n"
|
||||
" ]}]\n"
|
||||
" }\n"
|
||||
" ]\n"
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
23
watcherclient/v1/resource_fields.py
Normal file → Executable file
23
watcherclient/v1/resource_fields.py
Normal file → Executable file
@@ -30,19 +30,20 @@ AUDIT_TEMPLATE_SHORT_LIST_FIELDS = [
|
||||
AUDIT_TEMPLATE_SHORT_LIST_FIELD_LABELS = ['UUID', 'Name', 'Goal', 'Strategy']
|
||||
|
||||
# Audit
|
||||
AUDIT_FIELDS = ['uuid', 'created_at', 'updated_at', 'deleted_at',
|
||||
AUDIT_FIELDS = ['uuid', 'name', 'created_at', 'updated_at', 'deleted_at',
|
||||
'state', 'audit_type', 'parameters', 'interval', 'goal_name',
|
||||
'strategy_name', 'scope', 'auto_trigger']
|
||||
'strategy_name', 'scope', 'auto_trigger', 'next_run_time']
|
||||
|
||||
AUDIT_FIELD_LABELS = ['UUID', 'Created At', 'Updated At', 'Deleted At',
|
||||
AUDIT_FIELD_LABELS = ['UUID', 'Name', 'Created At', 'Updated At', 'Deleted At',
|
||||
'State', 'Audit Type', 'Parameters', 'Interval', 'Goal',
|
||||
'Strategy', 'Audit Scope', 'Auto Trigger']
|
||||
'Strategy', 'Audit Scope', 'Auto Trigger',
|
||||
'Next Run Time']
|
||||
|
||||
AUDIT_SHORT_LIST_FIELDS = ['uuid', 'audit_type',
|
||||
AUDIT_SHORT_LIST_FIELDS = ['uuid', 'name', 'audit_type',
|
||||
'state', 'goal_name', 'strategy_name',
|
||||
'auto_trigger']
|
||||
|
||||
AUDIT_SHORT_LIST_FIELD_LABELS = ['UUID', 'Audit Type', 'State', 'Goal',
|
||||
AUDIT_SHORT_LIST_FIELD_LABELS = ['UUID', 'Name', 'Audit Type', 'State', 'Goal',
|
||||
'Strategy', 'Auto Trigger']
|
||||
|
||||
# Action Plan
|
||||
@@ -60,14 +61,16 @@ ACTION_PLAN_SHORT_LIST_FIELDS = ['uuid', 'audit_uuid', 'state',
|
||||
ACTION_PLAN_SHORT_LIST_FIELD_LABELS = ['UUID', 'Audit', 'State',
|
||||
'Updated At', 'Global efficacy']
|
||||
|
||||
GLOBAL_EFFICACY_FIELDS = ['value', 'unit', 'name', 'description']
|
||||
|
||||
# Action
|
||||
ACTION_FIELDS = ['uuid', 'created_at', 'updated_at', 'deleted_at', 'parents',
|
||||
'state', 'action_plan_uuid', 'action_type',
|
||||
'input_parameters']
|
||||
'input_parameters', 'description']
|
||||
|
||||
ACTION_FIELD_LABELS = ['UUID', 'Created At', 'Updated At', 'Deleted At',
|
||||
'Parents', 'State', 'Action Plan', 'Action',
|
||||
'Parameters']
|
||||
'Parameters', 'Description']
|
||||
|
||||
ACTION_SHORT_LIST_FIELDS = ['uuid', 'parents',
|
||||
'state', 'action_plan_uuid', 'action_type']
|
||||
@@ -96,6 +99,10 @@ STRATEGY_SHORT_LIST_FIELDS = ['uuid', 'name', 'display_name', 'goal_name']
|
||||
|
||||
STRATEGY_SHORT_LIST_FIELD_LABELS = ['UUID', 'Name', 'Display name', 'Goal']
|
||||
|
||||
STRATEGY_STATE_FIELDS = ['type', 'state', 'mandatory', 'comment']
|
||||
|
||||
STRATEGY_STATE_FIELD_LABELS = ['Type', 'State', 'Mandatory', 'Comment']
|
||||
|
||||
# Metric Collector
|
||||
METRIC_COLLECTOR_FIELDS = ['uuid', 'created_at', 'updated_at', 'deleted_at',
|
||||
'endpoint', 'category']
|
||||
|
||||
@@ -28,9 +28,14 @@ class StrategyManager(base.Manager):
|
||||
resource_class = Strategy
|
||||
|
||||
@staticmethod
|
||||
def _path(strategy=None):
|
||||
return ('/v1/strategies/%s' % strategy
|
||||
if strategy else '/v1/strategies')
|
||||
def _path(strategy=None, state=False):
|
||||
if strategy:
|
||||
path = '/v1/strategies/%s' % strategy
|
||||
if state:
|
||||
path = '/v1/strategies/%s/state' % strategy
|
||||
else:
|
||||
path = '/v1/strategies'
|
||||
return path
|
||||
|
||||
def list(self, goal=None, limit=None, sort_key=None,
|
||||
sort_dir=None, detail=False):
|
||||
@@ -82,3 +87,6 @@ class StrategyManager(base.Manager):
|
||||
return self._list(self._path(strategy))[0]
|
||||
except IndexError:
|
||||
return None
|
||||
|
||||
def state(self, strategy):
|
||||
return self._list(self._path(strategy, state=True))
|
||||
|
||||
@@ -57,6 +57,40 @@ class ShowStrategy(command.ShowOne):
|
||||
return column_headers, utils.get_item_properties(strategy, columns)
|
||||
|
||||
|
||||
class StateStrategy(command.Lister):
|
||||
"""Retrieve information about strategy requirements."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(StateStrategy, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'strategy',
|
||||
metavar='<strategy>',
|
||||
help=_('Name of the strategy'),
|
||||
)
|
||||
return parser
|
||||
|
||||
def _format_spec(self, requirements):
|
||||
for req in requirements:
|
||||
if type(req.state) == list:
|
||||
req.state = jsonutils.dumps(req.state, indent=2)
|
||||
return requirements
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = getattr(self.app.client_manager, "infra-optim")
|
||||
|
||||
try:
|
||||
requirements = client.strategy.state(parsed_args.strategy)
|
||||
except exceptions.HTTPNotFound as exc:
|
||||
raise exceptions.CommandError(str(exc))
|
||||
requirements = self._format_spec(requirements)
|
||||
columns = res_fields.STRATEGY_STATE_FIELDS
|
||||
column_headers = res_fields.STRATEGY_STATE_FIELD_LABELS
|
||||
|
||||
return (column_headers,
|
||||
(utils.get_item_properties(item, columns)
|
||||
for item in requirements))
|
||||
|
||||
|
||||
class ListStrategy(command.Lister):
|
||||
"""List information on retrieved strategies."""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user