Compare commits
21 Commits
queens-eol
...
2.0.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db012f1f8f | ||
|
|
a4c020c19f | ||
|
|
8ef72f18c4 | ||
|
|
673905fead | ||
|
|
d886672fb5 | ||
|
|
83ccfbb177 | ||
|
|
4c47c7364c | ||
|
|
8acf01859c | ||
|
|
d4af8d8834 | ||
|
|
40d8df21c8 | ||
|
|
b87399cb2c | ||
|
|
9bfefbf9ab | ||
|
|
b84039d7d4 | ||
|
|
f8ead12481 | ||
|
|
85e4e364b7 | ||
|
|
ed9ce5b952 | ||
|
|
731e019bc1 | ||
|
|
a22dab5f88 | ||
|
|
0d7233055d | ||
|
|
2777a9bba8 | ||
|
|
e359488cde |
3
.stestr.conf
Normal file
3
.stestr.conf
Normal file
@@ -0,0 +1,3 @@
|
||||
[DEFAULT]
|
||||
test_path=${OS_TEST_PATH:-./watcherclient/tests/functional}
|
||||
top_dir=./
|
||||
@@ -1,8 +1,9 @@
|
||||
- project:
|
||||
name: openstack/python-watcherclient
|
||||
check:
|
||||
jobs:
|
||||
- watcherclient-tempest-functional
|
||||
- openstack-tox-lower-constraints
|
||||
gate:
|
||||
jobs:
|
||||
- watcherclient-tempest-functional
|
||||
- openstack-tox-lower-constraints
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
Team and repository tags
|
||||
========================
|
||||
|
||||
.. image:: https://governance.openstack.org/badges/python-watcherclient.svg
|
||||
:target: https://governance.openstack.org/reference/tags/index.html
|
||||
.. image:: https://governance.openstack.org/tc/badges/python-watcherclient.svg
|
||||
:target: https://governance.openstack.org/tc/reference/tags/index.html
|
||||
|
||||
.. Change things from this point on
|
||||
|
||||
@@ -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
|
||||
|
||||
92
lower-constraints.txt
Normal file
92
lower-constraints.txt
Normal file
@@ -0,0 +1,92 @@
|
||||
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
|
||||
-e git://git.openstack.org/openstack/python-watcherclient@104894958882a4877dad6f469361d2adb41d0b59#egg=python_watcherclient
|
||||
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==1.0.0
|
||||
stevedore==1.28.0
|
||||
tempest==17.1.0
|
||||
testrepository==0.0.18
|
||||
testscenarios==0.4
|
||||
testtools==2.2.0
|
||||
traceback2==1.4.0
|
||||
unittest2==1.1.0
|
||||
urllib3==1.22
|
||||
wrapt==1.10.11
|
||||
@@ -9,6 +9,6 @@ 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
|
||||
keystoneauth1>=3.4.0 # Apache-2.0
|
||||
six>=1.10.0 # MIT
|
||||
PyYAML>=3.10 # MIT
|
||||
PyYAML>=3.12 # MIT
|
||||
|
||||
@@ -25,6 +25,8 @@ 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
|
||||
@@ -52,7 +54,6 @@ 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
|
||||
@@ -89,7 +90,6 @@ 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
|
||||
|
||||
@@ -9,7 +9,7 @@ mock>=2.0.0 # BSD
|
||||
openstackdocstheme>=1.18.1 # Apache-2.0
|
||||
oslotest>=3.2.0 # Apache-2.0
|
||||
python-subunit>=1.0.0 # Apache-2.0/BSD
|
||||
sphinx!=1.6.6,>=1.6.2 # BSD
|
||||
sphinx!=1.6.6,!=1.6.7,>=1.6.2 # BSD
|
||||
testrepository>=0.0.18 # Apache-2.0/BSD
|
||||
testscenarios>=0.4 # Apache-2.0/BSD
|
||||
testtools>=2.2.0 # MIT
|
||||
|
||||
8
tox.ini
8
tox.ini
@@ -60,3 +60,11 @@ 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
|
||||
|
||||
@@ -134,6 +134,11 @@ class Manager(object):
|
||||
def _delete(self, url):
|
||||
self.api.raw_request('DELETE', url)
|
||||
|
||||
def _start(self, url, body=None, method='POST'):
|
||||
resp, body = self.api.json_request(method, url, body={})
|
||||
if body:
|
||||
return self.resource_class(self, body)
|
||||
|
||||
|
||||
class Resource(base.Resource):
|
||||
"""Represents a particular instance of an object (tenant, user, etc).
|
||||
|
||||
23
watcherclient/config.py
Normal file
23
watcherclient/config.py
Normal file
@@ -0,0 +1,23 @@
|
||||
# -*- 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")
|
||||
34
watcherclient/plugin.py
Normal file
34
watcherclient/plugin.py
Normal file
@@ -0,0 +1,34 @@
|
||||
# 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])]
|
||||
@@ -1,53 +0,0 @@
|
||||
#!/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
|
||||
@@ -18,22 +18,31 @@ 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():
|
||||
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'),
|
||||
# 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),
|
||||
'--os-auth-url': os.environ.get('OS_AUTH_URL',
|
||||
'http://10.0.1.94/identity'),
|
||||
'--os-project-domain-id': os.environ.get('OS_PROJECT_DOMAIN_ID',
|
||||
'default'),
|
||||
'--os-user-domain-id': os.environ.get('OS_USER_DOMAIN_ID', 'default'),
|
||||
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),
|
||||
}
|
||||
return [x for sub in creds.items() for x in sub]
|
||||
return [x for sub in creds_dict.items() for x in sub]
|
||||
|
||||
|
||||
def execute(cmd, fail_ok=False, merge_stderr=False):
|
||||
@@ -123,3 +132,13 @@ 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'
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
import functools
|
||||
|
||||
from tempest.lib.common.utils import test_utils
|
||||
|
||||
from watcherclient.tests.functional.v1 import base
|
||||
|
||||
|
||||
@@ -33,17 +37,22 @@ 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_raw_output = cls.watcher(
|
||||
'audit create -a %s' % template_output['Name'])
|
||||
audit_output = cls.parse_show_as_object(audit_raw_output)
|
||||
audit_output = cls.parse_show_as_object(cls.watcher(
|
||||
'audit create -a %s' % template_output['Name']))
|
||||
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 = output[0].keys()[0]
|
||||
action_plan_uuid = list(output[0])[0]
|
||||
raw_output = cls.watcher('actionplan delete %s' % action_plan_uuid)
|
||||
cls.assertOutput('', raw_output)
|
||||
# Delete audit
|
||||
@@ -63,9 +72,10 @@ 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'))
|
||||
action_uuid = action_list[0].keys()[0]
|
||||
action = self.watcher('action show ' + action_uuid)
|
||||
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)
|
||||
self.assertIn(action_uuid, action)
|
||||
self.assert_table_structure([action],
|
||||
self.detailed_list_fields)
|
||||
|
||||
@@ -13,10 +13,12 @@
|
||||
# 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
|
||||
|
||||
|
||||
@@ -39,22 +41,19 @@ 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 = 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
|
||||
action_plan_uuid = list(output[0])[0]
|
||||
raw_output = cls.watcher('actionplan delete %s' % action_plan_uuid)
|
||||
cls.assertOutput('', raw_output)
|
||||
# Delete audit
|
||||
@@ -75,7 +74,7 @@ class ActionPlanTests(base.TestCase):
|
||||
|
||||
def test_action_plan_show(self):
|
||||
action_plan_list = self.parse_show(self.watcher('actionplan list'))
|
||||
action_plan_uuid = action_plan_list[0].keys()[0]
|
||||
action_plan_uuid = list(action_plan_list[0])[0]
|
||||
actionplan = self.watcher('actionplan show %s' % action_plan_uuid)
|
||||
self.assertIn(action_plan_uuid, actionplan)
|
||||
self.assert_table_structure([actionplan],
|
||||
@@ -84,50 +83,14 @@ 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 = output[0].keys()[0]
|
||||
action_plan_uuid = list(output[0])[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)
|
||||
|
||||
|
||||
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()
|
||||
self.assertTrue(test_utils.call_until_true(
|
||||
func=functools.partial(
|
||||
self.has_actionplan_succeeded, action_plan_uuid),
|
||||
duration=600,
|
||||
sleep_for=2
|
||||
))
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
import functools
|
||||
|
||||
from tempest.lib.common.utils import test_utils
|
||||
|
||||
from watcherclient.tests.functional.v1 import base
|
||||
|
||||
|
||||
@@ -39,12 +43,18 @@ 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 = output[0].keys()[0]
|
||||
action_plan_uuid = list(output[0])[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)
|
||||
@@ -76,39 +86,51 @@ class AuditActiveTests(base.TestCase):
|
||||
'Deleted At', 'Parameters',
|
||||
'Interval', 'Audit Scope']
|
||||
audit_template_name = 'a' + uuidutils.generate_uuid()
|
||||
audit_uuid = None
|
||||
|
||||
@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)
|
||||
|
||||
def _create_audit(self):
|
||||
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(
|
||||
return self.parse_show_as_object(
|
||||
self.watcher('audit create -a %s'
|
||||
% template_output['Name']))['UUID']
|
||||
% self.audit_template_name))['UUID']
|
||||
|
||||
def _delete_audit(self):
|
||||
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
|
||||
))
|
||||
output = self.parse_show(
|
||||
self.watcher('actionplan list --audit %s' % self.audit_uuid))
|
||||
action_plan_uuid = output[0].keys()[0]
|
||||
self.watcher('actionplan list --audit %s' % audit_uuid))
|
||||
action_plan_uuid = list(output[0])[0]
|
||||
self.watcher('actionplan delete %s' % action_plan_uuid)
|
||||
self.watcher('audit delete %s' % self.audit_uuid)
|
||||
self.watcher('audittemplate delete %s' % self.audit_template_name)
|
||||
self.watcher('audit delete %s' % audit_uuid)
|
||||
|
||||
def test_create_audit(self):
|
||||
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']
|
||||
audit = self.watcher('audit create -a %s' % self.audit_template_name)
|
||||
audit_uuid = self.parse_show_as_object(audit)['UUID']
|
||||
self.assert_table_structure([audit], self.detailed_list_fields)
|
||||
self._delete_audit()
|
||||
self._delete_audit(audit_uuid)
|
||||
|
||||
def test_delete_audit(self):
|
||||
self._create_audit()
|
||||
raw_output = self.watcher('audit delete %s' % self.audit_uuid)
|
||||
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.assertOutput('', raw_output)
|
||||
output = self.parse_show(
|
||||
self.watcher('actionplan list --audit %s' % self.audit_uuid))
|
||||
action_plan_uuid = output[0].keys()[0]
|
||||
self.watcher('actionplan list --audit %s' % audit_uuid))
|
||||
action_plan_uuid = list(output[0])[0]
|
||||
self.watcher('actionplan delete %s' % action_plan_uuid)
|
||||
self.watcher('audittemplate delete %s' % self.audit_template_name)
|
||||
|
||||
@@ -37,6 +37,8 @@ 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)
|
||||
|
||||
@@ -38,6 +38,8 @@ 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':
|
||||
@@ -69,6 +71,13 @@ 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': (
|
||||
@@ -220,3 +229,10 @@ 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)
|
||||
|
||||
@@ -27,8 +27,13 @@ class ActionPlanManager(base.Manager):
|
||||
resource_class = ActionPlan
|
||||
|
||||
@staticmethod
|
||||
def _path(id=None):
|
||||
return '/v1/action_plans/%s' % id if id else '/v1/action_plans'
|
||||
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 list(self, audit=None, limit=None, sort_key=None,
|
||||
sort_dir=None, detail=False, marker=None):
|
||||
@@ -90,8 +95,7 @@ class ActionPlanManager(base.Manager):
|
||||
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)
|
||||
return self._start(self._path(action_plan_id, 'start'))
|
||||
|
||||
def cancel(self, action_plan_id):
|
||||
action_plan = self.get(action_plan_id)
|
||||
|
||||
@@ -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'))
|
||||
@@ -200,47 +200,6 @@ 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."""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user