Compare commits

..

39 Commits
1.4.0 ... 1.6.0

Author SHA1 Message Date
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
33 changed files with 574 additions and 131 deletions

8
.zuul.yaml Normal file
View File

@@ -0,0 +1,8 @@
- project:
name: openstack/python-watcherclient
check:
jobs:
- watcherclient-tempest-functional
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

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