Compare commits

...

43 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
Zuul
a1b6eed54c Merge "Add strategy state command" 2018-01-25 20:34:01 +00:00
Alexander Chadin
a907c2d0cd Add strategy state command
This patch set adds command "strategy state"
that allows to request strategy requirements to run.

Partially-Implements: blueprint check-strategy-requirements
Change-Id: I327cc4f5a887f62af700bd646576caa036faaf75
2018-01-24 14:55:01 +00:00
Zuul
d38bb255ed Merge "Updated from global requirements" 2018-01-24 14:03:31 +00:00
Zuul
30e2aad126 Merge "Audit Template Help Message" 2018-01-24 12:37:57 +00:00
OpenStack Proposal Bot
bc0fb4f051 Updated from global requirements
Change-Id: I420d547482d84c9cf8e39e2e2069c46f6d86e993
2018-01-24 01:34:14 +00:00
Zuul
ef533eb151 Merge "Updated from global requirements" 2018-01-22 11:24:34 +00:00
OpenStack Proposal Bot
3c160af376 Updated from global requirements
Change-Id: I65f25febf490e24d2bea4182890400191ce3a16a
I08b68c15c3906885ce3ca6fb410d227c3e585978
2018-01-19 13:50:22 +00:00
OpenStack Proposal Bot
186029ac87 Updated from global requirements
Change-Id: I08b68c15c3906885ce3ca6fb410d227c3e585978
I65f25febf490e24d2bea4182890400191ce3a16a
2018-01-19 12:01:23 +00:00
aditi
b9112a1199 Audit Template Help Message
This patch updates help message of "watcher audittemplate create"
It updates help about storage scoper.

Change-Id: I46be98c2819c2dfb2a7ef3fe1aa98caa90ececfd
Implements: blueprint audit-scoper-for-storage-data-model
2018-01-19 11:16:44 +00:00
Alexander Chadin
9d301fa14a Fix test_action_plan functional tests
Change-Id: Ie5b5bd330c68b696dce48e2475baf77a81f2e8c4
Closes-Bug: #1744262
2018-01-19 13:36:19 +03:00
Zuul
15d7d78b8b Merge "Fix watcher actionplan list command" 2018-01-05 09:25:24 +00:00
OpenStack Proposal Bot
81b84bcff5 Updated from global requirements
Change-Id: I8dcbe4616e7618c783097baecd62f67ef6501e30
2017-12-21 00:47:51 +00:00
Alexander Chadin
79880c2dff Fix watcher actionplan list command
This patch set replaces itervalues() method with values()
to get py3.* compatibility.

Closes-Bug: #1738772
Change-Id: Ie13d15d6f407b08ba087168ac647669c0df2c30a
2017-12-18 15:45:33 +03:00
Zuul
32259fe287 Merge "Fix unnecessary retries during conflict" 2017-12-13 14:24:13 +00:00
Zuul
d36ba79e77 Merge "marker when retrive audit" 2017-12-13 11:43:17 +00:00
Zuul
4f5487b5e1 Merge "Update audit_template create help message" 2017-12-13 10:06:17 +00:00
Zuul
7bf192a981 Merge "marker when retrive action" 2017-12-13 08:36:22 +00:00
Zuul
f8b341c0f3 Merge "marker when retrive audit template" 2017-12-13 05:39:09 +00:00
Zuul
abd6d8a0cb Merge "Updated from global requirements" 2017-12-08 00:51:31 +00:00
Alexander Chadin
147e4cd383 Migrate to Zuul v3
This patch does step 1 in the docs: Move Legacy Jobs to Projects.

Partial-Implements: blueprint migrate-to-zuulv3
Change-Id: I2344ac5b711ba5d723887d225d72a133fa06555c
2017-12-06 12:25:14 +00:00
OpenStack Proposal Bot
3988e9e7a8 Updated from global requirements
Change-Id: I6459fb19ee9b306aa4dde19816318ae2dc71669a
2017-12-05 03:35:50 +00:00
Zuul
88131d19fd Merge "Updated from global requirements" 2017-11-30 14:00:45 +00:00
Zuul
c1668fff44 Merge "Add --marker for 'watcher actionplan list'" 2017-11-30 13:54:39 +00:00
Yumeng Bao
1a6703266f Update audit_template create help message
'id' should be an integer, not string.
Closes-Bug: #1734056
Change-Id: I4275127e7f76ba6ad05f478278204c3de535cf5c
2017-11-28 10:04:16 +08:00
suzhengwei
fada471714 marker when retrive audit
Change-Id: I72078850152e0ccf2abc0d35b06a5142df35c312
2017-11-27 06:56:01 +00:00
suzhengwei
1cd8c38d95 marker when retrive action
Change-Id: Ic733c3e79a31c7cd99226e6e49dfbbc8c3b58902
2017-11-27 06:54:42 +00:00
suzhengwei
0257aa9116 marker when retrive audit template
Change-Id: Ia2cd0598770359c2727ec569dd7f2531f7b5f40a
2017-11-22 13:34:18 +00:00
licanwei
aa9d1a65f6 Add --marker for 'watcher actionplan list'
Change-Id: I88bb986d484198add967cdd953f46e341bf6f9ac
Closes-Bug: #1731826
2017-11-21 18:42:44 -08:00
OpenStack Proposal Bot
b5f584dafa Updated from global requirements
Change-Id: If01512e04786c99347abaaf30715bf1e205d5f55
2017-11-16 11:27:22 +00:00
Zuul
bf706365ea Merge "Updated from global requirements" 2017-11-15 09:59:44 +00:00
Zuul
7898268426 Merge "Multiple global efficacy" 2017-11-15 01:36:32 +00:00
OpenStack Proposal Bot
1eecf8fd63 Updated from global requirements
Change-Id: I489ee3ce735d775108c676342c7ca9239099d5b8
2017-11-15 00:44:21 +00:00
aditi
e6f361804f Multiple global efficacy
This patch adds changes for python-watcherclient for
multiple global efficacy indicator.

Change-Id: I8a7b283f4f79dc5e412fc0addfc4302ae49425ae
Implements: blueprint multiple-global-efficacy-indicator
2017-11-13 10:04:37 +00:00
suzhengwei
f5b2e7e4f5 add name for audit, changes for python-watcherclient
Change-Id: I9000018459913cd3107814e34977525eb3da10f4
Implements:blueprint add-name-for-audit
2017-11-01 02:42:15 +00:00
Zuul
0a29b296ae Merge "Use generic user for both zuul v2 and v3" 2017-10-30 14:26:12 +00:00
Zuul
4789e22e4a Merge "Update audit_template create help message" 2017-10-25 13:40:05 +00:00
aditi
5378102cd6 Fix unnecessary retries during conflict
This patch removes retries from python-watcherclient in case
watcher-api responded with conflict case.

Change-Id: I830abe0a3cd67484e165a0a42d5a57b75ed4dac6
Closes-Bug: #1725088
2017-10-20 02:27:13 +00:00
Nam Nguyen Hoai
42cab67124 Use generic user for both zuul v2 and v3
Zuul v2 uses 'jenkins' as user, but Zuul v3 uses 'zuul'.
Using $USER solves it for both cases.

