Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b914e8877 | ||
|
|
918d2f0bbd | ||
|
|
91d1d8b0e1 | ||
|
|
3ffe4869f3 | ||
|
|
bde259e38c | ||
|
|
75dd8dc561 | ||
|
|
a6aed1772d | ||
|
|
63a1039fb2 | ||
|
|
9d3a6c51b1 | ||
|
|
8bcdf13d7f | ||
|
|
f9fb0875e0 | ||
|
|
d36d835d08 | ||
|
|
20931e2ce7 | ||
|
|
fb84ae9b25 | ||
|
|
e64e597aa6 | ||
|
|
f9aac4fc9f | ||
|
|
0f276e483b | ||
|
|
888a58fd2a | ||
|
|
89cfc55870 | ||
|
|
4c19084cb1 | ||
|
|
bc572e70dc | ||
|
|
544db1951f | ||
|
|
1b14be868e | ||
|
|
e8236aaf65 | ||
|
|
0260775f30 | ||
|
|
3b79b58f68 | ||
|
|
d9c558107e | ||
|
|
0be6832e6b | ||
|
|
5586bbdff3 | ||
|
|
cbc578998a | ||
|
|
94af770a6d | ||
|
|
d2c22f0353 | ||
|
|
c5a5b7dad7 | ||
|
|
e6ca4e54a7 | ||
|
|
e0d1e5facf | ||
|
|
35c4e93a09 | ||
|
|
567b74ad0a | ||
|
|
f306a61ece | ||
|
|
0aaaf13278 | ||
|
|
e17dbab7c6 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -42,6 +42,7 @@ output/*/index.html
|
||||
|
||||
# Sphinx
|
||||
doc/build
|
||||
doc/source/api
|
||||
|
||||
# pbr generates these
|
||||
AUTHORS
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[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
|
||||
OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-160} \
|
||||
${PYTHON:-python} -m subunit.run discover -t ./ ${OS_TEST_PATH:-./watcherclient/tests} $LISTOPT $IDOPTION
|
||||
test_id_option=--load-list $IDFILE
|
||||
test_list_option=--list
|
||||
test_list_option=--list
|
||||
|
||||
176
LICENSE
Normal file
176
LICENSE
Normal 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.
|
||||
|
||||
50
README.rst
50
README.rst
@@ -49,13 +49,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 <http://docs.openstack.org/cli-reference/overview.html>`_
|
||||
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 +81,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 +130,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::
|
||||
|
||||
|
||||
@@ -1,23 +1,25 @@
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
watcherclient._i18n.rst
|
||||
watcherclient.client.rst
|
||||
watcherclient.common.apiclient.base.rst
|
||||
watcherclient.common.apiclient.exceptions.rst
|
||||
watcherclient.common.base.rst
|
||||
watcherclient.common.cliutils.rst
|
||||
watcherclient.common.command.rst
|
||||
watcherclient.common.http.rst
|
||||
watcherclient.common.i18n.rst
|
||||
watcherclient.common.utils.rst
|
||||
watcherclient.exceptions.rst
|
||||
watcherclient.plugin.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.base.rst
|
||||
watcherclient.tests.v1.test_action.rst
|
||||
watcherclient.tests.v1.test_action_plan.rst
|
||||
watcherclient.tests.v1.test_action_plan_shell.rst
|
||||
@@ -29,7 +31,8 @@
|
||||
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.tests.v1.test_strategy.rst
|
||||
watcherclient.tests.v1.test_strategy_shell.rst
|
||||
watcherclient.v1.action.rst
|
||||
watcherclient.v1.action_plan.rst
|
||||
watcherclient.v1.action_plan_shell.rst
|
||||
@@ -42,7 +45,7 @@
|
||||
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.v1.strategy.rst
|
||||
watcherclient.v1.strategy_shell.rst
|
||||
watcherclient.version.rst
|
||||
|
||||
@@ -19,7 +19,7 @@ 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
|
||||
@@ -28,26 +28,26 @@ configuration options :option:`--os-username`, :option:`--os-password`,
|
||||
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/v2.0
|
||||
|
||||
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
|
||||
$ 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
|
||||
$ 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
|
||||
@@ -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
|
||||
$ source 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
|
||||
|
||||
@@ -18,6 +18,7 @@ Contents:
|
||||
installation
|
||||
api_v1
|
||||
cli
|
||||
openstack_cli
|
||||
contributing
|
||||
|
||||
Contributing
|
||||
@@ -39,12 +40,4 @@ 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
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
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
|
||||
|
||||
81
doc/source/openstack_cli.rst
Normal file
81
doc/source/openstack_cli.rst
Normal 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/v2.0
|
||||
|
||||
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
|
||||
|
||||
@@ -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
|
||||
Babel>=2.3.4 # BSD
|
||||
cliff!=1.16.0,!=1.17.0,>=1.15.0 # Apache-2.0
|
||||
oslo.i18n>=2.1.0 # Apache-2.0
|
||||
oslo.utils>=3.5.0 # Apache-2.0
|
||||
oslo.utils>=3.14.0 # Apache-2.0
|
||||
pbr>=1.6 # Apache-2.0
|
||||
python-keystoneclient!=1.8.0,!=2.1.0,>=1.6.0 # Apache-2.0
|
||||
PrettyTable<0.8,>=0.7 # BSD
|
||||
python-keystoneclient!=1.8.0,!=2.1.0,>=1.7.0 # Apache-2.0
|
||||
python-openstackclient>=2.1.0 # Apache-2.0
|
||||
six>=1.9.0 # MIT
|
||||
|
||||
64
setup.cfg
64
setup.cfg
@@ -26,6 +26,68 @@ packages =
|
||||
console_scripts =
|
||||
watcher = watcherclient.shell:main
|
||||
|
||||
openstack.cli.extension =
|
||||
infra_optim = watcherclient.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_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_list = watcherclient.v1.action_plan_shell:ListActionPlan
|
||||
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_action_show = watcherclient.v1.action_shell:ShowAction
|
||||
optimize_action_list = watcherclient.v1.action_shell:ListAction
|
||||
|
||||
# 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
|
||||
|
||||
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_create = watcherclient.v1.action_plan_shell:CreateActionPlan
|
||||
actionplan_update = watcherclient.v1.action_plan_shell:UpdateActionPlan
|
||||
actionplan_start = watcherclient.v1.action_plan_shell:StartActionPlan
|
||||
actionplan_delete = watcherclient.v1.action_plan_shell:DeleteActionPlan
|
||||
|
||||
action_show = watcherclient.v1.action_shell:ShowAction
|
||||
action_list = watcherclient.v1.action_shell:ListAction
|
||||
|
||||
[pbr]
|
||||
autodoc_index_modules = True
|
||||
|
||||
@@ -49,4 +111,4 @@ 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
|
||||
output_file = watcherclient/locale/watcherclient.pot
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
coverage>=3.6 # Apache-2.0
|
||||
discover # BSD
|
||||
hacking<0.11,>=0.10.2
|
||||
mock>=1.2 # BSD
|
||||
mock>=2.0 # 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
|
||||
sphinx!=1.3b1,<1.3,>=1.2.1 # BSD
|
||||
testrepository>=0.0.18 # Apache-2.0/BSD
|
||||
testscenarios>=0.4 # Apache-2.0/BSD
|
||||
testtools>=1.4.0 # MIT
|
||||
|
||||
@@ -169,15 +169,18 @@ def print_list(objs, fields, formatters=None, sortby_index=0,
|
||||
for o in objs:
|
||||
row = []
|
||||
for field in fields:
|
||||
data = '-'
|
||||
if field in formatters:
|
||||
row.append(formatters[field](o))
|
||||
data = 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)
|
||||
if data is None:
|
||||
data = '-'
|
||||
row.append(data)
|
||||
pt.add_row(row)
|
||||
|
||||
if six.PY3:
|
||||
@@ -210,6 +213,8 @@ def print_dict(dct, dict_property="Property", wrap=0):
|
||||
pt.add_row([col1, line])
|
||||
col1 = ''
|
||||
else:
|
||||
if v is None:
|
||||
v = '-'
|
||||
pt.add_row([k, v])
|
||||
|
||||
if six.PY3:
|
||||
@@ -267,5 +272,5 @@ def pretty_choice_list(l):
|
||||
|
||||
def exit(msg=''):
|
||||
if msg:
|
||||
print (msg, file=sys.stderr)
|
||||
print(msg, file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
46
watcherclient/common/command.py
Normal file
46
watcherclient/common/command.py
Normal file
@@ -0,0 +1,46 @@
|
||||
# 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):
|
||||
pass
|
||||
@@ -45,6 +45,8 @@ def _trim_endpoint_api_version(url):
|
||||
def _extract_error_json(body):
|
||||
"""Return error_message from the HTTP response body."""
|
||||
error_json = {}
|
||||
if six.PY3 and not isinstance(body, six.string_types):
|
||||
body = body.decode("utf-8")
|
||||
try:
|
||||
body_json = json.loads(body)
|
||||
if 'error_message' in body_json:
|
||||
@@ -163,7 +165,7 @@ class HTTPClient(object):
|
||||
url=url, e=e)
|
||||
except (socket.error, socket.timeout) as e:
|
||||
endpoint = self.endpoint
|
||||
raise exc.ConnectionRefused(
|
||||
raise exc.CommunicationError(
|
||||
_("Error communicating with %(endpoint)s %(e)s"),
|
||||
endpoint=endpoint, e=e)
|
||||
body_iter = ResponseBodyIterator(resp)
|
||||
@@ -360,6 +362,8 @@ class ResponseBodyIterator(object):
|
||||
def next(self):
|
||||
chunk = self.resp.read(CHUNKSIZE)
|
||||
if chunk:
|
||||
if six.PY3 and not isinstance(chunk, six.string_types):
|
||||
chunk = chunk.decode("utf-8")
|
||||
return chunk
|
||||
else:
|
||||
raise StopIteration()
|
||||
|
||||
@@ -19,6 +19,7 @@ from __future__ import print_function
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import uuid
|
||||
|
||||
from oslo_utils import importutils
|
||||
|
||||
@@ -178,3 +179,16 @@ def common_filters(limit=None, sort_key=None, sort_dir=None):
|
||||
if sort_dir is not None:
|
||||
filters.append('sort_dir=%s' % sort_dir)
|
||||
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
|
||||
|
||||
64
watcherclient/plugin.py
Normal file
64
watcherclient/plugin.py
Normal file
@@ -0,0 +1,64 @@
|
||||
# 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 openstackclient.common import utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
DEFAULT_API_VERSION = '1'
|
||||
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"""
|
||||
watcher_client = utils.get_client_class(
|
||||
API_NAME,
|
||||
instance._api_version[API_NAME],
|
||||
API_VERSIONS)
|
||||
LOG.debug('Instantiating infra-optim client: %s', watcher_client)
|
||||
|
||||
endpoint = instance.get_endpoint_for_service_type(
|
||||
API_NAME,
|
||||
region_name=instance._region_name,
|
||||
interface=instance._interface,
|
||||
)
|
||||
|
||||
client = watcher_client(
|
||||
endpoint=endpoint,
|
||||
session=instance.session,
|
||||
auth_url=instance._auth_url,
|
||||
username=instance._username,
|
||||
password=instance._password,
|
||||
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
|
||||
@@ -1,259 +1,126 @@
|
||||
# -*- 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 cliff import app
|
||||
from cliff import command
|
||||
from cliff import commandmanager
|
||||
from cliff import complete
|
||||
from cliff import help as cli_help
|
||||
from keystoneclient.auth.identity import v2
|
||||
from keystoneclient.auth.identity import v3
|
||||
from keystoneclient import discover
|
||||
from keystoneclient import exceptions as ks_exc
|
||||
from keystoneclient import session as kssession
|
||||
from keystoneclient import session
|
||||
from openstackclient.common import logs
|
||||
from openstackclient.common import utils
|
||||
import six.moves.urllib.parse as urlparse
|
||||
|
||||
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 version
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class WatcherShell(object):
|
||||
API_NAME = 'infra-optim'
|
||||
API_VERSIONS = {
|
||||
'1': 'watcherclient.v1.client.Client',
|
||||
}
|
||||
_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."""
|
||||
|
||||
parser.add_argument('--os-user-domain-id',
|
||||
default=cliutils.env('OS_USER_DOMAIN_ID'),
|
||||
help='Defaults to env[OS_USER_DOMAIN_ID].')
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
parser.add_argument('--os-user-domain-name',
|
||||
default=cliutils.env('OS_USER_DOMAIN_NAME'),
|
||||
help='Defaults to env[OS_USER_DOMAIN_NAME].')
|
||||
def __init__(self, **kwargs):
|
||||
self.client = None
|
||||
|
||||
parser.add_argument('--os-project-id',
|
||||
default=cliutils.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].')
|
||||
# Patch command.Command to add a default auth_required = True
|
||||
command.Command.auth_required = True
|
||||
|
||||
parser.add_argument('--os-project-name',
|
||||
default=cliutils.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].')
|
||||
# Some commands do not need authentication
|
||||
cli_help.HelpCommand.auth_required = False
|
||||
complete.CompleteCommand.auth_required = False
|
||||
|
||||
parser.add_argument('--os-project-domain-id',
|
||||
default=cliutils.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'),
|
||||
help='Defaults to env[OS_PROJECT_DOMAIN_NAME].')
|
||||
|
||||
def get_base_parser(self):
|
||||
parser = argparse.ArgumentParser(
|
||||
prog='watcher',
|
||||
super(WatcherShell, self).__init__(
|
||||
description=__doc__.strip(),
|
||||
epilog='See "watcher help COMMAND" '
|
||||
'for help on a specific command.',
|
||||
add_help=False,
|
||||
formatter_class=HelpFormatter,
|
||||
version=version.__version__,
|
||||
command_manager=commandmanager.CommandManager(
|
||||
'watcherclient.v1'),
|
||||
deferred_help=True,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
# Global arguments
|
||||
parser.add_argument('-h', '--help',
|
||||
action='store_true',
|
||||
help=argparse.SUPPRESS,
|
||||
)
|
||||
def create_client(self, args):
|
||||
service_type = 'infra-optim'
|
||||
project_id = args.os_project_id or args.os_tenant_id
|
||||
project_name = args.os_project_name or args.os_tenant_name
|
||||
|
||||
parser.add_argument('--version',
|
||||
action='version',
|
||||
version=watcherclient.__version__)
|
||||
keystone_session = session.Session.load_from_cli_options(args)
|
||||
|
||||
parser.add_argument('--debug',
|
||||
default=bool(cliutils.env('WATCHERCLIENT_DEBUG')),
|
||||
action='store_true',
|
||||
help='Defaults to env[WATCHERCLIENT_DEBUG]')
|
||||
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)
|
||||
region_name = args.os_region_name
|
||||
endpoint = keystone_auth.get_endpoint(keystone_session,
|
||||
service_type=service_type,
|
||||
region_name=region_name)
|
||||
|
||||
parser.add_argument('-v', '--verbose',
|
||||
default=False, action="store_true",
|
||||
help="Print more verbose output")
|
||||
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,
|
||||
}
|
||||
|
||||
# for backward compatibility only
|
||||
parser.add_argument('--cert-file',
|
||||
dest='os_cert',
|
||||
help='DEPRECATED! Use --os-cert.')
|
||||
watcher_client = utils.get_client_class(
|
||||
API_NAME,
|
||||
args.watcher_api_version or 1,
|
||||
API_VERSIONS)
|
||||
LOG.debug('Instantiating infra-optim client: %s', watcher_client)
|
||||
|
||||
# for backward compatibility only
|
||||
parser.add_argument('--key-file',
|
||||
dest='os_key',
|
||||
help='DEPRECATED! Use --os-key.')
|
||||
client = watcher_client(args.watcher_api_version, endpoint, **kwargs)
|
||||
|
||||
# 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)
|
||||
|
||||
parser.add_argument('--os-endpoint-type',
|
||||
default=cliutils.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)
|
||||
|
||||
return parser
|
||||
|
||||
def get_subcommand_parser(self, version):
|
||||
parser = self.get_base_parser()
|
||||
|
||||
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 _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)
|
||||
|
||||
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))
|
||||
return client
|
||||
|
||||
def _discover_auth_versions(self, session, auth_url):
|
||||
# discover the API versions the server is supporting base on the
|
||||
@@ -288,20 +155,20 @@ class WatcherShell(object):
|
||||
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)
|
||||
return v3.Token(v3_auth_url, auth_token)
|
||||
else:
|
||||
return v3_auth.Password(v3_auth_url, **kwargs)
|
||||
return v3.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(
|
||||
return v2.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(
|
||||
return v2.Password(
|
||||
v2_auth_url,
|
||||
username=kwargs.pop('username', None),
|
||||
password=kwargs.pop('password', None),
|
||||
@@ -347,161 +214,133 @@ class WatcherShell(object):
|
||||
|
||||
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)
|
||||
def build_option_parser(self, description, version, argparse_kwargs=None):
|
||||
"""Introduces global arguments for the application.
|
||||
|
||||
# build available subcommands based on version
|
||||
api_version = options.watcher_api_version
|
||||
subcommand_parser = self.get_subcommand_parser(api_version)
|
||||
self.parser = subcommand_parser
|
||||
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',
|
||||
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',
|
||||
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',
|
||||
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].')
|
||||
parser.add_argument('--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',
|
||||
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',
|
||||
metavar='<auth-project-domain-name>',
|
||||
default=utils.env('OS_PROJECT_DOMAIN_NAME'),
|
||||
help='Defaults to env[OS_PROJECT_DOMAIN_NAME].')
|
||||
parser.add_argument('--os-auth-token',
|
||||
metavar='<auth-token>',
|
||||
default=utils.env('OS_AUTH_TOKEN'),
|
||||
help='Defaults to env[OS_AUTH_TOKEN].')
|
||||
parser.add_argument('--watcher-api-version',
|
||||
metavar='<watcher-api-version>',
|
||||
default=utils.env('WATCHER_API_VERSION'),
|
||||
help='Defaults to env[WATCHER_API_VERSION].')
|
||||
parser.add_argument('--os-endpoint-type',
|
||||
default=utils.env('OS_ENDPOINT_TYPE'),
|
||||
help='Defaults to env[OS_ENDPOINT_TYPE] or '
|
||||
'"publicURL"')
|
||||
parser.epilog = ('See "watcher help COMMAND" for help '
|
||||
'on a specific command.')
|
||||
session.Session.register_cli_options(parser)
|
||||
return 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
|
||||
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
|
||||
|
||||
# Parse args again and call whatever callback was selected
|
||||
args = subcommand_parser.parse_args(argv)
|
||||
def prepare_to_run_command(self, cmd):
|
||||
"""Prepares to run the command
|
||||
|
||||
# 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)
|
||||
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 run(self, argv):
|
||||
ret_val = 1
|
||||
self.command_options = argv
|
||||
try:
|
||||
args.func(client, args)
|
||||
except exc.Unauthorized:
|
||||
raise exc.CommandError(_("Invalid OpenStack Identity credentials"))
|
||||
ret_val = super(WatcherShell, self).run(argv)
|
||||
return ret_val
|
||||
except Exception as e:
|
||||
if not logging.getLogger('').handlers:
|
||||
logging.basicConfig()
|
||||
self.log.error('Exception raised: %s', str(e))
|
||||
|
||||
@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()
|
||||
return ret_val
|
||||
|
||||
finally:
|
||||
self.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:]))
|
||||
|
||||
@@ -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))
|
||||
@@ -21,13 +21,13 @@ import os
|
||||
|
||||
import fixtures
|
||||
from oslo_utils import strutils
|
||||
from oslotest import base
|
||||
import six
|
||||
import testtools
|
||||
|
||||
from watcherclient.common import http
|
||||
|
||||
|
||||
class BaseTestCase(testtools.TestCase):
|
||||
class BaseTestCase(base.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(BaseTestCase, self).setUp()
|
||||
|
||||
67
watcherclient/tests/v1/base.py
Normal file
67
watcherclient/tests/v1/base.py
Normal file
@@ -0,0 +1,67 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Copyright (c) 2016 b<>com
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import json
|
||||
import shlex
|
||||
|
||||
import mock
|
||||
|
||||
from watcherclient import shell
|
||||
from watcherclient.tests import utils
|
||||
from watcherclient.v1 import client
|
||||
|
||||
|
||||
class CommandTestCase(utils.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(CommandTestCase, self).setUp()
|
||||
|
||||
self.p_build_http_client = mock.patch.object(
|
||||
client.Client, 'build_http_client')
|
||||
self.m_build_http_client = self.p_build_http_client.start()
|
||||
|
||||
self.m_watcher_client = mock.Mock(side_effect=client.Client)
|
||||
self.p_create_client = mock.patch.object(
|
||||
shell.WatcherShell, 'create_client', self.m_watcher_client)
|
||||
self.p_create_client.start()
|
||||
|
||||
self.addCleanup(self.p_build_http_client.stop)
|
||||
self.addCleanup(self.p_create_client.stop)
|
||||
|
||||
def run_cmd(self, cmd, formatting='json'):
|
||||
if formatting:
|
||||
formatter_arg = " -f %s" % formatting
|
||||
formatter = json.loads
|
||||
else:
|
||||
formatter_arg = ''
|
||||
formatter = str
|
||||
formatted_cmd = "%(cmd)s%(formatter)s" % dict(
|
||||
cmd=cmd, formatter=formatter_arg)
|
||||
|
||||
exit_code = self.cmd.run(shlex.split(formatted_cmd))
|
||||
|
||||
try:
|
||||
raw_data = self.stdout.getvalue()
|
||||
formatted_output = formatter(self.stdout.getvalue())
|
||||
except Exception:
|
||||
self.fail("Formatting error (`%s` -> '%s')" %
|
||||
(raw_data, formatting))
|
||||
return exit_code, formatted_output
|
||||
|
||||
def resource_as_dict(self, resource, columns=(), column_headers=()):
|
||||
mapping = dict(zip(columns, column_headers))
|
||||
return {mapping[k]: v for k, v in resource.to_dict().items()
|
||||
if not columns or columns and k in mapping}
|
||||
@@ -30,7 +30,6 @@ ACTION1 = {
|
||||
'description': 'Action_1 description',
|
||||
'next': '239f02a5-9649-4e14-9d33-ac2bf67cb755',
|
||||
'state': 'PENDING',
|
||||
'alarm': None
|
||||
}
|
||||
|
||||
ACTION2 = {
|
||||
@@ -40,7 +39,6 @@ ACTION2 = {
|
||||
'description': 'Action_2 description',
|
||||
'next': '67653274-eb24-c7ba-70f6-a84e73d80843',
|
||||
'state': 'PENDING',
|
||||
'alarm': None
|
||||
}
|
||||
|
||||
ACTION3 = {
|
||||
@@ -50,7 +48,6 @@ ACTION3 = {
|
||||
'description': 'Action_3 description',
|
||||
'next': None,
|
||||
'state': 'PENDING',
|
||||
'alarm': None
|
||||
}
|
||||
|
||||
ACTION_PLAN1 = {
|
||||
@@ -254,7 +251,6 @@ class ActionManagerTest(testtools.TestCase):
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(ACTION1['uuid'], action.uuid)
|
||||
self.assertEqual(ACTION1['action_plan'], action.action_plan)
|
||||
self.assertEqual(ACTION1['alarm'], action.alarm)
|
||||
self.assertEqual(ACTION1['next'], action.next)
|
||||
|
||||
def test_delete(self):
|
||||
|
||||
@@ -1,153 +1,259 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Copyright (c) 2016 b<>com
|
||||
#
|
||||
# Copyright 2013 IBM Corp
|
||||
# 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.
|
||||
|
||||
import datetime
|
||||
|
||||
import mock
|
||||
import six
|
||||
|
||||
from watcherclient.common import cliutils
|
||||
from watcherclient.common import utils as commonutils
|
||||
from watcherclient import exceptions
|
||||
from watcherclient.tests import utils
|
||||
import watcherclient.v1.action_plan_shell as ap_shell
|
||||
from watcherclient import shell
|
||||
from watcherclient.tests.v1 import base
|
||||
from watcherclient import v1 as resource
|
||||
from watcherclient.v1 import resource_fields
|
||||
|
||||
ACTION_PLAN_1 = {
|
||||
'uuid': 'd9d9978e-6db5-4a05-8eab-1531795d7004',
|
||||
'audit_uuid': '770ef053-ecb3-48b0-85b5-d55a2dbc6588',
|
||||
'state': 'RECOMMENDED',
|
||||
'efficacy_indicators': [{'description': 'Indicator 1',
|
||||
'name': 'indicator1',
|
||||
'unit': '%'}],
|
||||
'created_at': datetime.datetime.now().isoformat(),
|
||||
'updated_at': None,
|
||||
'global_efficacy': {
|
||||
"value": 99,
|
||||
"unit": "%",
|
||||
"name": "dummy_global_efficacy",
|
||||
"description": "Dummy Global Efficacy",
|
||||
},
|
||||
'deleted_at': None,
|
||||
}
|
||||
|
||||
ACTION_PLAN_2 = {
|
||||
'uuid': 'd6363285-5afa-4a26-96f2-89441e335765',
|
||||
'audit_uuid': '239f02a5-9649-4e14-9d33-ac2bf67cb755',
|
||||
'state': 'RECOMMENDED',
|
||||
'created_at': datetime.datetime.now().isoformat(),
|
||||
'efficacy_indicators': [{'description': 'Indicator 2',
|
||||
'name': 'indicator2',
|
||||
'unit': '%'}],
|
||||
'updated_at': None,
|
||||
'global_efficacy': {
|
||||
"value": 87,
|
||||
"unit": "%",
|
||||
"name": "dummy_global_efficacy",
|
||||
"description": "Dummy Global Efficacy",
|
||||
},
|
||||
'deleted_at': None,
|
||||
}
|
||||
|
||||
|
||||
class ActionPlanShellTest(utils.BaseTestCase):
|
||||
def test_do_action_plan_show(self):
|
||||
actual = {}
|
||||
fake_print_dict = lambda data, *args, **kwargs: actual.update(data)
|
||||
with mock.patch.object(cliutils, 'print_dict', fake_print_dict):
|
||||
action_plan = object()
|
||||
ap_shell._print_action_plan_show(action_plan)
|
||||
exp = ['uuid', 'created_at', 'updated_at', 'deleted_at',
|
||||
'state', 'audit_uuid']
|
||||
act = actual.keys()
|
||||
self.assertEqual(sorted(exp), sorted(act))
|
||||
class ActionPlanShellTest(base.CommandTestCase):
|
||||
|
||||
SHORT_LIST_FIELDS = resource_fields.ACTION_PLAN_SHORT_LIST_FIELDS
|
||||
SHORT_LIST_FIELD_LABELS = (
|
||||
resource_fields.ACTION_PLAN_SHORT_LIST_FIELD_LABELS)
|
||||
FIELDS = resource_fields.ACTION_PLAN_FIELDS
|
||||
FIELD_LABELS = resource_fields.ACTION_PLAN_FIELD_LABELS
|
||||
|
||||
def setUp(self):
|
||||
super(self.__class__, self).setUp()
|
||||
|
||||
p_audit_manager = mock.patch.object(resource, 'AuditManager')
|
||||
p_audit_template_manager = mock.patch.object(
|
||||
resource, 'ActionPlanManager')
|
||||
p_action_plan_manager = mock.patch.object(
|
||||
resource, 'ActionPlanManager')
|
||||
|
||||
self.m_audit_mgr_cls = p_audit_manager.start()
|
||||
self.m_audit_template_mgr_cls = p_audit_template_manager.start()
|
||||
self.m_action_plan_mgr_cls = p_action_plan_manager.start()
|
||||
|
||||
self.addCleanup(p_audit_manager.stop)
|
||||
self.addCleanup(p_audit_template_manager.stop)
|
||||
self.addCleanup(p_action_plan_manager.stop)
|
||||
|
||||
self.m_audit_mgr = mock.Mock()
|
||||
self.m_audit_template_mgr = mock.Mock()
|
||||
self.m_action_plan_mgr = mock.Mock()
|
||||
|
||||
self.m_audit_mgr_cls.return_value = self.m_audit_mgr
|
||||
self.m_audit_template_mgr_cls.return_value = self.m_audit_template_mgr
|
||||
self.m_action_plan_mgr_cls.return_value = self.m_action_plan_mgr
|
||||
|
||||
self.stdout = six.StringIO()
|
||||
self.cmd = shell.WatcherShell(stdout=self.stdout)
|
||||
|
||||
def test_do_action_plan_list(self):
|
||||
action_plan1 = resource.ActionPlan(mock.Mock(), ACTION_PLAN_1)
|
||||
action_plan2 = resource.ActionPlan(mock.Mock(), ACTION_PLAN_2)
|
||||
self.m_action_plan_mgr.list.return_value = [
|
||||
action_plan1, action_plan2]
|
||||
|
||||
exit_code, results = self.run_cmd('actionplan list')
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(
|
||||
[self.resource_as_dict(action_plan1, self.SHORT_LIST_FIELDS,
|
||||
self.SHORT_LIST_FIELD_LABELS),
|
||||
self.resource_as_dict(action_plan2, self.SHORT_LIST_FIELDS,
|
||||
self.SHORT_LIST_FIELD_LABELS)],
|
||||
results)
|
||||
|
||||
self.m_action_plan_mgr.list.assert_called_once_with(detail=False)
|
||||
|
||||
def test_do_action_plan_list_detail(self):
|
||||
action_plan1 = resource.ActionPlan(mock.Mock(), ACTION_PLAN_1)
|
||||
action_plan2 = resource.ActionPlan(mock.Mock(), ACTION_PLAN_2)
|
||||
self.m_action_plan_mgr.list.return_value = [
|
||||
action_plan1, action_plan2]
|
||||
|
||||
exit_code, results = self.run_cmd('actionplan list --detail')
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(
|
||||
[self.resource_as_dict(action_plan1, self.FIELDS,
|
||||
self.FIELD_LABELS),
|
||||
self.resource_as_dict(action_plan2, self.FIELDS,
|
||||
self.FIELD_LABELS)],
|
||||
results)
|
||||
|
||||
self.m_action_plan_mgr.list.assert_called_once_with(detail=True)
|
||||
|
||||
def test_do_action_plan_list_filter_by_audit(self):
|
||||
action_plan1 = resource.ActionPlan(mock.Mock(), ACTION_PLAN_1)
|
||||
self.m_action_plan_mgr.list.return_value = [action_plan1]
|
||||
|
||||
exit_code, results = self.run_cmd(
|
||||
'actionplan list --audit '
|
||||
'770ef053-ecb3-48b0-85b5-d55a2dbc6588')
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(
|
||||
[self.resource_as_dict(action_plan1, self.SHORT_LIST_FIELDS,
|
||||
self.SHORT_LIST_FIELD_LABELS)],
|
||||
results)
|
||||
|
||||
self.m_action_plan_mgr.list.assert_called_once_with(
|
||||
detail=False,
|
||||
audit='770ef053-ecb3-48b0-85b5-d55a2dbc6588',
|
||||
)
|
||||
|
||||
def test_do_action_plan_show_by_uuid(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
setattr(args, 'action-plan', 'a5199d0e-0702-4613-9234-5ae2af8dafea')
|
||||
action_plan = resource.ActionPlan(mock.Mock(), ACTION_PLAN_1)
|
||||
self.m_action_plan_mgr.get.return_value = action_plan
|
||||
|
||||
ap_shell.do_action_plan_show(client_mock, args)
|
||||
client_mock.action_plan.get.assert_called_once_with(
|
||||
'a5199d0e-0702-4613-9234-5ae2af8dafea'
|
||||
)
|
||||
# assert get_by_name() wasn't called
|
||||
self.assertFalse(client_mock.action_plan.get_by_name.called)
|
||||
exit_code, result = self.run_cmd(
|
||||
'actionplan show d9d9978e-6db5-4a05-8eab-1531795d7004')
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(
|
||||
self.resource_as_dict(
|
||||
action_plan, self.FIELDS, self.FIELD_LABELS),
|
||||
result)
|
||||
self.m_action_plan_mgr.get.assert_called_once_with(
|
||||
'd9d9978e-6db5-4a05-8eab-1531795d7004')
|
||||
|
||||
def test_do_action_plan_show_by_not_uuid(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
setattr(args, 'action-plan', 'not_uuid')
|
||||
self.m_action_plan_mgr.get.side_effect = exceptions.HTTPNotFound
|
||||
|
||||
self.assertRaises(
|
||||
exceptions.ValidationError,
|
||||
ap_shell.do_action_plan_show, client_mock, args)
|
||||
exit_code, result = self.run_cmd(
|
||||
'actionplan show not_uuid', formatting=None)
|
||||
|
||||
self.assertEqual(1, exit_code)
|
||||
self.assertEqual('', result)
|
||||
|
||||
def test_do_action_plan_delete(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
delete = ['a5199d0e-0702-4613-9234-5ae2af8dafea']
|
||||
setattr(args, 'action-plan', delete)
|
||||
self.m_action_plan_mgr.delete.return_value = ''
|
||||
|
||||
ap_shell.do_action_plan_delete(client_mock, args)
|
||||
client_mock.action_plan.delete.assert_called_once_with(
|
||||
'a5199d0e-0702-4613-9234-5ae2af8dafea')
|
||||
exit_code, result = self.run_cmd(
|
||||
'actionplan delete 5869da81-4876-4687-a1ed-12cd64cf53d9',
|
||||
formatting=None)
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual('', result)
|
||||
self.m_action_plan_mgr.delete.assert_called_once_with(
|
||||
'5869da81-4876-4687-a1ed-12cd64cf53d9')
|
||||
|
||||
def test_do_action_plan_delete_not_uuid(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
setattr(args, 'action-plan', ['not_uuid'])
|
||||
exit_code, result = self.run_cmd(
|
||||
'actionplan delete not_uuid', formatting=None)
|
||||
|
||||
self.assertRaises(
|
||||
exceptions.ValidationError,
|
||||
ap_shell.do_action_plan_delete, client_mock, args)
|
||||
self.assertEqual(1, exit_code)
|
||||
self.assertEqual('', result)
|
||||
|
||||
def test_do_action_plan_delete_multiple(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
setattr(args, 'action-plan',
|
||||
["a5199d0e-0702-4613-9234-5ae2af8dafea",
|
||||
"a5199d0e-0702-4613-9234-5ae2af8dafeb"])
|
||||
self.m_action_plan_mgr.delete.return_value = ''
|
||||
|
||||
ap_shell.do_action_plan_delete(client_mock, args)
|
||||
client_mock.action_plan.delete.assert_has_calls(
|
||||
[mock.call('a5199d0e-0702-4613-9234-5ae2af8dafea'),
|
||||
mock.call('a5199d0e-0702-4613-9234-5ae2af8dafeb')])
|
||||
exit_code, result = self.run_cmd(
|
||||
'actionplan delete 5869da81-4876-4687-a1ed-12cd64cf53d9 '
|
||||
'c20627fa-ea70-4d56-ae15-4106358f773b',
|
||||
formatting=None)
|
||||
|
||||
def test_do_action_plan_delete_multiple_not_uuid(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
setattr(args, 'action-plan',
|
||||
["a5199d0e-0702-4613-9234-5ae2af8dafea",
|
||||
"not_uuid",
|
||||
"a5199d0e-0702-4613-9234-5ae2af8dafeb"])
|
||||
|
||||
self.assertRaises(
|
||||
exceptions.ValidationError,
|
||||
ap_shell.do_action_plan_delete, client_mock, args)
|
||||
client_mock.action_plan.delete.assert_has_calls(
|
||||
[mock.call('a5199d0e-0702-4613-9234-5ae2af8dafea')])
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual('', result)
|
||||
self.m_action_plan_mgr.delete.assert_any_call(
|
||||
'5869da81-4876-4687-a1ed-12cd64cf53d9')
|
||||
self.m_action_plan_mgr.delete.assert_any_call(
|
||||
'c20627fa-ea70-4d56-ae15-4106358f773b')
|
||||
|
||||
def test_do_action_plan_update(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
action_plan = resource.ActionPlan(mock.Mock(), ACTION_PLAN_1)
|
||||
self.m_action_plan_mgr.update.return_value = action_plan
|
||||
|
||||
setattr(args, 'action-plan', "a5199d0e-0702-4613-9234-5ae2af8dafea")
|
||||
args.op = 'add'
|
||||
args.attributes = [['arg1=val1', 'arg2=val2']]
|
||||
exit_code, result = self.run_cmd(
|
||||
'actionplan update 5869da81-4876-4687-a1ed-12cd64cf53d9 '
|
||||
'replace state=CANCELLED')
|
||||
|
||||
ap_shell.do_action_plan_update(client_mock, args)
|
||||
patch = commonutils.args_array_to_patch(
|
||||
args.op,
|
||||
args.attributes[0])
|
||||
client_mock.action_plan.update.assert_called_once_with(
|
||||
'a5199d0e-0702-4613-9234-5ae2af8dafea', patch)
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(
|
||||
self.resource_as_dict(action_plan, self.FIELDS, self.FIELD_LABELS),
|
||||
result)
|
||||
self.m_action_plan_mgr.update.assert_called_once_with(
|
||||
'5869da81-4876-4687-a1ed-12cd64cf53d9',
|
||||
[{'op': 'replace', 'path': '/state', 'value': 'CANCELLED'}])
|
||||
|
||||
def test_do_action_plan_update_not_uuid(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
exit_code, result = self.run_cmd(
|
||||
'actionplan update not_uuid '
|
||||
'replace state=CANCELLED',
|
||||
formatting=None)
|
||||
|
||||
setattr(args, 'action-plan', "not_uuid")
|
||||
args.op = 'add'
|
||||
args.attributes = [['arg1=val1', 'arg2=val2']]
|
||||
|
||||
self.assertRaises(
|
||||
exceptions.ValidationError,
|
||||
ap_shell.do_action_plan_update, client_mock, args)
|
||||
self.assertEqual(1, exit_code)
|
||||
self.assertEqual('', result)
|
||||
|
||||
def test_do_action_plan_start(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
action_plan = resource.ActionPlan(mock.Mock(), ACTION_PLAN_1)
|
||||
self.m_action_plan_mgr.start.return_value = action_plan
|
||||
|
||||
action_plan = 'a5199d0e-0702-4613-9234-5ae2af8dafea'
|
||||
setattr(args, 'action-plan', action_plan)
|
||||
exit_code, result = self.run_cmd(
|
||||
'actionplan start 5869da81-4876-4687-a1ed-12cd64cf53d9')
|
||||
|
||||
ap_shell.do_action_plan_start(client_mock, args)
|
||||
patch = commonutils.args_array_to_patch(
|
||||
'replace', ['state=PENDING'])
|
||||
client_mock.action_plan.update.assert_called_once_with(
|
||||
'a5199d0e-0702-4613-9234-5ae2af8dafea', patch)
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(
|
||||
self.resource_as_dict(action_plan, self.FIELDS, self.FIELD_LABELS),
|
||||
result)
|
||||
self.m_action_plan_mgr.start.assert_called_once_with(
|
||||
'5869da81-4876-4687-a1ed-12cd64cf53d9')
|
||||
|
||||
def test_do_action_plan_start_not_uuid(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
exit_code, result = self.run_cmd(
|
||||
'actionplan start not_uuid',
|
||||
formatting=None)
|
||||
|
||||
action_plan = 'not_uuid'
|
||||
setattr(args, 'action-plan', action_plan)
|
||||
|
||||
self.assertRaises(
|
||||
exceptions.ValidationError,
|
||||
ap_shell.do_action_plan_start, client_mock, args)
|
||||
self.assertEqual(1, exit_code)
|
||||
self.assertEqual('', result)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Copyright 2013 IBM Corp
|
||||
#
|
||||
# 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
|
||||
# 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
|
||||
@@ -14,117 +14,143 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import datetime
|
||||
|
||||
import mock
|
||||
import six
|
||||
|
||||
from watcherclient.common import cliutils
|
||||
from watcherclient.common import utils as commonutils
|
||||
from watcherclient import exceptions
|
||||
from watcherclient.tests import utils
|
||||
import watcherclient.v1.action_shell as a_shell
|
||||
from watcherclient import shell
|
||||
from watcherclient.tests.v1 import base
|
||||
from watcherclient import v1 as resource
|
||||
from watcherclient.v1 import resource_fields
|
||||
|
||||
ACTION_1 = {
|
||||
'uuid': '770ef053-ecb3-48b0-85b5-d55a2dbc6588',
|
||||
'action_plan_uuid': 'f8e47706-efcf-49a4-a5c4-af604eb492f2',
|
||||
'state': 'PENDING',
|
||||
'action_type': 'migrate',
|
||||
'next_uuid': '239f02a5-9649-4e14-9d33-ac2bf67cb755',
|
||||
'input_parameters': {"test": 1},
|
||||
'created_at': datetime.datetime.now().isoformat(),
|
||||
'updated_at': None,
|
||||
'deleted_at': None,
|
||||
}
|
||||
|
||||
ACTION_2 = {
|
||||
'uuid': '239f02a5-9649-4e14-9d33-ac2bf67cb755',
|
||||
'action_plan_uuid': 'f8e47706-efcf-49a4-a5c4-af604eb492f2',
|
||||
'state': 'PENDING',
|
||||
'action_type': 'migrate',
|
||||
'next_uuid': '67653274-eb24-c7ba-70f6-a84e73d80843',
|
||||
'input_parameters': {"test": 2},
|
||||
'created_at': datetime.datetime.now().isoformat(),
|
||||
'updated_at': None,
|
||||
'deleted_at': None,
|
||||
}
|
||||
|
||||
ACTION_3 = {
|
||||
'uuid': '67653274-eb24-c7ba-70f6-a84e73d80843',
|
||||
'action_plan_uuid': 'a5199d0e-0702-4613-9234-5ae2af8dafea',
|
||||
'next_uuid': None,
|
||||
'state': 'PENDING',
|
||||
'action_type': 'sleep',
|
||||
'created_at': datetime.datetime.now().isoformat(),
|
||||
'updated_at': None,
|
||||
'deleted_at': None,
|
||||
}
|
||||
|
||||
ACTION_PLAN_1 = {
|
||||
'uuid': 'a5199d0e-0702-4613-9234-5ae2af8dafea',
|
||||
'action': '770ef053-ecb3-48b0-85b5-d55a2dbc6588',
|
||||
'state': 'RECOMMENDED',
|
||||
'created_at': datetime.datetime.now().isoformat(),
|
||||
'updated_at': None,
|
||||
'deleted_at': None,
|
||||
}
|
||||
|
||||
|
||||
class ActionShellTest(utils.BaseTestCase):
|
||||
def test_do_action_show(self):
|
||||
actual = {}
|
||||
fake_print_dict = lambda data, *args, **kwargs: actual.update(data)
|
||||
with mock.patch.object(cliutils, 'print_dict', fake_print_dict):
|
||||
action = object()
|
||||
a_shell._print_action_show(action)
|
||||
exp = ['action_type',
|
||||
'alarm',
|
||||
'applies_to',
|
||||
'created_at',
|
||||
'deleted_at',
|
||||
'description',
|
||||
'next_uuid',
|
||||
'input_parameters',
|
||||
'state',
|
||||
'action_plan_uuid',
|
||||
'updated_at',
|
||||
'uuid']
|
||||
act = actual.keys()
|
||||
self.assertEqual(sorted(exp), sorted(act))
|
||||
class ActionShellTest(base.CommandTestCase):
|
||||
|
||||
SHORT_LIST_FIELDS = resource_fields.ACTION_SHORT_LIST_FIELDS
|
||||
SHORT_LIST_FIELD_LABELS = resource_fields.ACTION_SHORT_LIST_FIELD_LABELS
|
||||
FIELDS = resource_fields.ACTION_FIELDS
|
||||
FIELD_LABELS = resource_fields.ACTION_FIELD_LABELS
|
||||
|
||||
def setUp(self):
|
||||
super(self.__class__, self).setUp()
|
||||
|
||||
p_action_manager = mock.patch.object(resource, 'ActionManager')
|
||||
p_action_plan_manager = mock.patch.object(
|
||||
resource, 'ActionPlanManager')
|
||||
self.m_action_mgr_cls = p_action_manager.start()
|
||||
self.m_action_plan_mgr_cls = p_action_plan_manager.start()
|
||||
self.addCleanup(p_action_manager.stop)
|
||||
self.addCleanup(p_action_plan_manager.stop)
|
||||
|
||||
self.m_action_mgr = mock.Mock()
|
||||
self.m_action_plan_mgr = mock.Mock()
|
||||
|
||||
self.m_action_mgr_cls.return_value = self.m_action_mgr
|
||||
self.m_action_plan_mgr_cls.return_value = self.m_action_plan_mgr
|
||||
|
||||
self.stdout = six.StringIO()
|
||||
self.cmd = shell.WatcherShell(stdout=self.stdout)
|
||||
|
||||
def test_do_action_list(self):
|
||||
action1 = resource.Action(mock.Mock(), ACTION_1)
|
||||
action2 = resource.Action(mock.Mock(), ACTION_2)
|
||||
self.m_action_mgr.list.return_value = [action1, action2]
|
||||
|
||||
exit_code, results = self.run_cmd('action list')
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(
|
||||
[self.resource_as_dict(action1, self.SHORT_LIST_FIELDS,
|
||||
self.SHORT_LIST_FIELD_LABELS),
|
||||
self.resource_as_dict(action2, self.SHORT_LIST_FIELDS,
|
||||
self.SHORT_LIST_FIELD_LABELS)],
|
||||
results)
|
||||
|
||||
self.m_action_mgr.list.assert_called_once_with(detail=False)
|
||||
|
||||
def test_do_action_list_detail(self):
|
||||
action1 = resource.Action(mock.Mock(), ACTION_1)
|
||||
action2 = resource.Action(mock.Mock(), ACTION_2)
|
||||
self.m_action_mgr.list.return_value = [action1, action2]
|
||||
|
||||
exit_code, results = self.run_cmd('action list --detail')
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(
|
||||
[self.resource_as_dict(action1, self.FIELDS,
|
||||
self.FIELD_LABELS),
|
||||
self.resource_as_dict(action2, self.FIELDS,
|
||||
self.FIELD_LABELS)],
|
||||
results)
|
||||
|
||||
self.m_action_mgr.list.assert_called_once_with(detail=True)
|
||||
|
||||
def test_do_action_show_by_uuid(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
args.action = 'a5199d0e-0702-4613-9234-5ae2af8dafea'
|
||||
action = resource.Action(mock.Mock(), ACTION_1)
|
||||
self.m_action_mgr.get.return_value = action
|
||||
self.m_action_plan_mgr.get.return_value = action
|
||||
|
||||
a_shell.do_action_show(client_mock, args)
|
||||
client_mock.action.get.assert_called_once_with(
|
||||
'a5199d0e-0702-4613-9234-5ae2af8dafea'
|
||||
)
|
||||
# assert get_by_name() wasn't called
|
||||
self.assertFalse(client_mock.action.get_by_name.called)
|
||||
exit_code, result = self.run_cmd(
|
||||
'action show 5869da81-4876-4687-a1ed-12cd64cf53d9')
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(
|
||||
self.resource_as_dict(action, self.FIELDS, self.FIELD_LABELS),
|
||||
result)
|
||||
self.m_action_mgr.get.assert_called_once_with(
|
||||
'5869da81-4876-4687-a1ed-12cd64cf53d9')
|
||||
|
||||
def test_do_action_show_by_not_uuid(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
args.action = 'not_uuid'
|
||||
self.m_action_mgr.get.side_effect = exceptions.HTTPNotFound
|
||||
|
||||
self.assertRaises(exceptions.ValidationError, a_shell.do_action_show,
|
||||
client_mock, args)
|
||||
exit_code, result = self.run_cmd(
|
||||
'action show not_uuid', formatting=None)
|
||||
|
||||
def test_do_action_delete(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
args.action = ['a5199d0e-0702-4613-9234-5ae2af8dafea']
|
||||
|
||||
a_shell.do_action_delete(client_mock, args)
|
||||
client_mock.action.delete.assert_called_once_with(
|
||||
'a5199d0e-0702-4613-9234-5ae2af8dafea')
|
||||
|
||||
def test_do_action_delete_not_uuid(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
args.action = ['not_uuid']
|
||||
|
||||
self.assertRaises(exceptions.ValidationError, a_shell.do_action_delete,
|
||||
client_mock, args)
|
||||
|
||||
def test_do_action_delete_multiple(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
args.action = ['a5199d0e-0702-4613-9234-5ae2af8dafea',
|
||||
'a5199d0e-0702-4613-9234-5ae2af8dafeb']
|
||||
|
||||
a_shell.do_action_delete(client_mock, args)
|
||||
client_mock.action.delete.assert_has_calls(
|
||||
[mock.call('a5199d0e-0702-4613-9234-5ae2af8dafea'),
|
||||
mock.call('a5199d0e-0702-4613-9234-5ae2af8dafeb')])
|
||||
|
||||
def test_do_action_delete_multiple_not_uuid(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
args.action = ['a5199d0e-0702-4613-9234-5ae2af8dafea',
|
||||
'not_uuid'
|
||||
'a5199d0e-0702-4613-9234-5ae2af8dafeb']
|
||||
|
||||
self.assertRaises(exceptions.ValidationError, a_shell.do_action_delete,
|
||||
client_mock, args)
|
||||
client_mock.action.delete.assert_has_calls(
|
||||
[mock.call('a5199d0e-0702-4613-9234-5ae2af8dafea')])
|
||||
|
||||
def test_do_action_update(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
args.action = 'a5199d0e-0702-4613-9234-5ae2af8dafea'
|
||||
args.op = 'add'
|
||||
args.attributes = [['arg1=val1', 'arg2=val2']]
|
||||
|
||||
a_shell.do_action_update(client_mock, args)
|
||||
patch = commonutils.args_array_to_patch(
|
||||
args.op,
|
||||
args.attributes[0])
|
||||
client_mock.action.update.assert_called_once_with(
|
||||
'a5199d0e-0702-4613-9234-5ae2af8dafea', patch)
|
||||
|
||||
def test_do_action_update_not_uuid(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
args.action = 'not_uuid'
|
||||
args.op = 'add'
|
||||
args.attributes = [['arg1=val1', 'arg2=val2']]
|
||||
|
||||
self.assertRaises(exceptions.ValidationError, a_shell.do_action_update,
|
||||
client_mock, args)
|
||||
self.assertEqual(1, exit_code)
|
||||
self.assertEqual('', result)
|
||||
|
||||
@@ -27,7 +27,7 @@ AUDIT1 = {
|
||||
'id': 1,
|
||||
'uuid': 'f8e47706-efcf-49a4-a5c4-af604eb492f2',
|
||||
'deadline': None,
|
||||
'type': 'ONE_SHOT',
|
||||
'audit_type': 'ONE_SHOT',
|
||||
'audit_template_uuid': '770ef053-ecb3-48b0-85b5-d55a2dbc6588'
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ AUDIT2 = {
|
||||
'id': 2,
|
||||
'uuid': 'a5199d0e-0702-4613-9234-5ae2af8dafea',
|
||||
'deadline': None,
|
||||
'type': 'ONE_SHOT',
|
||||
'audit_type': 'ONE_SHOT',
|
||||
'audit_template_uuid': '770ef053-ecb3-48b0-85b5-d55a2dbc6588'
|
||||
}
|
||||
|
||||
|
||||
@@ -14,132 +14,320 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import datetime
|
||||
|
||||
import mock
|
||||
import six
|
||||
|
||||
from watcherclient.common import cliutils
|
||||
from watcherclient.common import utils as commonutils
|
||||
from watcherclient import exceptions
|
||||
from watcherclient.tests import utils
|
||||
import watcherclient.v1.audit_shell as a_shell
|
||||
from watcherclient import shell
|
||||
from watcherclient.tests.v1 import base
|
||||
from watcherclient import v1 as resource
|
||||
from watcherclient.v1 import resource_fields
|
||||
|
||||
AUDIT_TEMPLATE_1 = {
|
||||
'uuid': 'f8e47706-efcf-49a4-a5c4-af604eb492f2',
|
||||
'name': 'at1',
|
||||
'description': 'Audit Template 1 description',
|
||||
'host_aggregate': 5,
|
||||
'extra': {'automatic': False},
|
||||
'goal_uuid': '7568667b-51fe-4087-9eb1-29b26891036f',
|
||||
'strategy_uuid': 'bbe6b966-f98e-439b-a01a-17b9b3b8478b',
|
||||
'created_at': datetime.datetime.now().isoformat(),
|
||||
'updated_at': None,
|
||||
'deleted_at': None,
|
||||
}
|
||||
|
||||
AUDIT_1 = {
|
||||
'uuid': '5869da81-4876-4687-a1ed-12cd64cf53d9',
|
||||
'deadline': None,
|
||||
'audit_type': 'ONESHOT',
|
||||
'state': 'PENDING',
|
||||
'audit_template_uuid': 'f8e47706-efcf-49a4-a5c4-af604eb492f2',
|
||||
'audit_template_name': 'at1',
|
||||
'created_at': datetime.datetime.now().isoformat(),
|
||||
'updated_at': None,
|
||||
'deleted_at': None,
|
||||
'parameters': None,
|
||||
'interval': None,
|
||||
}
|
||||
|
||||
AUDIT_2 = {
|
||||
'uuid': 'a5199d0e-0702-4613-9234-5ae2af8dafea',
|
||||
'deadline': None,
|
||||
'audit_type': 'ONESHOT',
|
||||
'audit_template_uuid': '770ef053-ecb3-48b0-85b5-d55a2dbc6588',
|
||||
'audit_template_name': 'at2',
|
||||
'state': 'PENDING',
|
||||
'created_at': datetime.datetime.now().isoformat(),
|
||||
'updated_at': None,
|
||||
'deleted_at': None,
|
||||
'parameters': None,
|
||||
'interval': None,
|
||||
}
|
||||
|
||||
AUDIT_3 = {
|
||||
'uuid': '43199d0e-0712-1213-9674-5ae2af8dhgte',
|
||||
'deadline': None,
|
||||
'audit_type': 'CONTINUOUS',
|
||||
'audit_template_uuid': 'f8e47706-efcf-49a4-a5c4-af604eb492f2',
|
||||
'audit_template_name': 'at1',
|
||||
'state': 'PENDING',
|
||||
'created_at': datetime.datetime.now().isoformat(),
|
||||
'updated_at': None,
|
||||
'deleted_at': None,
|
||||
'parameters': None,
|
||||
'interval': 3600,
|
||||
}
|
||||
|
||||
|
||||
class AuditShellTest(utils.BaseTestCase):
|
||||
def test_do_audit_show(self):
|
||||
actual = {}
|
||||
fake_print_dict = lambda data, *args, **kwargs: actual.update(data)
|
||||
with mock.patch.object(cliutils, 'print_dict', fake_print_dict):
|
||||
audit = object()
|
||||
a_shell._print_audit_show(audit)
|
||||
exp = ['created_at', 'audit_template_uuid', 'audit_template_name',
|
||||
'updated_at', 'uuid', 'deleted_at', 'state', 'type',
|
||||
'deadline']
|
||||
act = actual.keys()
|
||||
self.assertEqual(sorted(exp), sorted(act))
|
||||
class AuditShellTest(base.CommandTestCase):
|
||||
|
||||
SHORT_LIST_FIELDS = resource_fields.AUDIT_SHORT_LIST_FIELDS
|
||||
SHORT_LIST_FIELD_LABELS = resource_fields.AUDIT_SHORT_LIST_FIELD_LABELS
|
||||
FIELDS = resource_fields.AUDIT_FIELDS
|
||||
FIELD_LABELS = resource_fields.AUDIT_FIELD_LABELS
|
||||
|
||||
def setUp(self):
|
||||
super(self.__class__, self).setUp()
|
||||
|
||||
p_audit_manager = mock.patch.object(resource, 'AuditManager')
|
||||
p_audit_template_manager = mock.patch.object(
|
||||
resource, 'AuditTemplateManager')
|
||||
self.m_audit_mgr_cls = p_audit_manager.start()
|
||||
self.m_audit_template_mgr_cls = p_audit_template_manager.start()
|
||||
self.addCleanup(p_audit_manager.stop)
|
||||
self.addCleanup(p_audit_template_manager.stop)
|
||||
|
||||
self.m_audit_mgr = mock.Mock()
|
||||
self.m_audit_template_mgr = mock.Mock()
|
||||
|
||||
self.m_audit_mgr_cls.return_value = self.m_audit_mgr
|
||||
self.m_audit_template_mgr_cls.return_value = self.m_audit_template_mgr
|
||||
|
||||
self.stdout = six.StringIO()
|
||||
self.cmd = shell.WatcherShell(stdout=self.stdout)
|
||||
|
||||
def test_do_audit_list(self):
|
||||
audit1 = resource.Audit(mock.Mock(), AUDIT_1)
|
||||
audit2 = resource.Audit(mock.Mock(), AUDIT_2)
|
||||
self.m_audit_mgr.list.return_value = [
|
||||
audit1, audit2]
|
||||
|
||||
exit_code, results = self.run_cmd('audit list')
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(
|
||||
[self.resource_as_dict(audit1, self.SHORT_LIST_FIELDS,
|
||||
self.SHORT_LIST_FIELD_LABELS),
|
||||
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)
|
||||
|
||||
def test_do_audit_list_detail(self):
|
||||
audit1 = resource.Audit(mock.Mock(), AUDIT_1)
|
||||
audit2 = resource.Audit(mock.Mock(), AUDIT_2)
|
||||
self.m_audit_mgr.list.return_value = [
|
||||
audit1, audit2]
|
||||
|
||||
exit_code, results = self.run_cmd('audit list --detail')
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(
|
||||
[self.resource_as_dict(audit1, self.FIELDS,
|
||||
self.FIELD_LABELS),
|
||||
self.resource_as_dict(audit2, self.FIELDS,
|
||||
self.FIELD_LABELS)],
|
||||
results)
|
||||
|
||||
self.m_audit_mgr.list.assert_called_once_with(detail=True)
|
||||
|
||||
def test_do_audit_show_by_uuid(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
args.audit = 'a5199d0e-0702-4613-9234-5ae2af8dafea'
|
||||
audit = resource.Audit(mock.Mock(), AUDIT_1)
|
||||
self.m_audit_mgr.get.return_value = audit
|
||||
self.m_audit_template_mgr.get.return_value = audit
|
||||
|
||||
a_shell.do_audit_show(client_mock, args)
|
||||
client_mock.audit.get.assert_called_once_with(
|
||||
'a5199d0e-0702-4613-9234-5ae2af8dafea'
|
||||
)
|
||||
# assert get_by_name() wasn't called
|
||||
self.assertFalse(client_mock.audit.get_by_name.called)
|
||||
exit_code, result = self.run_cmd(
|
||||
'audit show 5869da81-4876-4687-a1ed-12cd64cf53d9')
|
||||
|
||||
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(
|
||||
'5869da81-4876-4687-a1ed-12cd64cf53d9')
|
||||
|
||||
def test_do_audit_show_by_not_uuid(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
args.audit = 'not_uuid'
|
||||
self.m_audit_mgr.get.side_effect = exceptions.HTTPNotFound
|
||||
|
||||
self.assertRaises(exceptions.ValidationError, a_shell.do_audit_show,
|
||||
client_mock, args)
|
||||
exit_code, result = self.run_cmd(
|
||||
'audit show not_uuid', formatting=None)
|
||||
|
||||
self.assertEqual(1, exit_code)
|
||||
self.assertEqual('', result)
|
||||
|
||||
def test_do_audit_delete(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
args.audit = ['a5199d0e-0702-4613-9234-5ae2af8dafea']
|
||||
self.m_audit_mgr.delete.return_value = ''
|
||||
|
||||
a_shell.do_audit_delete(client_mock, args)
|
||||
client_mock.audit.delete.assert_called_once_with(
|
||||
'a5199d0e-0702-4613-9234-5ae2af8dafea')
|
||||
exit_code, result = self.run_cmd(
|
||||
'audit delete 5869da81-4876-4687-a1ed-12cd64cf53d9',
|
||||
formatting=None)
|
||||
|
||||
def test_do_audit_delete_with_not_uuid(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
args.audit = ['not_uuid']
|
||||
|
||||
self.assertRaises(exceptions.ValidationError, a_shell.do_audit_delete,
|
||||
client_mock, args)
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual('', result)
|
||||
self.m_audit_mgr.delete.assert_called_once_with(
|
||||
'5869da81-4876-4687-a1ed-12cd64cf53d9')
|
||||
|
||||
def test_do_audit_delete_multiple(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
args.audit = ['a5199d0e-0702-4613-9234-5ae2af8dafea',
|
||||
'a5199d0e-0702-4613-9234-5ae2af8dafeb']
|
||||
self.m_audit_mgr.delete.return_value = ''
|
||||
|
||||
a_shell.do_audit_delete(client_mock, args)
|
||||
client_mock.audit.delete.assert_has_calls(
|
||||
[mock.call('a5199d0e-0702-4613-9234-5ae2af8dafea'),
|
||||
mock.call('a5199d0e-0702-4613-9234-5ae2af8dafeb')])
|
||||
exit_code, result = self.run_cmd(
|
||||
'audit delete 5869da81-4876-4687-a1ed-12cd64cf53d9 '
|
||||
'5b157edd-5a7e-4aaa-b511-f7b33ec86e9f',
|
||||
formatting=None)
|
||||
|
||||
def test_do_audit_delete_multiple_with_not_uuid(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
args.audit = ['a5199d0e-0702-4613-9234-5ae2af8dafea',
|
||||
'not_uuid',
|
||||
'a5199d0e-0702-4613-9234-5ae2af8dafeb']
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual('', result)
|
||||
self.m_audit_mgr.delete.assert_any_call(
|
||||
'5869da81-4876-4687-a1ed-12cd64cf53d9')
|
||||
self.m_audit_mgr.delete.assert_any_call(
|
||||
'5b157edd-5a7e-4aaa-b511-f7b33ec86e9f')
|
||||
|
||||
self.assertRaises(exceptions.ValidationError, a_shell.do_audit_delete,
|
||||
client_mock, args)
|
||||
client_mock.audit.delete.assert_has_calls(
|
||||
[mock.call('a5199d0e-0702-4613-9234-5ae2af8dafea')])
|
||||
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):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
args.audit = 'a5199d0e-0702-4613-9234-5ae2af8dafea'
|
||||
args.op = 'add'
|
||||
args.attributes = [['arg1=val1', 'arg2=val2']]
|
||||
audit = resource.Audit(mock.Mock(), AUDIT_1)
|
||||
self.m_audit_mgr.update.return_value = audit
|
||||
|
||||
a_shell.do_audit_update(client_mock, args)
|
||||
patch = commonutils.args_array_to_patch(
|
||||
args.op,
|
||||
args.attributes[0])
|
||||
client_mock.audit.update.assert_called_once_with(
|
||||
'a5199d0e-0702-4613-9234-5ae2af8dafea', patch)
|
||||
exit_code, result = self.run_cmd(
|
||||
'audit update 5869da81-4876-4687-a1ed-12cd64cf53d9 '
|
||||
'replace state=PENDING')
|
||||
|
||||
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(
|
||||
'5869da81-4876-4687-a1ed-12cd64cf53d9',
|
||||
[{'op': 'replace', 'path': '/state', 'value': 'PENDING'}])
|
||||
|
||||
def test_do_audit_update_with_not_uuid(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
args.audit = ['not_uuid']
|
||||
args.op = 'add'
|
||||
args.attributes = [['arg1=val1', 'arg2=val2']]
|
||||
self.m_audit_mgr.update.return_value = ''
|
||||
|
||||
self.assertRaises(exceptions.ValidationError, a_shell.do_audit_update,
|
||||
client_mock, args)
|
||||
exit_code, result = self.run_cmd(
|
||||
'audit update not_uuid replace state=PENDING', formatting=None)
|
||||
|
||||
def test_do_audit_create(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
self.assertEqual(1, exit_code)
|
||||
self.assertEqual('', result)
|
||||
|
||||
a_shell.do_audit_create(client_mock, args)
|
||||
client_mock.audit.create.assert_called_once_with()
|
||||
def test_do_audit_create_with_audit_template_uuid(self):
|
||||
audit = resource.Audit(mock.Mock(), AUDIT_1)
|
||||
self.m_audit_mgr.create.return_value = audit
|
||||
|
||||
exit_code, result = self.run_cmd(
|
||||
'audit create -a f8e47706-efcf-49a4-a5c4-af604eb492f2')
|
||||
|
||||
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(
|
||||
audit_template_uuid='f8e47706-efcf-49a4-a5c4-af604eb492f2',
|
||||
audit_type='ONESHOT')
|
||||
|
||||
def test_do_audit_create_with_audit_template_name(self):
|
||||
audit = resource.Audit(mock.Mock(), AUDIT_1)
|
||||
audit_template = resource.AuditTemplate(mock.Mock(), AUDIT_TEMPLATE_1)
|
||||
self.m_audit_template_mgr.get.return_value = audit_template
|
||||
self.m_audit_mgr.create.return_value = audit
|
||||
|
||||
exit_code, result = self.run_cmd('audit create -a at1')
|
||||
|
||||
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(
|
||||
audit_template_uuid='f8e47706-efcf-49a4-a5c4-af604eb492f2',
|
||||
audit_type='ONESHOT')
|
||||
|
||||
def test_do_audit_create_with_deadline(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
args.deadline = 'deadline'
|
||||
audit = resource.Audit(mock.Mock(), AUDIT_1)
|
||||
audit_template = resource.AuditTemplate(mock.Mock(), AUDIT_TEMPLATE_1)
|
||||
self.m_audit_template_mgr.get.return_value = audit_template
|
||||
self.m_audit_mgr.create.return_value = audit
|
||||
|
||||
a_shell.do_audit_create(client_mock, args)
|
||||
client_mock.audit.create.assert_called_once_with(
|
||||
deadline='deadline')
|
||||
exit_code, result = self.run_cmd(
|
||||
'audit create -a at1 -d 2016-04-28T10:48:32.064802')
|
||||
|
||||
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(
|
||||
audit_template_uuid='f8e47706-efcf-49a4-a5c4-af604eb492f2',
|
||||
audit_type='ONESHOT',
|
||||
deadline='2016-04-28T10:48:32.064802')
|
||||
|
||||
def test_do_audit_create_with_type(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
args.type = 'type'
|
||||
audit = resource.Audit(mock.Mock(), AUDIT_1)
|
||||
audit_template = resource.AuditTemplate(mock.Mock(), AUDIT_TEMPLATE_1)
|
||||
self.m_audit_template_mgr.get.return_value = audit_template
|
||||
self.m_audit_mgr.create.return_value = audit
|
||||
|
||||
a_shell.do_audit_create(client_mock, args)
|
||||
client_mock.audit.create.assert_called_once_with(type='type')
|
||||
exit_code, result = self.run_cmd(
|
||||
'audit create -a at1 -t ONESHOT')
|
||||
|
||||
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(
|
||||
audit_template_uuid='f8e47706-efcf-49a4-a5c4-af604eb492f2',
|
||||
audit_type='ONESHOT')
|
||||
|
||||
def test_do_audit_create_with_parameter(self):
|
||||
audit = resource.Audit(mock.Mock(), AUDIT_1)
|
||||
audit_template = resource.AuditTemplate(mock.Mock(), AUDIT_TEMPLATE_1)
|
||||
self.m_audit_template_mgr.get.return_value = audit_template
|
||||
self.m_audit_mgr.create.return_value = audit
|
||||
|
||||
exit_code, result = self.run_cmd(
|
||||
'audit create -a at1 -p para1=10 -p para2=20')
|
||||
|
||||
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(
|
||||
audit_template_uuid='f8e47706-efcf-49a4-a5c4-af604eb492f2',
|
||||
audit_type='ONESHOT',
|
||||
parameters={'para1': 10, 'para2': 20})
|
||||
|
||||
def test_do_audit_create_with_type_continuous(self):
|
||||
audit = resource.Audit(mock.Mock(), AUDIT_3)
|
||||
audit_template = resource.AuditTemplate(mock.Mock(), AUDIT_TEMPLATE_1)
|
||||
self.m_audit_template_mgr.get.return_value = audit_template
|
||||
self.m_audit_mgr.create.return_value = audit
|
||||
|
||||
exit_code, result = self.run_cmd(
|
||||
'audit create -a at1 -t CONTINUOUS -i 3600')
|
||||
|
||||
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(
|
||||
audit_template_uuid='f8e47706-efcf-49a4-a5c4-af604eb492f2',
|
||||
audit_type='CONTINUOUS',
|
||||
interval='3600')
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
import copy
|
||||
|
||||
from six.moves.urllib import parse as urlparse
|
||||
import testtools
|
||||
from testtools import matchers
|
||||
|
||||
from watcherclient.tests import utils
|
||||
@@ -31,7 +30,10 @@ AUDIT_TMPL1 = {
|
||||
'description': 'Audit Template 1 description',
|
||||
'host_aggregate': 5,
|
||||
'extra': {'automatic': False},
|
||||
'goal': 'MINIMIZE_LICENSING_COST'
|
||||
'goal_uuid': '7568667b-51fe-4087-9eb1-29b26891036f',
|
||||
'goal_name': 'SERVER_CONSOLIDATION',
|
||||
'strategy_uuid': 'bbe6b966-f98e-439b-a01a-17b9b3b8478b',
|
||||
'strategy_name': 'server_consolidation',
|
||||
}
|
||||
|
||||
AUDIT_TMPL2 = {
|
||||
@@ -41,7 +43,10 @@ AUDIT_TMPL2 = {
|
||||
'description': 'Audit Template 2 description',
|
||||
'host_aggregate': 8,
|
||||
'extra': {'automatic': True},
|
||||
'goal': 'BASIC_CONSOLIDATION'
|
||||
'goal_uuid': 'e75ee410-b32b-465f-88b5-4397705f9473',
|
||||
'goal_name': 'DUMMY',
|
||||
'strategy_uuid': 'ae99a4a4-acbc-4c67-abe1-e37128fac45d',
|
||||
'strategy_name': 'dummy',
|
||||
}
|
||||
|
||||
AUDIT_TMPL3 = {
|
||||
@@ -51,12 +56,17 @@ AUDIT_TMPL3 = {
|
||||
'description': 'Audit Template 3 description',
|
||||
'host_aggregate': 7,
|
||||
'extra': {'automatic': True},
|
||||
'goal': 'MINIMIZE_LICENSING_COST'
|
||||
'goal_uuid': '7568667b-51fe-4087-9eb1-29b26891036f',
|
||||
'goal_name': 'SERVER_CONSOLIDATION',
|
||||
}
|
||||
|
||||
CREATE_AUDIT_TEMPLATE = copy.deepcopy(AUDIT_TMPL1)
|
||||
del CREATE_AUDIT_TEMPLATE['id']
|
||||
del CREATE_AUDIT_TEMPLATE['uuid']
|
||||
del CREATE_AUDIT_TEMPLATE['goal_name']
|
||||
del CREATE_AUDIT_TEMPLATE['strategy_name']
|
||||
CREATE_AUDIT_TEMPLATE['goal'] = CREATE_AUDIT_TEMPLATE.pop('goal_uuid')
|
||||
CREATE_AUDIT_TEMPLATE['strategy'] = CREATE_AUDIT_TEMPLATE.pop('strategy_uuid')
|
||||
|
||||
UPDATED_AUDIT_TMPL1 = copy.deepcopy(AUDIT_TMPL1)
|
||||
NEW_NAME = 'Audit Template_1 new name'
|
||||
@@ -125,14 +135,14 @@ fake_responses = {
|
||||
{"audit_templates": [AUDIT_TMPL1]},
|
||||
),
|
||||
},
|
||||
'/v1/audit_templates/detail?goal=%s' % AUDIT_TMPL1['goal']:
|
||||
'/v1/audit_templates/detail?goal=%s' % AUDIT_TMPL1['goal_uuid']:
|
||||
{
|
||||
'GET': (
|
||||
{},
|
||||
{"audit_templates": [AUDIT_TMPL1, AUDIT_TMPL3]},
|
||||
),
|
||||
},
|
||||
'/v1/audit_templates/?goal=%s' % AUDIT_TMPL1['goal']:
|
||||
'/v1/audit_templates/?goal=%s' % AUDIT_TMPL1['goal_uuid']:
|
||||
{
|
||||
'GET': (
|
||||
{},
|
||||
@@ -176,8 +186,48 @@ fake_responses_sorting = {
|
||||
},
|
||||
}
|
||||
|
||||
fake_responses_filter_by_goal = {
|
||||
'/v1/audit_templates/?goal=BASIC_CONSOLIDATION':
|
||||
fake_responses_filter_by_goal_uuid = {
|
||||
'/v1/audit_templates/?goal=e75ee410-b32b-465f-88b5-4397705f9473':
|
||||
{
|
||||
'GET': (
|
||||
{},
|
||||
{"audit_templates": [AUDIT_TMPL2]}
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
fake_responses_filter_by_goal_name = {
|
||||
'/v1/audit_templates/?goal=DUMMY':
|
||||
{
|
||||
'GET': (
|
||||
{},
|
||||
{"audit_templates": [AUDIT_TMPL2]}
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
fake_responses_filter_by_strategy_uuid = {
|
||||
'/v1/audit_templates/?strategy=ae99a4a4-acbc-4c67-abe1-e37128fac45d':
|
||||
{
|
||||
'GET': (
|
||||
{},
|
||||
{"audit_templates": [AUDIT_TMPL2]}
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
fake_responses_filter_by_strategy_name = {
|
||||
'/v1/audit_templates/?strategy=dummy':
|
||||
{
|
||||
'GET': (
|
||||
{},
|
||||
{"audit_templates": [AUDIT_TMPL2]}
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
fake_responses_filter_by_strategy_and_goal_name = {
|
||||
'/v1/audit_templates/?goal=DUMMY&strategy=dummy':
|
||||
{
|
||||
'GET': (
|
||||
{},
|
||||
@@ -187,7 +237,7 @@ fake_responses_filter_by_goal = {
|
||||
}
|
||||
|
||||
|
||||
class AuditTemplateManagerTest(testtools.TestCase):
|
||||
class AuditTemplateManagerTest(utils.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(AuditTemplateManagerTest, self).setUp()
|
||||
@@ -203,7 +253,7 @@ class AuditTemplateManagerTest(testtools.TestCase):
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(1, len(audit_templates))
|
||||
|
||||
def test_audit_templates_list_by_name(self):
|
||||
def test_audit_templates_list_filter_by_name(self):
|
||||
audit_templates = self.mgr.list(name=AUDIT_TMPL1['name'])
|
||||
expect = [
|
||||
('GET', '/v1/audit_templates/?name=%s' % AUDIT_TMPL1['name'],
|
||||
@@ -212,13 +262,72 @@ class AuditTemplateManagerTest(testtools.TestCase):
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(1, len(audit_templates))
|
||||
|
||||
def test_audit_templates_list_by_goal(self):
|
||||
self.api = utils.FakeAPI(fake_responses_filter_by_goal)
|
||||
def test_audit_templates_list_filter_by_goal_uuid(self):
|
||||
self.api = utils.FakeAPI(fake_responses_filter_by_goal_uuid)
|
||||
self.mgr = watcherclient.v1.audit_template.AuditTemplateManager(
|
||||
self.api)
|
||||
audit_templates = self.mgr.list(goal="BASIC_CONSOLIDATION")
|
||||
audit_templates = self.mgr.list(
|
||||
goal="e75ee410-b32b-465f-88b5-4397705f9473")
|
||||
expect = [
|
||||
('GET', '/v1/audit_templates/?goal=%s' % AUDIT_TMPL2['goal'],
|
||||
('GET',
|
||||
'/v1/audit_templates/?goal=%s' % AUDIT_TMPL2['goal_uuid'],
|
||||
{}, None),
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(1, len(audit_templates))
|
||||
|
||||
def test_audit_templates_list_filter_by_goal_name(self):
|
||||
self.api = utils.FakeAPI(fake_responses_filter_by_goal_name)
|
||||
self.mgr = watcherclient.v1.audit_template.AuditTemplateManager(
|
||||
self.api)
|
||||
audit_templates = self.mgr.list(goal="DUMMY")
|
||||
expect = [
|
||||
('GET',
|
||||
'/v1/audit_templates/?goal=%s' % AUDIT_TMPL2['goal_name'],
|
||||
{}, None),
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(1, len(audit_templates))
|
||||
|
||||
def test_audit_templates_list_filter_by_strategy_uuid(self):
|
||||
self.api = utils.FakeAPI(fake_responses_filter_by_strategy_uuid)
|
||||
self.mgr = watcherclient.v1.audit_template.AuditTemplateManager(
|
||||
self.api)
|
||||
audit_templates = self.mgr.list(
|
||||
strategy="ae99a4a4-acbc-4c67-abe1-e37128fac45d")
|
||||
expect = [
|
||||
('GET',
|
||||
'/v1/audit_templates/?strategy=%s' % (
|
||||
AUDIT_TMPL2['strategy_uuid']),
|
||||
{}, None),
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(1, len(audit_templates))
|
||||
|
||||
def test_audit_templates_list_filter_by_strategy_name(self):
|
||||
self.api = utils.FakeAPI(fake_responses_filter_by_strategy_name)
|
||||
self.mgr = watcherclient.v1.audit_template.AuditTemplateManager(
|
||||
self.api)
|
||||
audit_templates = self.mgr.list(strategy="dummy")
|
||||
expect = [
|
||||
('GET',
|
||||
'/v1/audit_templates/?strategy=%s' % (
|
||||
AUDIT_TMPL2['strategy_name']),
|
||||
{}, None),
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(1, len(audit_templates))
|
||||
|
||||
def test_audit_templates_list_filter_by_goal_and_strategy_name(self):
|
||||
self.api = utils.FakeAPI(
|
||||
fake_responses_filter_by_strategy_and_goal_name)
|
||||
self.mgr = watcherclient.v1.audit_template.AuditTemplateManager(
|
||||
self.api)
|
||||
audit_templates = self.mgr.list(goal="DUMMY", strategy="dummy")
|
||||
expect = [
|
||||
('GET',
|
||||
'/v1/audit_templates/?goal=%s&strategy=%s' % (
|
||||
AUDIT_TMPL2['goal_name'], AUDIT_TMPL2['strategy_name']),
|
||||
{}, None),
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
@@ -300,9 +409,10 @@ class AuditTemplateManagerTest(testtools.TestCase):
|
||||
audit_template.description)
|
||||
self.assertEqual(AUDIT_TMPL1['host_aggregate'],
|
||||
audit_template.host_aggregate)
|
||||
self.assertEqual(AUDIT_TMPL1['goal'], audit_template.goal)
|
||||
self.assertEqual(AUDIT_TMPL1['extra'],
|
||||
audit_template.extra)
|
||||
self.assertEqual(AUDIT_TMPL1['goal_uuid'], audit_template.goal_uuid)
|
||||
self.assertEqual(AUDIT_TMPL1['strategy_uuid'],
|
||||
audit_template.strategy_uuid)
|
||||
self.assertEqual(AUDIT_TMPL1['extra'], audit_template.extra)
|
||||
|
||||
def test_audit_templates_show_by_name(self):
|
||||
audit_template = self.mgr.get(urlparse.quote(AUDIT_TMPL1['name']))
|
||||
@@ -319,9 +429,10 @@ class AuditTemplateManagerTest(testtools.TestCase):
|
||||
audit_template.description)
|
||||
self.assertEqual(AUDIT_TMPL1['host_aggregate'],
|
||||
audit_template.host_aggregate)
|
||||
self.assertEqual(AUDIT_TMPL1['goal'], audit_template.goal)
|
||||
self.assertEqual(AUDIT_TMPL1['extra'],
|
||||
audit_template.extra)
|
||||
self.assertEqual(AUDIT_TMPL1['goal_uuid'], audit_template.goal_uuid)
|
||||
self.assertEqual(AUDIT_TMPL1['strategy_uuid'],
|
||||
audit_template.strategy_uuid)
|
||||
self.assertEqual(AUDIT_TMPL1['extra'], audit_template.extra)
|
||||
|
||||
def test_create(self):
|
||||
audit_template = self.mgr.create(**CREATE_AUDIT_TEMPLATE)
|
||||
|
||||
@@ -14,124 +14,363 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import datetime
|
||||
|
||||
import mock
|
||||
import six
|
||||
|
||||
from watcherclient.common import cliutils
|
||||
from watcherclient.common import utils as commonutils
|
||||
from watcherclient.tests import utils
|
||||
import watcherclient.v1.audit_template_shell as at_shell
|
||||
from watcherclient import shell
|
||||
from watcherclient.tests.v1 import base
|
||||
from watcherclient import v1 as resource
|
||||
from watcherclient.v1 import resource_fields
|
||||
|
||||
GOAL_1 = {
|
||||
'uuid': "fc087747-61be-4aad-8126-b701731ae836",
|
||||
'name': "SERVER_CONSOLIDATION",
|
||||
'display_name': 'Server Consolidation',
|
||||
'created_at': datetime.datetime.now().isoformat(),
|
||||
'updated_at': None,
|
||||
'deleted_at': None,
|
||||
}
|
||||
|
||||
STRATEGY_1 = {
|
||||
'uuid': '2cf86250-d309-4b81-818e-1537f3dba6e5',
|
||||
'name': 'basic',
|
||||
'display_name': 'Basic consolidation',
|
||||
'goal_uuid': 'fc087747-61be-4aad-8126-b701731ae836',
|
||||
'created_at': datetime.datetime.now().isoformat(),
|
||||
'updated_at': None,
|
||||
'deleted_at': None,
|
||||
}
|
||||
|
||||
AUDIT_TEMPLATE_1 = {
|
||||
'uuid': 'f8e47706-efcf-49a4-a5c4-af604eb492f2',
|
||||
'name': 'at1',
|
||||
'description': 'Audit Template 1 description',
|
||||
'host_aggregate': 5,
|
||||
'extra': {'automatic': False},
|
||||
'goal_uuid': 'fc087747-61be-4aad-8126-b701731ae836',
|
||||
'goal_name': 'SERVER_CONSOLIDATION',
|
||||
'strategy_uuid': '2cf86250-d309-4b81-818e-1537f3dba6e5',
|
||||
'strategy_name': 'basic',
|
||||
'created_at': datetime.datetime.now().isoformat(),
|
||||
'updated_at': None,
|
||||
'deleted_at': None,
|
||||
}
|
||||
|
||||
AUDIT_TEMPLATE_2 = {
|
||||
'uuid': '2a60ca9b-09b0-40ff-8674-de8a36fc4bc8',
|
||||
'name': 'at2',
|
||||
'description': 'Audit Template 2',
|
||||
'host_aggregate': 3,
|
||||
'extra': {'automatic': False},
|
||||
'goal_uuid': 'fc087747-61be-4aad-8126-b701731ae836',
|
||||
'goal_name': 'SERVER_CONSOLIDATION',
|
||||
'strategy_uuid': None,
|
||||
'strategy_name': None,
|
||||
'created_at': datetime.datetime.now().isoformat(),
|
||||
'updated_at': None,
|
||||
'deleted_at': None,
|
||||
}
|
||||
|
||||
|
||||
class AuditTemplateShellTest(utils.BaseTestCase):
|
||||
def test_do_audit_template_show(self):
|
||||
actual = {}
|
||||
fake_print_dict = lambda data, *args, **kwargs: actual.update(data)
|
||||
with mock.patch.object(cliutils, 'print_dict', fake_print_dict):
|
||||
audit_template = object()
|
||||
at_shell._print_audit_template_show(audit_template)
|
||||
exp = [
|
||||
'uuid', 'created_at', 'updated_at', 'deleted_at',
|
||||
'description', 'host_aggregate', 'name',
|
||||
'extra', 'goal']
|
||||
act = actual.keys()
|
||||
self.assertEqual(sorted(exp), sorted(act))
|
||||
class AuditTemplateShellTest(base.CommandTestCase):
|
||||
|
||||
def test_do_audit_template_show_by_uuid(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
setattr(args, 'audit-template', 'a5199d0e-0702-4613-9234-5ae2af8dafea')
|
||||
SHORT_LIST_FIELDS = resource_fields.AUDIT_TEMPLATE_SHORT_LIST_FIELDS
|
||||
SHORT_LIST_FIELD_LABELS = (
|
||||
resource_fields.AUDIT_TEMPLATE_SHORT_LIST_FIELD_LABELS)
|
||||
FIELDS = resource_fields.AUDIT_TEMPLATE_FIELDS
|
||||
FIELD_LABELS = resource_fields.AUDIT_TEMPLATE_FIELD_LABELS
|
||||
|
||||
at_shell.do_audit_template_show(client_mock, args)
|
||||
client_mock.audit_template.get.assert_called_once_with(
|
||||
'a5199d0e-0702-4613-9234-5ae2af8dafea'
|
||||
def setUp(self):
|
||||
super(self.__class__, self).setUp()
|
||||
|
||||
# goal mock
|
||||
p_goal_manager = mock.patch.object(resource, 'GoalManager')
|
||||
self.m_goal_mgr_cls = p_goal_manager.start()
|
||||
self.addCleanup(p_goal_manager.stop)
|
||||
|
||||
self.m_goal_mgr = mock.Mock()
|
||||
self.m_goal_mgr_cls.return_value = self.m_goal_mgr
|
||||
|
||||
# strategy mock
|
||||
p_strategy_manager = mock.patch.object(resource, 'StrategyManager')
|
||||
self.m_strategy_mgr_cls = p_strategy_manager.start()
|
||||
self.addCleanup(p_strategy_manager.stop)
|
||||
|
||||
self.m_strategy_mgr = mock.Mock()
|
||||
self.m_strategy_mgr_cls.return_value = self.m_strategy_mgr
|
||||
|
||||
# audit template mock
|
||||
p_audit_template_manager = mock.patch.object(
|
||||
resource, 'AuditTemplateManager')
|
||||
self.m_audit_template_mgr_cls = p_audit_template_manager.start()
|
||||
self.addCleanup(p_audit_template_manager.stop)
|
||||
|
||||
self.m_audit_template_mgr = mock.Mock()
|
||||
self.m_audit_template_mgr_cls.return_value = self.m_audit_template_mgr
|
||||
|
||||
# stdout mock
|
||||
self.stdout = six.StringIO()
|
||||
self.cmd = shell.WatcherShell(stdout=self.stdout)
|
||||
|
||||
def test_do_audit_template_list(self):
|
||||
audit_template1 = resource.AuditTemplate(mock.Mock(), AUDIT_TEMPLATE_1)
|
||||
audit_template2 = resource.AuditTemplate(mock.Mock(), AUDIT_TEMPLATE_2)
|
||||
self.m_audit_template_mgr.list.return_value = [
|
||||
audit_template1, audit_template2]
|
||||
|
||||
exit_code, results = self.run_cmd('audittemplate list')
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(
|
||||
[self.resource_as_dict(audit_template1, self.SHORT_LIST_FIELDS,
|
||||
self.SHORT_LIST_FIELD_LABELS),
|
||||
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)
|
||||
|
||||
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)
|
||||
self.m_audit_template_mgr.list.return_value = [
|
||||
audit_template1, audit_template2]
|
||||
|
||||
exit_code, results = self.run_cmd('audittemplate list --detail')
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(
|
||||
[self.resource_as_dict(audit_template1, self.FIELDS,
|
||||
self.FIELD_LABELS),
|
||||
self.resource_as_dict(audit_template2, self.FIELDS,
|
||||
self.FIELD_LABELS)],
|
||||
results)
|
||||
|
||||
self.m_audit_template_mgr.list.assert_called_once_with(detail=True)
|
||||
|
||||
def test_do_audit_template_list_filter_by_goal_uuid(self):
|
||||
audit_template1 = resource.AuditTemplate(mock.Mock(), AUDIT_TEMPLATE_1)
|
||||
audit_template2 = resource.AuditTemplate(mock.Mock(), AUDIT_TEMPLATE_2)
|
||||
self.m_audit_template_mgr.list.return_value = [
|
||||
audit_template1, audit_template2]
|
||||
|
||||
exit_code, results = self.run_cmd(
|
||||
'audittemplate list --goal '
|
||||
'fc087747-61be-4aad-8126-b701731ae836')
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(
|
||||
[self.resource_as_dict(audit_template1, self.SHORT_LIST_FIELDS,
|
||||
self.SHORT_LIST_FIELD_LABELS),
|
||||
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,
|
||||
goal='fc087747-61be-4aad-8126-b701731ae836',
|
||||
)
|
||||
|
||||
def test_do_audit_template_list_filter_by_goal_name(self):
|
||||
goal1 = resource.Goal(mock.Mock(), GOAL_1)
|
||||
strategy1 = resource.Strategy(mock.Mock(), STRATEGY_1)
|
||||
audit_template1 = resource.AuditTemplate(mock.Mock(), AUDIT_TEMPLATE_1)
|
||||
audit_template2 = resource.AuditTemplate(mock.Mock(), AUDIT_TEMPLATE_2)
|
||||
self.m_goal_mgr.get.return_value = goal1
|
||||
self.m_strategy_mgr.get.return_value = strategy1
|
||||
self.m_audit_template_mgr.list.return_value = [
|
||||
audit_template1, audit_template2]
|
||||
|
||||
exit_code, results = self.run_cmd(
|
||||
'audittemplate list --goal SERVER_CONSOLIDATION')
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(
|
||||
[self.resource_as_dict(audit_template1, self.SHORT_LIST_FIELDS,
|
||||
self.SHORT_LIST_FIELD_LABELS),
|
||||
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,
|
||||
goal='SERVER_CONSOLIDATION',
|
||||
)
|
||||
|
||||
def test_do_audit_template_list_filter_by_strategy_uuid(self):
|
||||
goal1 = resource.Goal(mock.Mock(), GOAL_1)
|
||||
strategy1 = resource.Strategy(mock.Mock(), STRATEGY_1)
|
||||
audit_template1 = resource.AuditTemplate(mock.Mock(), AUDIT_TEMPLATE_1)
|
||||
self.m_goal_mgr.get.return_value = goal1
|
||||
self.m_strategy_mgr.get.return_value = strategy1
|
||||
self.m_audit_template_mgr.list.return_value = [audit_template1]
|
||||
|
||||
exit_code, results = self.run_cmd(
|
||||
'audittemplate list --strategy '
|
||||
'2cf86250-d309-4b81-818e-1537f3dba6e5')
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(
|
||||
[self.resource_as_dict(audit_template1, self.SHORT_LIST_FIELDS,
|
||||
self.SHORT_LIST_FIELD_LABELS)],
|
||||
results)
|
||||
|
||||
self.m_audit_template_mgr.list.assert_called_once_with(
|
||||
detail=False,
|
||||
strategy='2cf86250-d309-4b81-818e-1537f3dba6e5',
|
||||
)
|
||||
|
||||
def test_do_audit_template_list_filter_by_strategy_name(self):
|
||||
audit_template1 = resource.AuditTemplate(mock.Mock(), AUDIT_TEMPLATE_1)
|
||||
self.m_audit_template_mgr.list.return_value = [audit_template1]
|
||||
|
||||
exit_code, results = self.run_cmd(
|
||||
'audittemplate list --strategy '
|
||||
'basic')
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(
|
||||
[self.resource_as_dict(audit_template1, self.SHORT_LIST_FIELDS,
|
||||
self.SHORT_LIST_FIELD_LABELS)],
|
||||
results)
|
||||
|
||||
self.m_audit_template_mgr.list.assert_called_once_with(
|
||||
detail=False,
|
||||
strategy='basic',
|
||||
)
|
||||
# assert get_by_name() wasn't called
|
||||
self.assertFalse(client_mock.audit_template.get_by_name.called)
|
||||
|
||||
def test_do_audit_template_show_by_name(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
setattr(args, 'audit-template', "a5199d0e-0702-4613-9234-5ae2af8dafea")
|
||||
audit_template = resource.AuditTemplate(mock.Mock(), AUDIT_TEMPLATE_1)
|
||||
self.m_audit_template_mgr.get.return_value = audit_template
|
||||
|
||||
at_shell.do_audit_template_show(client_mock, args)
|
||||
client_mock.audit_template.get.assert_called_once_with(
|
||||
'a5199d0e-0702-4613-9234-5ae2af8dafea')
|
||||
exit_code, result = self.run_cmd('audittemplate show at1')
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(self.resource_as_dict(audit_template, self.FIELDS,
|
||||
self.FIELD_LABELS),
|
||||
result)
|
||||
self.m_audit_template_mgr.get.assert_called_once_with('at1')
|
||||
|
||||
def test_do_audit_template_show_by_uuid(self):
|
||||
audit_template = resource.AuditTemplate(mock.Mock(), AUDIT_TEMPLATE_1)
|
||||
self.m_audit_template_mgr.get.return_value = audit_template
|
||||
|
||||
exit_code, result = self.run_cmd(
|
||||
'audittemplate show f8e47706-efcf-49a4-a5c4-af604eb492f2')
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(self.resource_as_dict(audit_template, self.FIELDS,
|
||||
self.FIELD_LABELS),
|
||||
result)
|
||||
self.m_audit_template_mgr.get.assert_called_once_with(
|
||||
'f8e47706-efcf-49a4-a5c4-af604eb492f2')
|
||||
|
||||
def test_do_audit_template_delete(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
setattr(args, 'audit-template',
|
||||
['a5199d0e-0702-4613-9234-5ae2af8dafea'])
|
||||
self.m_audit_template_mgr.delete.return_value = ''
|
||||
|
||||
at_shell.do_audit_template_delete(client_mock, args)
|
||||
client_mock.audit_template.delete.assert_called_once_with(
|
||||
'a5199d0e-0702-4613-9234-5ae2af8dafea')
|
||||
exit_code, result = self.run_cmd(
|
||||
'audittemplate delete f8e47706-efcf-49a4-a5c4-af604eb492f2',
|
||||
formatting=None)
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual('', result)
|
||||
self.m_audit_template_mgr.delete.assert_called_once_with(
|
||||
'f8e47706-efcf-49a4-a5c4-af604eb492f2')
|
||||
|
||||
def test_do_audit_template_delete_multiple(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
setattr(args, 'audit-template',
|
||||
['a5199d0e-0702-4613-9234-5ae2af8dafea',
|
||||
'a5199d0e-0702-4613-9234-5ae2af8dafeb'])
|
||||
self.m_audit_template_mgr.delete.return_value = ''
|
||||
|
||||
at_shell.do_audit_template_delete(client_mock, args)
|
||||
client_mock.audit_template.delete.assert_has_calls(
|
||||
[mock.call('a5199d0e-0702-4613-9234-5ae2af8dafea'),
|
||||
mock.call('a5199d0e-0702-4613-9234-5ae2af8dafeb')])
|
||||
exit_code, result = self.run_cmd(
|
||||
'audittemplate delete f8e47706-efcf-49a4-a5c4-af604eb492f2 '
|
||||
'92dfce2f-0a5e-473f-92b7-d92e21839e4d',
|
||||
formatting=None)
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual('', result)
|
||||
self.m_audit_template_mgr.delete.assert_any_call(
|
||||
'f8e47706-efcf-49a4-a5c4-af604eb492f2')
|
||||
self.m_audit_template_mgr.delete.assert_any_call(
|
||||
'92dfce2f-0a5e-473f-92b7-d92e21839e4d')
|
||||
|
||||
def test_do_audit_template_update(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
setattr(args, 'audit-template', "a5199d0e-0702-4613-9234-5ae2af8dafea")
|
||||
args.op = 'add'
|
||||
args.attributes = [['arg1=val1', 'arg2=val2']]
|
||||
audit_template = resource.AuditTemplate(mock.Mock(), AUDIT_TEMPLATE_1)
|
||||
self.m_audit_template_mgr.update.return_value = audit_template
|
||||
|
||||
at_shell.do_audit_template_update(client_mock, args)
|
||||
patch = commonutils.args_array_to_patch(
|
||||
args.op,
|
||||
args.attributes[0])
|
||||
client_mock.audit_template.update.assert_called_once_with(
|
||||
'a5199d0e-0702-4613-9234-5ae2af8dafea', patch)
|
||||
exit_code, result = self.run_cmd(
|
||||
'audittemplate update at1 replace host_aggregate=5')
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(self.resource_as_dict(audit_template, self.FIELDS,
|
||||
self.FIELD_LABELS),
|
||||
result)
|
||||
self.m_audit_template_mgr.update.assert_called_once_with(
|
||||
'at1',
|
||||
[{'op': 'replace', 'path': '/host_aggregate', 'value': 5}])
|
||||
|
||||
def test_do_audit_template_create(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
audit_template = resource.AuditTemplate(mock.Mock(), AUDIT_TEMPLATE_1)
|
||||
self.m_audit_template_mgr.create.return_value = audit_template
|
||||
|
||||
at_shell.do_audit_template_create(client_mock, args)
|
||||
client_mock.audit_template.create.assert_called_once_with()
|
||||
exit_code, result = self.run_cmd(
|
||||
'audittemplate create at1 fc087747-61be-4aad-8126-b701731ae836')
|
||||
|
||||
def test_do_audit_template_create_with_name(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
args.name = 'my audit template'
|
||||
|
||||
at_shell.do_audit_template_create(client_mock, args)
|
||||
client_mock.audit_template.create.assert_called_once_with(
|
||||
name='my audit template')
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(self.resource_as_dict(audit_template, self.FIELDS,
|
||||
self.FIELD_LABELS),
|
||||
result)
|
||||
self.m_audit_template_mgr.create.assert_called_once_with(
|
||||
goal='fc087747-61be-4aad-8126-b701731ae836',
|
||||
name='at1')
|
||||
|
||||
def test_do_audit_template_create_with_description(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
args.description = 'description'
|
||||
audit_template = resource.AuditTemplate(mock.Mock(), AUDIT_TEMPLATE_1)
|
||||
self.m_audit_template_mgr.create.return_value = audit_template
|
||||
|
||||
at_shell.do_audit_template_create(client_mock, args)
|
||||
client_mock.audit_template.create.assert_called_once_with(
|
||||
description='description')
|
||||
exit_code, result = self.run_cmd(
|
||||
'audittemplate create at1 fc087747-61be-4aad-8126-b701731ae836 '
|
||||
'-d "Audit Template 1 description"')
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(self.resource_as_dict(audit_template, self.FIELDS,
|
||||
self.FIELD_LABELS),
|
||||
result)
|
||||
self.m_audit_template_mgr.create.assert_called_once_with(
|
||||
goal='fc087747-61be-4aad-8126-b701731ae836',
|
||||
name='at1',
|
||||
description='Audit Template 1 description')
|
||||
|
||||
def test_do_audit_template_create_with_aggregate(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
args.host_aggregate = 5
|
||||
audit_template = resource.AuditTemplate(mock.Mock(), AUDIT_TEMPLATE_1)
|
||||
self.m_audit_template_mgr.create.return_value = audit_template
|
||||
|
||||
at_shell.do_audit_template_create(client_mock, args)
|
||||
client_mock.audit_template.create.assert_called_once_with(
|
||||
host_aggregate=5)
|
||||
exit_code, result = self.run_cmd(
|
||||
'audittemplate create at1 fc087747-61be-4aad-8126-b701731ae836 '
|
||||
'-a 5')
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(self.resource_as_dict(audit_template, self.FIELDS,
|
||||
self.FIELD_LABELS),
|
||||
result)
|
||||
self.m_audit_template_mgr.create.assert_called_once_with(
|
||||
goal='fc087747-61be-4aad-8126-b701731ae836',
|
||||
name='at1',
|
||||
host_aggregate='5')
|
||||
|
||||
def test_do_audit_template_create_with_extra(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
args.extra = ['automatic=true']
|
||||
audit_template = resource.AuditTemplate(mock.Mock(), AUDIT_TEMPLATE_1)
|
||||
self.m_audit_template_mgr.create.return_value = audit_template
|
||||
|
||||
at_shell.do_audit_template_create(client_mock, args)
|
||||
client_mock.audit_template.create.assert_called_once_with(
|
||||
exit_code, result = self.run_cmd(
|
||||
'audittemplate create at1 fc087747-61be-4aad-8126-b701731ae836 '
|
||||
'-e automatic=true')
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(self.resource_as_dict(audit_template, self.FIELDS,
|
||||
self.FIELD_LABELS),
|
||||
result)
|
||||
self.m_audit_template_mgr.create.assert_called_once_with(
|
||||
goal='fc087747-61be-4aad-8126-b701731ae836',
|
||||
name='at1',
|
||||
extra={'automatic': True})
|
||||
|
||||
@@ -23,13 +23,15 @@ from watcherclient.tests import utils
|
||||
import watcherclient.v1.goal
|
||||
|
||||
GOAL1 = {
|
||||
'name': "BASIC_CONSOLIDATION",
|
||||
'strategy': 'basic'
|
||||
'uuid': "fc087747-61be-4aad-8126-b701731ae836",
|
||||
'name': "SERVER_CONSOLIDATION",
|
||||
'display_name': 'Server Consolidation'
|
||||
}
|
||||
|
||||
GOAL2 = {
|
||||
'uuid': "407b03b1-63c6-49b2-adaf-4df5c0090047",
|
||||
'name': "COST_OPTIMIZATION",
|
||||
'strategy': 'basic'
|
||||
'display_name': 'Cost Optimization'
|
||||
}
|
||||
|
||||
fake_responses = {
|
||||
@@ -47,6 +49,13 @@ fake_responses = {
|
||||
{"goals": [GOAL1]},
|
||||
)
|
||||
},
|
||||
'/v1/goals/%s' % GOAL1['uuid']:
|
||||
{
|
||||
'GET': (
|
||||
{},
|
||||
GOAL1,
|
||||
),
|
||||
},
|
||||
'/v1/goals/%s' % GOAL1['name']:
|
||||
{
|
||||
'GET': (
|
||||
@@ -75,7 +84,7 @@ fake_responses_pagination = {
|
||||
}
|
||||
|
||||
fake_responses_sorting = {
|
||||
'/v1/goals/?sort_key=name':
|
||||
'/v1/goals/?sort_key=id':
|
||||
{
|
||||
'GET': (
|
||||
{},
|
||||
@@ -139,9 +148,9 @@ class GoalManagerTest(testtools.TestCase):
|
||||
def test_goals_list_sort_key(self):
|
||||
self.api = utils.FakeAPI(fake_responses_sorting)
|
||||
self.mgr = watcherclient.v1.goal.GoalManager(self.api)
|
||||
goals = self.mgr.list(sort_key='name')
|
||||
goals = self.mgr.list(sort_key='id')
|
||||
expect = [
|
||||
('GET', '/v1/goals/?sort_key=name', {}, None)
|
||||
('GET', '/v1/goals/?sort_key=id', {}, None)
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(2, len(goals))
|
||||
@@ -157,6 +166,14 @@ class GoalManagerTest(testtools.TestCase):
|
||||
self.assertEqual(2, len(goals))
|
||||
|
||||
def test_goals_show(self):
|
||||
goal = self.mgr.get(GOAL1['uuid'])
|
||||
expect = [
|
||||
('GET', '/v1/goals/%s' % GOAL1['uuid'], {}, None),
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(GOAL1['uuid'], goal.uuid)
|
||||
|
||||
def test_goals_show_by_name(self):
|
||||
goal = self.mgr.get(GOAL1['name'])
|
||||
expect = [
|
||||
('GET', '/v1/goals/%s' % GOAL1['name'], {}, None),
|
||||
|
||||
@@ -1,34 +1,140 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Copyright (c) 2016 b<>com
|
||||
#
|
||||
# Copyright 2013 IBM Corp
|
||||
# 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.
|
||||
|
||||
import datetime
|
||||
|
||||
import mock
|
||||
import six
|
||||
|
||||
from watcherclient.common import cliutils
|
||||
from watcherclient.tests import utils
|
||||
import watcherclient.v1.goal_shell as a_shell
|
||||
from watcherclient import shell
|
||||
from watcherclient.tests.v1 import base
|
||||
from watcherclient import v1 as resource
|
||||
from watcherclient.v1 import resource_fields
|
||||
|
||||
GOAL_1 = {
|
||||
'uuid': "fc087747-61be-4aad-8126-b701731ae836",
|
||||
'name': "SERVER_CONSOLIDATION",
|
||||
'display_name': 'Server Consolidation',
|
||||
'efficacy_specification': [
|
||||
{'description': 'Indicator 1', 'name': 'indicator1',
|
||||
'schema': 'Range(min=0, max=100, min_included=True, '
|
||||
'max_included=True, msg=None)',
|
||||
'unit': '%'}
|
||||
],
|
||||
'created_at': datetime.datetime.now().isoformat(),
|
||||
'updated_at': None,
|
||||
'deleted_at': None,
|
||||
}
|
||||
|
||||
GOAL_2 = {
|
||||
'uuid': "407b03b1-63c6-49b2-adaf-4df5c0090047",
|
||||
'name': "COST_OPTIMIZATION",
|
||||
'display_name': 'Cost Optimization',
|
||||
'efficacy_specification': [
|
||||
{'description': 'Indicator 2', 'name': 'indicator2',
|
||||
'schema': 'Range(min=0, max=100, min_included=True, '
|
||||
'max_included=True, msg=None)',
|
||||
'unit': '%'}
|
||||
],
|
||||
'created_at': datetime.datetime.now().isoformat(),
|
||||
'updated_at': None,
|
||||
'deleted_at': None,
|
||||
}
|
||||
|
||||
|
||||
class GoalShellTest(utils.BaseTestCase):
|
||||
class GoalShellTest(base.CommandTestCase):
|
||||
|
||||
def test_do_goal_show(self):
|
||||
actual = {}
|
||||
fake_print_dict = lambda data, *args, **kwargs: actual.update(data)
|
||||
with mock.patch.object(cliutils, 'print_dict', fake_print_dict):
|
||||
goal = object()
|
||||
a_shell._print_goal_show(goal)
|
||||
exp = ['name', 'strategy']
|
||||
act = actual.keys()
|
||||
self.assertEqual(sorted(exp), sorted(act))
|
||||
SHORT_LIST_FIELDS = resource_fields.GOAL_SHORT_LIST_FIELDS
|
||||
SHORT_LIST_FIELD_LABELS = (
|
||||
resource_fields.GOAL_SHORT_LIST_FIELD_LABELS)
|
||||
FIELDS = resource_fields.GOAL_FIELDS
|
||||
FIELD_LABELS = resource_fields.GOAL_FIELD_LABELS
|
||||
|
||||
def setUp(self):
|
||||
super(self.__class__, self).setUp()
|
||||
|
||||
p_goal_manager = mock.patch.object(
|
||||
resource, 'GoalManager')
|
||||
self.m_goal_mgr_cls = p_goal_manager.start()
|
||||
self.addCleanup(p_goal_manager.stop)
|
||||
|
||||
self.m_goal_mgr = mock.Mock()
|
||||
self.m_goal_mgr_cls.return_value = self.m_goal_mgr
|
||||
|
||||
self.stdout = six.StringIO()
|
||||
self.cmd = shell.WatcherShell(stdout=self.stdout)
|
||||
|
||||
def test_do_goal_list(self):
|
||||
goal1 = resource.Goal(mock.Mock(), GOAL_1)
|
||||
goal2 = resource.Goal(mock.Mock(), GOAL_2)
|
||||
self.m_goal_mgr.list.return_value = [
|
||||
goal1, goal2]
|
||||
|
||||
exit_code, results = self.run_cmd('goal list')
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(
|
||||
[self.resource_as_dict(goal1, self.SHORT_LIST_FIELDS,
|
||||
self.SHORT_LIST_FIELD_LABELS),
|
||||
self.resource_as_dict(goal2, self.SHORT_LIST_FIELDS,
|
||||
self.SHORT_LIST_FIELD_LABELS)],
|
||||
results)
|
||||
|
||||
self.m_goal_mgr.list.assert_called_once_with(detail=False)
|
||||
|
||||
def test_do_goal_list_detail(self):
|
||||
goal1 = resource.Goal(mock.Mock(), GOAL_1)
|
||||
goal2 = resource.Goal(mock.Mock(), GOAL_2)
|
||||
self.m_goal_mgr.list.return_value = [
|
||||
goal1, goal2]
|
||||
|
||||
exit_code, results = self.run_cmd('goal list --detail')
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(
|
||||
[self.resource_as_dict(goal1, self.FIELDS, self.FIELD_LABELS),
|
||||
self.resource_as_dict(goal2, self.FIELDS, self.FIELD_LABELS)],
|
||||
results)
|
||||
|
||||
self.m_goal_mgr.list.assert_called_once_with(detail=True)
|
||||
|
||||
def test_do_goal_show_by_name(self):
|
||||
goal = resource.Goal(mock.Mock(), GOAL_1)
|
||||
self.m_goal_mgr.get.return_value = goal
|
||||
|
||||
exit_code, result = self.run_cmd('goal show SERVER_CONSOLIDATION')
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(
|
||||
self.resource_as_dict(goal, self.FIELDS,
|
||||
self.FIELD_LABELS),
|
||||
result)
|
||||
self.m_goal_mgr.get.assert_called_once_with('SERVER_CONSOLIDATION')
|
||||
|
||||
def test_do_goal_show_by_uuid(self):
|
||||
goal = resource.Goal(mock.Mock(), GOAL_1)
|
||||
self.m_goal_mgr.get.return_value = goal
|
||||
|
||||
exit_code, result = self.run_cmd(
|
||||
'goal show fc087747-61be-4aad-8126-b701731ae836')
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(
|
||||
self.resource_as_dict(goal, self.FIELDS,
|
||||
self.FIELD_LABELS),
|
||||
result)
|
||||
self.m_goal_mgr.get.assert_called_once_with(
|
||||
'fc087747-61be-4aad-8126-b701731ae836')
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2013 IBM Corp
|
||||
#
|
||||
# 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 mock
|
||||
|
||||
from watcherclient.common import cliutils
|
||||
from watcherclient.common import utils as commonutils
|
||||
from watcherclient.tests import utils
|
||||
import watcherclient.v1.metric_collector_shell as mc_shell
|
||||
|
||||
|
||||
class MetricCollectorShellTest(utils.BaseTestCase):
|
||||
def test_do_metric_collector_show(self):
|
||||
actual = {}
|
||||
fake_print_dict = lambda data, *args, **kwargs: actual.update(data)
|
||||
with mock.patch.object(cliutils, 'print_dict', fake_print_dict):
|
||||
metric_collector = object()
|
||||
mc_shell._print_metric_collector_show(metric_collector)
|
||||
exp = ['uuid', 'created_at', 'updated_at', 'deleted_at',
|
||||
'category', 'endpoint']
|
||||
act = actual.keys()
|
||||
self.assertEqual(sorted(exp), sorted(act))
|
||||
|
||||
def test_do_metric_collector_show_by_uuid(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
args.metric_collector = 'a5199d0e-0702-4613-9234-5ae2af8dafea'
|
||||
|
||||
mc_shell.do_metric_collector_show(client_mock, args)
|
||||
client_mock.metric_collector.get.assert_called_once_with(
|
||||
'a5199d0e-0702-4613-9234-5ae2af8dafea'
|
||||
)
|
||||
# assert get_by_name() wasn't called
|
||||
self.assertFalse(client_mock.metric_collector.get_by_name.called)
|
||||
|
||||
def test_do_metric_collector_delete(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
args.metric_collector = ['metric_collector_uuid']
|
||||
|
||||
mc_shell.do_metric_collector_delete(client_mock, args)
|
||||
client_mock.metric_collector.delete.assert_called_once_with(
|
||||
'metric_collector_uuid'
|
||||
)
|
||||
|
||||
def test_do_metric_collector_delete_multiple(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
args.metric_collector = ['metric_collector_uuid1',
|
||||
'metric_collector_uuid2']
|
||||
|
||||
mc_shell.do_metric_collector_delete(client_mock, args)
|
||||
client_mock.metric_collector.delete.assert_has_calls(
|
||||
[mock.call('metric_collector_uuid1'),
|
||||
mock.call('metric_collector_uuid2')])
|
||||
|
||||
def test_do_metric_collector_update(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
setattr(args, 'metric-collector', "metric_collector_uuid")
|
||||
args.op = 'add'
|
||||
args.attributes = [['arg1=val1', 'arg2=val2']]
|
||||
|
||||
mc_shell.do_metric_collector_update(client_mock, args)
|
||||
patch = commonutils.args_array_to_patch(
|
||||
args.op,
|
||||
args.attributes[0])
|
||||
client_mock.metric_collector.update.assert_called_once_with(
|
||||
'metric_collector_uuid', patch)
|
||||
|
||||
def test_do_metric_collector_create(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
|
||||
mc_shell.do_metric_collector_create(client_mock, args)
|
||||
client_mock.metric_collector.create.assert_called_once_with()
|
||||
|
||||
def test_do_metric_collector_create_with_category(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
args.category = 'mc_category'
|
||||
|
||||
mc_shell.do_metric_collector_create(client_mock, args)
|
||||
client_mock.metric_collector.create.assert_called_once_with(
|
||||
category='mc_category')
|
||||
|
||||
def test_do_metric_collector_create_with_endpoint(self):
|
||||
client_mock = mock.MagicMock()
|
||||
args = mock.MagicMock()
|
||||
args.endpoint = 'mc_endpoint'
|
||||
|
||||
mc_shell.do_metric_collector_create(client_mock, args)
|
||||
client_mock.metric_collector.create.assert_called_once_with(
|
||||
endpoint='mc_endpoint')
|
||||
184
watcherclient/tests/v1/test_strategy.py
Normal file
184
watcherclient/tests/v1/test_strategy.py
Normal file
@@ -0,0 +1,184 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2013 Red Hat, Inc.
|
||||
# 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 testtools
|
||||
from testtools.matchers import HasLength
|
||||
|
||||
from watcherclient.tests import utils
|
||||
import watcherclient.v1.strategy
|
||||
|
||||
STRATEGY1 = {
|
||||
'uuid': '2cf86250-d309-4b81-818e-1537f3dba6e5',
|
||||
'name': 'basic',
|
||||
'display_name': 'Basic consolidation',
|
||||
'strategy_id': 'SERVER_CONSOLIDATION',
|
||||
}
|
||||
|
||||
STRATEGY2 = {
|
||||
'uuid': 'b20bb987-ea8f-457a-a4ea-ab3ffdfeff8b',
|
||||
'name': 'dummy',
|
||||
'display_name': 'Dummy',
|
||||
'strategy_id': 'DUMMY',
|
||||
}
|
||||
|
||||
fake_responses = {
|
||||
'/v1/strategies':
|
||||
{
|
||||
'GET': (
|
||||
{},
|
||||
{"strategies": [STRATEGY1]},
|
||||
),
|
||||
},
|
||||
'/v1/strategies/detail':
|
||||
{
|
||||
'GET': (
|
||||
{},
|
||||
{"strategies": [STRATEGY1]},
|
||||
)
|
||||
},
|
||||
'/v1/strategies/%s' % STRATEGY1['uuid']:
|
||||
{
|
||||
'GET': (
|
||||
{},
|
||||
STRATEGY1,
|
||||
),
|
||||
},
|
||||
'/v1/strategies/%s' % STRATEGY1['name']:
|
||||
{
|
||||
'GET': (
|
||||
{},
|
||||
STRATEGY1,
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
fake_responses_pagination = {
|
||||
'/v1/strategies':
|
||||
{
|
||||
'GET': (
|
||||
{},
|
||||
{"strategies": [STRATEGY1],
|
||||
"next": "http://127.0.0.1:6385/v1/strategies/?limit=1"}
|
||||
),
|
||||
},
|
||||
'/v1/strategies/?limit=1':
|
||||
{
|
||||
'GET': (
|
||||
{},
|
||||
{"strategies": [STRATEGY2]}
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
fake_responses_sorting = {
|
||||
'/v1/strategies/?sort_key=id':
|
||||
{
|
||||
'GET': (
|
||||
{},
|
||||
{"strategies": [STRATEGY1, STRATEGY2]}
|
||||
),
|
||||
},
|
||||
'/v1/strategies/?sort_dir=desc':
|
||||
{
|
||||
'GET': (
|
||||
{},
|
||||
{"strategies": [STRATEGY2, STRATEGY1]}
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class StrategyManagerTest(testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(StrategyManagerTest, self).setUp()
|
||||
self.api = utils.FakeAPI(fake_responses)
|
||||
self.mgr = watcherclient.v1.strategy.StrategyManager(self.api)
|
||||
|
||||
def test_strategies_list(self):
|
||||
strategies = self.mgr.list()
|
||||
expect = [
|
||||
('GET', '/v1/strategies', {}, None),
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(1, len(strategies))
|
||||
|
||||
def test_strategies_list_detail(self):
|
||||
strategies = self.mgr.list(detail=True)
|
||||
expect = [
|
||||
('GET', '/v1/strategies/detail', {}, None),
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(1, len(strategies))
|
||||
|
||||
def test_strategies_list_limit(self):
|
||||
self.api = utils.FakeAPI(fake_responses_pagination)
|
||||
self.mgr = watcherclient.v1.strategy.StrategyManager(self.api)
|
||||
strategies = self.mgr.list(limit=1)
|
||||
expect = [
|
||||
('GET', '/v1/strategies/?limit=1', {}, None),
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertThat(strategies, HasLength(1))
|
||||
|
||||
def test_strategies_list_pagination_no_limit(self):
|
||||
self.api = utils.FakeAPI(fake_responses_pagination)
|
||||
self.mgr = watcherclient.v1.strategy.StrategyManager(self.api)
|
||||
strategies = self.mgr.list(limit=0)
|
||||
expect = [
|
||||
('GET', '/v1/strategies', {}, None),
|
||||
('GET', '/v1/strategies/?limit=1', {}, None)
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertThat(strategies, HasLength(2))
|
||||
|
||||
def test_strategies_list_sort_key(self):
|
||||
self.api = utils.FakeAPI(fake_responses_sorting)
|
||||
self.mgr = watcherclient.v1.strategy.StrategyManager(self.api)
|
||||
strategies = self.mgr.list(sort_key='id')
|
||||
expect = [
|
||||
('GET', '/v1/strategies/?sort_key=id', {}, None)
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(2, len(strategies))
|
||||
|
||||
def test_strategies_list_sort_dir(self):
|
||||
self.api = utils.FakeAPI(fake_responses_sorting)
|
||||
self.mgr = watcherclient.v1.strategy.StrategyManager(self.api)
|
||||
strategies = self.mgr.list(sort_dir='desc')
|
||||
expect = [
|
||||
('GET', '/v1/strategies/?sort_dir=desc', {}, None)
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(2, len(strategies))
|
||||
|
||||
def test_strategies_show(self):
|
||||
strategy = self.mgr.get(STRATEGY1['uuid'])
|
||||
expect = [
|
||||
('GET', '/v1/strategies/%s' % STRATEGY1['uuid'], {}, None),
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(STRATEGY1['uuid'], strategy.uuid)
|
||||
|
||||
def test_strategies_show_by_name(self):
|
||||
strategy = self.mgr.get(STRATEGY1['name'])
|
||||
expect = [
|
||||
('GET', '/v1/strategies/%s' % STRATEGY1['name'], {}, None),
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(STRATEGY1['name'], strategy.name)
|
||||
159
watcherclient/tests/v1/test_strategy_shell.py
Normal file
159
watcherclient/tests/v1/test_strategy_shell.py
Normal file
@@ -0,0 +1,159 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Copyright (c) 2016 b<>com
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import datetime
|
||||
|
||||
import mock
|
||||
import six
|
||||
|
||||
from watcherclient import shell
|
||||
from watcherclient.tests.v1 import base
|
||||
from watcherclient import v1 as resource
|
||||
from watcherclient.v1 import resource_fields
|
||||
|
||||
STRATEGY_1 = {
|
||||
'uuid': '2cf86250-d309-4b81-818e-1537f3dba6e5',
|
||||
'name': 'basic',
|
||||
'display_name': 'Basic consolidation',
|
||||
'goal_uuid': 'fc087747-61be-4aad-8126-b701731ae836',
|
||||
'goal_name': 'SERVER_CONSOLIDATION',
|
||||
'created_at': datetime.datetime.now().isoformat(),
|
||||
'updated_at': None,
|
||||
'deleted_at': None,
|
||||
'parameters_spec': {},
|
||||
}
|
||||
|
||||
STRATEGY_2 = {
|
||||
'uuid': 'b20bb987-ea8f-457a-a4ea-ab3ffdfeff8b',
|
||||
'name': 'dummy',
|
||||
'display_name': 'Dummy',
|
||||
'goal_uuid': '407b03b1-63c6-49b2-adaf-4df5c0090047',
|
||||
'goal_name': 'DUMMY',
|
||||
'created_at': datetime.datetime.now().isoformat(),
|
||||
'updated_at': None,
|
||||
'deleted_at': None,
|
||||
'parameters_spec': {},
|
||||
}
|
||||
|
||||
|
||||
class StrategyShellTest(base.CommandTestCase):
|
||||
|
||||
SHORT_LIST_FIELDS = resource_fields.STRATEGY_SHORT_LIST_FIELDS
|
||||
SHORT_LIST_FIELD_LABELS = (
|
||||
resource_fields.STRATEGY_SHORT_LIST_FIELD_LABELS)
|
||||
FIELDS = resource_fields.STRATEGY_FIELDS
|
||||
FIELD_LABELS = resource_fields.STRATEGY_FIELD_LABELS
|
||||
|
||||
def setUp(self):
|
||||
super(self.__class__, self).setUp()
|
||||
|
||||
p_strategy_manager = mock.patch.object(resource, 'StrategyManager')
|
||||
self.m_strategy_mgr_cls = p_strategy_manager.start()
|
||||
self.addCleanup(p_strategy_manager.stop)
|
||||
|
||||
self.m_strategy_mgr = mock.Mock()
|
||||
self.m_strategy_mgr_cls.return_value = self.m_strategy_mgr
|
||||
|
||||
self.stdout = six.StringIO()
|
||||
self.cmd = shell.WatcherShell(stdout=self.stdout)
|
||||
|
||||
def test_do_strategy_list(self):
|
||||
strategy1 = resource.Strategy(mock.Mock(), STRATEGY_1)
|
||||
strategy2 = resource.Strategy(mock.Mock(), STRATEGY_2)
|
||||
self.m_strategy_mgr.list.return_value = [
|
||||
strategy1, strategy2]
|
||||
|
||||
exit_code, results = self.run_cmd('strategy list')
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(
|
||||
[self.resource_as_dict(strategy1, self.SHORT_LIST_FIELDS,
|
||||
self.SHORT_LIST_FIELD_LABELS),
|
||||
self.resource_as_dict(strategy2, self.SHORT_LIST_FIELDS,
|
||||
self.SHORT_LIST_FIELD_LABELS)],
|
||||
results)
|
||||
|
||||
self.m_strategy_mgr.list.assert_called_once_with(detail=False)
|
||||
|
||||
def test_do_strategy_list_detail(self):
|
||||
strategy1 = resource.Strategy(mock.Mock(), STRATEGY_1)
|
||||
strategy2 = resource.Strategy(mock.Mock(), STRATEGY_2)
|
||||
self.m_strategy_mgr.list.return_value = [
|
||||
strategy1, strategy2]
|
||||
|
||||
exit_code, results = self.run_cmd('strategy list --detail')
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(
|
||||
[self.resource_as_dict(strategy1, self.FIELDS,
|
||||
self.FIELD_LABELS),
|
||||
self.resource_as_dict(strategy2, self.FIELDS,
|
||||
self.FIELD_LABELS)],
|
||||
results)
|
||||
|
||||
self.m_strategy_mgr.list.assert_called_once_with(detail=True)
|
||||
|
||||
def test_do_strategy_list_filter_by_goal_name(self):
|
||||
strategy2 = resource.Strategy(mock.Mock(), STRATEGY_2)
|
||||
self.m_strategy_mgr.list.return_value = [strategy2]
|
||||
|
||||
exit_code, results = self.run_cmd(
|
||||
'strategy list --goal '
|
||||
'DUMMY')
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(
|
||||
[self.resource_as_dict(strategy2, self.SHORT_LIST_FIELDS,
|
||||
self.SHORT_LIST_FIELD_LABELS)],
|
||||
results)
|
||||
|
||||
self.m_strategy_mgr.list.assert_called_once_with(
|
||||
detail=False,
|
||||
goal='DUMMY',
|
||||
)
|
||||
|
||||
def test_do_strategy_list_filter_by_goal_uuid(self):
|
||||
strategy1 = resource.Strategy(mock.Mock(), STRATEGY_1)
|
||||
self.m_strategy_mgr.list.return_value = [strategy1]
|
||||
|
||||
exit_code, results = self.run_cmd(
|
||||
'strategy list --goal '
|
||||
'fc087747-61be-4aad-8126-b701731ae836')
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(
|
||||
[self.resource_as_dict(strategy1, self.SHORT_LIST_FIELDS,
|
||||
self.SHORT_LIST_FIELD_LABELS)],
|
||||
results)
|
||||
|
||||
self.m_strategy_mgr.list.assert_called_once_with(
|
||||
detail=False,
|
||||
goal='fc087747-61be-4aad-8126-b701731ae836',
|
||||
)
|
||||
|
||||
def test_do_strategy_show_by_uuid(self):
|
||||
strategy = resource.Strategy(mock.Mock(), STRATEGY_1)
|
||||
self.m_strategy_mgr.get.return_value = strategy
|
||||
|
||||
exit_code, result = self.run_cmd(
|
||||
'strategy show f8e47706-efcf-49a4-a5c4-af604eb492f2')
|
||||
|
||||
self.assertEqual(0, exit_code)
|
||||
self.assertEqual(
|
||||
self.resource_as_dict(strategy, self.FIELDS, self.FIELD_LABELS),
|
||||
result)
|
||||
self.m_strategy_mgr.get.assert_called_once_with(
|
||||
'f8e47706-efcf-49a4-a5c4-af604eb492f2')
|
||||
@@ -0,0 +1,40 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Copyright (c) 2016 b<>com
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from watcherclient.v1 import action
|
||||
from watcherclient.v1 import action_plan
|
||||
from watcherclient.v1 import audit
|
||||
from watcherclient.v1 import audit_template
|
||||
from watcherclient.v1 import goal
|
||||
from watcherclient.v1 import strategy
|
||||
|
||||
Action = action.Action
|
||||
ActionManager = action.ActionManager
|
||||
ActionPlan = action_plan.ActionPlan
|
||||
ActionPlanManager = action_plan.ActionPlanManager
|
||||
Audit = audit.Audit
|
||||
AuditManager = audit.AuditManager
|
||||
AuditTemplate = audit_template.AuditTemplate
|
||||
AuditTemplateManager = audit_template.AuditTemplateManager
|
||||
Goal = goal.Goal
|
||||
GoalManager = goal.GoalManager
|
||||
Strategy = strategy.Strategy
|
||||
StrategyManager = strategy.StrategyManager
|
||||
|
||||
__all__ = (
|
||||
"Action", "ActionManager", "ActionPlan", "ActionPlanManager",
|
||||
"Audit", "AuditManager", "AuditTemplate", "AuditTemplateManager",
|
||||
"Goal", "GoalManager", "Strategy", "StrategyManager")
|
||||
|
||||
@@ -86,3 +86,7 @@ class ActionPlanManager(base.Manager):
|
||||
|
||||
def update(self, action_plan_id, patch):
|
||||
return self._update(self._path(action_plan_id), patch)
|
||||
|
||||
def start(self, action_plan_id):
|
||||
patch = [{'op': 'replace', 'value': 'PENDING', 'path': '/state'}]
|
||||
return self._update(self._path(action_plan_id), patch)
|
||||
|
||||
@@ -1,157 +1,307 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Copyright (c) 2016 b<>com
|
||||
#
|
||||
# Copyright 2013 Red Hat, Inc.
|
||||
# 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
|
||||
#
|
||||
# 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.
|
||||
|
||||
# import argparse
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from cliff.formatters import yaml_format
|
||||
from openstackclient.common import utils
|
||||
from oslo_utils import uuidutils
|
||||
import six
|
||||
|
||||
from watcherclient.common import cliutils
|
||||
from watcherclient.common import utils
|
||||
from watcherclient._i18n import _
|
||||
from watcherclient.common import command
|
||||
from watcherclient.common import utils as common_utils
|
||||
from watcherclient import exceptions
|
||||
from watcherclient.v1 import resource_fields as res_fields
|
||||
|
||||
|
||||
def _print_action_plan_show(action_plan):
|
||||
fields = res_fields.ACTION_PLAN_FIELDS
|
||||
data = dict([(f, getattr(action_plan, f, '')) for f in fields])
|
||||
cliutils.print_dict(data, wrap=72)
|
||||
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)s %(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
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'action-plan',
|
||||
metavar='<action-plan>',
|
||||
help="UUID of the action_plan.")
|
||||
def do_action_plan_show(cc, args):
|
||||
"""Show detailed information about an action plan."""
|
||||
action_plan_uuid = getattr(args, 'action-plan')
|
||||
if uuidutils.is_uuid_like(action_plan_uuid):
|
||||
action_plan = cc.action_plan.get(action_plan_uuid)
|
||||
_print_action_plan_show(action_plan)
|
||||
else:
|
||||
raise exceptions.ValidationError()
|
||||
class ShowActionPlan(command.ShowOne):
|
||||
"""Show detailed information about a given action plan."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowActionPlan, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'action_plan',
|
||||
metavar='<action-plan>',
|
||||
help=_('UUID of the action plan'),
|
||||
)
|
||||
return parser
|
||||
|
||||
@cliutils.arg(
|
||||
'--audit',
|
||||
metavar='<audit>',
|
||||
help='UUID of an audit used for filtering.')
|
||||
@cliutils.arg(
|
||||
'--detail',
|
||||
dest='detail',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help="Show detailed information about action plans.")
|
||||
@cliutils.arg(
|
||||
'--limit',
|
||||
metavar='<limit>',
|
||||
type=int,
|
||||
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.')
|
||||
@cliutils.arg(
|
||||
'--sort-key',
|
||||
metavar='<field>',
|
||||
help='Action Plan field that will be used for sorting.')
|
||||
@cliutils.arg(
|
||||
'--sort-dir',
|
||||
metavar='<direction>',
|
||||
choices=['asc', 'desc'],
|
||||
help='Sort direction: "asc" (the default) or "desc".')
|
||||
def do_action_plan_list(cc, args):
|
||||
"""List the action plans."""
|
||||
params = {}
|
||||
def _format_indicators(self, action_plan, parsed_args):
|
||||
out = six.StringIO()
|
||||
efficacy_indicators = action_plan.efficacy_indicators
|
||||
fields = ['name', 'description', 'value', 'unit']
|
||||
yaml_format.YAMLFormatter().emit_list(
|
||||
column_names=list(field.capitalize()
|
||||
for field in fields),
|
||||
data=[utils.get_dict_properties(spec, fields)
|
||||
for spec in efficacy_indicators],
|
||||
stdout=out,
|
||||
parsed_args=parsed_args,
|
||||
)
|
||||
return out.getvalue() or ''
|
||||
|
||||
if args.audit is not None:
|
||||
params['audit'] = args.audit
|
||||
if args.detail:
|
||||
fields = res_fields.ACTION_PLAN_FIELDS
|
||||
field_labels = res_fields.ACTION_PLAN_FIELD_LABELS
|
||||
else:
|
||||
fields = res_fields.ACTION_PLAN_SHORT_LIST_FIELDS
|
||||
field_labels = res_fields.ACTION_PLAN_SHORT_LIST_FIELD_LABELS
|
||||
def take_action(self, parsed_args):
|
||||
client = getattr(self.app.client_manager, "infra-optim")
|
||||
|
||||
params.update(utils.common_params_for_list(args,
|
||||
fields,
|
||||
field_labels))
|
||||
action_plan_uuid = parsed_args.action_plan
|
||||
|
||||
action_plan = cc.action_plan.list(**params)
|
||||
cliutils.print_list(action_plan, fields,
|
||||
field_labels=field_labels,
|
||||
sortby_index=None)
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'action-plan',
|
||||
metavar='<action-plan>',
|
||||
nargs='+',
|
||||
help="UUID of the action plan.")
|
||||
def do_action_plan_delete(cc, args):
|
||||
"""Delete an action plan."""
|
||||
for p in getattr(args, 'action-plan'):
|
||||
if uuidutils.is_uuid_like(p):
|
||||
cc.action_plan.delete(p)
|
||||
print ('Deleted action plan %s' % p)
|
||||
else:
|
||||
if not uuidutils.is_uuid_like(action_plan_uuid):
|
||||
raise exceptions.ValidationError()
|
||||
|
||||
try:
|
||||
action_plan = client.action_plan.get(action_plan_uuid)
|
||||
except exceptions.HTTPNotFound as exc:
|
||||
raise exceptions.CommandError(str(exc))
|
||||
|
||||
@cliutils.arg(
|
||||
'action-plan',
|
||||
metavar='<action-plan>',
|
||||
help="UUID of the action plan.")
|
||||
@cliutils.arg(
|
||||
'op',
|
||||
metavar='<op>',
|
||||
choices=['add', 'replace', 'remove'],
|
||||
help="Operation: 'add', 'replace', or 'remove'.")
|
||||
@cliutils.arg(
|
||||
'attributes',
|
||||
metavar='<path=value>',
|
||||
nargs='+',
|
||||
action='append',
|
||||
default=[],
|
||||
help="Attribute to add, replace, or remove. Can be specified multiple "
|
||||
"times. For 'remove', only <path> is necessary.")
|
||||
def do_action_plan_update(cc, args):
|
||||
"""Update information about an action plan."""
|
||||
action_plan_uuid = getattr(args, 'action-plan')
|
||||
if uuidutils.is_uuid_like(action_plan_uuid):
|
||||
patch = utils.args_array_to_patch(args.op, args.attributes[0])
|
||||
action_plan = cc.action_plan.update(action_plan_uuid, patch)
|
||||
_print_action_plan_show(action_plan)
|
||||
else:
|
||||
raise exceptions.ValidationError()
|
||||
if parsed_args.formatter == 'table':
|
||||
# Update the raw efficacy indicators with the formatted ones
|
||||
action_plan.efficacy_indicators = (
|
||||
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)
|
||||
|
||||
columns = res_fields.ACTION_PLAN_FIELDS
|
||||
column_headers = res_fields.ACTION_PLAN_FIELD_LABELS
|
||||
return column_headers, utils.get_item_properties(action_plan, columns)
|
||||
|
||||
|
||||
@cliutils.arg('action-plan',
|
||||
metavar='<action-plan>',
|
||||
help="UUID of the action plan.")
|
||||
def do_action_plan_start(cc, args):
|
||||
"""Execute an action plan."""
|
||||
action_plan_uuid = getattr(args, 'action-plan')
|
||||
if uuidutils.is_uuid_like(action_plan_uuid):
|
||||
args.op = 'replace'
|
||||
args.attributes = [['state=PENDING']]
|
||||
class ListActionPlan(command.Lister):
|
||||
"""List information on retrieved action plans."""
|
||||
|
||||
patch = utils.args_array_to_patch(
|
||||
args.op,
|
||||
args.attributes[0])
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListActionPlan, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'--audit',
|
||||
metavar='<audit>',
|
||||
help=_('UUID of an audit used for filtering.'))
|
||||
parser.add_argument(
|
||||
'--detail',
|
||||
dest='detail',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help=_("Show detailed information about action plans."))
|
||||
parser.add_argument(
|
||||
'--limit',
|
||||
metavar='<limit>',
|
||||
type=int,
|
||||
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(
|
||||
'--sort-key',
|
||||
metavar='<field>',
|
||||
help=_('Action Plan field that will be used for sorting.'))
|
||||
parser.add_argument(
|
||||
'--sort-dir',
|
||||
metavar='<direction>',
|
||||
choices=['asc', 'desc'],
|
||||
help=_('Sort direction: "asc" (the default) or "desc".'))
|
||||
|
||||
action_plan = cc.action_plan.update(action_plan_uuid, patch)
|
||||
_print_action_plan_show(action_plan)
|
||||
else:
|
||||
raise exceptions.ValidationError()
|
||||
return parser
|
||||
|
||||
def _format_indicators(self, action_plan, parsed_args):
|
||||
out = six.StringIO()
|
||||
efficacy_indicators = action_plan.efficacy_indicators
|
||||
fields = ['name', 'value', 'unit']
|
||||
yaml_format.YAMLFormatter().emit_list(
|
||||
column_names=list(field.capitalize()
|
||||
for field in fields),
|
||||
data=[utils.get_dict_properties(spec, fields)
|
||||
for spec in efficacy_indicators],
|
||||
stdout=out,
|
||||
parsed_args=parsed_args,
|
||||
)
|
||||
return out.getvalue() or ''
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = getattr(self.app.client_manager, "infra-optim")
|
||||
|
||||
params = {}
|
||||
if parsed_args.audit is not None:
|
||||
params['audit'] = parsed_args.audit
|
||||
if parsed_args.detail:
|
||||
fields = res_fields.ACTION_PLAN_FIELDS
|
||||
field_labels = res_fields.ACTION_PLAN_FIELD_LABELS
|
||||
else:
|
||||
fields = res_fields.ACTION_PLAN_SHORT_LIST_FIELDS
|
||||
field_labels = res_fields.ACTION_PLAN_SHORT_LIST_FIELD_LABELS
|
||||
|
||||
params.update(common_utils.common_params_for_list(
|
||||
parsed_args, fields, field_labels))
|
||||
|
||||
data = client.action_plan.list(**params)
|
||||
|
||||
if parsed_args.formatter == 'table':
|
||||
for action_plan in data:
|
||||
# Update the raw efficacy indicators with the formatted ones
|
||||
action_plan.efficacy_indicators = (
|
||||
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)
|
||||
|
||||
return (field_labels,
|
||||
(utils.get_item_properties(item, fields) for item in data))
|
||||
|
||||
|
||||
class CreateActionPlan(command.ShowOne):
|
||||
"""Create new audit."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CreateActionPlan, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'-a', '--audit-template',
|
||||
required=True,
|
||||
dest='audit_template_uuid',
|
||||
metavar='<audit_template>',
|
||||
help=_('ActionPlan template used for this audit (name or uuid).'))
|
||||
parser.add_argument(
|
||||
'-d', '--deadline',
|
||||
dest='deadline',
|
||||
metavar='<deadline>',
|
||||
help=_('Descrition of the audit.'))
|
||||
parser.add_argument(
|
||||
'-t', '--audit_type',
|
||||
dest='audit_type',
|
||||
metavar='<audit_type>',
|
||||
default='ONESHOT',
|
||||
help=_("ActionPlan type."))
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = getattr(self.app.client_manager, "infra-optim")
|
||||
|
||||
field_list = ['audit_template_uuid', 'audit_type', 'deadline']
|
||||
fields = dict((k, v) for (k, v) in vars(parsed_args).items()
|
||||
if k in field_list and v is not None)
|
||||
if fields.get('audit_template_uuid'):
|
||||
if not uuidutils.is_uuid_like(fields['audit_template_uuid']):
|
||||
fields['audit_template_uuid'] = client.audit_template.get(
|
||||
fields['audit_template_uuid']).uuid
|
||||
|
||||
audit = client.audit.create(**fields)
|
||||
|
||||
columns = res_fields.ACTION_PLAN_FIELDS
|
||||
column_headers = res_fields.ACTION_PLAN_FIELD_LABELS
|
||||
|
||||
return column_headers, utils.get_item_properties(audit, columns)
|
||||
|
||||
|
||||
class UpdateActionPlan(command.ShowOne):
|
||||
"""Update action plan command."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(UpdateActionPlan, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'action_plan',
|
||||
metavar='<action-plan>',
|
||||
help=_("UUID of the action_plan."))
|
||||
parser.add_argument(
|
||||
'op',
|
||||
metavar='<op>',
|
||||
choices=['add', 'replace', 'remove'],
|
||||
help=_("Operation: 'add'), 'replace', or 'remove'."))
|
||||
parser.add_argument(
|
||||
'attributes',
|
||||
metavar='<path=value>',
|
||||
nargs='+',
|
||||
action='append',
|
||||
default=[],
|
||||
help=_("Attribute to add, replace, or remove. Can be specified "
|
||||
"multiple times. For 'remove', only <path> is necessary."))
|
||||
|
||||
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()
|
||||
|
||||
patch = common_utils.args_array_to_patch(
|
||||
parsed_args.op, parsed_args.attributes[0])
|
||||
|
||||
action_plan = client.action_plan.update(parsed_args.action_plan, patch)
|
||||
|
||||
columns = res_fields.ACTION_PLAN_FIELDS
|
||||
column_headers = res_fields.ACTION_PLAN_FIELD_LABELS
|
||||
|
||||
return column_headers, utils.get_item_properties(action_plan, columns)
|
||||
|
||||
|
||||
class StartActionPlan(command.ShowOne):
|
||||
"""Start action plan command."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(StartActionPlan, 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.start(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)
|
||||
|
||||
|
||||
class DeleteActionPlan(command.Command):
|
||||
"""Delete action plan command."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(DeleteActionPlan, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'action_plans',
|
||||
metavar='<action-plan>',
|
||||
nargs='+',
|
||||
help=_('UUID of the action plan'),
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = getattr(self.app.client_manager, "infra-optim")
|
||||
|
||||
for action_plan in parsed_args.action_plans:
|
||||
if not uuidutils.is_uuid_like(action_plan):
|
||||
raise exceptions.ValidationError()
|
||||
|
||||
client.action_plan.delete(action_plan)
|
||||
|
||||
@@ -1,138 +1,115 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Copyright (c) 2016 b<>com
|
||||
#
|
||||
# Copyright 2013 Red Hat, Inc.
|
||||
# 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
|
||||
#
|
||||
# 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.
|
||||
|
||||
# import argparse
|
||||
from openstackclient.common import utils
|
||||
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from watcherclient.common import cliutils
|
||||
from watcherclient.common import utils
|
||||
from watcherclient._i18n import _
|
||||
from watcherclient.common import command
|
||||
from watcherclient.common import utils as common_utils
|
||||
from watcherclient import exceptions
|
||||
from watcherclient.v1 import resource_fields as res_fields
|
||||
|
||||
|
||||
def _print_action_show(action):
|
||||
fields = res_fields.ACTION_FIELDS
|
||||
data = dict([(f, getattr(action, f, '')) for f in fields])
|
||||
cliutils.print_dict(data, wrap=72)
|
||||
class ShowAction(command.ShowOne):
|
||||
"""Show detailed information about a given action."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowAction, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'action',
|
||||
metavar='<action>',
|
||||
help=_('UUID of the action'),
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = getattr(self.app.client_manager, "infra-optim")
|
||||
|
||||
try:
|
||||
action = client.action.get(parsed_args.action)
|
||||
except exceptions.HTTPNotFound as exc:
|
||||
raise exceptions.CommandError(str(exc))
|
||||
|
||||
columns = res_fields.ACTION_FIELDS
|
||||
column_headers = res_fields.ACTION_FIELD_LABELS
|
||||
|
||||
return column_headers, utils.get_item_properties(action, columns)
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'action',
|
||||
metavar='<action>',
|
||||
help="UUID of the action")
|
||||
def do_action_show(cc, args):
|
||||
"""Show detailed information about an action."""
|
||||
if uuidutils.is_uuid_like(args.action):
|
||||
action = cc.action.get(args.action)
|
||||
_print_action_show(action)
|
||||
else:
|
||||
raise exceptions.ValidationError()
|
||||
class ListAction(command.Lister):
|
||||
"""List information on retrieved actions."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListAction, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'--action-plan',
|
||||
metavar='<action-plan>',
|
||||
help=_('UUID of the action plan used for filtering.'))
|
||||
parser.add_argument(
|
||||
'--audit',
|
||||
metavar='<audit>',
|
||||
help=_(' UUID of the audit used for filtering.'))
|
||||
parser.add_argument(
|
||||
'--detail',
|
||||
dest='detail',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help=_("Show detailed information about actions."))
|
||||
parser.add_argument(
|
||||
'--limit',
|
||||
metavar='<limit>',
|
||||
type=int,
|
||||
help=_('Maximum number of actions to return per request, '
|
||||
'0 for no limit. Default is the maximum number used '
|
||||
'by the Watcher API Service.'))
|
||||
parser.add_argument(
|
||||
'--sort-key',
|
||||
metavar='<field>',
|
||||
help=_('Action field that will be used for sorting.'))
|
||||
parser.add_argument(
|
||||
'--sort-dir',
|
||||
metavar='<direction>',
|
||||
choices=['asc', 'desc'],
|
||||
help=_('Sort direction: "asc" (the default) or "desc".'))
|
||||
|
||||
@cliutils.arg(
|
||||
'--action-plan',
|
||||
metavar='<action_plan>',
|
||||
help='UUID of the action plan used for filtering.')
|
||||
@cliutils.arg(
|
||||
'--audit',
|
||||
metavar='<audit>',
|
||||
help=' UUID of the audit used for filtering.')
|
||||
@cliutils.arg(
|
||||
'--detail',
|
||||
dest='detail',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help="Show detailed information about actions.")
|
||||
@cliutils.arg(
|
||||
'--limit',
|
||||
metavar='<limit>',
|
||||
type=int,
|
||||
help='Maximum number of actions to return per request, '
|
||||
'0 for no limit. Default is the maximum number used '
|
||||
'by the Watcher API Service.')
|
||||
@cliutils.arg(
|
||||
'--sort-key',
|
||||
metavar='<field>',
|
||||
help='Action field that will be used for sorting.')
|
||||
@cliutils.arg(
|
||||
'--sort-dir',
|
||||
metavar='<direction>',
|
||||
choices=['asc', 'desc'],
|
||||
help='Sort direction: "asc" (the default) or "desc".')
|
||||
def do_action_list(cc, args):
|
||||
"""List the actions."""
|
||||
params = {}
|
||||
return parser
|
||||
|
||||
if args.action_plan is not None:
|
||||
params['action_plan'] = args.action_plan
|
||||
if args.audit is not None:
|
||||
params['audit'] = args.audit
|
||||
if args.detail:
|
||||
fields = res_fields.ACTION_FIELDS
|
||||
field_labels = res_fields.ACTION_FIELD_LABELS
|
||||
else:
|
||||
fields = res_fields.ACTION_SHORT_LIST_FIELDS
|
||||
field_labels = res_fields.ACTION_SHORT_LIST_FIELD_LABELS
|
||||
def take_action(self, parsed_args):
|
||||
client = getattr(self.app.client_manager, "infra-optim")
|
||||
|
||||
params.update(utils.common_params_for_list(args,
|
||||
fields,
|
||||
field_labels))
|
||||
|
||||
action = cc.action.list(**params)
|
||||
cliutils.print_list(action, fields,
|
||||
field_labels=field_labels,
|
||||
sortby_index=None)
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'action',
|
||||
metavar='<action>',
|
||||
nargs='+',
|
||||
help="UUID of the action.")
|
||||
def do_action_delete(cc, args):
|
||||
"""Delete an action."""
|
||||
for p in args.action:
|
||||
if uuidutils.is_uuid_like(p):
|
||||
cc.action.delete(p)
|
||||
print ('Deleted action %s' % p)
|
||||
params = {}
|
||||
if parsed_args.action_plan is not None:
|
||||
params['action_plan'] = parsed_args.action_plan
|
||||
if parsed_args.audit is not None:
|
||||
params['audit'] = parsed_args.audit
|
||||
if parsed_args.detail:
|
||||
fields = res_fields.ACTION_FIELDS
|
||||
field_labels = res_fields.ACTION_FIELD_LABELS
|
||||
else:
|
||||
raise exceptions.ValidationError()
|
||||
fields = res_fields.ACTION_SHORT_LIST_FIELDS
|
||||
field_labels = res_fields.ACTION_SHORT_LIST_FIELD_LABELS
|
||||
|
||||
params.update(
|
||||
common_utils.common_params_for_list(
|
||||
parsed_args, fields, field_labels))
|
||||
|
||||
@cliutils.arg('action', metavar='<action>', help="UUID of the action.")
|
||||
@cliutils.arg(
|
||||
'op',
|
||||
metavar='<op>',
|
||||
choices=['add', 'replace', 'remove'],
|
||||
help="Operation: 'add', 'replace', or 'remove'.")
|
||||
@cliutils.arg(
|
||||
'attributes',
|
||||
metavar='<path=value>',
|
||||
nargs='+',
|
||||
action='append',
|
||||
default=[],
|
||||
help="Attribute to add, replace, or remove. Can be specified multiple "
|
||||
"times. For 'remove', only <path> is necessary.")
|
||||
def do_action_update(cc, args):
|
||||
"""Update information about an action."""
|
||||
if uuidutils.is_uuid_like(args.action):
|
||||
patch = utils.args_array_to_patch(args.op, args.attributes[0])
|
||||
action = cc.action.update(args.action, patch)
|
||||
_print_action_show(action)
|
||||
else:
|
||||
raise exceptions.ValidationError()
|
||||
try:
|
||||
data = client.action.list(**params)
|
||||
except exceptions.HTTPNotFound as ex:
|
||||
raise exceptions.CommandError(str(ex))
|
||||
|
||||
return (field_labels,
|
||||
(utils.get_item_properties(item, fields) for item in data))
|
||||
|
||||
@@ -18,7 +18,9 @@ from watcherclient.common import base
|
||||
from watcherclient.common import utils
|
||||
from watcherclient import exceptions as exc
|
||||
|
||||
CREATION_ATTRIBUTES = ['audit_template_uuid', 'deadline', 'type']
|
||||
|
||||
CREATION_ATTRIBUTES = ['audit_template_uuid', 'deadline',
|
||||
'audit_type', 'parameters', 'interval']
|
||||
|
||||
|
||||
class Audit(base.Resource):
|
||||
|
||||
@@ -1,163 +1,234 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Copyright (c) 2016 b<>com
|
||||
#
|
||||
# Copyright 2013 Red Hat, Inc.
|
||||
# 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
|
||||
#
|
||||
# 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.
|
||||
|
||||
# import argparse
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from openstackclient.common import utils
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from watcherclient.common import cliutils
|
||||
from watcherclient.common import utils
|
||||
from watcherclient._i18n import _
|
||||
from watcherclient.common import command
|
||||
from watcherclient.common import utils as common_utils
|
||||
from watcherclient import exceptions
|
||||
from watcherclient.v1 import resource_fields as res_fields
|
||||
|
||||
|
||||
def _print_audit_show(audit):
|
||||
fields = res_fields.AUDIT_FIELDS
|
||||
data = dict([(f, getattr(audit, f, '')) for f in fields])
|
||||
cliutils.print_dict(data, wrap=72)
|
||||
class ShowAudit(command.ShowOne):
|
||||
"""Show detailed information about a given audit."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowAudit, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'audit',
|
||||
metavar='<audit>',
|
||||
help=_('UUID of the audit'),
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = getattr(self.app.client_manager, "infra-optim")
|
||||
|
||||
try:
|
||||
audit = client.audit.get(parsed_args.audit)
|
||||
except exceptions.HTTPNotFound as exc:
|
||||
raise exceptions.CommandError(str(exc))
|
||||
|
||||
columns = res_fields.AUDIT_FIELDS
|
||||
column_headers = res_fields.AUDIT_FIELD_LABELS
|
||||
|
||||
return column_headers, utils.get_item_properties(audit, columns)
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'audit',
|
||||
metavar='<audit>',
|
||||
help="UUID of the audit.")
|
||||
def do_audit_show(cc, args):
|
||||
"""Show detailed information about an audit."""
|
||||
class ListAudit(command.Lister):
|
||||
"""List information on retrieved audits."""
|
||||
|
||||
if uuidutils.is_uuid_like(args.audit):
|
||||
audit = cc.audit.get(args.audit)
|
||||
_print_audit_show(audit)
|
||||
else:
|
||||
raise exceptions.ValidationError()
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListAudit, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'--audit-template',
|
||||
metavar='<audit_template>',
|
||||
dest='audit_template',
|
||||
help=_('Name or UUID of an audit template used for filtering.'))
|
||||
parser.add_argument(
|
||||
'--detail',
|
||||
dest='detail',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help=_("Show detailed information about audits."))
|
||||
parser.add_argument(
|
||||
'--limit',
|
||||
metavar='<limit>',
|
||||
type=int,
|
||||
help=_('Maximum number of audits to return per request, '
|
||||
'0 for no limit. Default is the maximum number used '
|
||||
'by the Watcher API Service.'))
|
||||
parser.add_argument(
|
||||
'--sort-key',
|
||||
metavar='<field>',
|
||||
help=_('Audit field that will be used for sorting.'))
|
||||
parser.add_argument(
|
||||
'--sort-dir',
|
||||
metavar='<direction>',
|
||||
choices=['asc', 'desc'],
|
||||
help=_('Sort direction: "asc" (the default) or "desc".'))
|
||||
|
||||
return parser
|
||||
|
||||
@cliutils.arg(
|
||||
'--audit-template',
|
||||
metavar='<audit_template>',
|
||||
dest='audit_template',
|
||||
help='Name or UUID of an audit template used for filtering.')
|
||||
@cliutils.arg(
|
||||
'--detail',
|
||||
dest='detail',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help="Show detailed information about audits.")
|
||||
@cliutils.arg(
|
||||
'--limit',
|
||||
metavar='<limit>',
|
||||
type=int,
|
||||
help='Maximum number of audits to return per request, '
|
||||
'0 for no limit. Default is the maximum number used '
|
||||
'by the Watcher API Service.')
|
||||
@cliutils.arg(
|
||||
'--sort-key',
|
||||
metavar='<field>',
|
||||
help='Audit field that will be used for sorting.')
|
||||
@cliutils.arg(
|
||||
'--sort-dir',
|
||||
metavar='<direction>',
|
||||
choices=['asc', 'desc'],
|
||||
help='Sort direction: "asc" (the default) or "desc".')
|
||||
def do_audit_list(cc, args):
|
||||
"""List the audits."""
|
||||
params = {}
|
||||
def take_action(self, parsed_args):
|
||||
client = getattr(self.app.client_manager, "infra-optim")
|
||||
|
||||
if args.audit_template is not None:
|
||||
params['audit_template'] = args.audit_template
|
||||
if args.detail:
|
||||
fields = res_fields.AUDIT_FIELDS
|
||||
field_labels = res_fields.AUDIT_FIELD_LABELS
|
||||
else:
|
||||
fields = res_fields.AUDIT_SHORT_LIST_FIELDS
|
||||
field_labels = res_fields.AUDIT_SHORT_LIST_FIELD_LABELS
|
||||
|
||||
# params.update(utils.common_params_for_list(args, fields, field_labels))
|
||||
|
||||
audit = cc.audit.list(**params)
|
||||
cliutils.print_list(audit, fields,
|
||||
field_labels=field_labels,
|
||||
sortby_index=None)
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'-a', '--audit-template',
|
||||
required=True,
|
||||
dest='audit_template_uuid',
|
||||
metavar='<audit_template>',
|
||||
help='Audit template used for this audit (name or uuid).')
|
||||
@cliutils.arg(
|
||||
'-d', '--deadline',
|
||||
dest='deadline',
|
||||
metavar='<deadline>',
|
||||
help='Descrition of the audit.')
|
||||
@cliutils.arg(
|
||||
'-t', '--type',
|
||||
dest='type',
|
||||
metavar='<type>',
|
||||
default='ONESHOT',
|
||||
help="Audit type.")
|
||||
def do_audit_create(cc, args):
|
||||
"""Create a new audit."""
|
||||
field_list = ['audit_template_uuid', 'type', 'deadline']
|
||||
fields = dict((k, v) for (k, v) in vars(args).items()
|
||||
if k in field_list and not (v is None))
|
||||
audit = cc.audit.create(**fields)
|
||||
field_list.append('uuid')
|
||||
data = dict([(f, getattr(audit, f, '')) for f in field_list])
|
||||
cliutils.print_dict(data, wrap=72)
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'audit',
|
||||
metavar='<audit>',
|
||||
nargs='+',
|
||||
help="UUID of the audit.")
|
||||
def do_audit_delete(cc, args):
|
||||
"""Delete an audit."""
|
||||
for p in args.audit:
|
||||
if uuidutils.is_uuid_like(p):
|
||||
cc.audit.delete(p)
|
||||
print ('Deleted audit %s' % p)
|
||||
params = {}
|
||||
if parsed_args.audit_template is not None:
|
||||
params['audit_template'] = parsed_args.audit_template
|
||||
if parsed_args.detail:
|
||||
fields = res_fields.AUDIT_FIELDS
|
||||
field_labels = res_fields.AUDIT_FIELD_LABELS
|
||||
else:
|
||||
fields = res_fields.AUDIT_SHORT_LIST_FIELDS
|
||||
field_labels = res_fields.AUDIT_SHORT_LIST_FIELD_LABELS
|
||||
|
||||
params.update(common_utils.common_params_for_list(
|
||||
parsed_args, fields, field_labels))
|
||||
|
||||
try:
|
||||
data = client.audit.list(**params)
|
||||
except exceptions.HTTPNotFound as ex:
|
||||
raise exceptions.CommandError(str(ex))
|
||||
|
||||
return (field_labels,
|
||||
(utils.get_item_properties(item, fields) for item in data))
|
||||
|
||||
|
||||
class CreateAudit(command.ShowOne):
|
||||
"""Create new audit."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CreateAudit, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'-a', '--audit-template',
|
||||
required=True,
|
||||
dest='audit_template_uuid',
|
||||
metavar='<audit_template>',
|
||||
help=_('Audit template used for this audit (name or uuid).'))
|
||||
parser.add_argument(
|
||||
'-d', '--deadline',
|
||||
dest='deadline',
|
||||
metavar='<deadline>',
|
||||
help=_('Descrition of the audit.'))
|
||||
parser.add_argument(
|
||||
'-t', '--audit_type',
|
||||
dest='audit_type',
|
||||
metavar='<audit_type>',
|
||||
default='ONESHOT',
|
||||
help=_("Audit type."))
|
||||
parser.add_argument(
|
||||
'-p', '--parameter',
|
||||
dest='parameters',
|
||||
metavar='<name=value>',
|
||||
action='append',
|
||||
help=_("Record strategy parameter/value metadata. "
|
||||
"Can be specified multiple times."))
|
||||
parser.add_argument(
|
||||
'-i', '--interval',
|
||||
dest='interval',
|
||||
metavar='<interval>',
|
||||
help=_("Audit interval."))
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = getattr(self.app.client_manager, "infra-optim")
|
||||
|
||||
field_list = ['audit_template_uuid', 'audit_type',
|
||||
'deadline', 'parameters', 'interval']
|
||||
|
||||
fields = dict((k, v) for (k, v) in vars(parsed_args).items()
|
||||
if k in field_list and v is not None)
|
||||
fields = common_utils.args_array_to_dict(fields, 'parameters')
|
||||
if fields.get('audit_template_uuid'):
|
||||
if not uuidutils.is_uuid_like(fields['audit_template_uuid']):
|
||||
fields['audit_template_uuid'] = client.audit_template.get(
|
||||
fields['audit_template_uuid']).uuid
|
||||
|
||||
audit = client.audit.create(**fields)
|
||||
|
||||
columns = res_fields.AUDIT_FIELDS
|
||||
column_headers = res_fields.AUDIT_FIELD_LABELS
|
||||
|
||||
return column_headers, utils.get_item_properties(audit, columns)
|
||||
|
||||
|
||||
class UpdateAudit(command.ShowOne):
|
||||
"""Update audit command."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(UpdateAudit, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'audit',
|
||||
metavar='<audit>',
|
||||
help=_("UUID of the audit."))
|
||||
parser.add_argument(
|
||||
'op',
|
||||
metavar='<op>',
|
||||
choices=['add', 'replace', 'remove'],
|
||||
help=_("Operation: 'add'), 'replace', or 'remove'."))
|
||||
parser.add_argument(
|
||||
'attributes',
|
||||
metavar='<path=value>',
|
||||
nargs='+',
|
||||
action='append',
|
||||
default=[],
|
||||
help=_("Attribute to add, replace, or remove. Can be specified "
|
||||
"multiple times. For 'remove', only <path> is necessary."))
|
||||
|
||||
return parser
|
||||
|
||||
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])
|
||||
|
||||
@cliutils.arg(
|
||||
'audit',
|
||||
metavar='<audit>',
|
||||
help="UUID of the audit.")
|
||||
@cliutils.arg(
|
||||
'op',
|
||||
metavar='<op>',
|
||||
choices=['add', 'replace', 'remove'],
|
||||
help="Operation: 'add', 'replace', or 'remove'.")
|
||||
@cliutils.arg(
|
||||
'attributes',
|
||||
metavar='<path=value>',
|
||||
nargs='+',
|
||||
action='append',
|
||||
default=[],
|
||||
help="Attribute to add, replace, or remove. Can be specified multiple "
|
||||
"times. For 'remove', only <path> is necessary.")
|
||||
def do_audit_update(cc, args):
|
||||
"""Update information about an audit."""
|
||||
if uuidutils.is_uuid_like(args.audit):
|
||||
patch = utils.args_array_to_patch(args.op, args.attributes[0])
|
||||
audit = cc.audit.update(args.audit, patch)
|
||||
_print_audit_show(audit)
|
||||
else:
|
||||
raise exceptions.ValidationError()
|
||||
audit = client.audit.update(parsed_args.audit, patch)
|
||||
|
||||
columns = res_fields.AUDIT_FIELDS
|
||||
column_headers = res_fields.AUDIT_FIELD_LABELS
|
||||
|
||||
return column_headers, utils.get_item_properties(audit, columns)
|
||||
|
||||
|
||||
class DeleteAudit(command.Command):
|
||||
"""Delete audit command."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(DeleteAudit, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'audits',
|
||||
metavar='<audit>',
|
||||
nargs='+',
|
||||
help=_('UUID of the audit'),
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
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)
|
||||
|
||||
@@ -19,7 +19,7 @@ from watcherclient.common import utils
|
||||
from watcherclient import exceptions as exc
|
||||
|
||||
CREATION_ATTRIBUTES = ['host_aggregate', 'description', 'name',
|
||||
'extra', 'goal']
|
||||
'extra', 'goal', 'strategy']
|
||||
|
||||
|
||||
class AuditTemplate(base.Resource):
|
||||
@@ -31,11 +31,11 @@ class AuditTemplateManager(base.Manager):
|
||||
resource_class = AuditTemplate
|
||||
|
||||
@staticmethod
|
||||
def _path(id=None):
|
||||
return '/v1/audit_templates/%s' % id if id else '/v1/audit_templates'
|
||||
def _path(id_=None):
|
||||
return '/v1/audit_templates/%s' % id_ if id_ else '/v1/audit_templates'
|
||||
|
||||
def list(self, name=None, goal=None, limit=None, sort_key=None,
|
||||
sort_dir=None, detail=False):
|
||||
def list(self, name=None, goal=None, strategy=None, limit=None,
|
||||
sort_key=None, sort_dir=None, detail=False):
|
||||
"""Retrieve a list of audit template.
|
||||
|
||||
:param name: Name of the audit template
|
||||
@@ -67,6 +67,8 @@ class AuditTemplateManager(base.Manager):
|
||||
filters.append('name=%s' % name)
|
||||
if goal is not None:
|
||||
filters.append("goal=%s" % goal)
|
||||
if strategy is not None:
|
||||
filters.append("strategy=%s" % strategy)
|
||||
|
||||
path = ''
|
||||
if detail:
|
||||
|
||||
@@ -1,161 +1,248 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Copyright (c) 2016 b<>com
|
||||
#
|
||||
# Copyright 2013 Red Hat, Inc.
|
||||
# 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
|
||||
#
|
||||
# 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.
|
||||
|
||||
# import argparse
|
||||
from openstackclient.common import utils
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from watcherclient.common import cliutils
|
||||
from watcherclient.common import utils
|
||||
from watcherclient._i18n import _
|
||||
from watcherclient.common import command
|
||||
from watcherclient.common import utils as common_utils
|
||||
from watcherclient import exceptions
|
||||
from watcherclient.v1 import resource_fields as res_fields
|
||||
|
||||
|
||||
def _print_audit_template_show(audit_template):
|
||||
fields = res_fields.AUDIT_TEMPLATE_FIELDS
|
||||
data = dict([(f, getattr(audit_template, f, '')) for f in fields])
|
||||
cliutils.print_dict(data, wrap=72)
|
||||
class ShowAuditTemplate(command.ShowOne):
|
||||
"""Show detailed information about a given audit template."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowAuditTemplate, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'audit_template',
|
||||
metavar='<audit-template>',
|
||||
help=_('UUID or name of the audit template'),
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = getattr(self.app.client_manager, "infra-optim")
|
||||
|
||||
audit_template_uuid = parsed_args.audit_template
|
||||
|
||||
try:
|
||||
audit_template = client.audit_template.get(audit_template_uuid)
|
||||
except exceptions.HTTPNotFound as exc:
|
||||
raise exceptions.CommandError(str(exc))
|
||||
|
||||
columns = res_fields.AUDIT_TEMPLATE_FIELDS
|
||||
column_headers = res_fields.AUDIT_TEMPLATE_FIELD_LABELS
|
||||
|
||||
return column_headers, utils.get_item_properties(
|
||||
audit_template, columns)
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'audit-template',
|
||||
metavar='<audit-template>',
|
||||
help="Name or UUID of the audit template.")
|
||||
def do_audit_template_show(cc, args):
|
||||
"""Show detailed information about a audit template."""
|
||||
class ListAuditTemplate(command.Lister):
|
||||
"""List information on retrieved audit templates."""
|
||||
|
||||
audit_template = cc.audit_template.get(getattr(args, 'audit-template'))
|
||||
_print_audit_template_show(audit_template)
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListAuditTemplate, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'--detail',
|
||||
dest='detail',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help=_("Show detailed information about audit templates."))
|
||||
parser.add_argument(
|
||||
'--goal',
|
||||
dest='goal',
|
||||
metavar='<goal>',
|
||||
help=_('UUID or name of the goal used for filtering.'))
|
||||
parser.add_argument(
|
||||
'--strategy',
|
||||
dest='strategy',
|
||||
metavar='<strategy>',
|
||||
help=_('UUID or name of the strategy used for filtering.'))
|
||||
parser.add_argument(
|
||||
'--limit',
|
||||
metavar='<limit>',
|
||||
type=int,
|
||||
help=_('Maximum number of audit templates to return per request, '
|
||||
'0 for no limit. Default is the maximum number used '
|
||||
'by the Watcher API Service.'))
|
||||
parser.add_argument(
|
||||
'--sort-key',
|
||||
metavar='<field>',
|
||||
help=_('Audit template field that will be used for sorting.'))
|
||||
parser.add_argument(
|
||||
'--sort-dir',
|
||||
metavar='<direction>',
|
||||
choices=['asc', 'desc'],
|
||||
help=_('Sort direction: "asc" (the default) or "desc".'))
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = getattr(self.app.client_manager, "infra-optim")
|
||||
|
||||
params = {}
|
||||
|
||||
# Optional
|
||||
if parsed_args.goal:
|
||||
params['goal'] = parsed_args.goal
|
||||
|
||||
# Optional
|
||||
if parsed_args.strategy:
|
||||
params['strategy'] = parsed_args.strategy
|
||||
|
||||
if parsed_args.detail:
|
||||
fields = res_fields.AUDIT_TEMPLATE_FIELDS
|
||||
field_labels = res_fields.AUDIT_TEMPLATE_FIELD_LABELS
|
||||
else:
|
||||
fields = res_fields.AUDIT_TEMPLATE_SHORT_LIST_FIELDS
|
||||
field_labels = res_fields.AUDIT_TEMPLATE_SHORT_LIST_FIELD_LABELS
|
||||
|
||||
params.update(common_utils.common_params_for_list(
|
||||
parsed_args, fields, field_labels))
|
||||
|
||||
data = client.audit_template.list(**params)
|
||||
|
||||
return (field_labels,
|
||||
(utils.get_item_properties(item, fields) for item in data))
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'--detail',
|
||||
dest='detail',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help="Show detailed information about audit templates.")
|
||||
@cliutils.arg(
|
||||
'--goal',
|
||||
metavar='<goal>',
|
||||
help='Name the goal used for filtering.')
|
||||
@cliutils.arg(
|
||||
'--limit',
|
||||
metavar='<limit>',
|
||||
type=int,
|
||||
help='Maximum number of audit templates to return per request, '
|
||||
'0 for no limit. Default is the maximum number used '
|
||||
'by the Watcher API Service.')
|
||||
@cliutils.arg(
|
||||
'--sort-key',
|
||||
metavar='<field>',
|
||||
help='Audit template field that will be used for sorting.')
|
||||
@cliutils.arg(
|
||||
'--sort-dir',
|
||||
metavar='<direction>',
|
||||
choices=['asc', 'desc'],
|
||||
help='Sort direction: "asc" (the default) or "desc".')
|
||||
def do_audit_template_list(cc, args):
|
||||
"""List the audit templates."""
|
||||
params = {}
|
||||
class CreateAuditTemplate(command.ShowOne):
|
||||
"""Create new audit template."""
|
||||
|
||||
if args.goal is not None:
|
||||
params['goal'] = args.goal
|
||||
if args.detail:
|
||||
fields = res_fields.AUDIT_TEMPLATE_FIELDS
|
||||
field_labels = res_fields.AUDIT_TEMPLATE_FIELD_LABELS
|
||||
else:
|
||||
fields = res_fields.AUDIT_TEMPLATE_SHORT_LIST_FIELDS
|
||||
field_labels = res_fields.AUDIT_TEMPLATE_SHORT_LIST_FIELD_LABELS
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CreateAuditTemplate, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'name',
|
||||
metavar='<name>',
|
||||
help=_('Name for this audit template.'))
|
||||
parser.add_argument(
|
||||
'goal',
|
||||
metavar='<goal>',
|
||||
help=_('Goal UUID or name associated to this audit template.'))
|
||||
parser.add_argument(
|
||||
'-s', '--strategy',
|
||||
dest='strategy',
|
||||
metavar='<strategy>',
|
||||
help=_('Strategy UUID or name associated to this audit template.'))
|
||||
parser.add_argument(
|
||||
'-d', '--description',
|
||||
metavar='<description>',
|
||||
help=_('Descrition of the audit template.'))
|
||||
parser.add_argument(
|
||||
'-e', '--extra',
|
||||
metavar='<key=value>',
|
||||
action='append',
|
||||
help=_("Record arbitrary key/value metadata. "
|
||||
"Can be specified multiple times."))
|
||||
parser.add_argument(
|
||||
'-a', '--host-aggregate',
|
||||
dest='host_aggregate',
|
||||
metavar='<host-aggregate>',
|
||||
help=_('Name or UUID of the host aggregate targeted '
|
||||
'by this audit template.'))
|
||||
|
||||
params.update(utils.common_params_for_list(args,
|
||||
fields,
|
||||
field_labels))
|
||||
return parser
|
||||
|
||||
audit_template = cc.audit_template.list(**params)
|
||||
cliutils.print_list(audit_template, fields,
|
||||
field_labels=field_labels,
|
||||
sortby_index=None)
|
||||
def take_action(self, parsed_args):
|
||||
client = getattr(self.app.client_manager, "infra-optim")
|
||||
|
||||
field_list = ['host_aggregate', 'description', 'name', 'extra',
|
||||
'goal', 'strategy']
|
||||
fields = dict((k, v) for (k, v) in vars(parsed_args).items()
|
||||
if k in field_list and v is not None)
|
||||
|
||||
# mandatory
|
||||
if not uuidutils.is_uuid_like(fields['goal']):
|
||||
fields['goal'] = client.goal.get(fields['goal']).uuid
|
||||
|
||||
# optional
|
||||
if fields.get('strategy'):
|
||||
if not uuidutils.is_uuid_like(fields['strategy']):
|
||||
fields['strategy'] = client.strategy.get(
|
||||
fields['strategy']).uuid
|
||||
|
||||
fields = common_utils.args_array_to_dict(fields, 'extra')
|
||||
audit_template = client.audit_template.create(**fields)
|
||||
|
||||
columns = res_fields.AUDIT_TEMPLATE_FIELDS
|
||||
column_headers = res_fields.AUDIT_TEMPLATE_FIELD_LABELS
|
||||
|
||||
return (column_headers,
|
||||
utils.get_item_properties(audit_template, columns))
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'name',
|
||||
metavar='<name>',
|
||||
help='Name for this audit template.')
|
||||
@cliutils.arg(
|
||||
'goal',
|
||||
metavar='<goal>',
|
||||
help='Goal Type associated to this audit template.')
|
||||
@cliutils.arg(
|
||||
'-d', '--description',
|
||||
metavar='<description>',
|
||||
help='Descrition of the audit template.')
|
||||
@cliutils.arg(
|
||||
'-e', '--extra',
|
||||
metavar='<key=value>',
|
||||
action='append',
|
||||
help="Record arbitrary key/value metadata. "
|
||||
"Can be specified multiple times.")
|
||||
@cliutils.arg(
|
||||
'-a', '--host-aggregate',
|
||||
dest='host_aggregate',
|
||||
metavar='<host-aggregate>',
|
||||
help='Name or ID of the host aggregate targeted by this audit template.')
|
||||
def do_audit_template_create(cc, args):
|
||||
"""Create a new audit template."""
|
||||
field_list = ['host_aggregate', 'description', 'name', 'extra', 'goal']
|
||||
fields = dict((k, v) for (k, v) in vars(args).items()
|
||||
if k in field_list and not (v is None))
|
||||
fields = utils.args_array_to_dict(fields, 'extra')
|
||||
audit_template = cc.audit_template.create(**fields)
|
||||
class UpdateAuditTemplate(command.ShowOne):
|
||||
"""Update audit template command."""
|
||||
|
||||
field_list.append('uuid')
|
||||
data = dict([(f, getattr(audit_template, f, '')) for f in field_list])
|
||||
cliutils.print_dict(data, wrap=72)
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(UpdateAuditTemplate, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'audit_template',
|
||||
metavar='<audit-template>',
|
||||
help=_("UUID or name of the audit_template."))
|
||||
parser.add_argument(
|
||||
'op',
|
||||
metavar='<op>',
|
||||
choices=['add', 'replace', 'remove'],
|
||||
help=_("Operation: 'add'), 'replace', or 'remove'."))
|
||||
parser.add_argument(
|
||||
'attributes',
|
||||
metavar='<path=value>',
|
||||
nargs='+',
|
||||
action='append',
|
||||
default=[],
|
||||
help=_("Attribute to add, replace, or remove. Can be specified "
|
||||
"multiple times. For 'remove', only <path> is necessary."))
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = getattr(self.app.client_manager, "infra-optim")
|
||||
|
||||
patch = common_utils.args_array_to_patch(
|
||||
parsed_args.op, parsed_args.attributes[0])
|
||||
|
||||
audit_template = client.audit_template.update(
|
||||
parsed_args.audit_template, patch)
|
||||
|
||||
columns = res_fields.AUDIT_TEMPLATE_FIELDS
|
||||
column_headers = res_fields.AUDIT_TEMPLATE_FIELD_LABELS
|
||||
|
||||
return column_headers, utils.get_item_properties(
|
||||
audit_template, columns)
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'audit-template',
|
||||
metavar='<audit-template>',
|
||||
nargs='+',
|
||||
help="UUID or name of the audit template.")
|
||||
def do_audit_template_delete(cc, args):
|
||||
"""Delete an audit template."""
|
||||
for p in getattr(args, 'audit-template'):
|
||||
cc.audit_template.delete(p)
|
||||
print ('Deleted audit template %s' % p)
|
||||
class DeleteAuditTemplate(command.Command):
|
||||
"""Delete audit template command."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(DeleteAuditTemplate, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'audit_templates',
|
||||
metavar='<audit-template>',
|
||||
nargs='+',
|
||||
help=_('UUID or name of the audit template'),
|
||||
)
|
||||
return parser
|
||||
|
||||
@cliutils.arg(
|
||||
'audit-template',
|
||||
metavar='<audit-template>',
|
||||
help="UUID or name of the audit template.")
|
||||
@cliutils.arg(
|
||||
'op',
|
||||
metavar='<op>',
|
||||
choices=['add', 'replace', 'remove'],
|
||||
help="Operation: 'add', 'replace', or 'remove'.")
|
||||
@cliutils.arg(
|
||||
'attributes',
|
||||
metavar='<path=value>',
|
||||
nargs='+',
|
||||
action='append',
|
||||
default=[],
|
||||
help="Attribute to add, replace, or remove. Can be specified multiple "
|
||||
"times. For 'remove', only <path> is necessary.")
|
||||
def do_audit_template_update(cc, args):
|
||||
"""Update information about an audit template."""
|
||||
patch = utils.args_array_to_patch(args.op, args.attributes[0])
|
||||
audit_template = cc.audit_template.update(getattr(args, 'audit-template'),
|
||||
patch)
|
||||
_print_audit_template_show(audit_template)
|
||||
def take_action(self, parsed_args):
|
||||
client = getattr(self.app.client_manager, "infra-optim")
|
||||
|
||||
for audit_template in parsed_args.audit_templates:
|
||||
client.audit_template.delete(audit_template)
|
||||
|
||||
@@ -16,12 +16,7 @@
|
||||
# under the License.
|
||||
|
||||
from watcherclient.common import http
|
||||
from watcherclient.v1 import action
|
||||
from watcherclient.v1 import action_plan
|
||||
from watcherclient.v1 import audit
|
||||
from watcherclient.v1 import audit_template
|
||||
from watcherclient.v1 import goal
|
||||
from watcherclient.v1 import metric_collector
|
||||
from watcherclient import v1
|
||||
|
||||
|
||||
class Client(object):
|
||||
@@ -36,13 +31,14 @@ class Client(object):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""Initialize a new client for the Watcher v1 API."""
|
||||
self.http_client = http._construct_http_client(*args, **kwargs)
|
||||
self.audit = audit.AuditManager(self.http_client)
|
||||
self.audit_template = audit_template.AuditTemplateManager(
|
||||
self.http_client)
|
||||
self.action = action.ActionManager(self.http_client)
|
||||
self.action_plan = action_plan.ActionPlanManager(self.http_client)
|
||||
self.goal = goal.GoalManager(self.http_client)
|
||||
self.metric_collector = metric_collector.MetricCollectorManager(
|
||||
self.http_client
|
||||
)
|
||||
self.http_client = self.build_http_client(*args, **kwargs)
|
||||
self.audit = v1.AuditManager(self.http_client)
|
||||
self.audit_template = v1.AuditTemplateManager(self.http_client)
|
||||
self.action = v1.ActionManager(self.http_client)
|
||||
self.action_plan = v1.ActionPlanManager(self.http_client)
|
||||
self.goal = v1.GoalManager(self.http_client)
|
||||
self.strategy = v1.StrategyManager(self.http_client)
|
||||
# self.metric_collector = v1.MetricCollectorManager(self.http_client)
|
||||
|
||||
def build_http_client(self, *args, **kwargs):
|
||||
return http._construct_http_client(*args, **kwargs)
|
||||
|
||||
@@ -27,11 +27,10 @@ class GoalManager(base.Manager):
|
||||
resource_class = Goal
|
||||
|
||||
@staticmethod
|
||||
def _path(goal_name=None):
|
||||
return '/v1/goals/%s' % goal_name if goal_name else '/v1/goals'
|
||||
def _path(goal=None):
|
||||
return '/v1/goals/%s' % goal if goal else '/v1/goals'
|
||||
|
||||
def list(self, limit=None, sort_key=None,
|
||||
sort_dir=None, detail=False):
|
||||
def list(self, limit=None, sort_key=None, sort_dir=None, detail=False):
|
||||
"""Retrieve a list of goal.
|
||||
|
||||
:param limit: The maximum number of results to return per
|
||||
@@ -70,8 +69,8 @@ class GoalManager(base.Manager):
|
||||
return self._list_pagination(self._path(path), "goals",
|
||||
limit=limit)
|
||||
|
||||
def get(self, goal_name):
|
||||
def get(self, goal):
|
||||
try:
|
||||
return self._list(self._path(goal_name))[0]
|
||||
return self._list(self._path(goal))[0]
|
||||
except IndexError:
|
||||
return None
|
||||
|
||||
@@ -15,65 +15,130 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from watcherclient.common import cliutils
|
||||
from watcherclient.common import utils
|
||||
from openstackclient.common import utils
|
||||
import six
|
||||
|
||||
from watcherclient._i18n import _
|
||||
from watcherclient.common import command
|
||||
from watcherclient.common import utils as common_utils
|
||||
from watcherclient import exceptions
|
||||
from watcherclient.v1 import resource_fields as res_fields
|
||||
|
||||
|
||||
def _print_goal_show(goal):
|
||||
fields = res_fields.GOAL_FIELDS
|
||||
data = dict([(f, getattr(goal, f, '')) for f in fields])
|
||||
cliutils.print_dict(data, wrap=72)
|
||||
class ShowGoal(command.ShowOne):
|
||||
"""Show detailed information about a given goal."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowGoal, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'goal',
|
||||
metavar='<goal>',
|
||||
help=_('UUID or name of the goal'),
|
||||
)
|
||||
return parser
|
||||
|
||||
def _format_indicator_spec_table(self, spec, parsed_args):
|
||||
out = six.StringIO()
|
||||
self.formatter.emit_one(
|
||||
column_names=list(field.capitalize() for field in spec.keys()),
|
||||
data=utils.get_dict_properties(spec, spec.keys()),
|
||||
stdout=out,
|
||||
parsed_args=parsed_args,
|
||||
)
|
||||
return out.getvalue() or ''
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = getattr(self.app.client_manager, "infra-optim")
|
||||
|
||||
try:
|
||||
goal = client.goal.get(parsed_args.goal)
|
||||
except exceptions.HTTPNotFound as exc:
|
||||
raise exceptions.CommandError(str(exc))
|
||||
|
||||
columns = res_fields.GOAL_FIELDS
|
||||
column_headers = res_fields.GOAL_FIELD_LABELS
|
||||
|
||||
if parsed_args.formatter == 'table':
|
||||
indicator_specs = ''
|
||||
# Format complex data types:
|
||||
for indicator_spec in goal.efficacy_specification:
|
||||
indicator_specs += self._format_indicator_spec_table(
|
||||
indicator_spec, parsed_args)
|
||||
# Update the raw efficacy specs with the formatted one
|
||||
goal.efficacy_specification = indicator_specs
|
||||
|
||||
return column_headers, utils.get_item_properties(goal, columns)
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'goal',
|
||||
metavar='<goal>',
|
||||
help="Name of the goal")
|
||||
def do_goal_show(cc, args):
|
||||
"""Show detailed information about a _print_goal_show."""
|
||||
goal = cc.goal.get(args.goal)
|
||||
_print_goal_show(goal)
|
||||
class ListGoal(command.Lister):
|
||||
"""List information on retrieved goals."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListGoal, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'--detail',
|
||||
dest='detail',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help=_("Show detailed information about metric collectors."))
|
||||
parser.add_argument(
|
||||
'--limit',
|
||||
metavar='<limit>',
|
||||
type=int,
|
||||
help=_('Maximum number of goals to return per request, '
|
||||
'0 for no limit. Default is the maximum number used '
|
||||
'by the Watcher API Service.'))
|
||||
parser.add_argument(
|
||||
'--sort-key',
|
||||
metavar='<field>',
|
||||
help=_('Goal field that will be used for sorting.'))
|
||||
parser.add_argument(
|
||||
'--sort-dir',
|
||||
metavar='<direction>',
|
||||
choices=['asc', 'desc'],
|
||||
help=_('Sort direction: "asc" (the default) or "desc".'))
|
||||
|
||||
@cliutils.arg(
|
||||
'--detail',
|
||||
dest='detail',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help="Show detailed information about metric collectors.")
|
||||
@cliutils.arg(
|
||||
'--limit',
|
||||
metavar='<limit>',
|
||||
type=int,
|
||||
help='Maximum number of goals to return per request, '
|
||||
'0 for no limit. Default is the maximum number used '
|
||||
'by the Watcher API Service.')
|
||||
@cliutils.arg(
|
||||
'--sort-key',
|
||||
metavar='<field>',
|
||||
help='Goal field that will be used for sorting.')
|
||||
@cliutils.arg(
|
||||
'--sort-dir',
|
||||
metavar='<direction>',
|
||||
choices=['asc', 'desc'],
|
||||
help='Sort direction: "asc" (the default) or "desc".')
|
||||
def do_goal_list(cc, args):
|
||||
"""List the goals."""
|
||||
params = {}
|
||||
return parser
|
||||
|
||||
if args.detail:
|
||||
fields = res_fields.GOAL_FIELDS
|
||||
field_labels = res_fields.GOAL_FIELD_LABELS
|
||||
else:
|
||||
fields = res_fields.GOAL_SHORT_LIST_FIELDS
|
||||
field_labels = res_fields.GOAL_SHORT_LIST_FIELD_LABELS
|
||||
def _format_indicator_spec_table(self, goal, parsed_args):
|
||||
out = six.StringIO()
|
||||
efficacy_specification = goal.efficacy_specification
|
||||
fields = ['name', 'unit']
|
||||
self.formatter.emit_list(
|
||||
column_names=list(field.capitalize()
|
||||
for field in fields),
|
||||
data=[utils.get_dict_properties(spec, fields)
|
||||
for spec in efficacy_specification],
|
||||
stdout=out,
|
||||
parsed_args=parsed_args,
|
||||
)
|
||||
return out.getvalue() or ''
|
||||
|
||||
params.update(utils.common_params_for_list(args,
|
||||
fields,
|
||||
field_labels))
|
||||
def take_action(self, parsed_args):
|
||||
client = getattr(self.app.client_manager, "infra-optim")
|
||||
|
||||
goal = cc.goal.list(**params)
|
||||
cliutils.print_list(goal, fields,
|
||||
field_labels=field_labels,
|
||||
sortby_index=None)
|
||||
if parsed_args.detail:
|
||||
fields = res_fields.GOAL_FIELDS
|
||||
field_labels = res_fields.GOAL_FIELD_LABELS
|
||||
else:
|
||||
fields = res_fields.GOAL_SHORT_LIST_FIELDS
|
||||
field_labels = res_fields.GOAL_SHORT_LIST_FIELD_LABELS
|
||||
|
||||
params = {}
|
||||
params.update(
|
||||
common_utils.common_params_for_list(
|
||||
parsed_args, fields, field_labels))
|
||||
|
||||
try:
|
||||
data = client.goal.list(**params)
|
||||
except exceptions.HTTPNotFound as ex:
|
||||
raise exceptions.CommandError(str(ex))
|
||||
|
||||
if parsed_args.formatter == 'table':
|
||||
for goal in data:
|
||||
# Update the raw efficacy specs with the formatted one
|
||||
goal.efficacy_specification = (
|
||||
self._format_indicator_spec_table(goal, parsed_args))
|
||||
|
||||
return (field_labels,
|
||||
(utils.get_item_properties(item, fields) for item in data))
|
||||
|
||||
@@ -1,144 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2013 Red Hat, Inc.
|
||||
# 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 argparse
|
||||
|
||||
from watcherclient.common import cliutils
|
||||
from watcherclient.common import utils
|
||||
from watcherclient.v1 import resource_fields as res_fields
|
||||
|
||||
|
||||
def _print_metric_collector_show(metric_collector):
|
||||
fields = res_fields.METRIC_COLLECTOR_FIELDS
|
||||
data = dict([(f, getattr(metric_collector, f, '')) for f in fields])
|
||||
cliutils.print_dict(data, wrap=72)
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'metric_collector',
|
||||
metavar='<metric_collector>',
|
||||
help="UUID of the metric collector")
|
||||
def do_metric_collector_show(cc, args):
|
||||
"""Show detailed information about a metric collector."""
|
||||
metric_collector = cc.metric_collector.get(args.metric_collector)
|
||||
_print_metric_collector_show(metric_collector)
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'--category',
|
||||
metavar='<category>',
|
||||
help='Only show information for metric collectors with this category.')
|
||||
@cliutils.arg(
|
||||
'--detail',
|
||||
dest='detail',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help="Show detailed information about metric collectors.")
|
||||
@cliutils.arg(
|
||||
'--limit',
|
||||
metavar='<limit>',
|
||||
type=int,
|
||||
help='Maximum number of metric collectors to return per request, '
|
||||
'0 for no limit. Default is the maximum number used '
|
||||
'by the Watcher API Service.')
|
||||
@cliutils.arg(
|
||||
'--sort-key',
|
||||
metavar='<field>',
|
||||
help='Metric collector field that will be used for sorting.')
|
||||
@cliutils.arg(
|
||||
'--sort-dir',
|
||||
metavar='<direction>',
|
||||
choices=['asc', 'desc'],
|
||||
help='Sort direction: "asc" (the default) or "desc".')
|
||||
def do_metric_collector_list(cc, args):
|
||||
"""List the metric collectors."""
|
||||
params = {}
|
||||
|
||||
if args.detail:
|
||||
fields = res_fields.METRIC_COLLECTOR_FIELDS
|
||||
field_labels = res_fields.METRIC_COLLECTOR_FIELD_LABELS
|
||||
else:
|
||||
fields = res_fields.METRIC_COLLECTOR_SHORT_LIST_FIELDS
|
||||
field_labels = res_fields.METRIC_COLLECTOR_SHORT_LIST_FIELD_LABELS
|
||||
|
||||
params.update(utils.common_params_for_list(args,
|
||||
fields,
|
||||
field_labels))
|
||||
|
||||
metric_collector = cc.metric_collector.list(**params)
|
||||
cliutils.print_list(metric_collector, fields,
|
||||
field_labels=field_labels,
|
||||
sortby_index=None)
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'-c', '--category',
|
||||
metavar='<category>',
|
||||
required=True,
|
||||
help='Metric category.')
|
||||
@cliutils.arg(
|
||||
'-e', '--endpoint-url',
|
||||
required=True,
|
||||
metavar='<goal>',
|
||||
help='URL towards which publish metric data.')
|
||||
def do_metric_collector_create(cc, args):
|
||||
"""Create a new metric collector."""
|
||||
field_list = ['category', 'endpoint']
|
||||
fields = dict((k, v) for (k, v) in vars(args).items()
|
||||
if k in field_list and not (v is None))
|
||||
metric_collector = cc.metric_collector.create(**fields)
|
||||
|
||||
field_list.append('uuid')
|
||||
data = dict([(f, getattr(metric_collector, f, '')) for f in field_list])
|
||||
cliutils.print_dict(data, wrap=72)
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'metric_collector',
|
||||
metavar='<metric_collector>',
|
||||
nargs='+',
|
||||
help="UUID of the metric collector.")
|
||||
def do_metric_collector_delete(cc, args):
|
||||
"""Delete a metric collector."""
|
||||
for p in args.metric_collector:
|
||||
cc.metric_collector.delete(p)
|
||||
print ('Deleted metric collector %s' % p)
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'metric_collector',
|
||||
metavar='<metric_collector>',
|
||||
help="UUID of the metric collector.")
|
||||
@cliutils.arg(
|
||||
'op',
|
||||
metavar='<op>',
|
||||
choices=['add', 'replace', 'remove'],
|
||||
help="Operation: 'add', 'replace', or 'remove'.")
|
||||
@cliutils.arg(
|
||||
'attributes',
|
||||
metavar='<path=value>',
|
||||
nargs='+',
|
||||
action='append',
|
||||
default=[],
|
||||
help="Attribute to add, replace, or remove. Can be specified multiple "
|
||||
"times. For 'remove', only <path> is necessary.")
|
||||
def do_metric_collector_update(cc, args):
|
||||
"""Update information about a metric collector."""
|
||||
patch = utils.args_array_to_patch(args.op, args.attributes[0])
|
||||
metric_collector = cc.metric_collector.update(
|
||||
getattr(args, 'metric-collector'), patch)
|
||||
_print_metric_collector_show(metric_collector)
|
||||
@@ -20,50 +20,56 @@
|
||||
AUDIT_TEMPLATE_FIELDS = [
|
||||
'uuid', 'created_at', 'updated_at', 'deleted_at',
|
||||
'description', 'host_aggregate', 'name',
|
||||
'extra', 'goal']
|
||||
'extra', 'goal_name', 'strategy_name']
|
||||
|
||||
AUDIT_TEMPLATE_FIELD_LABELS = [
|
||||
'UUID', 'Created At', 'Updated At', 'Deleted At',
|
||||
'Description', 'Host Aggregate ID or Name', 'Name',
|
||||
'Extra', 'Goal Type']
|
||||
'Extra', 'Goal', 'Strategy']
|
||||
|
||||
AUDIT_TEMPLATE_SHORT_LIST_FIELDS = ['uuid', 'name']
|
||||
AUDIT_TEMPLATE_SHORT_LIST_FIELDS = [
|
||||
'uuid', 'name', 'goal_name', 'strategy_name']
|
||||
|
||||
AUDIT_TEMPLATE_SHORT_LIST_FIELD_LABELS = ['UUID', 'Name']
|
||||
AUDIT_TEMPLATE_SHORT_LIST_FIELD_LABELS = ['UUID', 'Name', 'Goal', 'Strategy']
|
||||
|
||||
# Audit
|
||||
AUDIT_FIELDS = ['uuid', 'created_at', 'updated_at', 'deleted_at',
|
||||
'deadline', 'state', 'type', 'audit_template_uuid',
|
||||
'audit_template_name']
|
||||
'deadline', 'state', 'audit_type', 'audit_template_uuid',
|
||||
'audit_template_name', 'parameters', 'interval']
|
||||
|
||||
AUDIT_FIELD_LABELS = ['UUID', 'Created At', 'Updated At', 'Deleted At',
|
||||
'Deadline', 'State', 'Type', 'Audit Template uuid',
|
||||
'Audit Template Name']
|
||||
'Deadline', 'State', 'Audit Type', 'Audit Template uuid',
|
||||
'Audit Template Name', 'Parameters', 'Interval']
|
||||
|
||||
AUDIT_SHORT_LIST_FIELDS = ['uuid', 'type', 'audit_template_name', 'state']
|
||||
AUDIT_SHORT_LIST_FIELDS = [
|
||||
'uuid', 'audit_type', 'audit_template_name', 'state']
|
||||
|
||||
AUDIT_SHORT_LIST_FIELD_LABELS = ['UUID', 'Type', 'Audit Template Name',
|
||||
'State']
|
||||
AUDIT_SHORT_LIST_FIELD_LABELS = [
|
||||
'UUID', 'Audit Type', 'Audit Template', 'State']
|
||||
|
||||
# Action Plan
|
||||
ACTION_PLAN_FIELDS = ['uuid', 'created_at', 'updated_at', 'deleted_at',
|
||||
'audit_uuid', 'state']
|
||||
'audit_uuid', 'state', 'efficacy_indicators',
|
||||
'global_efficacy']
|
||||
|
||||
ACTION_PLAN_FIELD_LABELS = ['UUID', 'Created At', 'Updated At', 'Deleted At',
|
||||
'Audit', 'State']
|
||||
'Audit', 'State', 'Efficacy indicators',
|
||||
'Global efficacy']
|
||||
|
||||
ACTION_PLAN_SHORT_LIST_FIELDS = ['uuid', 'audit_uuid', 'state', 'updated_at']
|
||||
ACTION_PLAN_SHORT_LIST_FIELDS = ['uuid', 'audit_uuid', 'state',
|
||||
'updated_at', 'global_efficacy']
|
||||
|
||||
ACTION_PLAN_SHORT_LIST_FIELD_LABELS = ['UUID', 'Audit', 'State', 'Updated At']
|
||||
ACTION_PLAN_SHORT_LIST_FIELD_LABELS = ['UUID', 'Audit', 'State',
|
||||
'Updated At', 'Global efficacy']
|
||||
|
||||
# Action
|
||||
ACTION_FIELDS = ['uuid', 'created_at', 'updated_at', 'deleted_at', 'next_uuid',
|
||||
'description', 'alarm', 'state', 'action_plan_uuid',
|
||||
'action_type', 'applies_to', 'input_parameters']
|
||||
'state', 'action_plan_uuid', 'action_type',
|
||||
'input_parameters']
|
||||
|
||||
ACTION_FIELD_LABELS = ['UUID', 'Created At', 'Updated At', 'Deleted At',
|
||||
'Next Action', 'Description', 'Alarm', 'State',
|
||||
'Action Plan', 'Action', 'Applies to', 'Parameters']
|
||||
'Next Action', 'State', 'Action Plan', 'Action',
|
||||
'Parameters']
|
||||
|
||||
ACTION_SHORT_LIST_FIELDS = ['uuid', 'next_uuid',
|
||||
'state', 'action_plan_uuid', 'action_type']
|
||||
@@ -72,13 +78,25 @@ ACTION_SHORT_LIST_FIELD_LABELS = ['UUID', 'Next Action', 'State',
|
||||
'Action Plan', 'Action']
|
||||
# Goals
|
||||
|
||||
GOAL_FIELDS = ['name', 'strategy']
|
||||
GOAL_FIELDS = ['uuid', 'name', 'display_name', 'efficacy_specification']
|
||||
|
||||
GOAL_FIELD_LABELS = ['Name', 'Strategy']
|
||||
GOAL_FIELD_LABELS = ['UUID', 'Name', 'Display name', 'Efficacy specification']
|
||||
|
||||
GOAL_SHORT_LIST_FIELDS = ['name', 'strategy']
|
||||
GOAL_SHORT_LIST_FIELDS = ['uuid', 'name', 'display_name']
|
||||
|
||||
GOAL_SHORT_LIST_FIELD_LABELS = ['Name', 'Strategy']
|
||||
GOAL_SHORT_LIST_FIELD_LABELS = ['UUID', 'Name', 'Display name']
|
||||
|
||||
# Strategies
|
||||
|
||||
STRATEGY_FIELDS = ['uuid', 'name', 'display_name', 'goal_name',
|
||||
'parameters_spec']
|
||||
|
||||
STRATEGY_FIELD_LABELS = ['UUID', 'Name', 'Display name', 'Goal',
|
||||
'Parameters spec']
|
||||
|
||||
STRATEGY_SHORT_LIST_FIELDS = ['uuid', 'name', 'display_name', 'goal_name']
|
||||
|
||||
STRATEGY_SHORT_LIST_FIELD_LABELS = ['UUID', 'Name', 'Display name', 'Goal']
|
||||
|
||||
# Metric Collector
|
||||
METRIC_COLLECTOR_FIELDS = ['uuid', 'created_at', 'updated_at', 'deleted_at',
|
||||
|
||||
@@ -1,45 +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.
|
||||
|
||||
|
||||
from watcherclient.common import utils
|
||||
from watcherclient.v1 import action_plan_shell
|
||||
from watcherclient.v1 import action_shell
|
||||
from watcherclient.v1 import audit_shell
|
||||
from watcherclient.v1 import audit_template_shell
|
||||
from watcherclient.v1 import goal_shell
|
||||
# from watcherclient.v1 import metric_collector_shell
|
||||
|
||||
COMMAND_MODULES = [
|
||||
audit_template_shell,
|
||||
audit_shell,
|
||||
action_plan_shell,
|
||||
action_shell,
|
||||
# metric_collector_shell,
|
||||
goal_shell
|
||||
]
|
||||
|
||||
|
||||
def enhance_parser(parser, subparsers, cmd_mapper):
|
||||
"""Enhance parser with API version specific options.
|
||||
|
||||
Take a basic (nonversioned) parser and enhance it with
|
||||
commands and options specific for this version of API.
|
||||
|
||||
:param parser: top level parser :param subparsers: top level
|
||||
parser's subparsers collection where subcommands will go
|
||||
"""
|
||||
for command_module in COMMAND_MODULES:
|
||||
utils.define_commands_from_module(subparsers, command_module,
|
||||
cmd_mapper)
|
||||
85
watcherclient/v1/strategy.py
Normal file
85
watcherclient/v1/strategy.py
Normal file
@@ -0,0 +1,85 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2013 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.
|
||||
|
||||
import six.moves.urllib.parse as parse
|
||||
|
||||
from watcherclient.common import base
|
||||
from watcherclient.common import utils
|
||||
|
||||
|
||||
class Strategy(base.Resource):
|
||||
def __repr__(self):
|
||||
return "<Strategy %s>" % self._info
|
||||
|
||||
|
||||
class StrategyManager(base.Manager):
|
||||
resource_class = Strategy
|
||||
|
||||
@staticmethod
|
||||
def _path(strategy=None):
|
||||
return ('/v1/strategies/%s' % strategy
|
||||
if strategy else '/v1/strategies')
|
||||
|
||||
def list(self, goal=None, limit=None, sort_key=None,
|
||||
sort_dir=None, detail=False):
|
||||
"""Retrieve a list of strategy.
|
||||
|
||||
:param goal: The UUID of the goal to filter by
|
||||
:param limit: The maximum number of results to return per
|
||||
request, if:
|
||||
|
||||
1) limit > 0, the maximum number of audits to return.
|
||||
2) limit == 0, return the entire list of audits.
|
||||
3) limit param is NOT specified (None), the number of items
|
||||
returned respect the maximum imposed by the Watcher API
|
||||
(see Watcher's api.max_limit option).
|
||||
|
||||
:param sort_key: Optional, field used for sorting.
|
||||
|
||||
:param sort_dir: Optional, direction of sorting, either 'asc' (the
|
||||
default) or 'desc'.
|
||||
|
||||
:param detail: Optional, boolean whether to return detailed information
|
||||
about audits.
|
||||
|
||||
:returns: A list of audits.
|
||||
|
||||
"""
|
||||
if limit is not None:
|
||||
limit = int(limit)
|
||||
|
||||
filters = utils.common_filters(limit, sort_key, sort_dir)
|
||||
|
||||
if goal:
|
||||
filters.append(parse.urlencode(dict(goal=goal)))
|
||||
|
||||
path = ''
|
||||
if detail:
|
||||
path += 'detail'
|
||||
if filters:
|
||||
path += '?' + '&'.join(filters)
|
||||
|
||||
if limit is None:
|
||||
return self._list(self._path(path), "strategies")
|
||||
else:
|
||||
return self._list_pagination(self._path(path), "strategies",
|
||||
limit=limit)
|
||||
|
||||
def get(self, strategy):
|
||||
try:
|
||||
return self._list(self._path(strategy))[0]
|
||||
except IndexError:
|
||||
return None
|
||||
120
watcherclient/v1/strategy_shell.py
Normal file
120
watcherclient/v1/strategy_shell.py
Normal file
@@ -0,0 +1,120 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Copyright (c) 2016 b<>com
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import json
|
||||
from openstackclient.common import utils
|
||||
|
||||
from watcherclient._i18n import _
|
||||
from watcherclient.common import command
|
||||
from watcherclient.common import utils as common_utils
|
||||
from watcherclient import exceptions
|
||||
from watcherclient.v1 import resource_fields as res_fields
|
||||
|
||||
|
||||
class ShowStrategy(command.ShowOne):
|
||||
"""Show detailed information about a given strategy."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowStrategy, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'strategy',
|
||||
metavar='<strategy>',
|
||||
help=_('UUID or name of the strategy'),
|
||||
)
|
||||
return parser
|
||||
|
||||
def _format_spec(self, strategy):
|
||||
parameters_spec = strategy.parameters_spec.get('properties')
|
||||
if parameters_spec:
|
||||
return json.dumps(parameters_spec, indent=2)
|
||||
|
||||
return {}
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = getattr(self.app.client_manager, "infra-optim")
|
||||
|
||||
try:
|
||||
strategy = client.strategy.get(parsed_args.strategy)
|
||||
except exceptions.HTTPNotFound as exc:
|
||||
raise exceptions.CommandError(str(exc))
|
||||
|
||||
strategy.parameters_spec = self._format_spec(strategy)
|
||||
columns = res_fields.STRATEGY_FIELDS
|
||||
column_headers = res_fields.STRATEGY_FIELD_LABELS
|
||||
|
||||
return column_headers, utils.get_item_properties(strategy, columns)
|
||||
|
||||
|
||||
class ListStrategy(command.Lister):
|
||||
"""List information on retrieved strategies."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListStrategy, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'--goal',
|
||||
metavar='<goal>',
|
||||
dest='goal',
|
||||
help=_('UUID or name of the goal'))
|
||||
parser.add_argument(
|
||||
'--detail',
|
||||
dest='detail',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help=_("Show detailed information about each strategy."))
|
||||
parser.add_argument(
|
||||
'--limit',
|
||||
metavar='<limit>',
|
||||
type=int,
|
||||
help=_('Maximum number of strategies to return per request, '
|
||||
'0 for no limit. Default is the maximum number used '
|
||||
'by the Watcher API Service.'))
|
||||
parser.add_argument(
|
||||
'--sort-key',
|
||||
metavar='<field>',
|
||||
help=_('Goal field that will be used for sorting.'))
|
||||
parser.add_argument(
|
||||
'--sort-dir',
|
||||
metavar='<direction>',
|
||||
choices=['asc', 'desc'],
|
||||
help='Sort direction: "asc" (the default) or "desc".')
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = getattr(self.app.client_manager, "infra-optim")
|
||||
|
||||
params = {}
|
||||
if parsed_args.detail:
|
||||
fields = res_fields.STRATEGY_FIELDS
|
||||
field_labels = res_fields.STRATEGY_FIELD_LABELS
|
||||
else:
|
||||
fields = res_fields.STRATEGY_SHORT_LIST_FIELDS
|
||||
field_labels = res_fields.STRATEGY_SHORT_LIST_FIELD_LABELS
|
||||
|
||||
if parsed_args.goal:
|
||||
params["goal"] = parsed_args.goal
|
||||
|
||||
params.update(
|
||||
common_utils.common_params_for_list(
|
||||
parsed_args, fields, field_labels))
|
||||
|
||||
try:
|
||||
data = client.strategy.list(**params)
|
||||
except exceptions.HTTPNotFound as ex:
|
||||
raise exceptions.CommandError(str(ex))
|
||||
|
||||
return (field_labels,
|
||||
(utils.get_item_properties(item, fields) for item in data))
|
||||
@@ -16,3 +16,4 @@
|
||||
from pbr import version
|
||||
|
||||
version_info = version.VersionInfo('python-watcherclient')
|
||||
__version__ = version_info.version_string()
|
||||
|
||||
Reference in New Issue
Block a user