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
This commit is contained in:
parent
92940ba9e2
commit
62570525ad
@ -42,8 +42,8 @@ watcher.database.migration_backend =
|
|||||||
sqlalchemy = watcher.db.sqlalchemy.migration
|
sqlalchemy = watcher.db.sqlalchemy.migration
|
||||||
|
|
||||||
watcher_strategies =
|
watcher_strategies =
|
||||||
dummy = watcher.decision_engine.strategy.dummy_strategy:DummyStrategy
|
dummy = watcher.decision_engine.strategy.strategies.dummy_strategy:DummyStrategy
|
||||||
basic = watcher.decision_engine.strategy.basic_consolidation:BasicConsolidation
|
basic = watcher.decision_engine.strategy.strategies.basic_consolidation:BasicConsolidation
|
||||||
|
|
||||||
[build_sphinx]
|
[build_sphinx]
|
||||||
source-dir = doc/source
|
source-dir = doc/source
|
||||||
|
@ -22,7 +22,7 @@ import pecan
|
|||||||
from watcher.api import acl
|
from watcher.api import acl
|
||||||
from watcher.api import config as api_config
|
from watcher.api import config as api_config
|
||||||
from watcher.api import middleware
|
from watcher.api import middleware
|
||||||
from watcher.decision_engine.strategy.selector import default \
|
from watcher.decision_engine.strategy.selection import default \
|
||||||
as strategy_selector
|
as strategy_selector
|
||||||
|
|
||||||
# Register options for the service
|
# Register options for the service
|
||||||
|
@ -17,9 +17,9 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
import abc
|
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)
|
@six.add_metaclass(abc.ABCMeta)
|
||||||
|
@ -17,7 +17,7 @@ from oslo_log import log
|
|||||||
|
|
||||||
from watcher.decision_engine.planner.default import DefaultPlanner
|
from watcher.decision_engine.planner.default import DefaultPlanner
|
||||||
from watcher.decision_engine.strategy.context.base import BaseStrategyContext
|
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__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
43
watcher/decision_engine/strategy/loading/base.py
Normal file
43
watcher/decision_engine/strategy/loading/base.py
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
# -*- encoding: utf-8 -*-
|
||||||
|
# Copyright (c) 2015 b<>com
|
||||||
|
#
|
||||||
|
# Authors: Jean-Emile DARTOIS <jean-emile.dartois@b-com.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.
|
||||||
|
#
|
||||||
|
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
|
@ -21,32 +21,21 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
from oslo_log import log
|
from oslo_log import log
|
||||||
from stevedore import ExtensionManager
|
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
|
BasicConsolidation
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class StrategyLoader(object):
|
class DefaultStrategyLoader(BaseStrategyLoader):
|
||||||
|
|
||||||
default_strategy_cls = BasicConsolidation
|
default_strategy_cls = BasicConsolidation
|
||||||
|
|
||||||
def load_strategies(self):
|
def load_available_strategies(self):
|
||||||
extension_manager = ExtensionManager(
|
extension_manager = ExtensionManager(
|
||||||
namespace='watcher_strategies',
|
namespace='watcher_strategies',
|
||||||
invoke_on_load=True,
|
invoke_on_load=True,
|
||||||
)
|
)
|
||||||
return {ext.name: ext.plugin for ext in extension_manager.extensions}
|
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
|
|
@ -16,9 +16,12 @@
|
|||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log
|
from oslo_log import log
|
||||||
|
|
||||||
from watcher.common.exception import WatcherException
|
from watcher.common.exception import WatcherException
|
||||||
from watcher.decision_engine.strategy.loader import StrategyLoader
|
from watcher.decision_engine.strategy.loading.default import \
|
||||||
from watcher.decision_engine.strategy.selector.base import BaseSelector
|
DefaultStrategyLoader
|
||||||
|
from watcher.decision_engine.strategy.selection.base import BaseSelector
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
|
|
||||||
@ -41,7 +44,7 @@ CONF.register_opts(WATCHER_GOALS_OPTS, goals_opt_group)
|
|||||||
class StrategySelector(BaseSelector):
|
class StrategySelector(BaseSelector):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.strategy_loader = StrategyLoader()
|
self.strategy_loader = DefaultStrategyLoader()
|
||||||
|
|
||||||
def define_from_goal(self, goal_name):
|
def define_from_goal(self, goal_name):
|
||||||
strategy_to_load = None
|
strategy_to_load = None
|
@ -16,12 +16,12 @@
|
|||||||
|
|
||||||
import abc
|
import abc
|
||||||
from oslo_log import log
|
from oslo_log import log
|
||||||
|
|
||||||
import six
|
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__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
@ -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.power_state import PowerState
|
||||||
from watcher.decision_engine.model.resource import ResourceType
|
from watcher.decision_engine.model.resource import ResourceType
|
||||||
from watcher.decision_engine.model.vm_state import VMState
|
from watcher.decision_engine.model.vm_state import VMState
|
||||||
from watcher.decision_engine.strategy.base import BaseStrategy
|
from watcher.decision_engine.strategy.common.level import StrategyLevel
|
||||||
from watcher.decision_engine.strategy.level import StrategyLevel
|
from watcher.decision_engine.strategy.strategies.base import BaseStrategy
|
||||||
from watcher.metrics_engine.cluster_history.ceilometer import \
|
from watcher.metrics_engine.cluster_history.ceilometer import \
|
||||||
CeilometerClusterHistory
|
CeilometerClusterHistory
|
||||||
|
|
||||||
@ -53,12 +53,12 @@ class BasicConsolidation(BaseStrategy):
|
|||||||
and often tend to migrate from one physical machine to another.
|
and often tend to migrate from one physical machine to another.
|
||||||
Hence, the traditional and offline heuristics such as bin packing
|
Hence, the traditional and offline heuristics such as bin packing
|
||||||
are not applicable for the placement VM in cloud computing.
|
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
|
not only the performance effects but also the workload characteristics of
|
||||||
VMs and others metrics like the power consumption and
|
VMs and others metrics like the power consumption and
|
||||||
the tenants constraints (SLAs).
|
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 :
|
based on machine learning and meta-heuristics that must handle :
|
||||||
- multi-objectives
|
- multi-objectives
|
||||||
- Contradictory objectives
|
- Contradictory objectives
|
||||||
@ -121,8 +121,8 @@ class BasicConsolidation(BaseStrategy):
|
|||||||
vm_to_mig):
|
vm_to_mig):
|
||||||
'''check if the migration is possible
|
'''check if the migration is possible
|
||||||
|
|
||||||
:param model: current state of the cluster
|
:param model: the current state of the cluster
|
||||||
:param src_hypervisor: the current of the virtual machine
|
:param src_hypervisor: the current node of the virtual machine
|
||||||
:param dest_hypervisor: the destination of the virtual machine
|
:param dest_hypervisor: the destination of the virtual machine
|
||||||
:param vm_to_mig: the virtual machine
|
:param vm_to_mig: the virtual machine
|
||||||
:return: True if the there is enough place otherwise false
|
:return: True if the there is enough place otherwise false
|
||||||
@ -167,7 +167,7 @@ class BasicConsolidation(BaseStrategy):
|
|||||||
"""Check threshold
|
"""Check threshold
|
||||||
|
|
||||||
check the threshold value defined by the ratio of
|
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.
|
of this node must not exceed the threshold value.
|
||||||
:param dest_hypervisor:
|
:param dest_hypervisor:
|
||||||
:param total_cores
|
:param total_cores
|
||||||
@ -213,7 +213,7 @@ class BasicConsolidation(BaseStrategy):
|
|||||||
|
|
||||||
def calculate_weight(self, model, element, total_cores_used,
|
def calculate_weight(self, model, element, total_cores_used,
|
||||||
total_disk_used, total_memory_used):
|
total_disk_used, total_memory_used):
|
||||||
"""Calculate weight of every
|
"""Calculate weight of every resource
|
||||||
|
|
||||||
:param model:
|
:param model:
|
||||||
:param element:
|
:param element:
|
||||||
@ -248,7 +248,7 @@ class BasicConsolidation(BaseStrategy):
|
|||||||
return (score_cores + score_disk + score_memory) / 3
|
return (score_cores + score_disk + score_memory) / 3
|
||||||
|
|
||||||
def calculate_score_node(self, hypervisor, model):
|
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 hypervisor:
|
||||||
:param model:
|
:param model:
|
||||||
@ -331,7 +331,7 @@ class BasicConsolidation(BaseStrategy):
|
|||||||
model)))
|
model)))
|
||||||
|
|
||||||
def execute(self, orign_model):
|
def execute(self, orign_model):
|
||||||
LOG.debug("initialize Sercon Consolidation")
|
LOG.debug("Initialize Sercon Consolidation")
|
||||||
|
|
||||||
if orign_model is None:
|
if orign_model is None:
|
||||||
raise ClusterStateNotDefined()
|
raise ClusterStateNotDefined()
|
||||||
@ -411,7 +411,7 @@ class BasicConsolidation(BaseStrategy):
|
|||||||
vm_score.append(
|
vm_score.append(
|
||||||
(vm_id, self.calculate_score_vm(vm, current_model)))
|
(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]))
|
v = sorted(vm_score, reverse=True, key=lambda x: (x[1]))
|
||||||
LOG.debug("VM(s) BFD {0}".format(v))
|
LOG.debug("VM(s) BFD {0}".format(v))
|
||||||
|
|
@ -17,9 +17,9 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
from oslo_log import log
|
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.actions.nop import Nop
|
||||||
from watcher.decision_engine.strategy.base import BaseStrategy
|
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
@ -18,7 +18,7 @@
|
|||||||
import watcher.api.app
|
import watcher.api.app
|
||||||
from watcher.applier import manager_applier
|
from watcher.applier import manager_applier
|
||||||
from watcher.decision_engine import manager
|
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
|
as strategy_selector
|
||||||
|
|
||||||
|
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
# implied.
|
# implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from mock import call
|
from mock import call
|
||||||
from mock import MagicMock
|
from mock import MagicMock
|
||||||
from watcher.decision_engine.command.audit import TriggerAuditCommand
|
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 Audit
|
||||||
from watcher.objects.audit import AuditStatus
|
from watcher.objects.audit import AuditStatus
|
||||||
from watcher.tests.db.base import DbTestCase
|
from watcher.tests.db.base import DbTestCase
|
||||||
from watcher.tests.decision_engine.faker_cluster_state import \
|
from watcher.tests.decision_engine.strategy.strategies.faker_cluster_state \
|
||||||
FakerModelCollector
|
import FakerModelCollector
|
||||||
from watcher.tests.objects import utils as obj_utils
|
from watcher.tests.objects import utils as obj_utils
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ from watcher.decision_engine.messaging.audit_endpoint import AuditEndpoint
|
|||||||
from watcher.metrics_engine.cluster_model_collector.manager import \
|
from watcher.metrics_engine.cluster_model_collector.manager import \
|
||||||
CollectorManager
|
CollectorManager
|
||||||
from watcher.tests import base
|
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
|
FakerModelCollector
|
||||||
|
|
||||||
|
|
||||||
|
@ -17,17 +17,18 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from watcher.decision_engine.model.hypervisor import Hypervisor
|
from watcher.decision_engine.model.hypervisor import Hypervisor
|
||||||
from watcher.decision_engine.model.vm_state import VMState
|
from watcher.decision_engine.model.vm_state import VMState
|
||||||
from watcher.tests import base
|
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
|
FakerModelCollector
|
||||||
|
|
||||||
|
|
||||||
class TestMapping(base.BaseTestCase):
|
class TestMapping(base.BaseTestCase):
|
||||||
def test_get_node_from_vm(self):
|
def test_get_node_from_vm(self):
|
||||||
fake_cluster = FakerModelCollector()
|
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()
|
vms = model.get_all_vms()
|
||||||
keys = list(vms.keys())
|
keys = list(vms.keys())
|
||||||
@ -39,14 +40,14 @@ class TestMapping(base.BaseTestCase):
|
|||||||
|
|
||||||
def test_get_node_from_vm_id(self):
|
def test_get_node_from_vm_id(self):
|
||||||
fake_cluster = FakerModelCollector()
|
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")
|
hyps = model.mapping.get_node_vms_from_id("BLABLABLA")
|
||||||
self.assertEqual(hyps.__len__(), 0)
|
self.assertEqual(hyps.__len__(), 0)
|
||||||
|
|
||||||
def test_get_all_vms(self):
|
def test_get_all_vms(self):
|
||||||
fake_cluster = FakerModelCollector()
|
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()
|
vms = model.get_all_vms()
|
||||||
self.assertEqual(vms.__len__(), 2)
|
self.assertEqual(vms.__len__(), 2)
|
||||||
@ -57,7 +58,7 @@ class TestMapping(base.BaseTestCase):
|
|||||||
|
|
||||||
def test_get_mapping(self):
|
def test_get_mapping(self):
|
||||||
fake_cluster = FakerModelCollector()
|
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()
|
mapping_vm = model.mapping.get_mapping_vm()
|
||||||
self.assertEqual(mapping_vm.__len__(), 2)
|
self.assertEqual(mapping_vm.__len__(), 2)
|
||||||
@ -66,7 +67,7 @@ class TestMapping(base.BaseTestCase):
|
|||||||
|
|
||||||
def test_migrate_vm(self):
|
def test_migrate_vm(self):
|
||||||
fake_cluster = FakerModelCollector()
|
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()
|
vms = model.get_all_vms()
|
||||||
keys = list(vms.keys())
|
keys = list(vms.keys())
|
||||||
vm0 = vms[keys[0]]
|
vm0 = vms[keys[0]]
|
||||||
@ -81,7 +82,7 @@ class TestMapping(base.BaseTestCase):
|
|||||||
|
|
||||||
def test_unmap_from_id_log_warning(self):
|
def test_unmap_from_id_log_warning(self):
|
||||||
fake_cluster = FakerModelCollector()
|
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()
|
vms = model.get_all_vms()
|
||||||
keys = list(vms.keys())
|
keys = list(vms.keys())
|
||||||
vm0 = vms[keys[0]]
|
vm0 = vms[keys[0]]
|
||||||
@ -95,7 +96,7 @@ class TestMapping(base.BaseTestCase):
|
|||||||
|
|
||||||
def test_unmap_from_id(self):
|
def test_unmap_from_id(self):
|
||||||
fake_cluster = FakerModelCollector()
|
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()
|
vms = model.get_all_vms()
|
||||||
keys = list(vms.keys())
|
keys = list(vms.keys())
|
||||||
vm0 = vms[keys[0]]
|
vm0 = vms[keys[0]]
|
||||||
|
@ -17,15 +17,15 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from watcher.common import exception
|
from watcher.common import exception
|
||||||
from watcher.common.exception import IllegalArgumentException
|
from watcher.common.exception import IllegalArgumentException
|
||||||
from watcher.decision_engine.model.hypervisor import Hypervisor
|
from watcher.decision_engine.model.hypervisor import Hypervisor
|
||||||
from watcher.decision_engine.model.hypervisor_state import HypervisorState
|
from watcher.decision_engine.model.hypervisor_state import HypervisorState
|
||||||
from watcher.decision_engine.model.model_root import ModelRoot
|
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 import base
|
||||||
|
from watcher.tests.decision_engine.strategy.strategies.faker_cluster_state import \
|
||||||
|
FakerModelCollector
|
||||||
|
|
||||||
|
|
||||||
class TestModel(base.BaseTestCase):
|
class TestModel(base.BaseTestCase):
|
||||||
|
@ -13,20 +13,40 @@
|
|||||||
# implied.
|
# implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from mock import patch
|
from mock import patch
|
||||||
from stevedore.extension import Extension
|
from stevedore.extension import Extension
|
||||||
from stevedore.extension import ExtensionManager
|
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
|
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):
|
def test_strategy_loader(self, m_extension_manager):
|
||||||
dummy_strategy_name = "dummy"
|
dummy_strategy_name = "dummy"
|
||||||
# Set up the fake Stevedore extensions
|
# Set up the fake Stevedore extensions
|
||||||
@ -40,15 +60,13 @@ class TestStrategyLoader(TestCase):
|
|||||||
)],
|
)],
|
||||||
namespace="watcher_strategies",
|
namespace="watcher_strategies",
|
||||||
)
|
)
|
||||||
strategy_loader = StrategyLoader()
|
strategy_loader = DefaultStrategyLoader()
|
||||||
loaded_strategy = strategy_loader.load("dummy")
|
loaded_strategy = strategy_loader.load("dummy")
|
||||||
|
|
||||||
self.assertEqual("dummy", loaded_strategy.name)
|
self.assertEqual("dummy", loaded_strategy.name)
|
||||||
self.assertEqual("Dummy Strategy", loaded_strategy.description)
|
self.assertEqual("Dummy Strategy", loaded_strategy.description)
|
||||||
|
|
||||||
def test_load_dummy_strategy(self):
|
def test_load_dummy_strategy(self):
|
||||||
strategy_loader = StrategyLoader()
|
strategy_loader = DefaultStrategyLoader()
|
||||||
loaded_strategy = strategy_loader.load("dummy")
|
loaded_strategy = strategy_loader.load("dummy")
|
||||||
|
self.assertIsInstance(loaded_strategy, DummyStrategy)
|
||||||
self.assertEqual("dummy", loaded_strategy.name)
|
|
||||||
self.assertEqual("Dummy Strategy", loaded_strategy.description)
|
|
@ -15,10 +15,13 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
from mock import patch
|
from mock import patch
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
|
|
||||||
from watcher.common.exception import WatcherException
|
from watcher.common.exception import WatcherException
|
||||||
from watcher.decision_engine.strategy.loader import StrategyLoader
|
from watcher.decision_engine.strategy.loading.default import \
|
||||||
from watcher.decision_engine.strategy.selector.default import StrategySelector
|
DefaultStrategyLoader
|
||||||
|
from watcher.decision_engine.strategy.selection.default import StrategySelector
|
||||||
from watcher.tests.base import TestCase
|
from watcher.tests.base import TestCase
|
||||||
|
|
||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
|
|
||||||
|
|
||||||
@ -26,7 +29,7 @@ class TestStrategySelector(TestCase):
|
|||||||
|
|
||||||
strategy_selector = StrategySelector()
|
strategy_selector = StrategySelector()
|
||||||
|
|
||||||
@patch.object(StrategyLoader, 'load')
|
@patch.object(DefaultStrategyLoader, 'load')
|
||||||
def test_define_from_goal(self, mock_call):
|
def test_define_from_goal(self, mock_call):
|
||||||
cfg.CONF.set_override(
|
cfg.CONF.set_override(
|
||||||
'goals', {"DUMMY": "fake"}, group='watcher_goals'
|
'goals', {"DUMMY": "fake"}, group='watcher_goals'
|
||||||
@ -36,7 +39,7 @@ class TestStrategySelector(TestCase):
|
|||||||
self.strategy_selector.define_from_goal(expected_goal)
|
self.strategy_selector.define_from_goal(expected_goal)
|
||||||
mock_call.assert_called_once_with(expected_strategy)
|
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):
|
def test_define_from_goal_with_incorrect_mapping(self, mock_call):
|
||||||
cfg.CONF.set_override(
|
cfg.CONF.set_override(
|
||||||
'goals', {}, group='watcher_goals'
|
'goals', {}, group='watcher_goals'
|
||||||
|
@ -167,39 +167,12 @@ class FakerModelCollector(BaseClusterModelCollector):
|
|||||||
|
|
||||||
return current_state_cluster
|
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):
|
def map(self, model, h_id, vm_id):
|
||||||
model.get_mapping().map(
|
model.get_mapping().map(
|
||||||
model.get_hypervisor_from_id(h_id),
|
model.get_hypervisor_from_id(h_id),
|
||||||
model.get_vm_from_id(vm_id))
|
model.get_vm_from_id(vm_id))
|
||||||
|
|
||||||
def generate_scenario_3(self):
|
def generate_scenario_2(self):
|
||||||
vms = []
|
vms = []
|
||||||
|
|
||||||
current_state_cluster = ModelRoot()
|
current_state_cluster = ModelRoot()
|
||||||
@ -263,7 +236,7 @@ class FakerModelCollector(BaseClusterModelCollector):
|
|||||||
|
|
||||||
return current_state_cluster
|
return current_state_cluster
|
||||||
|
|
||||||
def generate_scenario_4_with_2_hypervisors(self):
|
def generate_scenario_3_with_2_hypervisors(self):
|
||||||
vms = []
|
vms = []
|
||||||
|
|
||||||
current_state_cluster = ModelRoot()
|
current_state_cluster = ModelRoot()
|
||||||
@ -317,7 +290,7 @@ class FakerModelCollector(BaseClusterModelCollector):
|
|||||||
|
|
||||||
return current_state_cluster
|
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()
|
current_state_cluster = ModelRoot()
|
||||||
# number of nodes
|
# number of nodes
|
||||||
count_node = 1
|
count_node = 1
|
@ -22,20 +22,18 @@ import mock
|
|||||||
from mock import MagicMock
|
from mock import MagicMock
|
||||||
|
|
||||||
from watcher.common import exception
|
from watcher.common import exception
|
||||||
|
|
||||||
from watcher.decision_engine.actions.hypervisor_state import \
|
from watcher.decision_engine.actions.hypervisor_state import \
|
||||||
ChangeHypervisorState
|
ChangeHypervisorState
|
||||||
from watcher.decision_engine.actions.power_state import ChangePowerState
|
|
||||||
|
|
||||||
from watcher.decision_engine.actions.migration import Migrate
|
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.model.model_root import ModelRoot
|
||||||
from watcher.decision_engine.strategy.basic_consolidation import \
|
from watcher.decision_engine.strategy.strategies.basic_consolidation import \
|
||||||
BasicConsolidation
|
BasicConsolidation
|
||||||
from watcher.tests import base
|
from watcher.tests import base
|
||||||
from watcher.tests.decision_engine.faker_cluster_state import \
|
from watcher.tests.decision_engine.strategy.strategies.faker_cluster_state \
|
||||||
FakerModelCollector
|
import FakerModelCollector
|
||||||
from watcher.tests.decision_engine.faker_metrics_collector import \
|
from watcher.tests.decision_engine.strategy.strategies.faker_metrics_collector\
|
||||||
FakerMetricsCollector
|
import FakerMetricsCollector
|
||||||
|
|
||||||
|
|
||||||
class TestBasicConsolidation(base.BaseTestCase):
|
class TestBasicConsolidation(base.BaseTestCase):
|
||||||
@ -154,7 +152,7 @@ class TestBasicConsolidation(base.BaseTestCase):
|
|||||||
def test_check_migration(self):
|
def test_check_migration(self):
|
||||||
sercon = BasicConsolidation()
|
sercon = BasicConsolidation()
|
||||||
fake_cluster = FakerModelCollector()
|
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_vms = model.get_all_vms()
|
||||||
all_hyps = model.get_all_hypervisors()
|
all_hyps = model.get_all_hypervisors()
|
||||||
@ -166,7 +164,7 @@ class TestBasicConsolidation(base.BaseTestCase):
|
|||||||
def test_threshold(self):
|
def test_threshold(self):
|
||||||
sercon = BasicConsolidation()
|
sercon = BasicConsolidation()
|
||||||
fake_cluster = FakerModelCollector()
|
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()
|
all_hyps = model.get_all_hypervisors()
|
||||||
hyp0 = all_hyps[list(all_hyps.keys())[0]]
|
hyp0 = all_hyps[list(all_hyps.keys())[0]]
|
||||||
@ -188,7 +186,7 @@ class TestBasicConsolidation(base.BaseTestCase):
|
|||||||
statistic_aggregation=self.fake_metrics.mock_get_statistics)
|
statistic_aggregation=self.fake_metrics.mock_get_statistics)
|
||||||
|
|
||||||
solution = sercon.execute(
|
solution = sercon.execute(
|
||||||
self.fake_cluster.generate_scenario_3())
|
self.fake_cluster.generate_scenario_2())
|
||||||
|
|
||||||
actions_counter = Counter(
|
actions_counter = Counter(
|
||||||
[type(action) for action in solution.actions])
|
[type(action) for action in solution.actions])
|
||||||
@ -224,7 +222,7 @@ class TestBasicConsolidation(base.BaseTestCase):
|
|||||||
|
|
||||||
current_state_cluster = FakerModelCollector()
|
current_state_cluster = FakerModelCollector()
|
||||||
model = current_state_cluster. \
|
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') \
|
with mock.patch.object(BasicConsolidation, 'calculate_weight') \
|
||||||
as mock_score_call:
|
as mock_score_call:
|
@ -13,15 +13,16 @@
|
|||||||
# implied.
|
# implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# 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 import base
|
||||||
from watcher.tests.decision_engine.faker_cluster_state import \
|
from watcher.tests.decision_engine.strategy.strategies.faker_cluster_state\
|
||||||
FakerModelCollector
|
import FakerModelCollector
|
||||||
|
|
||||||
|
|
||||||
class TestDummyStrategy(base.TestCase):
|
class TestDummyStrategy(base.TestCase):
|
||||||
def test_dummy_strategy(self):
|
def test_dummy_strategy(self):
|
||||||
tactique = DummyStrategy("basic", "Basic offline consolidation")
|
tactique = DummyStrategy("basic", "Basic offline consolidation")
|
||||||
fake_cluster = FakerModelCollector()
|
fake_cluster = FakerModelCollector()
|
||||||
model = fake_cluster.generate_scenario_4_with_2_hypervisors()
|
model = fake_cluster.generate_scenario_3_with_2_hypervisors()
|
||||||
tactique.execute(model)
|
tactique.execute(model)
|
@ -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')
|
|
@ -16,20 +16,22 @@
|
|||||||
|
|
||||||
import mock
|
import mock
|
||||||
from mock import MagicMock
|
from mock import MagicMock
|
||||||
|
|
||||||
from watcher.common.exception import MetaActionNotFound
|
from watcher.common.exception import MetaActionNotFound
|
||||||
from watcher.common import utils
|
from watcher.common import utils
|
||||||
|
|
||||||
from watcher.db import api as db_api
|
from watcher.db import api as db_api
|
||||||
from watcher.decision_engine.actions.base import BaseAction
|
from watcher.decision_engine.actions.base import BaseAction
|
||||||
from watcher.decision_engine.planner.default import DefaultPlanner
|
from watcher.decision_engine.planner.default import DefaultPlanner
|
||||||
from watcher.decision_engine.solution.default import DefaultSolution
|
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
|
BasicConsolidation
|
||||||
from watcher.tests.db import base
|
from watcher.tests.db import base
|
||||||
from watcher.tests.db import utils as db_utils
|
from watcher.tests.db import utils as db_utils
|
||||||
from watcher.tests.decision_engine.faker_cluster_state import \
|
from watcher.tests.decision_engine.strategy.strategies.faker_cluster_state\
|
||||||
FakerModelCollector
|
import FakerModelCollector
|
||||||
from watcher.tests.decision_engine.faker_metrics_collector import \
|
from watcher.tests.decision_engine.strategy.strategies.faker_metrics_collector\
|
||||||
FakerMetricsCollector
|
import FakerMetricsCollector
|
||||||
from watcher.tests.objects import utils as obj_utils
|
from watcher.tests.objects import utils as obj_utils
|
||||||
|
|
||||||
|
|
||||||
@ -54,7 +56,7 @@ class SolutionFakerSingleHyp(object):
|
|||||||
get_statistics=metrics.mock_get_statistics)
|
get_statistics=metrics.mock_get_statistics)
|
||||||
|
|
||||||
return sercon.execute(
|
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):
|
class TestActionScheduling(base.DbTestCase):
|
||||||
|
Loading…
Reference in New Issue
Block a user