Change-Id: I42c3328bf7ce5dbb745eb21954bc5528a6befed5
2017-10-17 07:33:36 +00:00
Hidekazu Nakamura
74773a60b2 Update audit_template create help message
Since scoping file format has changed by implementing cdm-scoping,
this patch updates audit_template create help message
about scoping file example.

Partially-Implements blueprint cdm-scoping

Change-Id: Ia9c4c23b5f6c4d99d59305297ea3c7aa9dcfbc94
2017-10-10 11:55:20 +00:00
35 changed files with 586 additions and 133 deletions

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

17
.zuul.yaml Normal file
View File

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

View File

@@ -68,7 +68,7 @@ Once you have an watcher `Client`_, you can perform various tasks::
>>> watcher.action.list() # list of actions
>>> watcher.action_plan.list() # list of action_plan
>>> watcher.audit.get(audit_uuid) # information about a particular audit
>>> watcher.audit.get(audit_uuid_or_name) # information about a particular audit
When the `Client`_ needs to propagate an exception, it will usually
raise an instance subclassed from

View File

@@ -4,11 +4,11 @@
Babel!=2.4.0,>=2.3.4 # BSD
cliff!=2.9.0,>=2.8.0 # Apache-2.0
osc-lib>=1.7.0 # Apache-2.0
osc-lib>=1.8.0 # Apache-2.0
oslo.i18n>=3.15.3 # Apache-2.0
oslo.utils>=3.28.0 # 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.2.0 # Apache-2.0
six>=1.9.0 # MIT
keystoneauth1>=3.3.0 # Apache-2.0
six>=1.10.0 # MIT
PyYAML>=3.10 # MIT

View File

@@ -36,6 +36,7 @@ openstack.infra_optim.v1 =
optimize_strategy_show = watcherclient.v1.strategy_shell:ShowStrategy
optimize_strategy_list = watcherclient.v1.strategy_shell:ListStrategy
optimize_strategy_state = watcherclient.v1.strategy_shell:StateStrategy
optimize_audittemplate_show = watcherclient.v1.audit_template_shell:ShowAuditTemplate
optimize_audittemplate_list = watcherclient.v1.audit_template_shell:ListAuditTemplate
@@ -72,6 +73,7 @@ watcherclient.v1 =
strategy_show = watcherclient.v1.strategy_shell:ShowStrategy
strategy_list = watcherclient.v1.strategy_shell:ListStrategy
strategy_state = watcherclient.v1.strategy_shell:StateStrategy
audittemplate_show = watcherclient.v1.audit_template_shell:ShowAuditTemplate
audittemplate_list = watcherclient.v1.audit_template_shell:ListAuditTemplate

View File

@@ -6,14 +6,14 @@ coverage!=4.4,>=4.0 # Apache-2.0
fixtures>=3.0.0 # Apache-2.0/BSD
hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0
mock>=2.0.0 # BSD
openstackdocstheme>=1.17.0 # Apache-2.0
oslotest>=1.10.0 # Apache-2.0
python-subunit>=0.0.18 # Apache-2.0/BSD
sphinx>=1.6.2 # BSD
openstackdocstheme>=1.18.1 # Apache-2.0
oslotest>=3.2.0 # Apache-2.0
python-subunit>=1.0.0 # Apache-2.0/BSD
sphinx!=1.6.6,>=1.6.2 # BSD
testrepository>=0.0.18 # Apache-2.0/BSD
testscenarios>=0.4 # Apache-2.0/BSD
testtools>=1.4.0 # MIT
tempest>=16.1.0 # Apache-2.0
testtools>=2.2.0 # MIT
tempest>=17.1.0 # Apache-2.0
# Needed for pypi packaging
wheel>=0.24.0 # MIT

View File

@@ -6,7 +6,7 @@ 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}

View File

@@ -165,8 +165,7 @@ class VersionNegotiationMixin(object):
raise NotImplementedError()
_RETRY_EXCEPTIONS = (exceptions.Conflict,
exceptions.ServiceUnavailable,
_RETRY_EXCEPTIONS = (exceptions.ServiceUnavailable,
exceptions.ConnectionRefused,
kexceptions.RetriableConnectionFailure)

View File

@@ -161,17 +161,21 @@ def common_params_for_list(args, fields, field_labels):
args.sort_dir)
params['sort_dir'] = args.sort_dir
marker = getattr(args, 'marker', None)
if marker is not None:
params['marker'] = marker
params['detail'] = args.detail
return params
def common_filters(limit=None, sort_key=None, sort_dir=None):
def common_filters(limit=None, sort_key=None, sort_dir=None, marker=None):
"""Generate common filters for any list request.
:param limit: maximum number of entities to return.
:param sort_key: field to use for sorting.
:param sort_dir: direction of sorting: 'asc' or 'desc'.
:param marker: The last actionplan UUID of the previous page.
:returns: list of string filters.
"""
filters = []
@@ -181,6 +185,8 @@ def common_filters(limit=None, sort_key=None, sort_dir=None):
filters.append('sort_key=%s' % sort_key)
if sort_dir is not None:
filters.append('sort_dir=%s' % sort_dir)
if marker is not None:
filters.append('marker=%s' % marker)
return filters

View File

