Compare commits

..

4 Commits

Author SHA1 Message Date
OpenDev Sysadmins
1a9bbf244b OpenDev Migration Patch
This commit was bulk generated and pushed by the OpenDev sysadmins
as a part of the Git hosting and code review systems migration
detailed in these mailing list posts:

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

Attempts have been made to correct repository namespaces and
hostnames based on simple pattern matching, but it's possible some
were updated incorrectly or missed entirely. Please reach out to us
via the contact information listed at https://opendev.org/ with any
questions you may have.
2019-04-19 19:45:01 +00:00
Nguyen Hai
da805f8983 import zuul job settings from project-config
This is a mechanically generated patch to complete step 1 of moving
the zuul job settings out of project-config and into each project
repository.

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

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

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

Change-Id: I3a81add983bcd1accdfdd6915f689b5f37946402
Story: #2002586
Task: #24344
2018-08-19 00:59:03 +09:00
2142c8e51d Update UPPER_CONSTRAINTS_FILE for stable/queens
Change-Id: I7c170cc9ac357e5b9f6b3fd2bf4af3f4d9d8932c
2018-01-26 10:45:00 +00:00
ed55462a72 Update .gitreview for stable/queens
Change-Id: Ie4c4d3e3a6fd220c189811bd82801e8c598df410
2018-01-26 10:44:55 +00:00
31 changed files with 273 additions and 427 deletions

2
.gitignore vendored
View File

@@ -26,7 +26,7 @@ pip-log.txt
.coverage
.tox
nosetests.xml
.stestr/
.testrepository
.venv
# Translations

View File

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

View File

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

7
.testr.conf Normal file
View File

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

View File

@@ -1,13 +1,17 @@
- project:
templates:
- openstack-lower-constraints-jobs
- openstack-python-jobs
- openstack-python35-jobs
- openstack-python36-jobs
- publish-openstack-docs-pti
- publish-openstack-sphinx-docs
- check-requirements
- openstackclient-plugin-jobs
name: openstack/python-watcherclient
check:
jobs:
- watcherclient-tempest-functional:
- watcherclient-tempest-functional
- openstack-tox-cover:
voting: false
gate:
jobs:
- watcherclient-tempest-functional

View File

@@ -2,8 +2,8 @@
Team and repository tags
========================
.. image:: https://governance.openstack.org/tc/badges/python-watcherclient.svg
:target: https://governance.openstack.org/tc/reference/tags/index.html
.. image:: https://governance.openstack.org/badges/python-watcherclient.svg
:target: https://governance.openstack.org/reference/tags/index.html
.. Change things from this point on
@@ -20,7 +20,7 @@ metrics receiver, complex event processor and profiler, optimization processor
and an action plan applier. This provides a robust framework to realize a wide
range of cloud optimization goals, including the reduction of data center
operating costs, increased system performance via intelligent virtual machine
migration, increased energy efficiency and more!
migration, increased energy efficiency-and more!
* Free software: Apache license
* Wiki: https://wiki.openstack.org/wiki/Watcher

View File

