From a907c2d0cd14b839a895e6652787a5c3e137a367 Mon Sep 17 00:00:00 2001 From: Alexander Chadin Date: Tue, 28 Nov 2017 17:28:54 +0300 Subject: [PATCH] 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 --- setup.cfg | 2 ++ .../tests/functional/v1/test_strategy.py | 7 ++++ watcherclient/tests/unit/v1/test_strategy.py | 14 ++++++++ .../tests/unit/v1/test_strategy_shell.py | 34 +++++++++++++++++++ watcherclient/v1/resource_fields.py | 4 +++ watcherclient/v1/strategy.py | 14 ++++++-- watcherclient/v1/strategy_shell.py | 34 +++++++++++++++++++ 7 files changed, 106 insertions(+), 3 deletions(-) diff --git a/setup.cfg b/setup.cfg index 90d72ef..0fdda87 100644 --- a/setup.cfg +++ b/setup.cfg @@ -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 diff --git a/watcherclient/tests/functional/v1/test_strategy.py b/watcherclient/tests/functional/v1/test_strategy.py index 5a75919..8f87bd4 100644 --- a/watcherclient/tests/functional/v1/test_strategy.py +++ b/watcherclient/tests/functional/v1/test_strategy.py @@ -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) diff --git a/watcherclient/tests/unit/v1/test_strategy.py b/watcherclient/tests/unit/v1/test_strategy.py index a3ed2cd..d6f332e 100644 --- a/watcherclient/tests/unit/v1/test_strategy.py +++ b/watcherclient/tests/unit/v1/test_strategy.py @@ -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) diff --git a/watcherclient/tests/unit/v1/test_strategy_shell.py b/watcherclient/tests/unit/v1/test_strategy_shell.py index dc897e9..2834fe1 100644 --- a/watcherclient/tests/unit/v1/test_strategy_shell.py +++ b/watcherclient/tests/unit/v1/test_strategy_shell.py @@ -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) diff --git a/watcherclient/v1/resource_fields.py b/watcherclient/v1/resource_fields.py index 7d2a1cf..0c5d7f8 100755 --- a/watcherclient/v1/resource_fields.py +++ b/watcherclient/v1/resource_fields.py @@ -99,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'] diff --git a/watcherclient/v1/strategy.py b/watcherclient/v1/strategy.py index f709b85..c464513 100644 --- a/watcherclient/v1/strategy.py +++ b/watcherclient/v1/strategy.py @@ -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)) diff --git a/watcherclient/v1/strategy_shell.py b/watcherclient/v1/strategy_shell.py index edb4e58..7c0161b 100644 --- a/watcherclient/v1/strategy_shell.py +++ b/watcherclient/v1/strategy_shell.py @@ -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='', + 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."""