@@ -24,14 +24,14 @@ function generate_testr_results {
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 jenkins:jenkins $BASE/logs/testrepository.subunit.gz $BASE/logs/testr_results.html.gz
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 jenkins:stack $WATCHERCLIENT_DIR
sudo chown -R $USER:stack $WATCHERCLIENT_DIR
# Get admin credentials
cd $STACK_DIR
@@ -44,7 +44,7 @@ cd $WATCHERCLIENT_DIR
echo "Running watcherclient functional test suite"
set +e
# Preserve env for OS_ credentials
sudo -E -H -u jenkins tox -efunctional
sudo -E -H -u $USER tox -efunctional
EXIT_CODE=$?
set -e

View File

@@ -13,6 +13,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import time
from oslo_utils import uuidutils
from watcherclient.tests.functional.v1 import base
@@ -44,6 +46,15 @@ class ActionPlanTests(base.TestCase):
output = cls.parse_show(
cls.watcher('actionplan list --audit %s' % cls.audit_uuid))
action_plan_uuid = output[0].keys()[0]
retry = 10
while retry > 0:
output = cls.parse_show(
cls.watcher('actionplan show %s' % action_plan_uuid))
state = [x for x in output if x.keys()[0] == 'State'][0]['State']
if state == 'SUCCEEDED':
break
time.sleep(1)
retry -= 1
raw_output = cls.watcher('actionplan delete %s' % action_plan_uuid)
cls.assertOutput('', raw_output)
# Delete audit

View File

@@ -22,7 +22,7 @@ class AuditTests(base.TestCase):
"""Functional tests for audit."""
dummy_name = 'dummy'
list_fields = ['UUID', 'Audit Type', 'State', 'Goal', 'Strategy']
list_fields = ['UUID', 'Name', 'Audit Type', 'State', 'Goal', 'Strategy']
detailed_list_fields = list_fields + ['Created At', 'Updated At',
'Deleted At', 'Parameters',
'Interval', 'Audit Scope',
@@ -71,7 +71,7 @@ class AuditTests(base.TestCase):
class AuditActiveTests(base.TestCase):
list_fields = ['UUID', 'Audit Type', 'State', 'Goal', 'Strategy']
list_fields = ['UUID', 'Name', 'Audit Type', 'State', 'Goal', 'Strategy']
detailed_list_fields = list_fields + ['Created At', 'Updated At',
'Deleted At', 'Parameters',
'Interval', 'Audit Scope']

View File

@@ -20,7 +20,9 @@ class StrategyTests(base.TestCase):
"""Functional tests for strategy."""
dummy_name = 'dummy'
basic_strategy = 'basic'
list_fields = ['UUID', 'Name', 'Display name', 'Goal']
state_fields = ['Datasource', 'Metrics', 'CDM', 'Name']
def test_strategy_list(self):
raw_output = self.watcher('strategy list')
@@ -39,3 +41,8 @@ class StrategyTests(base.TestCase):
self.assert_table_structure([raw_output],
self.list_fields + ['Parameters spec'])
self.assertNotIn('basic', raw_output)
def test_strategy_state(self):
raw_output = self.watcher('strategy state %s' % self.basic_strategy)
self.assertIn(self.basic_strategy, raw_output)
self.assert_table_structure([raw_output], self.state_fields)

View File

@@ -97,7 +97,8 @@ class UtilsTest(test_utils.BaseTestCase):
class CommonParamsForListTest(test_utils.BaseTestCase):
def setUp(self):
super(CommonParamsForListTest, self).setUp()
self.args = mock.Mock(limit=None, sort_key=None, sort_dir=None)
self.args = mock.Mock(limit=None, marker=None,
sort_key=None, sort_dir=None)
self.args.detail = False
self.expected_params = {'detail': False}
@@ -117,6 +118,13 @@ class CommonParamsForListTest(test_utils.BaseTestCase):
utils.common_params_for_list,
self.args, [], [])
def test_marker(self):
self.args.marker = 'e420a881-d7df-4de2-bbf3-378cc13d9b3a'
self.expected_params.update(
{'marker': 'e420a881-d7df-4de2-bbf3-378cc13d9b3a'})
self.assertEqual(self.expected_params,
utils.common_params_for_list(self.args, [], []))
def test_sort_key_and_sort_dir(self):
self.args.sort_key = 'field'
self.args.sort_dir = 'desc'

View File

@@ -144,6 +144,16 @@ fake_responses_sorting = {
},
}
fake_responses_marker = {
'/v1/actions/?marker=770ef053-ecb3-48b0-85b5-d55a2dbc6588':
{
'GET': (
{},
{"actions": [ACTION2, ACTION3]}
),
},
}
class ActionManagerTest(testtools.TestCase):
@@ -231,6 +241,20 @@ class ActionManagerTest(testtools.TestCase):
self.assertEqual(expect, self.api.calls)
self.assertEqual(3, len(actions))
def test_actions_list_marker(self):
self.api = utils.FakeAPI(fake_responses_marker)
self.mgr = watcherclient.v1.action.ActionManager(self.api)
actions = self.mgr.list(
marker='770ef053-ecb3-48b0-85b5-d55a2dbc6588')
expect = [
('GET',
'/v1/actions/?marker=770ef053-ecb3-48b0-85b5-d55a2dbc6588',
{},
None)
]
self.assertEqual(expect, self.api.calls)
self.assertEqual(2, len(actions))
def test_actions_show(self):
action = self.mgr.get(ACTION1['uuid'])
expect = [

View File

@@ -94,6 +94,13 @@ fake_responses_pagination = {
{"action_plans": [ACTION_PLAN2]}
),
},
'/v1/action_plans/?marker=f8e47706-efcf-49a4-a5c4-af604eb492f2':
{
'GET': (
{},
{"action_plans": [ACTION_PLAN2]}
),
},
}
fake_responses_sorting = {
@@ -158,6 +165,19 @@ class ActionPlanManagerTest(testtools.TestCase):
self.assertEqual(expect, self.api.calls)
self.assertThat(action_plans, matchers.HasLength(2))
def test_action_plans_list_marker(self):
self.api = utils.FakeAPI(fake_responses_pagination)
self.mgr = watcherclient.v1.action_plan.ActionPlanManager(self.api)
action_plans = self.mgr.list(
marker='f8e47706-efcf-49a4-a5c4-af604eb492f2')
expect = [
('GET', '/v1/action_plans/?'
'marker=f8e47706-efcf-49a4-a5c4-af604eb492f2',
{}, None),
]
self.assertEqual(expect, self.api.calls)
self.assertThat(action_plans, matchers.HasLength(1))
def test_action_plans_list_sort_key(self):
self.api = utils.FakeAPI(fake_responses_sorting)
self.mgr = watcherclient.v1.action_plan.ActionPlanManager(self.api)

View File

@@ -33,12 +33,16 @@ ACTION_PLAN_1 = {
'unit': '%'}],
'created_at': datetime.datetime.now().isoformat(),
'updated_at': None,
'global_efficacy': {
"value": 99,
"unit": "%",
"name": "dummy_global_efficacy",
"description": "Dummy Global Efficacy",
},
'global_efficacy': [
{"value": 99,
"unit": "%",
"name": "dummy_global_efficacy",
"description": "Dummy Global Efficacy"},
{"value": 75,
"unit": "%",
"name": "dummy_global_efficacy2",
"description": "Dummy Global Efficacy2"}
],
'deleted_at': None,
}
@@ -52,12 +56,12 @@ ACTION_PLAN_2 = {
'name': 'indicator2',
'unit': '%'}],
'updated_at': None,
'global_efficacy': {
'global_efficacy': [{
"value": 87,
"unit": "%",
"name": "dummy_global_efficacy",
"description": "Dummy Global Efficacy",
},
}],
'deleted_at': None,
}
@@ -69,6 +73,7 @@ class ActionPlanShellTest(base.CommandTestCase):
resource_fields.ACTION_PLAN_SHORT_LIST_FIELD_LABELS)
FIELDS = resource_fields.ACTION_PLAN_FIELDS
FIELD_LABELS = resource_fields.ACTION_PLAN_FIELD_LABELS
GLOBAL_EFFICACY_FIELDS = resource_fields.GLOBAL_EFFICACY_FIELDS
def setUp(self):
super(self.__class__, self).setUp()
@@ -114,6 +119,11 @@ class ActionPlanShellTest(base.CommandTestCase):
self.SHORT_LIST_FIELD_LABELS)],
results)
self.assertEqual(action_plan1.global_efficacy,
results[0]['Global efficacy'])
self.assertEqual(action_plan2.global_efficacy,
results[1]['Global efficacy'])
self.m_action_plan_mgr.list.assert_called_once_with(detail=False)
def test_do_action_plan_list_detail(self):
@@ -131,6 +141,10 @@ class ActionPlanShellTest(base.CommandTestCase):
self.resource_as_dict(action_plan2, self.FIELDS,
self.FIELD_LABELS)],
results)
self.assertEqual(action_plan1.global_efficacy,
results[0]['Global efficacy'])
self.assertEqual(action_plan2.global_efficacy,
results[1]['Global efficacy'])
self.m_action_plan_mgr.list.assert_called_once_with(detail=True)
@@ -165,6 +179,8 @@ class ActionPlanShellTest(base.CommandTestCase):
self.resource_as_dict(
action_plan, self.FIELDS, self.FIELD_LABELS),
result)
self.assertEqual(action_plan.global_efficacy,
result['Global efficacy'])
self.m_action_plan_mgr.get.assert_called_once_with(
'd9d9978e-6db5-4a05-8eab-1531795d7004')