@@ -157,7 +157,7 @@ watcher action list
[--quote {all,minimal,none,nonnumeric}]
[--action-plan <action-plan>] [--audit <audit>]
[--detail] [--limit <limit>] [--sort-key <field>]
[--sort-dir <direction>] [--marker <marker>]
[--sort-dir <direction>]
List information on retrieved actions.
@@ -186,10 +186,6 @@ List information on retrieved actions.
``--sort-dir <direction>``
Sort direction: "asc" (the default) or "desc".
``--marker <marker>``
UUID of the last action in the previous page; displays
list of actions after "marker".
.. _watcher_action_show:
watcher action show
@@ -299,8 +295,7 @@ watcher actionplan list
[--fit-width] [--print-empty] [--noindent]
[--quote {all,minimal,none,nonnumeric}]
[--audit <audit>] [--detail] [--limit <limit>]
[--marker <actionplan>] [--sort-key <field>]
[--sort-dir <direction>]
[--sort-key <field>] [--sort-dir <direction>]
List information on retrieved action plans.
@@ -320,10 +315,6 @@ List information on retrieved action plans.
0 for no limit. Default is the maximum number used by
the Watcher API Service.
``--marker <actionplan>``
The last actionplan UUID of the previous page;
displays list of actionplans after "marker".
``--sort-key <field>``
Action Plan field that will be used for sorting.
@@ -475,7 +466,7 @@ Delete audit command.
**Positional arguments:**
``<audit>``
UUID or name of the audit
UUID of the audit
**Optional arguments:**
@@ -541,7 +532,7 @@ Show detailed information about a given audit.
**Positional arguments:**
``<audit>``
UUID or name of the audit
UUID of the audit
**Optional arguments:**
@@ -565,7 +556,7 @@ Update audit command.
**Positional arguments:**
``<audit>``
UUID or name of the audit.
UUID of the audit.
``<op>``
Operation: 'add', 'replace', or 'remove'.
@@ -689,7 +680,7 @@ watcher audittemplate list
[--detail] [--goal <goal>]
[--strategy <strategy>] [--limit <limit>]
[--sort-key <field>]
[--sort-dir <direction>][--marker <marker>]
[--sort-dir <direction>]
List information on retrieved audit templates.
@@ -718,10 +709,6 @@ List information on retrieved audit templates.
``--sort-dir <direction>``
Sort direction: "asc" (the default) or "desc".
``--marker <marker>``
UUID of the last audittemplate in the previous page; displays
list of audittemplates after "marker".
.. _watcher_audittemplate_show:
watcher audittemplate show
@@ -794,7 +781,7 @@ watcher goal list
[--print-empty] [--noindent]
[--quote {all,minimal,none,nonnumeric}] [--detail]
[--limit <limit>] [--sort-key <field>]
[--sort-dir <direction>][--marker <marker>]
[--sort-dir <direction>]
List information on retrieved goals.
@@ -817,10 +804,6 @@ List information on retrieved goals.
``--sort-dir <direction>``
Sort direction: "asc" (the default) or "desc".
``--marker <marker>``
UUID of the last goal in the previous page; displays
list of goals after "marker".
.. _watcher_goal_show:
watcher goal show
@@ -858,7 +841,7 @@ watcher scoringengine list
[--quote {all,minimal,none,nonnumeric}]
[--detail] [--limit <limit>]
[--sort-key <field>]
[--sort-dir <direction>][--marker <marker>]
[--sort-dir <direction>]
List information on retrieved scoring engines.
@@ -881,10 +864,6 @@ List information on retrieved scoring engines.
``--sort-dir <direction>``
Sort direction: "asc" (the default) or "desc".
``--marker <marker>``
UUID of the last scoringengine in the previous page; displays
list of scoringengines after "marker".
.. _watcher_scoringengine_show:
watcher scoringengine show
@@ -982,7 +961,6 @@ watcher strategy list
[--quote {all,minimal,none,nonnumeric}]
[--goal <goal>] [--detail] [--limit <limit>]
[--sort-key <field>] [--sort-dir <direction>]
[--marker <marker>]
List information on retrieved strategies.
@@ -1008,10 +986,6 @@ List information on retrieved strategies.
``--sort-dir <direction>``
Sort direction: "asc" (the default) or "desc".
``--marker <marker>``
UUID of the last strategy in the previous page; displays
list of strategies after "marker".
.. _watcher_strategy_show:
watcher strategy show
@@ -1036,28 +1010,3 @@ Show detailed information about a given strategy.
``-h, --help``
show this help message and exit
.. _watcher_strategy_state:
watcher strategy state
----------------------
.. code-block:: console
usage: watcher strategy state [-h] [-f {csv,html,json,table,value,yaml}]
[-c COLUMN] [--max-width <integer>]
[--fit-width] [--print-empty] [--noindent]
[--quote {all,minimal,none,nonnumeric}]
[--sort-column SORT_COLUMN]
<strategy>
Retrieve information about strategy requirements.
**Positional arguments:**
``<strategy>``
Name of the strategy
**Optional arguments:**
``-h, --help``
show this help message and exit

View File

@@ -71,7 +71,8 @@ Once you have an watcher `Client`_, you can perform various tasks::
>>> watcher.audit.get(audit_uuid_or_name) # information about a particular audit
When the `Client`_ needs to propagate an exception, it will usually
raise an instance listed in `watcherclient.exceptions`_.
raise an instance subclassed from
`watcherclient.exc.BaseException`_ or `watcherclient.exc.ClientException`_.
Refer to the modules themselves, for more details.
@@ -83,4 +84,5 @@ watcherclient Modules
.. _watcherclient.v1.client.Client: api/watcherclient.v1.client.html#watcherclient.v1.client.Client
.. _Client: api/watcherclient.v1.client.html#watcherclient.v1.client.Client
.. _watcherclient.client.get_client(): api/watcherclient.client.html#watcherclient.client.get_client
.. _watcherclient.exceptions: api/watcherclient.exceptions.html
.. _watcherclient.exc.BaseException: api/watcherclient.exc.html#watcherclient.exc.BaseException
.. _watcherclient.exc.ClientException: api/watcherclient.exc.html#watcherclient.exc.ClientException

View File

