Compare commits

...

22 Commits

Author SHA1 Message Date
David.T
89cfc55870 Update Watcher CLI documentation
I updated, in this patchset, some examples of wacher CLI, because
option format has changed (we have no more '-' character in
keywords)
I added a new page for the openstack client + our watcher plugin.

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

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

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

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

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

Partially Implements: blueprint openstackclient-plugin

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

Partially Implements: blueprint openstackclient-plugin

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

Partially Implements: blueprint openstackclient-plugin

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

Partially Implements: blueprint openstackclient-plugin

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

Partially Implements: blueprint openstackclient-plugin

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

Partially Implements: blueprint openstackclient-plugin

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

Partially Implements: blueprint openstackclient-plugin

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

Partially Implements: blueprint openstackclient-plugin

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

Partially Implements: blueprint get-goal-from-strategy

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

Partially Implements: blueprint get-goal-from-strategy

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

Partially Implements: blueprint get-goal-from-strategy

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

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

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

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

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

1
.gitignore vendored
View File

@@ -42,6 +42,7 @@ output/*/index.html
# Sphinx
doc/build
doc/source/api
# pbr generates these
AUTHORS

View File

@@ -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

View File

@@ -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::

View File

@@ -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

View File

@@ -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

View File

@@ -18,6 +18,7 @@ Contents:
installation
api_v1
cli
openstack_cli
contributing
Contributing

View File

@@ -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

View File

@@ -0,0 +1,81 @@
=====================================================================
:program:`openstack` Command-Line Interface (CLI) with Watcher plugin
=====================================================================
.. program:: openstack
.. highlight:: bash
SYNOPSIS
========
:program:`openstack` [options] :program:`optimize` <command> [command-options]
:program:`openstack help optimize`
:program:`openstack help optimize` <command>
DESCRIPTION
===========
The :program:`openstack` command-line interface (CLI) can interact with the
OpenStack infra-optim Service (Watcher), by using our additional plugin
(included into the python-watcherclient package).
In order to use the CLI, you must provide your OpenStack username, password,
project (historically called tenant), and auth endpoint. You can use
configuration options :option:`--os-username`, :option:`--os-password`,
:option:`--os-tenant-id` (or :option:`--os-tenant-name`),
and :option:`--os-auth-url`, or set the corresponding
environment variables::
$ export OS_USERNAME=user
$ export OS_PASSWORD=password
$ export OS_TENANT_ID=b363706f891f48019483f8bd6503c54b # or OS_TENANT_NAME
$ export OS_TENANT_NAME=project # or OS_TENANT_ID
$ export OS_AUTH_URL=http://auth.example.com:5000/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

View File

@@ -2,9 +2,12 @@
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
Babel>=1.3 # BSD
Babel!=2.3.0,!=2.3.1,!=2.3.2,!=2.3.3,>=1.3 # 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
pbr>=1.6 # Apache-2.0
PrettyTable>=0.7,<0.8 # BSD
python-keystoneclient!=1.8.0,!=2.1.0,>=1.6.0 # Apache-2.0
python-openstackclient>=2.1.0 # Apache-2.0
six>=1.9.0 # MIT

View File

@@ -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

View File

@@ -10,6 +10,7 @@ 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
tempest-lib>=0.14.0 # Apache-2.0
testrepository>=0.0.18 # Apache-2.0/BSD
testscenarios>=0.4 # Apache-2.0/BSD
testtools>=1.4.0 # MIT

View 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

View File

@@ -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:
@@ -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()

View File

@@ -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
View 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

View File

@@ -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:]))

View File

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

View File

@@ -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()

View 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}

View File

@@ -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):

View File

@@ -1,153 +1,241 @@
# -*- 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',
'created_at': datetime.datetime.now().isoformat(),
'updated_at': None,
'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(),
'updated_at': None,
'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)

View File

@@ -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)

View File

@@ -14,132 +14,266 @@
# 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,
'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,
}
AUDIT_2 = {
'uuid': 'a5199d0e-0702-4613-9234-5ae2af8dafea',
'deadline': None,
'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,
}
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',
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',
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',
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',
type='ONESHOT')

View File

@@ -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)

View File

@@ -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})

View File

@@ -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),

View File

@@ -1,34 +1,130 @@
# -*- 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',
'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',
'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.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=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.SHORT_LIST_FIELDS,
self.SHORT_LIST_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.SHORT_LIST_FIELDS,
self.SHORT_LIST_FIELD_LABELS),
result)
self.m_goal_mgr.get.assert_called_once_with(
'fc087747-61be-4aad-8126-b701731ae836')

View File

@@ -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')

View 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)

View File

@@ -0,0 +1,157 @@
# -*- 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,
}
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,
}
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.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=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')

View File

@@ -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")

View File

@@ -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)

View File

@@ -1,157 +1,245 @@
# -*- 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_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)
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(
'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()
def take_action(self, parsed_args):
client = getattr(self.app.client_manager, "infra-optim")
action_plan_uuid = parsed_args.action_plan
@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 = {}
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
params.update(utils.common_params_for_list(args,
fields,
field_labels))
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()
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 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)
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', '--type',
dest='type',
metavar='<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', '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)

View File

@@ -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))

View File

@@ -1,163 +1,219 @@
# -*- 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', '--type',
dest='type',
metavar='<type>',
default='ONESHOT',
help=_("Audit type."))
return parser
def take_action(self, parsed_args):
client = getattr(self.app.client_manager, "infra-optim")
field_list = ['audit_template_uuid', '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.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)

View File

@@ -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:

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

View File

@@ -15,65 +15,90 @@
# 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
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 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
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 take_action(self, parsed_args):
client = getattr(self.app.client_manager, "infra-optim")
params.update(utils.common_params_for_list(args,
fields,
field_labels))
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
goal = cc.goal.list(**params)
cliutils.print_list(goal, fields,
field_labels=field_labels,
sortby_index=None)
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))
return (field_labels,
(utils.get_item_properties(item, fields) for item in data))

View File

@@ -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)

View File

@@ -20,16 +20,17 @@
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',
@@ -58,12 +59,12 @@ ACTION_PLAN_SHORT_LIST_FIELD_LABELS = ['UUID', 'Audit', 'State', 'Updated At']
# 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 +73,24 @@ ACTION_SHORT_LIST_FIELD_LABELS = ['UUID', 'Next Action', 'State',
'Action Plan', 'Action']
# Goals
GOAL_FIELDS = ['name', 'strategy']
GOAL_FIELDS = ['uuid', 'name', 'display_name']
GOAL_FIELD_LABELS = ['Name', 'Strategy']
GOAL_FIELD_LABELS = ['UUID', 'Name', 'Display name']
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_uuid']
STRATEGY_FIELD_LABELS = ['UUID', 'Name', 'Display name', 'Goal UUID']
STRATEGY_SHORT_LIST_FIELDS = ['uuid', 'name', 'display_name', 'goal_uuid']
STRATEGY_SHORT_LIST_FIELD_LABELS = ['UUID', 'Name', 'Display name',
'Goal UUID']
# Metric Collector
METRIC_COLLECTOR_FIELDS = ['uuid', 'created_at', 'updated_at', 'deleted_at',

View File

@@ -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)

View 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

View File

@@ -0,0 +1,111 @@
# -*- 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 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 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))
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))

View File

@@ -16,3 +16,4 @@
from pbr import version
version_info = version.VersionInfo('python-watcherclient')
__version__ = version_info.version_string()