21
watcherclient/tests/unit/v1/test_action_shell.py Executable file → Normal file
View File

@@ -132,6 +132,27 @@ class ActionShellTest(base.CommandTestCase):
self.m_action_mgr.list.assert_called_once_with(detail=True)
def test_do_action_list_marker(self):
action2 = resource.Action(mock.Mock(), ACTION_2)
action3 = resource.Action(mock.Mock(), ACTION_3)
self.m_action_mgr.list.return_value = [
action2, action3]
exit_code, results = self.run_cmd(
'action list --marker 770ef053-ecb3-48b0-85b5-d55a2dbc6588')
self.assertEqual(0, exit_code)
self.assertEqual(
[self.resource_as_dict(action2, self.SHORT_LIST_FIELDS,
self.SHORT_LIST_FIELD_LABELS),
self.resource_as_dict(action3, self.SHORT_LIST_FIELDS,
self.SHORT_LIST_FIELD_LABELS)],
results)
self.m_action_mgr.list.assert_called_once_with(
detail=False,
marker='770ef053-ecb3-48b0-85b5-d55a2dbc6588')
def test_do_action_show_by_uuid(self):
action = resource.Action(mock.Mock(), ACTION_1)
self.m_action_mgr.get.return_value = action

View File

@@ -145,6 +145,16 @@ fake_responses_strategy = {
},
}
fake_responses_marker = {
'/v1/audits/?marker=5869da81-4876-4687-a1ed-12cd64cf53d9':
{
'GET': (
{},
{"audits": [AUDIT2]}
),
},
}
class AuditManagerTest(testtools.TestCase):
def setUp(self):
@@ -229,6 +239,17 @@ class AuditManagerTest(testtools.TestCase):
self.assertEqual(expect, self.api.calls)
self.assertEqual(1, len(audits))
def test_audits_list_marker(self):
self.api = utils.FakeAPI(fake_responses_marker)
self.mgr = watcherclient.v1.audit.AuditManager(self.api)
audits = self.mgr.list(marker=AUDIT1['uuid'])
expect = [
('GET', '/v1/audits/?marker=5869da81-4876-4687-a1ed-12cd64cf53d9',
{}, None),
]
self.assertEqual(expect, self.api.calls)
self.assertEqual(1, len(audits))
def test_audits_show(self):
audit = self.mgr.get(AUDIT1['uuid'])
expect = [

111
watcherclient/tests/unit/v1/test_audit_shell.py Normal file → Executable file
View File

@@ -17,7 +17,6 @@ import datetime
import mock
import six
from watcherclient import exceptions
from watcherclient import shell
from watcherclient.tests.unit.v1 import base
from watcherclient import v1 as resource
@@ -69,6 +68,7 @@ AUDIT_1 = {
'scope': '',
'auto_trigger': False,
'next_run_time': None,
'name': 'my_audit1',
}
AUDIT_2 = {
@@ -87,6 +87,7 @@ AUDIT_2 = {
'scope': '',
'auto_trigger': False,
'next_run_time': None,
'name': 'my_audit2',
}
AUDIT_3 = {
@@ -105,6 +106,7 @@ AUDIT_3 = {
'scope': '',
'auto_trigger': True,
'next_run_time': None,
'name': 'my_audit3',
}
@@ -170,6 +172,23 @@ class AuditShellTest(base.CommandTestCase):
self.m_audit_mgr.list.assert_called_once_with(detail=False)
def test_do_audit_list_marker(self):
audit2 = resource.Audit(mock.Mock(), AUDIT_2)
self.m_audit_mgr.list.return_value = [audit2]
exit_code, results = self.run_cmd(
'audit list --marker 5869da81-4876-4687-a1ed-12cd64cf53d9')
self.assertEqual(0, exit_code)
self.assertEqual(
[self.resource_as_dict(audit2, self.SHORT_LIST_FIELDS,
self.SHORT_LIST_FIELD_LABELS)],
results)
self.m_audit_mgr.list.assert_called_once_with(
detail=False,
marker='5869da81-4876-4687-a1ed-12cd64cf53d9')
def test_do_audit_list_detail(self):
audit1 = resource.Audit(mock.Mock(), AUDIT_1)
audit2 = resource.Audit(mock.Mock(), AUDIT_2)
@@ -202,14 +221,19 @@ class AuditShellTest(base.CommandTestCase):
self.m_audit_mgr.get.assert_called_once_with(
'5869da81-4876-4687-a1ed-12cd64cf53d9')
def test_do_audit_show_by_not_uuid(self):
self.m_audit_mgr.get.side_effect = exceptions.HTTPNotFound
def test_do_audit_show_by_name(self):
audit = resource.Audit(mock.Mock(), AUDIT_1)
self.m_audit_mgr.get.return_value = audit
exit_code, result = self.run_cmd(
'audit show not_uuid', formatting=None)
'audit show my_audit')
self.assertEqual(1, exit_code)
self.assertEqual('', result)
self.assertEqual(0, exit_code)
self.assertEqual(
self.resource_as_dict(audit, self.FIELDS, self.FIELD_LABELS),
result)
self.m_audit_mgr.get.assert_called_once_with(
'my_audit')
def test_do_audit_delete(self):
self.m_audit_mgr.delete.return_value = ''
@@ -223,6 +247,18 @@ class AuditShellTest(base.CommandTestCase):
self.m_audit_mgr.delete.assert_called_once_with(
'5869da81-4876-4687-a1ed-12cd64cf53d9')
def test_do_audit_delete_by_name(self):
self.m_audit_mgr.delete.return_value = ''
exit_code, result = self.run_cmd(
'audit delete my_audit',
formatting=None)
self.assertEqual(0, exit_code)
self.assertEqual('', result)
self.m_audit_mgr.delete.assert_called_once_with(
'my_audit')
def test_do_audit_delete_multiple(self):
self.m_audit_mgr.delete.return_value = ''
@@ -238,16 +274,6 @@ class AuditShellTest(base.CommandTestCase):
self.m_audit_mgr.delete.assert_any_call(
'5b157edd-5a7e-4aaa-b511-f7b33ec86e9f')
def test_do_audit_delete_with_not_uuid(self):
self.m_audit_mgr.delete.return_value = ''
exit_code, result = self.run_cmd(
'audit delete not_uuid',
formatting=None)
self.assertEqual(1, exit_code)
self.assertEqual('', result)
def test_do_audit_update(self):
audit = resource.Audit(mock.Mock(), AUDIT_1)
self.m_audit_mgr.update.return_value = audit
@@ -264,14 +290,20 @@ class AuditShellTest(base.CommandTestCase):
'5869da81-4876-4687-a1ed-12cd64cf53d9',
[{'op': 'replace', 'path': '/state', 'value': 'PENDING'}])
def test_do_audit_update_with_not_uuid(self):
self.m_audit_mgr.update.return_value = ''
def test_do_audit_update_by_name(self):
audit = resource.Audit(mock.Mock(), AUDIT_1)
self.m_audit_mgr.update.return_value = audit
exit_code, result = self.run_cmd(
'audit update not_uuid replace state=PENDING', formatting=None)
'audit update my_audit replace state=PENDING')
self.assertEqual(1, exit_code)
self.assertEqual('', result)
self.assertEqual(0, exit_code)
self.assertEqual(
self.resource_as_dict(audit, self.FIELDS, self.FIELD_LABELS),
result)
self.m_audit_mgr.update.assert_called_once_with(
'my_audit',
[{'op': 'replace', 'path': '/state', 'value': 'PENDING'}])
def test_do_audit_create_with_audit_template_uuid(self):
audit = resource.Audit(mock.Mock(), AUDIT_3)
@@ -288,7 +320,9 @@ class AuditShellTest(base.CommandTestCase):
result)
self.m_audit_mgr.create.assert_called_once_with(
audit_template_uuid='f8e47706-efcf-49a4-a5c4-af604eb492f2',
audit_type='ONESHOT', auto_trigger=False)
audit_type='ONESHOT',
auto_trigger=False
)
def test_do_audit_create_with_audit_template_name(self):
audit = resource.Audit(mock.Mock(), AUDIT_3)
@@ -305,7 +339,8 @@ class AuditShellTest(base.CommandTestCase):
self.m_audit_mgr.create.assert_called_once_with(
audit_template_uuid='f8e47706-efcf-49a4-a5c4-af604eb492f2',
auto_trigger=False,
audit_type='ONESHOT')
audit_type='ONESHOT'
)
def test_do_audit_create_with_goal(self):
audit = resource.Audit(mock.Mock(), AUDIT_1)
@@ -356,7 +391,9 @@ class AuditShellTest(base.CommandTestCase):
result)
self.m_audit_mgr.create.assert_called_once_with(
goal='fc087747-61be-4aad-8126-b701731ae836',
auto_trigger=False, audit_type='ONESHOT')
auto_trigger=False,
audit_type='ONESHOT'
)
def test_do_audit_create_with_parameter(self):
audit = resource.Audit(mock.Mock(), AUDIT_1)
@@ -374,7 +411,8 @@ class AuditShellTest(base.CommandTestCase):
goal='fc087747-61be-4aad-8126-b701731ae836',
audit_type='ONESHOT',
auto_trigger=False,
parameters={'para1': 10, 'para2': 20})
parameters={'para1': 10, 'para2': 20}
)
def test_do_audit_create_with_type_continuous(self):
audit = resource.Audit(mock.Mock(), AUDIT_1)
@@ -392,4 +430,25 @@ class AuditShellTest(base.CommandTestCase):
goal='fc087747-61be-4aad-8126-b701731ae836',
audit_type='CONTINUOUS',
auto_trigger=False,
interval='3600')
interval='3600'
)
def test_do_audit_create_with_name(self):
audit = resource.Audit(mock.Mock(), AUDIT_1)
self.m_audit_mgr.create.return_value = audit
exit_code, result = self.run_cmd(
'audit create -g fc087747-61be-4aad-8126-b701731ae836 '
'-t CONTINUOUS -i 3600 --name my_audit')
self.assertEqual(0, exit_code)
self.assertEqual(
self.resource_as_dict(audit, self.FIELDS, self.FIELD_LABELS),
result)
self.m_audit_mgr.create.assert_called_once_with(
goal='fc087747-61be-4aad-8126-b701731ae836',
audit_type='CONTINUOUS',
auto_trigger=False,
interval='3600',
name='my_audit'
)