@@ -1,90 +0,0 @@
alabaster==0.7.10
appdirs==1.4.3
asn1crypto==0.23.0
Babel==2.5.3
certifi==2018.1.18
cffi==1.7.0
chardet==3.0.4
cliff==2.11.0
cmd2==0.8.2
coverage==4.0
cryptography==2.1
debtcollector==1.19.0
decorator==4.2.1
deprecation==2.0
docutils==0.11
dogpile.cache==0.6.5
dulwich==0.15.0
extras==1.0.0
fasteners==0.7.0
fixtures==3.0.0
flake8==2.5.5
future==0.16.0
hacking==0.12.0
idna==2.6
imagesize==0.7.1
iso8601==0.1.12
Jinja2==2.10
jmespath==0.9.3
jsonpatch==1.21
jsonpointer==2.0
jsonschema==2.6.0
keystoneauth1==3.4.0
linecache2==1.0.0
MarkupSafe==1.0
mccabe==0.2.1
mock==2.0.0
monotonic==1.4
mox3==0.20.0
msgpack-python==0.4.0
munch==2.2.0
netaddr==0.7.19
netifaces==0.10.6
openstackdocstheme==1.18.1
openstacksdk==0.12.0
os-client-config==1.29.0
os-service-types==1.2.0
os-testr==1.0.0
osc-lib==1.10.0
oslo.concurrency==3.25.0
oslo.config==5.2.0
oslo.context==2.19.2
oslo.i18n==3.20.0
oslo.log==3.36.0
oslo.serialization==2.18.0
oslo.utils==3.36.0
oslotest==3.2.0
packaging==17.1
paramiko==2.0.0
pbr==3.1.1
pep8==1.5.7
prettytable==0.7.2
pyasn1==0.1.8
pycparser==2.18
pyflakes==0.8.1
Pygments==2.2.0
pyinotify==0.9.6
pyparsing==2.2.0
pyperclip==1.6.0
python-dateutil==2.5.3
python-mimeparse==1.6.0
python-subunit==1.0.0
pytz==2018.3
PyYAML==3.12
requests==2.18.4
requestsexceptions==1.4.0
rfc3986==0.3.1
simplejson==3.13.2
six==1.11.0
snowballstemmer==1.2.1
Sphinx==1.6.5
sphinxcontrib-websupport==1.0.1
stestr==2.0.0
stevedore==1.28.0
tempest==17.1.0
testscenarios==0.4
testtools==2.2.0
traceback2==1.4.0
unittest2==1.1.0
urllib3==1.22
wrapt==1.10.11

View File

@@ -2,13 +2,13 @@
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
Babel!=2.4.0,>=2.5.3 # BSD
cliff!=2.9.0,>=2.11.0 # Apache-2.0
osc-lib>=1.10.0 # Apache-2.0
oslo.i18n>=3.20.0 # Apache-2.0
oslo.utils>=3.36.0 # Apache-2.0
pbr!=2.1.0,>=3.1.1 # Apache-2.0
PrettyTable<0.8,>=0.7.2 # BSD
keystoneauth1>=3.4.0 # Apache-2.0
six>=1.11.0 # MIT
PyYAML>=3.12 # MIT
Babel!=2.4.0,>=2.3.4 # BSD
cliff!=2.9.0,>=2.8.0 # Apache-2.0
osc-lib>=1.8.0 # Apache-2.0
oslo.i18n>=3.15.3 # Apache-2.0
oslo.utils>=3.33.0 # Apache-2.0
pbr!=2.1.0,>=2.0.0 # Apache-2.0
PrettyTable<0.8,>=0.7.1 # BSD
keystoneauth1>=3.3.0 # Apache-2.0
six>=1.10.0 # MIT
PyYAML>=3.10 # MIT

View File

@@ -25,8 +25,6 @@ packages =
[entry_points]
console_scripts =
watcher = watcherclient.shell:main
tempest.test_plugins =
watcherclient_tests = watcherclient.plugin:WatcherClientTempestPlugin
openstack.cli.extension =
infra_optim = watcherclient.osc.plugin
@@ -54,6 +52,7 @@ openstack.infra_optim.v1 =
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_actionplan_cancel = watcherclient.v1.action_plan_shell:CancelActionPlan
@@ -90,6 +89,7 @@ watcherclient.v1 =
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

View File

@@ -9,8 +9,11 @@ mock>=2.0.0 # BSD
openstackdocstheme>=1.18.1 # Apache-2.0
oslotest>=3.2.0 # Apache-2.0
python-subunit>=1.0.0 # Apache-2.0/BSD
sphinx!=1.6.6,!=1.6.7,>=1.6.5 # BSD
stestr>=2.0.0 # Apache-2.0
sphinx!=1.6.6,>=1.6.2 # BSD
testrepository>=0.0.18 # Apache-2.0/BSD
testscenarios>=0.4 # Apache-2.0/BSD
testtools>=2.2.0 # MIT
tempest>=17.1.0 # Apache-2.0
# Needed for pypi packaging
wheel>=0.24.0 # MIT

34
tox.ini
View File

@@ -6,40 +6,30 @@ skipsdist = True
[testenv]
usedevelop = True
install_command =
constraints: pip install -U --force-reinstall -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} {opts} {packages}
constraints: pip install -U --force-reinstall -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt?h=stable/queens} {opts} {packages}
pip install -U {opts} {packages}
setenv =
VIRTUAL_ENV={envdir}
OS_TEST_PATH=./watcherclient/tests/unit
deps = -r{toxinidir}/test-requirements.txt
commands = rm -f .testrepository/times.dbm
stestr --test-path=./watcherclient/tests/unit run {posargs}
stestr slowest
python setup.py testr --slowest --testr-args='{posargs}'
[testenv:pep8]
basepython = python3
commands = flake8
[testenv:venv]
basepython = python3
commands = {posargs}
[testenv:cover]
basepython = python3
setenv =
PYTHON=coverage run --source watcherclient --parallel-mode
commands =
stestr run {posargs}
coverage combine
coverage html -d cover
coverage xml -o cover/coverage.xml
coverage report
python setup.py testr --coverage --testr-args='{posargs}'
coverage report
[testenv:docs]
basepython = python3
commands = python setup.py build_sphinx
[testenv:debug]
basepython = python3
commands = oslo_debug_helper -t watcherclient/tests/unit {posargs}
[testenv:functional]
@@ -53,8 +43,9 @@ passenv =
OS_AUTH_URL
OS_IDENTITY_API_VERSION
OS_IMAGE_API_VERSION
commands = stestr --test-path=./watcherclient/tests/functional run --concurrency=1 {posargs}
stestr slowest
setenv =
OS_TEST_PATH = ./watcherclient/tests/functional
commands = python setup.py testr --slowest --testr-args='--concurrency=1 {posargs}'
[flake8]
# E123, E125 skipped as they are invalid PEP-8.
@@ -65,16 +56,7 @@ builtins = _
exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build
[testenv:wheel]
basepython = python3
commands = python setup.py bdist_wheel
[hacking]
import_exceptions = watcherclient._i18n
[testenv:lower-constraints]
basepython = python3
install_command = pip install -U {opts} {packages}
deps =
-c{toxinidir}/lower-constraints.txt
-r{toxinidir}/test-requirements.txt
-r{toxinidir}/requirements.txt

