diff --git a/etc/watcher/watcher.conf.sample b/etc/watcher/watcher.conf.sample index 3728e07f2..e03c4681e 100644 --- a/etc/watcher/watcher.conf.sample +++ b/etc/watcher/watcher.conf.sample @@ -454,8 +454,10 @@ # From watcher # -# Goals used for the optimization (dict value) -#goals = BALANCE_LOAD:basic,MINIMIZE_ENERGY_CONSUMPTION:basic,MINIMIZE_LICENSING_COST:basic,PREPARE_PLANNED_OPERATION:basic,SERVERS_CONSOLIDATION:basic +# Goals used for the optimization. Maps each goal to an associated +# strategy (for example: BASIC_CONSOLIDATION:basic, +# MY_GOAL:my_strategy_1) (dict value) +#goals = DUMMY:dummy [watcher_messaging] diff --git a/setup.cfg b/setup.cfg index ae3f96107..b4d3c576c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -44,8 +44,8 @@ watcher.database.migration_backend = sqlalchemy = watcher.db.sqlalchemy.migration watcher_strategies = - basic = watcher.decision_engine.strategies.basic_consolidation:BasicConsolidation - + dummy = watcher.decision_engine.strategy.dummy_strategy:DummyStrategy + basic = watcher.decision_engine.strategy.basic_consolidation:BasicConsolidation [build_sphinx] source-dir = doc/source diff --git a/watcher/decision_engine/strategy/selector/default.py b/watcher/decision_engine/strategy/selector/default.py index c5f66e990..053e1bcd5 100644 --- a/watcher/decision_engine/strategy/selector/default.py +++ b/watcher/decision_engine/strategy/selector/default.py @@ -16,23 +16,21 @@ from oslo_config import cfg from oslo_log import log +from watcher.common.exception import WatcherException from watcher.decision_engine.strategy.loader import StrategyLoader from watcher.decision_engine.strategy.selector.base import Selector -from watcher.objects.audit_template import Goal - LOG = log.getLogger(__name__) CONF = cfg.CONF -goals = { - 'SERVERS_CONSOLIDATION': 'basic', - 'MINIMIZE_ENERGY_CONSUMPTION': 'basic', - 'BALANCE_LOAD': 'basic', - 'MINIMIZE_LICENSING_COST': 'basic', - 'PREPARE_PLANNED_OPERATION': 'basic' -} +default_goals = {'DUMMY': 'dummy'} + WATCHER_GOALS_OPTS = [ - cfg.DictOpt('goals', - default=goals, help='Goals used for the optimization ') + cfg.DictOpt( + 'goals', + default=default_goals, + help='Goals used for the optimization. ' + 'Maps each goal to an associated strategy (for example: ' + 'BASIC_CONSOLIDATION:basic, MY_GOAL:my_strategy_1)'), ] goals_opt_group = cfg.OptGroup(name='watcher_goals', title='Goals available for the optimization') @@ -46,8 +44,13 @@ class StrategySelector(Selector): self.strategy_loader = StrategyLoader() def define_from_goal(self, goal_name): - if goal_name is None: - goal_name = Goal.SERVERS_CONSOLIDATION - - strategy_to_load = CONF.watcher_goals.goals[goal_name] - return self.strategy_loader.load(strategy_to_load) + strategy_to_load = None + try: + strategy_to_load = CONF.watcher_goals.goals[goal_name] + return self.strategy_loader.load(strategy_to_load) + except KeyError as exc: + LOG.exception(exc) + raise WatcherException( + "Incorrect mapping: could not find " + "associated strategy for '%s'" % goal_name + ) diff --git a/watcher/objects/audit_template.py b/watcher/objects/audit_template.py index 0f3ad5a0b..0fc5d6caf 100644 --- a/watcher/objects/audit_template.py +++ b/watcher/objects/audit_template.py @@ -23,14 +23,6 @@ from watcher.objects import base from watcher.objects import utils as obj_utils -class Goal(object): - SERVERS_CONSOLIDATION = 'SERVERS_CONSOLIDATION' - MINIMIZE_ENERGY_CONSUMPTION = 'MINIMIZE_ENERGY_CONSUMPTION' - BALANCE_LOAD = 'BALANCE_LOAD' - MINIMIZE_LICENSING_COST = 'MINIMIZE_LICENSING_COST' - PREPARE_PLANNED_OPERATION = 'PREPARE_PLANNED_OPERATION' - - class AuditTemplate(base.WatcherObject): # Version 1.0: Initial version VERSION = '1.0' diff --git a/watcher/tests/api/v1/test_audit_templates.py b/watcher/tests/api/v1/test_audit_templates.py index 9dae9a230..10296aabd 100644 --- a/watcher/tests/api/v1/test_audit_templates.py +++ b/watcher/tests/api/v1/test_audit_templates.py @@ -379,7 +379,7 @@ class TestPost(api_base.FunctionalTest): wraps=self.dbapi.create_audit_template ) as cn_mock: audit_template_dict = api_utils.audit_template_post_data( - goal='SERVERS_CONSOLIDATION') + goal='DUMMY') response = self.post_json('/audit_templates', audit_template_dict) self.assertEqual(audit_template_dict['goal'], response.json['goal']) diff --git a/watcher/tests/api/v1/test_goals.py b/watcher/tests/api/v1/test_goals.py index fdf41b59e..b201d2b1a 100644 --- a/watcher/tests/api/v1/test_goals.py +++ b/watcher/tests/api/v1/test_goals.py @@ -20,6 +20,13 @@ class TestListGoal(api_base.FunctionalTest): def setUp(self): super(TestListGoal, self).setUp() + # Override the default to get enough goals to test limit on query + cfg.CONF.set_override( + "goals", { + "DUMMY_1": "dummy", "DUMMY_2": "dummy", + "DUMMY_3": "dummy", "DUMMY_4": "dummy", + }, + group='watcher_goals') def _assert_goal_fields(self, goal): goal_fields = ['name', 'strategy'] @@ -53,11 +60,11 @@ class TestListGoal(api_base.FunctionalTest): self.assertEqual(len(CONF.watcher_goals.goals), len(response['goals'])) - def test_collection_links(self): + def test_goals_collection_links(self): response = self.get_json('/goals/?limit=2') self.assertEqual(2, len(response['goals'])) - def test_collection_links_default_limit(self): + def test_goals_collection_links_default_limit(self): cfg.CONF.set_override('max_limit', 3, 'api') response = self.get_json('/goals') self.assertEqual(3, len(response['goals'])) diff --git a/watcher/tests/db/utils.py b/watcher/tests/db/utils.py index 4bf57197d..6052a1435 100644 --- a/watcher/tests/db/utils.py +++ b/watcher/tests/db/utils.py @@ -21,7 +21,7 @@ def get_test_audit_template(**kwargs): return { 'id': kwargs.get('id', 1), 'uuid': kwargs.get('uuid', 'e74c40e0-d825-11e2-a28f-0800200c9a66'), - 'goal': kwargs.get('goal', 'SERVERS_CONSOLIDATION'), + 'goal': kwargs.get('goal', 'DUMMY'), 'name': kwargs.get('name', 'My Audit Template'), 'description': kwargs.get('description', 'Desc. Of My Audit Template'), 'extra': kwargs.get('extra', {'automatic': False}), diff --git a/watcher/tests/decision_engine/command/test_trigger_audit_command.py b/watcher/tests/decision_engine/command/test_trigger_audit_command.py index d89f4668f..bb81f405b 100644 --- a/watcher/tests/decision_engine/command/test_trigger_audit_command.py +++ b/watcher/tests/decision_engine/command/test_trigger_audit_command.py @@ -36,12 +36,9 @@ class TestTriggerAuditCommand(DbTestCase): audit_template_id=self.audit_template.id) def test_trigger_audit_without_errors(self): - try: - model_collector = FakerModelCollector() - command = TriggerAuditCommand(MagicMock(), model_collector) - command.execute(self.audit.uuid, self.context) - except Exception: - self.fail("The audit should be trigged without error") + model_collector = FakerModelCollector() + command = TriggerAuditCommand(MagicMock(), model_collector) + command.execute(self.audit.uuid, self.context) def test_trigger_audit_state_success(self): model_collector = FakerModelCollector() diff --git a/watcher/tests/decision_engine/strategy/selector/test_strategy_selector.py b/watcher/tests/decision_engine/strategy/selector/test_strategy_selector.py index ed33b6dc0..78268d240 100644 --- a/watcher/tests/decision_engine/strategy/selector/test_strategy_selector.py +++ b/watcher/tests/decision_engine/strategy/selector/test_strategy_selector.py @@ -13,33 +13,37 @@ # implied. # See the License for the specific language governing permissions and # limitations under the License. -import mock +from mock import patch from oslo_config import cfg +from watcher.common.exception import WatcherException from watcher.decision_engine.strategy.loader import StrategyLoader from watcher.decision_engine.strategy.selector.default import StrategySelector -from watcher.objects.audit_template import Goal -from watcher.tests import base - +from watcher.tests.base import TestCase CONF = cfg.CONF -class TestStrategySelector(base.BaseTestCase): +class TestStrategySelector(TestCase): strategy_selector = StrategySelector() - def test_define_from_with_empty(self): - expected_goal = None - expected_strategy = \ - CONF.watcher_goals.goals[Goal.SERVERS_CONSOLIDATION] - with mock.patch.object(StrategyLoader, 'load') as \ - mock_call: - self.strategy_selector.define_from_goal(expected_goal) - mock_call.assert_called_once_with(expected_strategy) - - def test_define_from_goal(self): - expected_goal = Goal.BALANCE_LOAD + @patch.object(StrategyLoader, 'load') + def test_define_from_goal(self, mock_call): + cfg.CONF.set_override( + 'goals', {"DUMMY": "fake"}, group='watcher_goals' + ) + expected_goal = 'DUMMY' expected_strategy = CONF.watcher_goals.goals[expected_goal] - with mock.patch.object(StrategyLoader, 'load') as \ - mock_call: - self.strategy_selector.define_from_goal(expected_goal) - mock_call.assert_called_once_with(expected_strategy) + self.strategy_selector.define_from_goal(expected_goal) + mock_call.assert_called_once_with(expected_strategy) + + @patch.object(StrategyLoader, 'load') + def test_define_from_goal_with_incorrect_mapping(self, mock_call): + cfg.CONF.set_override( + 'goals', {}, group='watcher_goals' + ) + self.assertRaises( + WatcherException, + self.strategy_selector.define_from_goal, + "DUMMY" + ) + self.assertEqual(mock_call.call_count, 0) diff --git a/watcher/tests/decision_engine/test_strategy_loader.py b/watcher/tests/decision_engine/test_strategy_loader.py index c35cead80..9c54b7230 100644 --- a/watcher/tests/decision_engine/test_strategy_loader.py +++ b/watcher/tests/decision_engine/test_strategy_loader.py @@ -21,14 +21,15 @@ from stevedore.extension import Extension from stevedore.extension import ExtensionManager from watcher.decision_engine.strategy.dummy_strategy import DummyStrategy from watcher.decision_engine.strategy.loader import StrategyLoader -from watcher.tests import base +from watcher.tests.base import TestCase -class TestLoader(base.BaseTestCase): +class TestStrategyLoader(TestCase): @patch("watcher.decision_engine.strategy.loader.ExtensionManager") def test_strategy_loader(self, m_extension_manager): dummy_strategy_name = "dummy" + # Set up the fake Stevedore extensions m_extension_manager.return_value = ExtensionManager.make_test_instance( extensions=[Extension( name=dummy_strategy_name, @@ -39,7 +40,13 @@ class TestLoader(base.BaseTestCase): )], namespace="watcher_strategies", ) - # Set up the fake Stevedore extensions + strategy_loader = StrategyLoader() + loaded_strategy = strategy_loader.load("dummy") + + self.assertEqual("dummy", loaded_strategy.name) + self.assertEqual("Dummy Strategy", loaded_strategy.description) + + def test_load_dummy_strategy(self): strategy_loader = StrategyLoader() loaded_strategy = strategy_loader.load("dummy")