View File

@@ -178,6 +178,16 @@ fake_responses_sorting = {
},
}
fake_responses_marker = {
'/v1/audit_templates/?marker=f8e47706-efcf-49a4-a5c4-af604eb492f2':
{
'GET': (
{},
{"audit_templates": [AUDIT_TMPL2, AUDIT_TMPL3]}
),
},
}
fake_responses_filter_by_goal_uuid = {
'/v1/audit_templates/?goal=e75ee410-b32b-465f-88b5-4397705f9473':
{
@@ -389,6 +399,18 @@ class AuditTemplateManagerTest(utils.BaseTestCase):
self.assertEqual(expect, self.api.calls)
self.assertEqual(3, len(audit_templates))
def test_audit_templates_list_marker(self):
self.api = utils.FakeAPI(fake_responses_marker)
self.mgr = watcherclient.v1.audit_template.AuditTemplateManager(
self.api)
audit_templates = self.mgr.list(marker=AUDIT_TMPL1['uuid'])
expect_url = '/v1/audit_templates/?marker=%s' % AUDIT_TMPL1['uuid']
expect = [
('GET', expect_url, {}, None)
]
self.assertEqual(expect, self.api.calls)
self.assertEqual(2, len(audit_templates))
def test_audit_templates_show(self):
audit_template = self.mgr.get(AUDIT_TMPL1['uuid'])
expect = [

View File

@@ -128,6 +128,24 @@ class AuditTemplateShellTest(base.CommandTestCase):
self.m_audit_template_mgr.list.assert_called_once_with(detail=False)
def test_do_audit_template_list_marker(self):
audit_template2 = resource.AuditTemplate(mock.Mock(), AUDIT_TEMPLATE_2)
self.m_audit_template_mgr.list.return_value = [audit_template2]
exit_code, results = self.run_cmd(
'audittemplate list --marker '
'f8e47706-efcf-49a4-a5c4-af604eb492f2')
self.assertEqual(0, exit_code)
self.assertEqual(
[self.resource_as_dict(audit_template2, self.SHORT_LIST_FIELDS,
self.SHORT_LIST_FIELD_LABELS)],
results)
self.m_audit_template_mgr.list.assert_called_once_with(
detail=False,
marker='f8e47706-efcf-49a4-a5c4-af604eb492f2')
def test_do_audit_template_list_detail(self):
audit_template1 = resource.AuditTemplate(mock.Mock(), AUDIT_TEMPLATE_1)
audit_template2 = resource.AuditTemplate(mock.Mock(), AUDIT_TEMPLATE_2)

View File

@@ -63,6 +63,13 @@ fake_responses = {
STRATEGY1,
),
},
'/v1/strategies/%s/state' % STRATEGY1['name']:
{
'GET': (
{},
STRATEGY1,
),
},
}
fake_responses_pagination = {
@@ -180,3 +187,10 @@ class StrategyManagerTest(testtools.TestCase):
]
self.assertEqual(expect, self.api.calls)
self.assertEqual(STRATEGY1['name'], strategy.name)
def test_strategies_state(self):
self.mgr.state(STRATEGY1['name'])
expect = [
('GET', '/v1/strategies/%s/state' % STRATEGY1['name'], {}, None),
]
self.assertEqual(expect, self.api.calls)

View File

@@ -17,6 +17,8 @@ import datetime
import mock
import six
from oslo_serialization import jsonutils
from watcherclient import shell
from watcherclient.tests.unit.v1 import base
from watcherclient import v1 as resource
@@ -54,6 +56,8 @@ class StrategyShellTest(base.CommandTestCase):
resource_fields.STRATEGY_SHORT_LIST_FIELD_LABELS)
FIELDS = resource_fields.STRATEGY_FIELDS
FIELD_LABELS = resource_fields.STRATEGY_FIELD_LABELS
STATE_FIELDS = resource_fields.STRATEGY_STATE_FIELDS
STATE_FIELD_LABELS = resource_fields.STRATEGY_STATE_FIELD_LABELS
def setUp(self):
super(self.__class__, self).setUp()
@@ -155,3 +159,33 @@ class StrategyShellTest(base.CommandTestCase):
result)
self.m_strategy_mgr.get.assert_called_once_with(
'f8e47706-efcf-49a4-a5c4-af604eb492f2')
def test_do_strategy_state(self):
strategy1 = resource.Strategy(mock.Mock(), STRATEGY_1)
strategy_req = [
{'type': 'Datasource', 'mandatory': True,
'comment': '', 'state': 'gnocchi: True'},
{'type': 'Metrics', 'mandatory': False,
'comment': '', 'state': jsonutils.dumps([
{'compute.node.cpu.percent': 'available'},
{'cpu_util': 'available'},
{'memory.resident': 'available'},
{'hardware.memory.used': 'not available'}])},
{'type': 'CDM', 'mandatory': True,
'comment': '',
'state': jsonutils.dumps([{'compute_model': 'available'},
{'storage_model': 'not available'}])},
{'type': 'Name', 'mandatory': '', 'comment': '',
'state': strategy1.name}]
requirements = [resource.Strategy(mock.Mock(), req)
for req in strategy_req]
self.m_strategy_mgr.state.return_value = requirements
exit_code, results = self.run_cmd('strategy state basic')
self.assertEqual(0, exit_code)
self.assertEqual(
[self.resource_as_dict(req, self.STATE_FIELDS,
self.STATE_FIELD_LABELS)
for req in requirements],
results)

