From 62570525add64e2eb87e6e1d9eb3bb643e1acb9d Mon Sep 17 00:00:00 2001 From: Jean-Emile DARTOIS Date: Thu, 10 Dec 2015 09:34:38 +0100 Subject: [PATCH] Tidy up - Watcher Decision Engine package Some Python class and packages need to be renamed for a better compliance with the shared terminology which provides a better understanding of Watcher objects and components by every contributor. This patchset is there to change the code structure by adding the folder "strategies" and "loading". Partially implements: blueprint glossary-related-refactoring Change-Id: I56fb24ee6762b3186eccde5983233e17bb227cc1 --- setup.cfg | 4 +- watcher/api/app.py | 2 +- watcher/decision_engine/actions/base.py | 4 +- .../strategy/{selector => common}/__init__.py | 0 .../strategy/{ => common}/level.py | 0 .../strategy/context/default.py | 2 +- .../strategy/loading/__init__.py | 0 .../decision_engine/strategy/loading/base.py | 43 +++++++++++++++++++ .../{loader.py => loading/default.py} | 21 +++------ .../strategy/selection/__init__.py | 0 .../strategy/{selector => selection}/base.py | 0 .../{selector => selection}/default.py | 9 ++-- .../strategy/strategies/__init__.py | 0 .../strategy/{ => strategies}/base.py | 6 +-- .../{ => strategies}/basic_consolidation.py | 24 +++++------ .../{ => strategies}/dummy_strategy.py | 2 +- watcher/opts.py | 2 +- .../command/test_trigger_audit_command.py | 5 +-- .../messaging/test_audit_endpoint.py | 2 +- .../decision_engine/model/test_mapping.py | 17 ++++---- .../tests/decision_engine/model/test_model.py | 6 +-- .../loading/test_default_strategy_loader.py} | 38 +++++++++++----- .../selector/test_strategy_selector.py | 11 +++-- .../strategy/strategies/__init__.py | 0 .../strategies}/faker_cluster_state.py | 33 ++------------ .../strategies}/faker_metrics_collector.py | 0 .../strategies}/test_basic_consolidation.py | 22 +++++----- .../strategies}/test_dummy_strategy.py | 9 ++-- .../strategy/test_strategy_loader.py | 37 ---------------- .../decision_engine/test_default_planner.py | 14 +++--- 30 files changed, 153 insertions(+), 160 deletions(-) rename watcher/decision_engine/strategy/{selector => common}/__init__.py (100%) rename watcher/decision_engine/strategy/{ => common}/level.py (100%) create mode 100644 watcher/decision_engine/strategy/loading/__init__.py create mode 100644 watcher/decision_engine/strategy/loading/base.py rename watcher/decision_engine/strategy/{loader.py => loading/default.py} (68%) create mode 100644 watcher/decision_engine/strategy/selection/__init__.py rename watcher/decision_engine/strategy/{selector => selection}/base.py (100%) rename watcher/decision_engine/strategy/{selector => selection}/default.py (89%) create mode 100644 watcher/decision_engine/strategy/strategies/__init__.py rename watcher/decision_engine/strategy/{ => strategies}/base.py (96%) rename watcher/decision_engine/strategy/{ => strategies}/basic_consolidation.py (96%) rename watcher/decision_engine/strategy/{ => strategies}/dummy_strategy.py (93%) rename watcher/tests/decision_engine/{test_strategy_loader.py => strategy/loading/test_default_strategy_loader.py} (58%) create mode 100644 watcher/tests/decision_engine/strategy/strategies/__init__.py rename watcher/tests/decision_engine/{ => strategy/strategies}/faker_cluster_state.py (92%) rename watcher/tests/decision_engine/{ => strategy/strategies}/faker_metrics_collector.py (100%) rename watcher/tests/decision_engine/{ => strategy/strategies}/test_basic_consolidation.py (94%) rename watcher/tests/decision_engine/{ => strategy/strategies}/test_dummy_strategy.py (76%) delete mode 100644 watcher/tests/decision_engine/strategy/test_strategy_loader.py diff --git a/setup.cfg b/setup.cfg index 2723ef010..2e658cfd7 100644 --- a/setup.cfg +++ b/setup.cfg @@ -42,8 +42,8 @@ watcher.database.migration_backend = sqlalchemy = watcher.db.sqlalchemy.migration watcher_strategies = - dummy = watcher.decision_engine.strategy.dummy_strategy:DummyStrategy - basic = watcher.decision_engine.strategy.basic_consolidation:BasicConsolidation + dummy = watcher.decision_engine.strategy.strategies.dummy_strategy:DummyStrategy + basic = watcher.decision_engine.strategy.strategies.basic_consolidation:BasicConsolidation [build_sphinx] source-dir = doc/source diff --git a/watcher/api/app.py b/watcher/api/app.py index f109ec816..3d1054f6e 100644 --- a/watcher/api/app.py +++ b/watcher/api/app.py @@ -22,7 +22,7 @@ import pecan from watcher.api import acl from watcher.api import config as api_config from watcher.api import middleware -from watcher.decision_engine.strategy.selector import default \ +from watcher.decision_engine.strategy.selection import default \ as strategy_selector # Register options for the service diff --git a/watcher/decision_engine/actions/base.py b/watcher/decision_engine/actions/base.py index c4c3c1153..deb2b79e8 100644 --- a/watcher/decision_engine/actions/base.py +++ b/watcher/decision_engine/actions/base.py @@ -17,9 +17,9 @@ # limitations under the License. # import abc -import six -from watcher.decision_engine.strategy.level import StrategyLevel +import six +from watcher.decision_engine.strategy.common.level import StrategyLevel @six.add_metaclass(abc.ABCMeta) diff --git a/watcher/decision_engine/strategy/selector/__init__.py b/watcher/decision_engine/strategy/common/__init__.py similarity index 100% rename from watcher/decision_engine/strategy/selector/__init__.py rename to watcher/decision_engine/strategy/common/__init__.py diff --git a/watcher/decision_engine/strategy/level.py b/watcher/decision_engine/strategy/common/level.py similarity index 100% rename from watcher/decision_engine/strategy/level.py rename to watcher/decision_engine/strategy/common/level.py diff --git a/watcher/decision_engine/strategy/context/default.py b/watcher/decision_engine/strategy/context/default.py index 49318c026..3455500ad 100644 --- a/watcher/decision_engine/strategy/context/default.py +++ b/watcher/decision_engine/strategy/context/default.py @@ -17,7 +17,7 @@ from oslo_log import log from watcher.decision_engine.planner.default import DefaultPlanner from watcher.decision_engine.strategy.context.base import BaseStrategyContext -from watcher.decision_engine.strategy.selector.default import StrategySelector +from watcher.decision_engine.strategy.selection.default import StrategySelector LOG = log.getLogger(__name__) diff --git a/watcher/decision_engine/strategy/loading/__init__.py b/watcher/decision_engine/strategy/loading/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/watcher/decision_engine/strategy/loading/base.py b/watcher/decision_engine/strategy/loading/base.py new file mode 100644 index 000000000..775f84399 --- /dev/null +++ b/watcher/decision_engine/strategy/loading/base.py @@ -0,0 +1,43 @@ +# -*- encoding: utf-8 -*- +# Copyright (c) 2015 b<>com +# +# Authors: Jean-Emile DARTOIS +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import abc +from oslo_log import log +import six + +LOG = log.getLogger(__name__) + + +@six.add_metaclass(abc.ABCMeta) +class BaseStrategyLoader(object): + @abc.abstractmethod + def load_available_strategies(self): + raise NotImplementedError() # pragma:no cover + + def load(self, strategy_to_load=None): + strategy_selected = None + try: + available_strategies = self.load_available_strategies() + strategy_cls = available_strategies.get( + strategy_to_load, self.default_strategy_cls + ) + strategy_selected = strategy_cls() + except Exception as exc: + LOG.exception(exc) + + return strategy_selected diff --git a/watcher/decision_engine/strategy/loader.py b/watcher/decision_engine/strategy/loading/default.py similarity index 68% rename from watcher/decision_engine/strategy/loader.py rename to watcher/decision_engine/strategy/loading/default.py index aac47d89b..357bda229 100644 --- a/watcher/decision_engine/strategy/loader.py +++ b/watcher/decision_engine/strategy/loading/default.py @@ -21,32 +21,21 @@ from __future__ import unicode_literals from oslo_log import log from stevedore import ExtensionManager -from watcher.decision_engine.strategy.basic_consolidation import \ + +from watcher.decision_engine.strategy.loading.base import BaseStrategyLoader +from watcher.decision_engine.strategy.strategies.basic_consolidation import \ BasicConsolidation LOG = log.getLogger(__name__) -class StrategyLoader(object): +class DefaultStrategyLoader(BaseStrategyLoader): default_strategy_cls = BasicConsolidation - def load_strategies(self): + def load_available_strategies(self): extension_manager = ExtensionManager( namespace='watcher_strategies', invoke_on_load=True, ) return {ext.name: ext.plugin for ext in extension_manager.extensions} - - def load(self, model): - strategy = None - try: - available_strategies = self.load_strategies() - strategy_cls = available_strategies.get( - model, self.default_strategy_cls - ) - strategy = strategy_cls() - except Exception as exc: - LOG.exception(exc) - - return strategy diff --git a/watcher/decision_engine/strategy/selection/__init__.py b/watcher/decision_engine/strategy/selection/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/watcher/decision_engine/strategy/selector/base.py b/watcher/decision_engine/strategy/selection/base.py similarity index 100% rename from watcher/decision_engine/strategy/selector/base.py rename to watcher/decision_engine/strategy/selection/base.py diff --git a/watcher/decision_engine/strategy/selector/default.py b/watcher/decision_engine/strategy/selection/default.py similarity index 89% rename from watcher/decision_engine/strategy/selector/default.py rename to watcher/decision_engine/strategy/selection/default.py index 46e86d9f0..e22d79224 100644 --- a/watcher/decision_engine/strategy/selector/default.py +++ b/watcher/decision_engine/strategy/selection/default.py @@ -16,9 +16,12 @@ 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 BaseSelector +from watcher.decision_engine.strategy.loading.default import \ + DefaultStrategyLoader +from watcher.decision_engine.strategy.selection.base import BaseSelector + LOG = log.getLogger(__name__) CONF = cfg.CONF @@ -41,7 +44,7 @@ CONF.register_opts(WATCHER_GOALS_OPTS, goals_opt_group) class StrategySelector(BaseSelector): def __init__(self): - self.strategy_loader = StrategyLoader() + self.strategy_loader = DefaultStrategyLoader() def define_from_goal(self, goal_name): strategy_to_load = None diff --git a/watcher/decision_engine/strategy/strategies/__init__.py b/watcher/decision_engine/strategy/strategies/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/watcher/decision_engine/strategy/base.py b/watcher/decision_engine/strategy/strategies/base.py similarity index 96% rename from watcher/decision_engine/strategy/base.py rename to watcher/decision_engine/strategy/strategies/base.py index 46c9563c3..5fd7a1ff0 100644 --- a/watcher/decision_engine/strategy/base.py +++ b/watcher/decision_engine/strategy/strategies/base.py @@ -16,12 +16,12 @@ import abc from oslo_log import log - import six -from watcher.decision_engine.solution.default import DefaultSolution -from watcher.decision_engine.strategy.level import StrategyLevel +from watcher.decision_engine.solution.default import DefaultSolution +from watcher.decision_engine.strategy.common.level import StrategyLevel + LOG = log.getLogger(__name__) diff --git a/watcher/decision_engine/strategy/basic_consolidation.py b/watcher/decision_engine/strategy/strategies/basic_consolidation.py similarity index 96% rename from watcher/decision_engine/strategy/basic_consolidation.py rename to watcher/decision_engine/strategy/strategies/basic_consolidation.py index b493a9cf5..4e268baca 100644 --- a/watcher/decision_engine/strategy/basic_consolidation.py +++ b/watcher/decision_engine/strategy/strategies/basic_consolidation.py @@ -28,8 +28,8 @@ from watcher.decision_engine.model.hypervisor_state import HypervisorState from watcher.decision_engine.model.power_state import PowerState from watcher.decision_engine.model.resource import ResourceType from watcher.decision_engine.model.vm_state import VMState -from watcher.decision_engine.strategy.base import BaseStrategy -from watcher.decision_engine.strategy.level import StrategyLevel +from watcher.decision_engine.strategy.common.level import StrategyLevel +from watcher.decision_engine.strategy.strategies.base import BaseStrategy from watcher.metrics_engine.cluster_history.ceilometer import \ CeilometerClusterHistory @@ -53,12 +53,12 @@ class BasicConsolidation(BaseStrategy): and often tend to migrate from one physical machine to another. Hence, the traditional and offline heuristics such as bin packing are not applicable for the placement VM in cloud computing. - So, the decision Engine optimizer provide placement strategy considering + So, the decision Engine optimizer provides placement strategy considering not only the performance effects but also the workload characteristics of VMs and others metrics like the power consumption and the tenants constraints (SLAs). - The watcher optimizer use an online VM placement technique + The watcher optimizer uses an online VM placement technique based on machine learning and meta-heuristics that must handle : - multi-objectives - Contradictory objectives @@ -121,9 +121,9 @@ class BasicConsolidation(BaseStrategy): vm_to_mig): '''check if the migration is possible - :param model: current state of the cluster - :param src_hypervisor: the current of the virtual machine - :param dest_hypervisor:the destination of the virtual machine + :param model: the current state of the cluster + :param src_hypervisor: the current node of the virtual machine + :param dest_hypervisor: the destination of the virtual machine :param vm_to_mig: the virtual machine :return: True if the there is enough place otherwise false ''' @@ -167,7 +167,7 @@ class BasicConsolidation(BaseStrategy): """Check threshold check the threshold value defined by the ratio of - aggregated CPU capacity of VMS on one node to CPU capacity + aggregated CPU capacity of VMs on one node to CPU capacity of this node must not exceed the threshold value. :param dest_hypervisor: :param total_cores @@ -213,7 +213,7 @@ class BasicConsolidation(BaseStrategy): def calculate_weight(self, model, element, total_cores_used, total_disk_used, total_memory_used): - """Calculate weight of every + """Calculate weight of every resource :param model: :param element: @@ -248,7 +248,7 @@ class BasicConsolidation(BaseStrategy): return (score_cores + score_disk + score_memory) / 3 def calculate_score_node(self, hypervisor, model): - """calculate the score that reprensent the utilization level + """calculate the score that represent the utilization level :param hypervisor: :param model: @@ -331,7 +331,7 @@ class BasicConsolidation(BaseStrategy): model))) def execute(self, orign_model): - LOG.debug("initialize Sercon Consolidation") + LOG.debug("Initialize Sercon Consolidation") if orign_model is None: raise ClusterStateNotDefined() @@ -411,7 +411,7 @@ class BasicConsolidation(BaseStrategy): vm_score.append( (vm_id, self.calculate_score_vm(vm, current_model))) - ''' sort VM's by Score ''' + ''' sort VMs by Score ''' v = sorted(vm_score, reverse=True, key=lambda x: (x[1])) LOG.debug("VM(s) BFD {0}".format(v)) diff --git a/watcher/decision_engine/strategy/dummy_strategy.py b/watcher/decision_engine/strategy/strategies/dummy_strategy.py similarity index 93% rename from watcher/decision_engine/strategy/dummy_strategy.py rename to watcher/decision_engine/strategy/strategies/dummy_strategy.py index 0d06542b2..e9db219a8 100644 --- a/watcher/decision_engine/strategy/dummy_strategy.py +++ b/watcher/decision_engine/strategy/strategies/dummy_strategy.py @@ -17,9 +17,9 @@ # limitations under the License. # from oslo_log import log +from watcher.decision_engine.strategy.strategies.base import BaseStrategy from watcher.decision_engine.actions.nop import Nop -from watcher.decision_engine.strategy.base import BaseStrategy LOG = log.getLogger(__name__) diff --git a/watcher/opts.py b/watcher/opts.py index ff7128059..6b2c4b084 100644 --- a/watcher/opts.py +++ b/watcher/opts.py @@ -18,7 +18,7 @@ import watcher.api.app from watcher.applier import manager_applier from watcher.decision_engine import manager -from watcher.decision_engine.strategy.selector import default \ +from watcher.decision_engine.strategy.selection import default \ as strategy_selector 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 1bf551137..1e783ef9c 100644 --- a/watcher/tests/decision_engine/command/test_trigger_audit_command.py +++ b/watcher/tests/decision_engine/command/test_trigger_audit_command.py @@ -13,7 +13,6 @@ # implied. # See the License for the specific language governing permissions and # limitations under the License. - from mock import call from mock import MagicMock from watcher.decision_engine.command.audit import TriggerAuditCommand @@ -21,8 +20,8 @@ from watcher.decision_engine.messaging.events import Events from watcher.objects.audit import Audit from watcher.objects.audit import AuditStatus from watcher.tests.db.base import DbTestCase -from watcher.tests.decision_engine.faker_cluster_state import \ - FakerModelCollector +from watcher.tests.decision_engine.strategy.strategies.faker_cluster_state \ + import FakerModelCollector from watcher.tests.objects import utils as obj_utils diff --git a/watcher/tests/decision_engine/messaging/test_audit_endpoint.py b/watcher/tests/decision_engine/messaging/test_audit_endpoint.py index 8f2c453a9..67378e968 100644 --- a/watcher/tests/decision_engine/messaging/test_audit_endpoint.py +++ b/watcher/tests/decision_engine/messaging/test_audit_endpoint.py @@ -22,7 +22,7 @@ from watcher.decision_engine.messaging.audit_endpoint import AuditEndpoint from watcher.metrics_engine.cluster_model_collector.manager import \ CollectorManager from watcher.tests import base -from watcher.tests.decision_engine.faker_cluster_state import \ +from watcher.tests.decision_engine.strategy.strategies.faker_cluster_state import \ FakerModelCollector diff --git a/watcher/tests/decision_engine/model/test_mapping.py b/watcher/tests/decision_engine/model/test_mapping.py index 3ec0d062f..fb9b300cc 100644 --- a/watcher/tests/decision_engine/model/test_mapping.py +++ b/watcher/tests/decision_engine/model/test_mapping.py @@ -17,17 +17,18 @@ # limitations under the License. # import uuid + from watcher.decision_engine.model.hypervisor import Hypervisor from watcher.decision_engine.model.vm_state import VMState from watcher.tests import base -from watcher.tests.decision_engine.faker_cluster_state import \ +from watcher.tests.decision_engine.strategy.strategies.faker_cluster_state import \ FakerModelCollector class TestMapping(base.BaseTestCase): def test_get_node_from_vm(self): fake_cluster = FakerModelCollector() - model = fake_cluster.generate_scenario_4_with_2_hypervisors() + model = fake_cluster.generate_scenario_3_with_2_hypervisors() vms = model.get_all_vms() keys = list(vms.keys()) @@ -39,14 +40,14 @@ class TestMapping(base.BaseTestCase): def test_get_node_from_vm_id(self): fake_cluster = FakerModelCollector() - model = fake_cluster.generate_scenario_4_with_2_hypervisors() + model = fake_cluster.generate_scenario_3_with_2_hypervisors() hyps = model.mapping.get_node_vms_from_id("BLABLABLA") self.assertEqual(hyps.__len__(), 0) def test_get_all_vms(self): fake_cluster = FakerModelCollector() - model = fake_cluster.generate_scenario_4_with_2_hypervisors() + model = fake_cluster.generate_scenario_3_with_2_hypervisors() vms = model.get_all_vms() self.assertEqual(vms.__len__(), 2) @@ -57,7 +58,7 @@ class TestMapping(base.BaseTestCase): def test_get_mapping(self): fake_cluster = FakerModelCollector() - model = fake_cluster.generate_scenario_4_with_2_hypervisors() + model = fake_cluster.generate_scenario_3_with_2_hypervisors() mapping_vm = model.mapping.get_mapping_vm() self.assertEqual(mapping_vm.__len__(), 2) @@ -66,7 +67,7 @@ class TestMapping(base.BaseTestCase): def test_migrate_vm(self): fake_cluster = FakerModelCollector() - model = fake_cluster.generate_scenario_4_with_2_hypervisors() + model = fake_cluster.generate_scenario_3_with_2_hypervisors() vms = model.get_all_vms() keys = list(vms.keys()) vm0 = vms[keys[0]] @@ -81,7 +82,7 @@ class TestMapping(base.BaseTestCase): def test_unmap_from_id_log_warning(self): fake_cluster = FakerModelCollector() - model = fake_cluster.generate_scenario_4_with_2_hypervisors() + model = fake_cluster.generate_scenario_3_with_2_hypervisors() vms = model.get_all_vms() keys = list(vms.keys()) vm0 = vms[keys[0]] @@ -95,7 +96,7 @@ class TestMapping(base.BaseTestCase): def test_unmap_from_id(self): fake_cluster = FakerModelCollector() - model = fake_cluster.generate_scenario_4_with_2_hypervisors() + model = fake_cluster.generate_scenario_3_with_2_hypervisors() vms = model.get_all_vms() keys = list(vms.keys()) vm0 = vms[keys[0]] diff --git a/watcher/tests/decision_engine/model/test_model.py b/watcher/tests/decision_engine/model/test_model.py index c5bfa81ab..fb6e43bf7 100644 --- a/watcher/tests/decision_engine/model/test_model.py +++ b/watcher/tests/decision_engine/model/test_model.py @@ -17,15 +17,15 @@ # limitations under the License. # import uuid + from watcher.common import exception from watcher.common.exception import IllegalArgumentException from watcher.decision_engine.model.hypervisor import Hypervisor from watcher.decision_engine.model.hypervisor_state import HypervisorState from watcher.decision_engine.model.model_root import ModelRoot -from watcher.tests.decision_engine.faker_cluster_state import \ - FakerModelCollector - from watcher.tests import base +from watcher.tests.decision_engine.strategy.strategies.faker_cluster_state import \ + FakerModelCollector class TestModel(base.BaseTestCase): diff --git a/watcher/tests/decision_engine/test_strategy_loader.py b/watcher/tests/decision_engine/strategy/loading/test_default_strategy_loader.py similarity index 58% rename from watcher/tests/decision_engine/test_strategy_loader.py rename to watcher/tests/decision_engine/strategy/loading/test_default_strategy_loader.py index 9c54b7230..44296cf3b 100644 --- a/watcher/tests/decision_engine/test_strategy_loader.py +++ b/watcher/tests/decision_engine/strategy/loading/test_default_strategy_loader.py @@ -13,20 +13,40 @@ # implied. # See the License for the specific language governing permissions and # limitations under the License. - from __future__ import unicode_literals from mock import patch 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.decision_engine.strategy.loading.default import \ + DefaultStrategyLoader +from watcher.decision_engine.strategy.strategies.base import BaseStrategy +from watcher.decision_engine.strategy.strategies.dummy_strategy import \ + DummyStrategy from watcher.tests.base import TestCase -class TestStrategyLoader(TestCase): +class TestDefaultStrategyLoader(TestCase): - @patch("watcher.decision_engine.strategy.loader.ExtensionManager") + strategy_loader = DefaultStrategyLoader() + + def test_load_strategy_with_empty_model(self): + selected_strategy = self.strategy_loader.load(None) + self.assertIsNotNone(selected_strategy, + 'The default strategy not be must none') + self.assertIsInstance(selected_strategy, BaseStrategy) + + def test_load_strategy_is_basic(self): + exptected_strategy = 'basic' + selected_strategy = self.strategy_loader.load(exptected_strategy) + self.assertEqual( + selected_strategy.name, + exptected_strategy, + 'The default strategy should be basic') + + @patch( + "watcher.decision_engine.strategy.loading.default.ExtensionManager") def test_strategy_loader(self, m_extension_manager): dummy_strategy_name = "dummy" # Set up the fake Stevedore extensions @@ -40,15 +60,13 @@ class TestStrategyLoader(TestCase): )], namespace="watcher_strategies", ) - strategy_loader = StrategyLoader() + strategy_loader = DefaultStrategyLoader() 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() + strategy_loader = DefaultStrategyLoader() loaded_strategy = strategy_loader.load("dummy") - - self.assertEqual("dummy", loaded_strategy.name) - self.assertEqual("Dummy Strategy", loaded_strategy.description) + self.assertIsInstance(loaded_strategy, DummyStrategy) 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 78268d240..fdb769896 100644 --- a/watcher/tests/decision_engine/strategy/selector/test_strategy_selector.py +++ b/watcher/tests/decision_engine/strategy/selector/test_strategy_selector.py @@ -15,10 +15,13 @@ # limitations under the License. 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.decision_engine.strategy.loading.default import \ + DefaultStrategyLoader +from watcher.decision_engine.strategy.selection.default import StrategySelector from watcher.tests.base import TestCase + CONF = cfg.CONF @@ -26,7 +29,7 @@ class TestStrategySelector(TestCase): strategy_selector = StrategySelector() - @patch.object(StrategyLoader, 'load') + @patch.object(DefaultStrategyLoader, 'load') def test_define_from_goal(self, mock_call): cfg.CONF.set_override( 'goals', {"DUMMY": "fake"}, group='watcher_goals' @@ -36,7 +39,7 @@ class TestStrategySelector(TestCase): self.strategy_selector.define_from_goal(expected_goal) mock_call.assert_called_once_with(expected_strategy) - @patch.object(StrategyLoader, 'load') + @patch.object(DefaultStrategyLoader, 'load') def test_define_from_goal_with_incorrect_mapping(self, mock_call): cfg.CONF.set_override( 'goals', {}, group='watcher_goals' diff --git a/watcher/tests/decision_engine/strategy/strategies/__init__.py b/watcher/tests/decision_engine/strategy/strategies/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/watcher/tests/decision_engine/faker_cluster_state.py b/watcher/tests/decision_engine/strategy/strategies/faker_cluster_state.py similarity index 92% rename from watcher/tests/decision_engine/faker_cluster_state.py rename to watcher/tests/decision_engine/strategy/strategies/faker_cluster_state.py index 666260d08..08a3dc853 100644 --- a/watcher/tests/decision_engine/faker_cluster_state.py +++ b/watcher/tests/decision_engine/strategy/strategies/faker_cluster_state.py @@ -167,39 +167,12 @@ class FakerModelCollector(BaseClusterModelCollector): return current_state_cluster - def generate_scenario_2(self): - current_state_cluster = ModelRoot() - # number of nodes - count_node = 5 - - # define ressouce ( CPU, MEM disk, ... ) - mem = Resource(ResourceType.memory) - # 2199.954 Mhz - num_cores = Resource(ResourceType.cpu_cores) - disk = Resource(ResourceType.disk) - - current_state_cluster.create_resource(mem) - current_state_cluster.create_resource(num_cores) - current_state_cluster.create_resource(disk) - - for i in range(0, count_node): - node_uuid = "Node_{0}".format(i) - node = Hypervisor() - node.uuid = node_uuid - node.hostname = "hostname_{0}".format(i) - mem.set_capacity(node, 132) - disk.set_capacity(node, 250) - num_cores.set_capacity(node, 40) - # print("create "+str(node)) - current_state_cluster.add_hypervisor(node) - return current_state_cluster - def map(self, model, h_id, vm_id): model.get_mapping().map( model.get_hypervisor_from_id(h_id), model.get_vm_from_id(vm_id)) - def generate_scenario_3(self): + def generate_scenario_2(self): vms = [] current_state_cluster = ModelRoot() @@ -263,7 +236,7 @@ class FakerModelCollector(BaseClusterModelCollector): return current_state_cluster - def generate_scenario_4_with_2_hypervisors(self): + def generate_scenario_3_with_2_hypervisors(self): vms = [] current_state_cluster = ModelRoot() @@ -317,7 +290,7 @@ class FakerModelCollector(BaseClusterModelCollector): return current_state_cluster - def generate_scenario_5_with_1_hypervisor_no_vm(self): + def generate_scenario_4_with_1_hypervisor_no_vm(self): current_state_cluster = ModelRoot() # number of nodes count_node = 1 diff --git a/watcher/tests/decision_engine/faker_metrics_collector.py b/watcher/tests/decision_engine/strategy/strategies/faker_metrics_collector.py similarity index 100% rename from watcher/tests/decision_engine/faker_metrics_collector.py rename to watcher/tests/decision_engine/strategy/strategies/faker_metrics_collector.py diff --git a/watcher/tests/decision_engine/test_basic_consolidation.py b/watcher/tests/decision_engine/strategy/strategies/test_basic_consolidation.py similarity index 94% rename from watcher/tests/decision_engine/test_basic_consolidation.py rename to watcher/tests/decision_engine/strategy/strategies/test_basic_consolidation.py index 07036ef3e..57e677c2b 100644 --- a/watcher/tests/decision_engine/test_basic_consolidation.py +++ b/watcher/tests/decision_engine/strategy/strategies/test_basic_consolidation.py @@ -22,20 +22,18 @@ import mock from mock import MagicMock from watcher.common import exception - from watcher.decision_engine.actions.hypervisor_state import \ ChangeHypervisorState -from watcher.decision_engine.actions.power_state import ChangePowerState - from watcher.decision_engine.actions.migration import Migrate +from watcher.decision_engine.actions.power_state import ChangePowerState from watcher.decision_engine.model.model_root import ModelRoot -from watcher.decision_engine.strategy.basic_consolidation import \ +from watcher.decision_engine.strategy.strategies.basic_consolidation import \ BasicConsolidation from watcher.tests import base -from watcher.tests.decision_engine.faker_cluster_state import \ - FakerModelCollector -from watcher.tests.decision_engine.faker_metrics_collector import \ - FakerMetricsCollector +from watcher.tests.decision_engine.strategy.strategies.faker_cluster_state \ + import FakerModelCollector +from watcher.tests.decision_engine.strategy.strategies.faker_metrics_collector\ + import FakerMetricsCollector class TestBasicConsolidation(base.BaseTestCase): @@ -154,7 +152,7 @@ class TestBasicConsolidation(base.BaseTestCase): def test_check_migration(self): sercon = BasicConsolidation() fake_cluster = FakerModelCollector() - model = fake_cluster.generate_scenario_4_with_2_hypervisors() + model = fake_cluster.generate_scenario_3_with_2_hypervisors() all_vms = model.get_all_vms() all_hyps = model.get_all_hypervisors() @@ -166,7 +164,7 @@ class TestBasicConsolidation(base.BaseTestCase): def test_threshold(self): sercon = BasicConsolidation() fake_cluster = FakerModelCollector() - model = fake_cluster.generate_scenario_4_with_2_hypervisors() + model = fake_cluster.generate_scenario_3_with_2_hypervisors() all_hyps = model.get_all_hypervisors() hyp0 = all_hyps[list(all_hyps.keys())[0]] @@ -188,7 +186,7 @@ class TestBasicConsolidation(base.BaseTestCase): statistic_aggregation=self.fake_metrics.mock_get_statistics) solution = sercon.execute( - self.fake_cluster.generate_scenario_3()) + self.fake_cluster.generate_scenario_2()) actions_counter = Counter( [type(action) for action in solution.actions]) @@ -224,7 +222,7 @@ class TestBasicConsolidation(base.BaseTestCase): current_state_cluster = FakerModelCollector() model = current_state_cluster. \ - generate_scenario_5_with_1_hypervisor_no_vm() + generate_scenario_4_with_1_hypervisor_no_vm() with mock.patch.object(BasicConsolidation, 'calculate_weight') \ as mock_score_call: diff --git a/watcher/tests/decision_engine/test_dummy_strategy.py b/watcher/tests/decision_engine/strategy/strategies/test_dummy_strategy.py similarity index 76% rename from watcher/tests/decision_engine/test_dummy_strategy.py rename to watcher/tests/decision_engine/strategy/strategies/test_dummy_strategy.py index aea1a2307..c0e54b9ed 100644 --- a/watcher/tests/decision_engine/test_dummy_strategy.py +++ b/watcher/tests/decision_engine/strategy/strategies/test_dummy_strategy.py @@ -13,15 +13,16 @@ # implied. # See the License for the specific language governing permissions and # limitations under the License. -from watcher.decision_engine.strategy.dummy_strategy import DummyStrategy +from watcher.decision_engine.strategy.strategies.dummy_strategy import \ + DummyStrategy from watcher.tests import base -from watcher.tests.decision_engine.faker_cluster_state import \ - FakerModelCollector +from watcher.tests.decision_engine.strategy.strategies.faker_cluster_state\ + import FakerModelCollector class TestDummyStrategy(base.TestCase): def test_dummy_strategy(self): tactique = DummyStrategy("basic", "Basic offline consolidation") fake_cluster = FakerModelCollector() - model = fake_cluster.generate_scenario_4_with_2_hypervisors() + model = fake_cluster.generate_scenario_3_with_2_hypervisors() tactique.execute(model) diff --git a/watcher/tests/decision_engine/strategy/test_strategy_loader.py b/watcher/tests/decision_engine/strategy/test_strategy_loader.py deleted file mode 100644 index 3f78f1944..000000000 --- a/watcher/tests/decision_engine/strategy/test_strategy_loader.py +++ /dev/null @@ -1,37 +0,0 @@ -# -*- encoding: utf-8 -*- -# Copyright (c) 2015 b<>com -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. -from watcher.decision_engine.strategy.base import BaseStrategy -from watcher.decision_engine.strategy.loader import StrategyLoader -from watcher.tests import base - - -class TestStrategySelector(base.BaseTestCase): - - strategy_loader = StrategyLoader() - - def test_load_strategy_with_empty_model(self): - selected_strategy = self.strategy_loader.load(None) - self.assertIsNotNone(selected_strategy, - 'The default strategy be must not none') - self.assertIsInstance(selected_strategy, BaseStrategy) - - def test_load_strategy_is_basic(self): - exptected_strategy = 'basic' - selected_strategy = self.strategy_loader.load(exptected_strategy) - self.assertEqual( - selected_strategy.name, - exptected_strategy, - 'The default strategy should be basic') diff --git a/watcher/tests/decision_engine/test_default_planner.py b/watcher/tests/decision_engine/test_default_planner.py index 0f018040c..284335d48 100644 --- a/watcher/tests/decision_engine/test_default_planner.py +++ b/watcher/tests/decision_engine/test_default_planner.py @@ -16,20 +16,22 @@ import mock from mock import MagicMock + from watcher.common.exception import MetaActionNotFound from watcher.common import utils + from watcher.db import api as db_api from watcher.decision_engine.actions.base import BaseAction from watcher.decision_engine.planner.default import DefaultPlanner from watcher.decision_engine.solution.default import DefaultSolution -from watcher.decision_engine.strategy.basic_consolidation import \ +from watcher.decision_engine.strategy.strategies.basic_consolidation import \ BasicConsolidation from watcher.tests.db import base from watcher.tests.db import utils as db_utils -from watcher.tests.decision_engine.faker_cluster_state import \ - FakerModelCollector -from watcher.tests.decision_engine.faker_metrics_collector import \ - FakerMetricsCollector +from watcher.tests.decision_engine.strategy.strategies.faker_cluster_state\ + import FakerModelCollector +from watcher.tests.decision_engine.strategy.strategies.faker_metrics_collector\ + import FakerMetricsCollector from watcher.tests.objects import utils as obj_utils @@ -54,7 +56,7 @@ class SolutionFakerSingleHyp(object): get_statistics=metrics.mock_get_statistics) return sercon.execute( - current_state_cluster.generate_scenario_4_with_2_hypervisors()) + current_state_cluster.generate_scenario_3_with_2_hypervisors()) class TestActionScheduling(base.DbTestCase):