View File

@@ -134,11 +134,6 @@ class Manager(object):
def _delete(self, url):
self.api.raw_request('DELETE', url)
def _start(self, url, body=None, method='POST'):
resp, body = self.api.json_request(method, url, body={})
if body:
return self.resource_class(self, body)
class Resource(base.Resource):
"""Represents a particular instance of an object (tenant, user, etc).

View File

@@ -354,15 +354,7 @@ class HTTPClient(VersionNegotiationMixin):
# Read body into string if it isn't obviously image data
body_str = None
if resp.headers.get('Content-Type') != 'application/octet-stream':
# decoding byte to string is necessary for Python 3 compatibility
# this issues has not been found with Python 3 unit tests
# because the test creates a fake http response of type str
# the if statement satisfies test (str) and real (bytes) behavior
body_list = [
chunk.decode("utf-8") if isinstance(chunk, bytes)
else chunk for chunk in body_iter
]
body_str = ''.join(body_list)
body_str = ''.join([chunk for chunk in body_iter])
self.log_http_response(resp, body_str)
body_iter = six.StringIO(body_str)
else:

View File

@@ -1,23 +0,0 @@
# -*- encoding: utf-8 -*-
# Copyright (c) 2018 Servionica
#
# 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 oslo_config import cfg
service_option = cfg.BoolOpt("watcher_client",
default=True,
help="Whether or not watcher_client is expected"
"to be available")

View File

@@ -1,34 +0,0 @@
# 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 os
from tempest.test_discover import plugins
from watcherclient import config as watcher_config
class WatcherClientTempestPlugin(plugins.TempestPlugin):
def load_tests(self):
base_path = os.path.split(os.path.dirname(
os.path.abspath(__file__)))[0]
test_dir = "watcherclient/tests/functional/v1"
full_test_dir = os.path.join(base_path, test_dir)
return full_test_dir, base_path
def register_opts(self, conf):
conf.register_opt(watcher_config.service_option,
group='service_available')
def get_opt_lists(self):
return [('service_available', [watcher_config.service_option])]

View File

@@ -47,6 +47,8 @@ _IDENTITY_API_VERSION_3 = ['3']
class WatcherShell(app.App):
"""Watcher command line interface."""
log = logging.getLogger(__name__)
def __init__(self, **kwargs):
self.client = None
@@ -192,12 +194,12 @@ class WatcherShell(app.App):
except Exception as e:
if not logging.getLogger('').handlers:
logging.basicConfig()
LOG.error('Exception raised: %s', str(e))
self.log.error('Exception raised: %s', str(e))
return ret_val
finally:
LOG.info("END return value: %s", ret_val)
self.log.info("END return value: %s", ret_val)
def main(argv=sys.argv[1:]):

View File

@@ -0,0 +1,53 @@
#!/bin/bash -xe
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
# This script is executed inside post_test_hook function in devstack gate.
# Default gate uses /opt/stack/new... but some of us may install differently
STACK_DIR=$BASE/new/devstack
function generate_testr_results {
if [ -f .testrepository/0 ]; then
sudo .tox/functional/bin/testr last --subunit > $WORKSPACE/testrepository.subunit
sudo mv $WORKSPACE/testrepository.subunit $BASE/logs/testrepository.subunit
sudo /usr/os-testr-env/bin/subunit2html $BASE/logs/testrepository.subunit $BASE/logs/testr_results.html
sudo gzip -9 $BASE/logs/testrepository.subunit
sudo gzip -9 $BASE/logs/testr_results.html
sudo chown $USER:$USER $BASE/logs/testrepository.subunit.gz $BASE/logs/testr_results.html.gz
sudo chmod a+r $BASE/logs/testrepository.subunit.gz $BASE/logs/testr_results.html.gz
fi
}
export WATCHERCLIENT_DIR="$BASE/new/python-watcherclient"
sudo chown -R $USER:stack $WATCHERCLIENT_DIR
# Get admin credentials
cd $STACK_DIR
source openrc admin admin
# Go to the watcherclient dir
cd $WATCHERCLIENT_DIR
# Run tests
echo "Running watcherclient functional test suite"
set +e
# Preserve env for OS_ credentials
sudo -E -H -u $USER tox -efunctional
EXIT_CODE=$?
set -e
# Collect and parse result
generate_testr_results
exit $EXIT_CODE

View File

@@ -18,31 +18,22 @@ import subprocess
import testtools
import six
from tempest import clients
from tempest.common import credentials_factory as creds_factory
from tempest.lib.cli import output_parser
from tempest.lib import exceptions
def credentials():
# You can get credentials either from tempest.conf file or
# from OS environment.
tempest_creds = clients.get_auth_provider(
creds_factory.get_configured_admin_credentials())
creds = tempest_creds.credentials
creds_dict = {
'--os-username': os.environ.get('OS_USERNAME', creds.username),
'--os-password': os.environ.get('OS_PASSWORD', creds.password),
'--os-project-name': os.environ.get('OS_PROJECT_NAME',
creds.project_name),
creds = {
'--os-username': os.environ.get('OS_USERNAME', 'admin'),
'--os-password': os.environ.get('OS_PASSWORD', 'secretadmin'),
'--os-project-name': os.environ.get('OS_PROJECT_NAME', 'admin'),
'--os-auth-url': os.environ.get('OS_AUTH_URL',
tempest_creds.auth_url),
'--os-project-domain-name': os.environ.get('OS_PROJECT_DOMAIN_ID',
creds.project_domain_name),
'--os-user-domain-name': os.environ.get('OS_USER_DOMAIN_ID',
creds.user_domain_name),
'http://10.0.1.94/identity'),
'--os-project-domain-id': os.environ.get('OS_PROJECT_DOMAIN_ID',
'default'),
'--os-user-domain-id': os.environ.get('OS_USER_DOMAIN_ID', 'default'),
}
return [x for sub in creds_dict.items() for x in sub]
return [x for sub in creds.items() for x in sub]
def execute(cmd, fail_ok=False, merge_stderr=False):
@@ -132,13 +123,3 @@ class TestCase(testtools.TestCase):
def parse_listing(self, raw_output):
"""Return list of dicts with basic item parsed from cli output."""
return output_parser.listing(raw_output)
def has_actionplan_succeeded(self, ap_uuid):
return self.parse_show_as_object(
self.watcher('actionplan show %s' % ap_uuid)
)['State'] == 'SUCCEEDED'
@classmethod
def has_audit_created(cls, audit_uuid):
return cls.parse_show_as_object(
cls.watcher('audit show %s' % audit_uuid))['State'] == 'SUCCEEDED'

View File

@@ -15,10 +15,6 @@
from oslo_utils import uuidutils
import functools
from tempest.lib.common.utils import test_utils
from watcherclient.tests.functional.v1 import base
@@ -37,22 +33,17 @@ class ActionTests(base.TestCase):
template_raw_output = cls.watcher(
'audittemplate create %s dummy -s dummy' % cls.audit_template_name)
template_output = cls.parse_show_as_object(template_raw_output)
audit_output = cls.parse_show_as_object(cls.watcher(
'audit create -a %s' % template_output['Name']))
audit_raw_output = cls.watcher(
'audit create -a %s' % template_output['Name'])
audit_output = cls.parse_show_as_object(audit_raw_output)
cls.audit_uuid = audit_output['UUID']
audit_created = test_utils.call_until_true(
func=functools.partial(cls.has_audit_created, cls.audit_uuid),
duration=600,
sleep_for=2)
if not audit_created:
raise Exception('Audit has not been succeeded')
@classmethod
def tearDownClass(cls):
# Delete Action Plan and all related actions.
output = cls.parse_show(
cls.watcher('actionplan list --audit %s' % cls.audit_uuid))
action_plan_uuid = list(output[0])[0]
action_plan_uuid = output[0].keys()[0]
raw_output = cls.watcher('actionplan delete %s' % action_plan_uuid)
cls.assertOutput('', raw_output)
# Delete audit
@@ -72,10 +63,9 @@ class ActionTests(base.TestCase):
self.assert_table_structure([raw_output], self.detailed_list_fields)
def test_action_show(self):
action_list = self.parse_show(self.watcher('action list --audit %s'
% self.audit_uuid))
action_uuid = list(action_list[0])[0]
action = self.watcher('action show %s' % action_uuid)
action_list = self.parse_show(self.watcher('action list'))
action_uuid = action_list[0].keys()[0]
action = self.watcher('action show ' + action_uuid)
self.assertIn(action_uuid, action)
self.assert_table_structure([action],
self.detailed_list_fields)

View File

@@ -13,12 +13,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import time
from oslo_utils import uuidutils
import functools
from tempest.lib.common.utils import test_utils
from watcherclient.tests.functional.v1 import base
@@ -28,8 +26,7 @@ class ActionPlanTests(base.TestCase):
dummy_name = 'dummy'
list_fields = ['UUID', 'Audit', 'State', 'Updated At', 'Global efficacy']
detailed_list_fields = list_fields + ['Created At', 'Deleted At',
'Strategy', 'Efficacy indicators',
'Hostname']
'Strategy', 'Efficacy indicators']
audit_template_name = 'a' + uuidutils.generate_uuid()
audit_uuid = None
@@ -42,19 +39,22 @@ class ActionPlanTests(base.TestCase):
% template_output['Name'])
audit_output = cls.parse_show_as_object(audit_raw_output)
cls.audit_uuid = audit_output['UUID']
audit_created = test_utils.call_until_true(
func=functools.partial(cls.has_audit_created, cls.audit_uuid),
duration=600,
sleep_for=2)
if not audit_created:
raise Exception('Audit has not been succeeded')
@classmethod
def tearDownClass(cls):
# Delete action plan
output = cls.parse_show(
cls.watcher('actionplan list --audit %s' % cls.audit_uuid))
action_plan_uuid = list(output[0])[0]
action_plan_uuid = output[0].keys()[0]
retry = 10
while retry > 0:
output = cls.parse_show(
cls.watcher('actionplan show %s' % action_plan_uuid))
state = [x for x in output if x.keys()[0] == 'State'][0]['State']
if state == 'SUCCEEDED':
break
time.sleep(1)
retry -= 1
raw_output = cls.watcher('actionplan delete %s' % action_plan_uuid)
cls.assertOutput('', raw_output)
# Delete audit
@@ -75,7 +75,7 @@ class ActionPlanTests(base.TestCase):
def test_action_plan_show(self):
action_plan_list = self.parse_show(self.watcher('actionplan list'))
action_plan_uuid = list(action_plan_list[0])[0]
action_plan_uuid = action_plan_list[0].keys()[0]
actionplan = self.watcher('actionplan show %s' % action_plan_uuid)
self.assertIn(action_plan_uuid, actionplan)
self.assert_table_structure([actionplan],
@@ -84,14 +84,50 @@ class ActionPlanTests(base.TestCase):
def test_action_plan_start(self):
output = self.parse_show(self.watcher('actionplan list --audit %s'
% self.audit_uuid))
action_plan_uuid = list(output[0])[0]
action_plan_uuid = output[0].keys()[0]
self.watcher('actionplan start %s' % action_plan_uuid)
raw_output = self.watcher('actionplan show %s' % action_plan_uuid)
self.assert_table_structure([raw_output], self.detailed_list_fields)
self.assertTrue(test_utils.call_until_true(
func=functools.partial(
self.has_actionplan_succeeded, action_plan_uuid),
duration=600,
sleep_for=2
))
class ActionPlanActiveTests(base.TestCase):
audit_uuid = None
audit_template_name = 'b' + uuidutils.generate_uuid()
list_fields = ['UUID', 'Audit', 'State', 'Updated At', 'Global efficacy']
detailed_list_fields = list_fields + ['Created At', 'Deleted At',
'Strategy', 'Efficacy indicators']
def _delete_action_plan(self):
output = self.parse_show(
self.watcher('actionplan list --audit %s' % self.audit_uuid))
action_plan_uuid = output[0].keys()[0]
raw_output = self.watcher('actionplan delete %s' % action_plan_uuid)
self.assertOutput('', raw_output)
def _delete_audit(self):
raw_output = self.watcher('audit delete %s' % self.audit_uuid)
self.assertOutput('', raw_output)
def _delete_audit_template(self):
raw_output = self.watcher(
'audittemplate delete %s' % self.audit_template_name)
self.assertOutput('', raw_output)
def _create_audit_template(self):
template_raw_output = self.watcher(
'audittemplate create %s dummy -s dummy'
% self.audit_template_name)
template_output = self.parse_show_as_object(template_raw_output)
return template_output
def test_action_plan_create(self):
template_output = self._create_audit_template()
action_plan = self.watcher(
'actionplan create -a %s' % template_output['Name'])
self.audit_uuid = self.parse_show_as_object(action_plan)['UUID']
self.assert_table_structure([action_plan], self.detailed_list_fields)
self._delete_action_plan()
self._delete_audit()
self._delete_audit_template()

View File

@@ -15,10 +15,6 @@
from oslo_utils import uuidutils
import functools
from tempest.lib.common.utils import test_utils
from watcherclient.tests.functional.v1 import base
@@ -30,7 +26,7 @@ class AuditTests(base.TestCase):
detailed_list_fields = list_fields + ['Created At', 'Updated At',
'Deleted At', 'Parameters',
'Interval', 'Audit Scope',
'Next Run Time', 'Hostname']
'Next Run Time']
audit_template_name = 'a' + uuidutils.generate_uuid()
audit_uuid = None
@@ -43,18 +39,12 @@ class AuditTests(base.TestCase):
'audit create -a %s' % template_output['Name'])
audit_output = cls.parse_show_as_object(audit_raw_output)
cls.audit_uuid = audit_output['UUID']
audit_created = test_utils.call_until_true(
func=functools.partial(cls.has_audit_created, cls.audit_uuid),
duration=600,
sleep_for=2)
if not audit_created:
raise Exception('Audit has not been succeeded')
@classmethod
def tearDownClass(cls):
output = cls.parse_show(
cls.watcher('actionplan list --audit %s' % cls.audit_uuid))
action_plan_uuid = list(output[0])[0]
action_plan_uuid = output[0].keys()[0]
cls.watcher('actionplan delete %s' % action_plan_uuid)
cls.watcher('audit delete %s' % cls.audit_uuid)
cls.watcher('audittemplate delete %s' % cls.audit_template_name)
@@ -86,51 +76,39 @@ class AuditActiveTests(base.TestCase):
'Deleted At', 'Parameters',
'Interval', 'Audit Scope']
audit_template_name = 'a' + uuidutils.generate_uuid()
@classmethod
def setUpClass(cls):
cls.watcher('audittemplate create %s dummy -s dummy'
% cls.audit_template_name)
@classmethod
def tearDownClass(cls):
cls.watcher('audittemplate delete %s' % cls.audit_template_name)
audit_uuid = None
def _create_audit(self):
return self.parse_show_as_object(
raw_output = self.watcher('audittemplate create %s dummy -s dummy'
% self.audit_template_name)
template_output = self.parse_show_as_object(raw_output)
self.audit_uuid = self.parse_show_as_object(
self.watcher('audit create -a %s'
% self.audit_template_name))['UUID']
% template_output['Name']))['UUID']
def _delete_audit(self, audit_uuid):
self.assertTrue(test_utils.call_until_true(
func=functools.partial(
self.has_audit_created, audit_uuid),
duration=600,
sleep_for=2
))
def _delete_audit(self):
output = self.parse_show(
self.watcher('actionplan list --audit %s' % audit_uuid))
action_plan_uuid = list(output[0])[0]
self.watcher('actionplan list --audit %s' % self.audit_uuid))
action_plan_uuid = output[0].keys()[0]
self.watcher('actionplan delete %s' % action_plan_uuid)
self.watcher('audit delete %s' % audit_uuid)
self.watcher('audit delete %s' % self.audit_uuid)
self.watcher('audittemplate delete %s' % self.audit_template_name)
def test_create_audit(self):
audit = self.watcher('audit create -a %s' % self.audit_template_name)
audit_uuid = self.parse_show_as_object(audit)['UUID']
raw_output = self.watcher('audittemplate create %s dummy -s dummy'
% self.audit_template_name)
template_output = self.parse_show_as_object(raw_output)
audit = self.watcher('audit create -a %s' % template_output['Name'])
self.audit_uuid = self.parse_show_as_object(audit)['UUID']
self.assert_table_structure([audit], self.detailed_list_fields)
self._delete_audit(audit_uuid)
self._delete_audit()
def test_delete_audit(self):
audit_uuid = self._create_audit()
self.assertTrue(test_utils.call_until_true(
func=functools.partial(
self.has_audit_created, audit_uuid),
duration=600,
sleep_for=2
))
raw_output = self.watcher('audit delete %s' % audit_uuid)
self._create_audit()
raw_output = self.watcher('audit delete %s' % self.audit_uuid)
self.assertOutput('', raw_output)
output = self.parse_show(
self.watcher('actionplan list --audit %s' % audit_uuid))
action_plan_uuid = list(output[0])[0]
self.watcher('actionplan list --audit %s' % self.audit_uuid))
action_plan_uuid = output[0].keys()[0]
self.watcher('actionplan delete %s' % action_plan_uuid)
self.watcher('audittemplate delete %s' % self.audit_template_name)

View File

@@ -37,8 +37,6 @@ class ServiceTests(base.TestCase):
self.list_fields + ['Last seen up'])
def test_service_show(self):
# TODO(alexchadin): this method should be refactored since Watcher will
# get HA support soon.
raw_output = self.watcher('service show %s'
% self.decision_engine_name)
self.assertIn(self.decision_engine_name, raw_output)

View File

@@ -38,8 +38,6 @@ ACTION_PLAN2 = {
UPDATED_ACTION_PLAN = copy.deepcopy(ACTION_PLAN1)
NEW_STATE = 'PENDING'
UPDATED_ACTION_PLAN['state'] = NEW_STATE
START_ACTION_PLAN = copy.deepcopy(ACTION_PLAN1)
START_ACTION_PLAN['state'] = NEW_STATE
fake_responses = {
'/v1/action_plans':
@@ -71,13 +69,6 @@ fake_responses = {
UPDATED_ACTION_PLAN,
),
},
'/v1/action_plans/%s/start' % ACTION_PLAN1['uuid']:
{
'POST': (
{},
START_ACTION_PLAN,
),
},
'/v1/action_plans/detail?uuid=%s' % ACTION_PLAN1['uuid']:
{
'GET': (
@@ -229,10 +220,3 @@ class ActionPlanManagerTest(testtools.TestCase):
]
self.assertEqual(expect, self.api.calls)
self.assertEqual(NEW_STATE, action_plan.state)
def test_action_plan_start(self):
action_plan = self.mgr.start(ACTION_PLAN1['uuid'])
expect = [('POST', '/v1/action_plans/%s/start'
% ACTION_PLAN1['uuid'], {}, {})]
self.assertEqual(expect, self.api.calls)
self.assertEqual(NEW_STATE, action_plan.state)

View File

@@ -44,7 +44,6 @@ ACTION_PLAN_1 = {
"description": "Dummy Global Efficacy2"}
],
'deleted_at': None,
'hostname': ''
}
ACTION_PLAN_2 = {
@@ -64,7 +63,6 @@ ACTION_PLAN_2 = {
"description": "Dummy Global Efficacy",
}],
'deleted_at': None,
'hostname': ''
}

View File

@@ -69,7 +69,6 @@ AUDIT_1 = {
'auto_trigger': False,
'next_run_time': None,
'name': 'my_audit1',
'hostname': '',
}
AUDIT_2 = {
@@ -89,7 +88,6 @@ AUDIT_2 = {
'auto_trigger': False,
'next_run_time': None,
'name': 'my_audit2',
'hostname': '',
}
AUDIT_3 = {
@@ -109,7 +107,6 @@ AUDIT_3 = {
'auto_trigger': True,
'next_run_time': None,
'name': 'my_audit3',
'hostname': '',
}

View File

@@ -27,13 +27,8 @@ class ActionPlanManager(base.Manager):
resource_class = ActionPlan
@staticmethod
def _path(id=None, q_param=None):
if id and q_param:
return '/v1/action_plans/%s/%s' % (id, q_param)
elif id:
return '/v1/action_plans/%s' % id
else:
return '/v1/action_plans'
def _path(id=None):
return '/v1/action_plans/%s' % id if id else '/v1/action_plans'
def list(self, audit=None, limit=None, sort_key=None,
sort_dir=None, detail=False, marker=None):
@@ -95,7 +90,8 @@ class ActionPlanManager(base.Manager):
return self._update(self._path(action_plan_id), patch)
def start(self, action_plan_id):
return self._start(self._path(action_plan_id, 'start'))
patch = [{'op': 'replace', 'value': 'PENDING', 'path': '/state'}]
return self._update(self._path(action_plan_id), patch)
def cancel(self, action_plan_id):
action_plan = self.get(action_plan_id)

View File

@@ -28,8 +28,8 @@ from watcherclient.v1 import resource_fields as res_fields
def format_global_efficacy(global_efficacy):
formatted_global_eff = {}
for eff in global_efficacy:
eff_name = eff.get('name')
if (eff.get('value') is not None and eff.get('unit')):
eff_name = eff.get('name')
formatted_global_eff[eff_name] = "%(value).2f %(unit)s" % dict(
unit=eff.get('unit'),
value=eff.get('value'))
@@ -70,7 +70,7 @@ class ShowActionPlan(command.ShowOne):
yaml_format.YAMLFormatter().emit_one(
column_names=list(resource.capitalize()
for resource in formatted_global_efficacy),
data=[value for value in formatted_global_efficacy.values()],
data=[value for value in formatted_global_efficacy.itervalues()],
stdout=out,
parsed_args=parsed_args,
)
@@ -200,6 +200,47 @@ class ListActionPlan(command.Lister):
(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=_('Audit template used for this audit (name or uuid).'))
parser.add_argument(
'-t', '--audit_type',
dest='audit_type',
metavar='<audit_type>',
default='ONESHOT',
choices=['ONESHOT', 'CONTINUOUS'],
help=_("Audit type. It must be ONESHOT or CONTINUOUS. "
"Default is ONESHOT."))
return parser
def take_action(self, parsed_args):
client = getattr(self.app.client_manager, "infra-optim")
field_list = ['audit_template_uuid', 'audit_type']
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."""