View File

@@ -30,7 +30,7 @@ class ActionManager(base.Manager):
return '/v1/actions/%s' % id if id else '/v1/actions'
def list(self, action_plan=None, audit=None, limit=None, sort_key=None,
sort_dir=None, detail=False):
sort_dir=None, detail=False, marker=None):
"""Retrieve a list of action.
:param action_plan: UUID of the action plan
@@ -52,13 +52,15 @@ class ActionManager(base.Manager):
:param detail: Optional, boolean whether to return detailed information
about actions.
:param marker: Optional, UUID of the last action in the previous page.
:returns: A list of actions.
"""
if limit is not None:
limit = int(limit)
filters = utils.common_filters(limit, sort_key, sort_dir)
filters = utils.common_filters(limit, sort_key, sort_dir, marker)
if action_plan is not None:
filters.append('action_plan_uuid=%s' % action_plan)
if audit is not None:

View File

@@ -31,7 +31,7 @@ class ActionPlanManager(base.Manager):
return '/v1/action_plans/%s' % id if id else '/v1/action_plans'
def list(self, audit=None, limit=None, sort_key=None,
sort_dir=None, detail=False):
sort_dir=None, detail=False, marker=None):
"""Retrieve a list of action plan.
:param audit: Name of the audit
@@ -52,13 +52,16 @@ class ActionPlanManager(base.Manager):
:param detail: Optional, boolean whether to return detailed information
about action plans.
:param marker: The last actionplan UUID of the previous page;
displays list of actionplans after "marker".
:returns: A list of action plans.
"""
if limit is not None:
limit = int(limit)
filters = utils.common_filters(limit, sort_key, sort_dir)
filters = utils.common_filters(limit, sort_key, sort_dir, marker)
if audit is not None:
filters.append('audit_uuid=%s' % audit)

View File

@@ -26,16 +26,16 @@ from watcherclient.v1 import resource_fields as res_fields
def format_global_efficacy(global_efficacy):
formatted_global_efficacy = None
if (global_efficacy.get('value') is not None and
global_efficacy.get('unit')):
formatted_global_efficacy = "%(value).2f %(unit)s" % dict(
unit=global_efficacy.get('unit'),
value=global_efficacy.get('value'))
elif global_efficacy.get('value') is not None:
formatted_global_efficacy = global_efficacy.get('value')
return formatted_global_efficacy
formatted_global_eff = {}
for eff in global_efficacy:
if (eff.get('value') is not None and eff.get('unit')):
eff_name = eff.get('name')
formatted_global_eff[eff_name] = "%(value).2f %(unit)s" % dict(
unit=eff.get('unit'),
value=eff.get('value'))
elif eff.get('value') is not None:
formatted_global_eff[eff_name] = eff.get('value')
return formatted_global_eff
class ShowActionPlan(command.ShowOne):
@@ -64,6 +64,18 @@ class ShowActionPlan(command.ShowOne):
)
return out.getvalue() or ''
def _format_global_efficacy(self, global_efficacy, parsed_args):
formatted_global_efficacy = format_global_efficacy(global_efficacy)
out = six.StringIO()
yaml_format.YAMLFormatter().emit_one(
column_names=list(resource.capitalize()
for resource in formatted_global_efficacy),
data=[value for value in formatted_global_efficacy.itervalues()],
stdout=out,
parsed_args=parsed_args,
)
return out.getvalue() or ''
def take_action(self, parsed_args):
client = getattr(self.app.client_manager, "infra-optim")
@@ -83,8 +95,8 @@ class ShowActionPlan(command.ShowOne):
self._format_indicators(action_plan, parsed_args))
# Update the raw global efficacy with the formatted one
action_plan.global_efficacy = format_global_efficacy(
action_plan.global_efficacy)
action_plan.global_efficacy = self._format_global_efficacy(
action_plan.global_efficacy, parsed_args)
columns = res_fields.ACTION_PLAN_FIELDS
column_headers = res_fields.ACTION_PLAN_FIELD_LABELS
@@ -113,6 +125,11 @@ class ListActionPlan(command.Lister):
help=_('Maximum number of action plans to return per request, '
'0 for no limit. Default is the maximum number used '
'by the Watcher API Service.'))
parser.add_argument(
'--marker',
metavar='<actionplan>',
help=_('The last actionplan UUID of the previous page; '
'displays list of actionplans after "marker".'))
parser.add_argument(
'--sort-key',
metavar='<field>',
@@ -139,6 +156,18 @@ class ListActionPlan(command.Lister):
)
return out.getvalue() or ''
def _format_global_efficacy(self, global_efficacy, parsed_args):
formatted_global_efficacy = format_global_efficacy(global_efficacy)
out = six.StringIO()
yaml_format.YAMLFormatter().emit_one(
column_names=list(resource.capitalize()
for resource in formatted_global_efficacy),
data=[value for value in formatted_global_efficacy.values()],
stdout=out,
parsed_args=parsed_args,
)
return out.getvalue() or ''
def take_action(self, parsed_args):
client = getattr(self.app.client_manager, "infra-optim")
@@ -164,8 +193,8 @@ class ListActionPlan(command.Lister):
self._format_indicators(action_plan, parsed_args))
# Update the raw global efficacy with the formatted one
action_plan.global_efficacy = format_global_efficacy(
action_plan.global_efficacy)
action_plan.global_efficacy = self._format_global_efficacy(
action_plan.global_efficacy, parsed_args)
return (field_labels,
(utils.get_item_properties(item, fields) for item in data))

View File

@@ -83,6 +83,13 @@ class ListAction(command.Lister):
metavar='<direction>',
choices=['asc', 'desc'],
help=_('Sort direction: "asc" (the default) or "desc".'))
parser.add_argument(
'--marker',
dest='marker',
metavar='<marker>',
default=None,
help=_('UUID of the last action in the previous page; '
'displays list of actions after "marker".'))
return parser

View File

@@ -19,7 +19,8 @@ from watcherclient import exceptions as exc
CREATION_ATTRIBUTES = ['audit_template_uuid', 'audit_type', 'interval',
'parameters', 'goal', 'strategy', 'auto_trigger']
'parameters', 'goal', 'strategy', 'auto_trigger',
'name']
class Audit(base.Resource):
@@ -35,11 +36,11 @@ class AuditManager(base.Manager):
return '/v1/audits/%s' % id if id else '/v1/audits'
def list(self, audit_template=None, limit=None, sort_key=None,
sort_dir=None, detail=False, goal=None, strategy=None):
sort_dir=None, detail=False, goal=None, strategy=None,
marker=None):
"""Retrieve a list of audit.
:param audit_template: Name of the audit
:param name: Name of the audit
:param audit_template: Name of the audit template
:param limit: The maximum number of results to return per
request, if:
@@ -57,13 +58,15 @@ class AuditManager(base.Manager):
:param detail: Optional, boolean whether to return detailed information
about audits.
:param marker: Optional, UUID of the last audit in the previous page.
:returns: A list of audits.
"""
if limit is not None:
limit = int(limit)
filters = utils.common_filters(limit, sort_key, sort_dir)
filters = utils.common_filters(limit, sort_key, sort_dir, marker)
if audit_template is not None:
filters.append('audit_template=%s' % audit_template)
if goal is not None:
@@ -92,14 +95,14 @@ class AuditManager(base.Manager):
raise exc.InvalidAttribute()
return self._create(self._path(), new)
def get(self, audit_id):
def get(self, audit):
try:
return self._list(self._path(audit_id))[0]
return self._list(self._path(audit))[0]
except IndexError:
return None
def delete(self, audit_id):
return self._delete(self._path(audit_id))
def delete(self, audit):
return self._delete(self._path(audit))
def update(self, audit_id, patch):
return self._update(self._path(audit_id), patch)
def update(self, audit, patch):
return self._update(self._path(audit), patch)

View File

@@ -31,7 +31,7 @@ class ShowAudit(command.ShowOne):
parser.add_argument(
'audit',
metavar='<audit>',
help=_('UUID of the audit'),
help=_('UUID or name of the audit'),
)
return parser
@@ -88,6 +88,13 @@ class ListAudit(command.Lister):
metavar='<direction>',
choices=['asc', 'desc'],
help=_('Sort direction: "asc" (the default) or "desc".'))
parser.add_argument(
'--marker',
dest='marker',
metavar='<marker>',
default=None,
help=_('UUID of the last audit in the previous page; '
'displays list of audits after "marker".'))
return parser
@@ -175,13 +182,19 @@ class CreateAudit(command.ShowOne):
default=False,
help=_('Trigger automatically action plan '
'once audit is succeeded.'))
parser.add_argument(
'--name',
dest='name',
metavar='<name>',
help=_('Name for this audit.'))
return parser
def take_action(self, parsed_args):
client = getattr(self.app.client_manager, "infra-optim")
field_list = ['audit_template_uuid', 'audit_type', 'parameters',
'interval', 'goal', 'strategy', 'auto_trigger']
'interval', 'goal', 'strategy', 'auto_trigger', 'name']
fields = dict((k, v) for (k, v) in vars(parsed_args).items()
if k in field_list and v is not None)
@@ -219,7 +232,7 @@ class UpdateAudit(command.ShowOne):
parser.add_argument(
'audit',
metavar='<audit>',
help=_("UUID of the audit."))
help=_("UUID or name of the audit."))
parser.add_argument(
'op',
metavar='<op>',
@@ -239,9 +252,6 @@ class UpdateAudit(command.ShowOne):
def take_action(self, parsed_args):
client = getattr(self.app.client_manager, "infra-optim")
if not uuidutils.is_uuid_like(parsed_args.audit):
raise exceptions.ValidationError()
patch = common_utils.args_array_to_patch(
parsed_args.op, parsed_args.attributes[0],
exclude_fields=['/interval'])
@@ -263,7 +273,7 @@ class DeleteAudit(command.Command):
'audits',
metavar='<audit>',
nargs='+',
help=_('UUID of the audit'),
help=_('UUID or name of the audit'),
)
return parser
@@ -271,7 +281,4 @@ class DeleteAudit(command.Command):
client = getattr(self.app.client_manager, "infra-optim")
for audit in parsed_args.audits:
if not uuidutils.is_uuid_like(audit):
raise exceptions.ValidationError()
client.audit.delete(audit)

View File

@@ -33,7 +33,7 @@ class AuditTemplateManager(base.Manager):
return '/v1/audit_templates/%s' % id_ if id_ else '/v1/audit_templates'
def list(self, name=None, goal=None, strategy=None, limit=None,
sort_key=None, sort_dir=None, detail=False):
sort_key=None, sort_dir=None, detail=False, marker=None):
"""Retrieve a list of audit template.
:param name: Name of the audit template
@@ -54,13 +54,16 @@ class AuditTemplateManager(base.Manager):
:param detail: Optional, boolean whether to return detailed information
about audit_templates.
:param marker: Optional, UUID of the last audit template of
the previous page.
:returns: A list of audit templates.
"""
if limit is not None:
limit = int(limit)
filters = utils.common_filters(limit, sort_key, sort_dir)
filters = utils.common_filters(limit, sort_key, sort_dir, marker)
if name is not None:
filters.append('name=%s' % name)
if goal is not None:

View File