View File

@@ -200,10 +200,19 @@ class CreateAudit(command.ShowOne):
if k in field_list and v is not None)
fields = common_utils.args_array_to_dict(fields, 'parameters')
if fields.get('goal'):
if not uuidutils.is_uuid_like(fields['goal']):
fields['goal'] = client.goal.get(fields['goal']).uuid
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
# optional
if fields.get('strategy'):
if not uuidutils.is_uuid_like(fields['strategy']):
fields['strategy'] = client.strategy.get(
fields['strategy']).uuid
audit = client.audit.create(**fields)
if audit.strategy_name is None:

View File

@@ -32,13 +32,12 @@ AUDIT_TEMPLATE_SHORT_LIST_FIELD_LABELS = ['UUID', 'Name', 'Goal', 'Strategy']
# Audit
AUDIT_FIELDS = ['uuid', 'name', 'created_at', 'updated_at', 'deleted_at',
'state', 'audit_type', 'parameters', 'interval', 'goal_name',
'strategy_name', 'scope', 'auto_trigger', 'next_run_time',
'hostname']
'strategy_name', 'scope', 'auto_trigger', 'next_run_time']
AUDIT_FIELD_LABELS = ['UUID', 'Name', 'Created At', 'Updated At', 'Deleted At',
'State', 'Audit Type', 'Parameters', 'Interval', 'Goal',
'Strategy', 'Audit Scope', 'Auto Trigger',
'Next Run Time', 'Hostname']
'Next Run Time']
AUDIT_SHORT_LIST_FIELDS = ['uuid', 'name', 'audit_type',
'state', 'goal_name', 'strategy_name',
@@ -50,12 +49,11 @@ AUDIT_SHORT_LIST_FIELD_LABELS = ['UUID', 'Name', 'Audit Type', 'State', 'Goal',
# Action Plan
ACTION_PLAN_FIELDS = ['uuid', 'created_at', 'updated_at', 'deleted_at',
'audit_uuid', 'strategy_name', 'state',
'efficacy_indicators', 'global_efficacy', 'hostname']
'efficacy_indicators', 'global_efficacy']
ACTION_PLAN_FIELD_LABELS = ['UUID', 'Created At', 'Updated At', 'Deleted At',
'Audit', 'Strategy', 'State',
'Efficacy indicators', 'Global efficacy',
'Hostname']
'Efficacy indicators', 'Global efficacy']
ACTION_PLAN_SHORT_LIST_FIELDS = ['uuid', 'audit_uuid', 'state',
'updated_at', 'global_efficacy']