@@ -91,6 +91,13 @@ class ListAuditTemplate(command.Lister):
metavar='<direction>',
choices=['asc', 'desc'],
help=_('Sort direction: "asc" (the default) or "desc".'))
parser.add_argument(
'--marker',
dest='marker',
metavar='<marker>',
default=None,
help=_('UUID of the last audit template of the previous page; '
'displays list of audit templates after "marker".'))
return parser
@@ -162,37 +169,81 @@ class CreateAuditTemplate(command.ShowOne):
"Can be provided either in yaml or json file.\n"
"YAML example:\n"
"---\n"
" - host_aggregates:\n"
" - id: 1\n"
" - id: 2\n"
" - id: 3\n"
" - availability_zones:\n"
" - name: AZ1\n"
" - name: AZ2\n"
" - exclude:\n"
" - instances:\n"
" - uuid: UUID1\n"
" - uuid: UUID2\n"
" - compute_nodes:\n"
" - name: compute1\n"
" - compute:\n"
" - host_aggregates:\n"
" - id: 1\n"
" - id: 2\n"
" - id: 3\n"
" - availability_zones:\n"
" - name: AZ1\n"
" - name: AZ2\n"
" - exclude:\n"
" - instances:\n"
" - uuid: UUID1\n"
" - uuid: UUID2\n"
" - compute_nodes:\n"
" - name: compute1\n"
" - storage: \n"
" - availability_zones:\n"
" - name: AZ1\n"
" - name: AZ2\n"
" - volume_types:\n"
" - name: lvm1\n"
" - name: lvm2\n"
" - exclude:\n"
" - storage_pools:\n"
" - name: host0@backend0#pool0\n"
" - name: host1@backend1#pool1\n"
" - volumes:\n"
" - uuid: UUID1\n"
" - uuid: UUID2\n"
" - projects:\n"
" - uuid: UUID1\n"
" - uuid: UUID2\n"
"\n"
"JSON example:\n"
"[{'host_aggregates': [\n"
" {'id': 1},\n"
" {'id': 2},\n"
" {'id': 3}]},\n"
" {'availability_zones': [\n"
" {'name': 'AZ1'},\n"
" {'name': 'AZ2'}]},\n"
" {'exclude': [\n"
" {'instances': [\n"
" {'uuid': 'UUID1'},\n"
" {'uuid': 'UUID2'}\n"
" ]},\n"
" {'compute_nodes': [\n"
" {'name': 'compute1'}\n"
" ]}\n"
"]}]\n"
"[\n"
" {\"compute\":\n"
" [{\"host_aggregates\": [\n"
" {\"id\": 1},\n"
" {\"id\": 2},\n"
" {\"id\": 3}]},\n"
" {\"availability_zones\": [\n"
" {\"name\": \"AZ1\"},\n"
" {\"name\": \"AZ2\"}]},\n"
" {\"exclude\": [\n"
" {\"instances\": [\n"
" {\"uuid\": \"UUID1\"},\n"
" {\"uuid\": \"UUID2\"}\n"
" ]},\n"
" {\"compute_nodes\": [\n"
" {\"name\": \"compute1\"}\n"
" ]}\n"
" ]}]\n"
" },\n"
" {\"storage\":\n"
" [{\"availability_zones\": [\n"
" {\"name\": \"AZ1\"},\n"
" {\"name\": \"AZ2\"}]},\n"
" {\"volume_types\": [\n"
" {\"name\": \"lvm1\"},\n"
" {\"name\": \"lvm2\"}]},\n"
" {\"exclude\": [\n"
" {\"storage_pools\": [\n"
" {\"name\": \"host0@backend0#pool0\"},\n"
" {\"name\": \"host1@backend1#pool1\"}\n"
" ]},\n"
" {\"volumes\": [\n"
" {\"uuid\": \"UUID1\"},\n"
" {\"uuid\": \"UUID2\"}\n"
" ]},\n"
" {\"projects\": [\n"
" {\"uuid\": \"UUID1\"},\n"
" {\"uuid\": \"UUID2\"}\n"
" ]},\n"
" ]}]\n"
" }\n"
" ]\n"
)
)

View File

@@ -30,20 +30,20 @@ AUDIT_TEMPLATE_SHORT_LIST_FIELDS = [
AUDIT_TEMPLATE_SHORT_LIST_FIELD_LABELS = ['UUID', 'Name', 'Goal', 'Strategy']
# Audit
AUDIT_FIELDS = ['uuid', 'created_at', 'updated_at', 'deleted_at',
AUDIT_FIELDS = ['uuid', 'name', 'created_at', 'updated_at', 'deleted_at',
'state', 'audit_type', 'parameters', 'interval', 'goal_name',
'strategy_name', 'scope', 'auto_trigger', 'next_run_time']
AUDIT_FIELD_LABELS = ['UUID', 'Created At', 'Updated At', 'Deleted At',
AUDIT_FIELD_LABELS = ['UUID', 'Name', 'Created At', 'Updated At', 'Deleted At',
'State', 'Audit Type', 'Parameters', 'Interval', 'Goal',
'Strategy', 'Audit Scope', 'Auto Trigger',
'Next Run Time']
AUDIT_SHORT_LIST_FIELDS = ['uuid', 'audit_type',
AUDIT_SHORT_LIST_FIELDS = ['uuid', 'name', 'audit_type',
'state', 'goal_name', 'strategy_name',
'auto_trigger']
AUDIT_SHORT_LIST_FIELD_LABELS = ['UUID', 'Audit Type', 'State', 'Goal',
AUDIT_SHORT_LIST_FIELD_LABELS = ['UUID', 'Name', 'Audit Type', 'State', 'Goal',
'Strategy', 'Auto Trigger']
# Action Plan
@@ -61,6 +61,8 @@ ACTION_PLAN_SHORT_LIST_FIELDS = ['uuid', 'audit_uuid', 'state',
ACTION_PLAN_SHORT_LIST_FIELD_LABELS = ['UUID', 'Audit', 'State',
'Updated At', 'Global efficacy']
GLOBAL_EFFICACY_FIELDS = ['value', 'unit', 'name', 'description']
# Action
ACTION_FIELDS = ['uuid', 'created_at', 'updated_at', 'deleted_at', 'parents',
'state', 'action_plan_uuid', 'action_type',
@@ -97,6 +99,10 @@ STRATEGY_SHORT_LIST_FIELDS = ['uuid', 'name', 'display_name', 'goal_name']
STRATEGY_SHORT_LIST_FIELD_LABELS = ['UUID', 'Name', 'Display name', 'Goal']
STRATEGY_STATE_FIELDS = ['type', 'state', 'mandatory', 'comment']
STRATEGY_STATE_FIELD_LABELS = ['Type', 'State', 'Mandatory', 'Comment']
# Metric Collector
METRIC_COLLECTOR_FIELDS = ['uuid', 'created_at', 'updated_at', 'deleted_at',
'endpoint', 'category']

View File

@@ -28,9 +28,14 @@ class StrategyManager(base.Manager):
resource_class = Strategy
@staticmethod
def _path(strategy=None):
return ('/v1/strategies/%s' % strategy
if strategy else '/v1/strategies')
def _path(strategy=None, state=False):
if strategy:
path = '/v1/strategies/%s' % strategy
if state:
path = '/v1/strategies/%s/state' % strategy
else:
path = '/v1/strategies'
return path
def list(self, goal=None, limit=None, sort_key=None,
sort_dir=None, detail=False):
@@ -82,3 +87,6 @@ class StrategyManager(base.Manager):
return self._list(self._path(strategy))[0]
except IndexError:
return None
def state(self, strategy):
return self._list(self._path(strategy, state=True))

View File

@@ -57,6 +57,40 @@ class ShowStrategy(command.ShowOne):
return column_headers, utils.get_item_properties(strategy, columns)
class StateStrategy(command.Lister):
"""Retrieve information about strategy requirements."""
def get_parser(self, prog_name):
parser = super(StateStrategy, self).get_parser(prog_name)
parser.add_argument(
'strategy',
metavar='<strategy>',
help=_('Name of the strategy'),
)
return parser
def _format_spec(self, requirements):
for req in requirements:
if type(req.state) == list:
req.state = jsonutils.dumps(req.state, indent=2)
return requirements
def take_action(self, parsed_args):
client = getattr(self.app.client_manager, "infra-optim")
try:
requirements = client.strategy.state(parsed_args.strategy)
except exceptions.HTTPNotFound as exc:
raise exceptions.CommandError(str(exc))
requirements = self._format_spec(requirements)
columns = res_fields.STRATEGY_STATE_FIELDS
column_headers = res_fields.STRATEGY_STATE_FIELD_LABELS
return (column_headers,
(utils.get_item_properties(item, columns)
for item in requirements))
class ListStrategy(command.Lister):
"""List information on retrieved strategies."""