Merge "use parameters to set the threshold"
This commit is contained in:
@@ -60,15 +60,7 @@ class UniformAirflow(base.BaseStrategy):
|
|||||||
METER_NAME_INLET_T = "hardware.ipmi.node.temperature"
|
METER_NAME_INLET_T = "hardware.ipmi.node.temperature"
|
||||||
# The meter to report system power of physical server in ceilometer
|
# The meter to report system power of physical server in ceilometer
|
||||||
METER_NAME_POWER = "hardware.ipmi.node.power"
|
METER_NAME_POWER = "hardware.ipmi.node.power"
|
||||||
# TODO(Junjie): make below thresholds configurable
|
|
||||||
# Unit: 0.1 CFM
|
|
||||||
THRESHOLD_AIRFLOW = 400.0
|
|
||||||
# Unit: degree C
|
|
||||||
THRESHOLD_INLET_T = 28.0
|
|
||||||
# Unit: watts
|
|
||||||
THRESHOLD_POWER = 350.0
|
|
||||||
# choose 300 seconds as the default duration of meter aggregation
|
# choose 300 seconds as the default duration of meter aggregation
|
||||||
# TODO(Junjie): make it configurable
|
|
||||||
PERIOD = 300
|
PERIOD = 300
|
||||||
|
|
||||||
MIGRATION = "migrate"
|
MIGRATION = "migrate"
|
||||||
@@ -83,10 +75,6 @@ class UniformAirflow(base.BaseStrategy):
|
|||||||
super(UniformAirflow, self).__init__(config, osc)
|
super(UniformAirflow, self).__init__(config, osc)
|
||||||
# The migration plan will be triggered when the airflow reaches
|
# The migration plan will be triggered when the airflow reaches
|
||||||
# threshold
|
# threshold
|
||||||
# TODO(Junjie): Threshold should be configurable for each audit
|
|
||||||
self.threshold_airflow = self.THRESHOLD_AIRFLOW
|
|
||||||
self.threshold_inlet_t = self.THRESHOLD_INLET_T
|
|
||||||
self.threshold_power = self.THRESHOLD_POWER
|
|
||||||
self.meter_name_airflow = self.METER_NAME_AIRFLOW
|
self.meter_name_airflow = self.METER_NAME_AIRFLOW
|
||||||
self.meter_name_inlet_t = self.METER_NAME_INLET_T
|
self.meter_name_inlet_t = self.METER_NAME_INLET_T
|
||||||
self.meter_name_power = self.METER_NAME_POWER
|
self.meter_name_power = self.METER_NAME_POWER
|
||||||
@@ -127,6 +115,37 @@ class UniformAirflow(base.BaseStrategy):
|
|||||||
def get_translatable_goal_display_name(cls):
|
def get_translatable_goal_display_name(cls):
|
||||||
return "Airflow optimization"
|
return "Airflow optimization"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_schema(cls):
|
||||||
|
# Mandatory default setting for each element
|
||||||
|
return {
|
||||||
|
"properties": {
|
||||||
|
"threshold_airflow": {
|
||||||
|
"description": "airflow threshold for migration, Unit is\
|
||||||
|
0.1CFM",
|
||||||
|
"type": "number",
|
||||||
|
"default": 400.0
|
||||||
|
},
|
||||||
|
"threshold_inlet_t": {
|
||||||
|
"description": "inlet temperature threshold for migration\
|
||||||
|
decision",
|
||||||
|
"type": "number",
|
||||||
|
"default": 28.0
|
||||||
|
},
|
||||||
|
"threshold_power": {
|
||||||
|
"description": "system power threshold for migration\
|
||||||
|
decision",
|
||||||
|
"type": "number",
|
||||||
|
"default": 350.0
|
||||||
|
},
|
||||||
|
"period": {
|
||||||
|
"description": "aggregate time period of ceilometer",
|
||||||
|
"type": "number",
|
||||||
|
"default": 300
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
def calculate_used_resource(self, hypervisor, cap_cores, cap_mem,
|
def calculate_used_resource(self, hypervisor, cap_cores, cap_mem,
|
||||||
cap_disk):
|
cap_disk):
|
||||||
"""Calculate the used vcpus, memory and disk based on VM flavors"""
|
"""Calculate the used vcpus, memory and disk based on VM flavors"""
|
||||||
@@ -276,6 +295,10 @@ class UniformAirflow(base.BaseStrategy):
|
|||||||
raise wexc.ClusterStateNotDefined()
|
raise wexc.ClusterStateNotDefined()
|
||||||
|
|
||||||
def do_execute(self):
|
def do_execute(self):
|
||||||
|
self.threshold_airflow = self.input_parameters.threshold_airflow
|
||||||
|
self.threshold_inlet_t = self.input_parameters.threshold_inlet_t
|
||||||
|
self.threshold_power = self.input_parameters.threshold_power
|
||||||
|
self._period = self.input_parameters.period
|
||||||
src_hypervisors, target_hypervisors = (
|
src_hypervisors, target_hypervisors = (
|
||||||
self.group_hosts_by_airflow())
|
self.group_hosts_by_airflow())
|
||||||
|
|
||||||
|
|||||||
@@ -59,11 +59,6 @@ class WorkloadBalance(base.WorkloadStabilizationBaseStrategy):
|
|||||||
# The meter to report CPU utilization % of VM in ceilometer
|
# The meter to report CPU utilization % of VM in ceilometer
|
||||||
METER_NAME = "cpu_util"
|
METER_NAME = "cpu_util"
|
||||||
# Unit: %, value range is [0 , 100]
|
# Unit: %, value range is [0 , 100]
|
||||||
# TODO(Junjie): make it configurable
|
|
||||||
THRESHOLD = 25.0
|
|
||||||
# choose 300 seconds as the default duration of meter aggregation
|
|
||||||
# TODO(Junjie): make it configurable
|
|
||||||
PERIOD = 300
|
|
||||||
|
|
||||||
MIGRATION = "migrate"
|
MIGRATION = "migrate"
|
||||||
|
|
||||||
@@ -77,11 +72,8 @@ class WorkloadBalance(base.WorkloadStabilizationBaseStrategy):
|
|||||||
super(WorkloadBalance, self).__init__(config, osc)
|
super(WorkloadBalance, self).__init__(config, osc)
|
||||||
# the migration plan will be triggered when the CPU utlization %
|
# the migration plan will be triggered when the CPU utlization %
|
||||||
# reaches threshold
|
# reaches threshold
|
||||||
# TODO(Junjie): Threshold should be configurable for each audit
|
|
||||||
self.threshold = self.THRESHOLD
|
|
||||||
self._meter = self.METER_NAME
|
self._meter = self.METER_NAME
|
||||||
self._ceilometer = None
|
self._ceilometer = None
|
||||||
self._period = self.PERIOD
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def ceilometer(self):
|
def ceilometer(self):
|
||||||
@@ -105,6 +97,24 @@ class WorkloadBalance(base.WorkloadStabilizationBaseStrategy):
|
|||||||
def get_translatable_display_name(cls):
|
def get_translatable_display_name(cls):
|
||||||
return "Workload Balance Migration Strategy"
|
return "Workload Balance Migration Strategy"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_schema(cls):
|
||||||
|
# Mandatory default setting for each element
|
||||||
|
return {
|
||||||
|
"properties": {
|
||||||
|
"threshold": {
|
||||||
|
"description": "workload threshold for migration",
|
||||||
|
"type": "number",
|
||||||
|
"default": 25.0
|
||||||
|
},
|
||||||
|
"period": {
|
||||||
|
"description": "aggregate time period of ceilometer",
|
||||||
|
"type": "number",
|
||||||
|
"default": 300
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
def calculate_used_resource(self, hypervisor, cap_cores, cap_mem,
|
def calculate_used_resource(self, hypervisor, cap_cores, cap_mem,
|
||||||
cap_disk):
|
cap_disk):
|
||||||
"""Calculate the used vcpus, memory and disk based on VM flavors"""
|
"""Calculate the used vcpus, memory and disk based on VM flavors"""
|
||||||
@@ -273,6 +283,8 @@ class WorkloadBalance(base.WorkloadStabilizationBaseStrategy):
|
|||||||
|
|
||||||
This phase is where you should put the main logic of your strategy.
|
This phase is where you should put the main logic of your strategy.
|
||||||
"""
|
"""
|
||||||
|
self.threshold = self.input_parameters.threshold
|
||||||
|
self._period = self.input_parameters.period
|
||||||
src_hypervisors, target_hypervisors, avg_workload, workload_cache = (
|
src_hypervisors, target_hypervisors, avg_workload, workload_cache = (
|
||||||
self.group_hosts_by_cpu_util())
|
self.group_hosts_by_cpu_util())
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import mock
|
|||||||
|
|
||||||
from watcher.applier.loading import default
|
from watcher.applier.loading import default
|
||||||
from watcher.common import exception
|
from watcher.common import exception
|
||||||
|
from watcher.common import utils
|
||||||
from watcher.decision_engine.model import model_root
|
from watcher.decision_engine.model import model_root
|
||||||
from watcher.decision_engine.model import resource
|
from watcher.decision_engine.model import resource
|
||||||
from watcher.decision_engine.strategy import strategies
|
from watcher.decision_engine.strategy import strategies
|
||||||
@@ -56,6 +57,15 @@ class TestUniformAirflow(base.BaseTestCase):
|
|||||||
self.m_ceilometer.return_value = mock.Mock(
|
self.m_ceilometer.return_value = mock.Mock(
|
||||||
statistic_aggregation=self.fake_metrics.mock_get_statistics)
|
statistic_aggregation=self.fake_metrics.mock_get_statistics)
|
||||||
self.strategy = strategies.UniformAirflow(config=mock.Mock())
|
self.strategy = strategies.UniformAirflow(config=mock.Mock())
|
||||||
|
self.strategy.input_parameters = utils.Struct()
|
||||||
|
self.strategy.input_parameters.update({'threshold_airflow': 400.0,
|
||||||
|
'threshold_inlet_t': 28.0,
|
||||||
|
'threshold_power': 350.0,
|
||||||
|
'period': 300})
|
||||||
|
self.strategy.threshold_airflow = 400
|
||||||
|
self.strategy.threshold_inlet_t = 28
|
||||||
|
self.strategy.threshold_power = 350
|
||||||
|
self._period = 300
|
||||||
|
|
||||||
def test_calc_used_res(self):
|
def test_calc_used_res(self):
|
||||||
model = self.fake_cluster.generate_scenario_7_with_2_hypervisors()
|
model = self.fake_cluster.generate_scenario_7_with_2_hypervisors()
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import mock
|
|||||||
|
|
||||||
from watcher.applier.loading import default
|
from watcher.applier.loading import default
|
||||||
from watcher.common import exception
|
from watcher.common import exception
|
||||||
|
from watcher.common import utils
|
||||||
from watcher.decision_engine.model import model_root
|
from watcher.decision_engine.model import model_root
|
||||||
from watcher.decision_engine.model import resource
|
from watcher.decision_engine.model import resource
|
||||||
from watcher.decision_engine.strategy import strategies
|
from watcher.decision_engine.strategy import strategies
|
||||||
@@ -47,15 +48,20 @@ class TestWorkloadBalance(base.BaseTestCase):
|
|||||||
self.addCleanup(p_model.stop)
|
self.addCleanup(p_model.stop)
|
||||||
|
|
||||||
p_ceilometer = mock.patch.object(
|
p_ceilometer = mock.patch.object(
|
||||||
strategies.BasicConsolidation, "ceilometer",
|
strategies.WorkloadBalance, "ceilometer",
|
||||||
new_callable=mock.PropertyMock)
|
new_callable=mock.PropertyMock)
|
||||||
self.m_ceilometer = p_ceilometer.start()
|
self.m_ceilometer = p_ceilometer.start()
|
||||||
self.addCleanup(p_ceilometer.stop)
|
self.addCleanup(p_ceilometer.stop)
|
||||||
|
|
||||||
self.m_model.return_value = model_root.ModelRoot()
|
self.m_model.return_value = model_root.ModelRoot()
|
||||||
self.m_ceilometer.return_value = mock.Mock(
|
self.m_ceilometer.return_value = mock.Mock(
|
||||||
statistic_aggregation=self.fake_metrics.mock_get_statistics)
|
statistic_aggregation=self.fake_metrics.mock_get_statistics_wb)
|
||||||
self.strategy = strategies.WorkloadBalance(config=mock.Mock())
|
self.strategy = strategies.WorkloadBalance(config=mock.Mock())
|
||||||
|
self.strategy.input_parameters = utils.Struct()
|
||||||
|
self.strategy.input_parameters.update({'threshold': 25.0,
|
||||||
|
'period': 300})
|
||||||
|
self.strategy.threshold = 25.0
|
||||||
|
self.strategy._period = 300
|
||||||
|
|
||||||
def test_calc_used_res(self):
|
def test_calc_used_res(self):
|
||||||
model = self.fake_cluster.generate_scenario_6_with_2_hypervisors()
|
model = self.fake_cluster.generate_scenario_6_with_2_hypervisors()
|
||||||
@@ -74,10 +80,7 @@ class TestWorkloadBalance(base.BaseTestCase):
|
|||||||
model = self.fake_cluster.generate_scenario_6_with_2_hypervisors()
|
model = self.fake_cluster.generate_scenario_6_with_2_hypervisors()
|
||||||
self.m_model.return_value = model
|
self.m_model.return_value = model
|
||||||
self.strategy.threshold = 30
|
self.strategy.threshold = 30
|
||||||
self.strategy.ceilometer = mock.MagicMock(
|
|
||||||
statistic_aggregation=self.fake_metrics.mock_get_statistics_wb)
|
|
||||||
h1, h2, avg, w_map = self.strategy.group_hosts_by_cpu_util()
|
h1, h2, avg, w_map = self.strategy.group_hosts_by_cpu_util()
|
||||||
# print h1, h2, avg, w_map
|
|
||||||
self.assertEqual(h1[0]['hv'].uuid, 'Node_0')
|
self.assertEqual(h1[0]['hv'].uuid, 'Node_0')
|
||||||
self.assertEqual(h2[0]['hv'].uuid, 'Node_1')
|
self.assertEqual(h2[0]['hv'].uuid, 'Node_1')
|
||||||
self.assertEqual(avg, 8.0)
|
self.assertEqual(avg, 8.0)
|
||||||
@@ -85,8 +88,6 @@ class TestWorkloadBalance(base.BaseTestCase):
|
|||||||
def test_choose_vm_to_migrate(self):
|
def test_choose_vm_to_migrate(self):
|
||||||
model = self.fake_cluster.generate_scenario_6_with_2_hypervisors()
|
model = self.fake_cluster.generate_scenario_6_with_2_hypervisors()
|
||||||
self.m_model.return_value = model
|
self.m_model.return_value = model
|
||||||
self.strategy.ceilometer = mock.MagicMock(
|
|
||||||
statistic_aggregation=self.fake_metrics.mock_get_statistics_wb)
|
|
||||||
h1, h2, avg, w_map = self.strategy.group_hosts_by_cpu_util()
|
h1, h2, avg, w_map = self.strategy.group_hosts_by_cpu_util()
|
||||||
vm_to_mig = self.strategy.choose_vm_to_migrate(h1, avg, w_map)
|
vm_to_mig = self.strategy.choose_vm_to_migrate(h1, avg, w_map)
|
||||||
self.assertEqual(vm_to_mig[0].uuid, 'Node_0')
|
self.assertEqual(vm_to_mig[0].uuid, 'Node_0')
|
||||||
@@ -96,8 +97,6 @@ class TestWorkloadBalance(base.BaseTestCase):
|
|||||||
def test_choose_vm_notfound(self):
|
def test_choose_vm_notfound(self):
|
||||||
model = self.fake_cluster.generate_scenario_6_with_2_hypervisors()
|
model = self.fake_cluster.generate_scenario_6_with_2_hypervisors()
|
||||||
self.m_model.return_value = model
|
self.m_model.return_value = model
|
||||||
self.strategy.ceilometer = mock.MagicMock(
|
|
||||||
statistic_aggregation=self.fake_metrics.mock_get_statistics_wb)
|
|
||||||
h1, h2, avg, w_map = self.strategy.group_hosts_by_cpu_util()
|
h1, h2, avg, w_map = self.strategy.group_hosts_by_cpu_util()
|
||||||
vms = model.get_all_vms()
|
vms = model.get_all_vms()
|
||||||
vms.clear()
|
vms.clear()
|
||||||
@@ -107,8 +106,6 @@ class TestWorkloadBalance(base.BaseTestCase):
|
|||||||
def test_filter_destination_hosts(self):
|
def test_filter_destination_hosts(self):
|
||||||
model = self.fake_cluster.generate_scenario_6_with_2_hypervisors()
|
model = self.fake_cluster.generate_scenario_6_with_2_hypervisors()
|
||||||
self.m_model.return_value = model
|
self.m_model.return_value = model
|
||||||
self.strategy.ceilometer = mock.MagicMock(
|
|
||||||
statistic_aggregation=self.fake_metrics.mock_get_statistics_wb)
|
|
||||||
h1, h2, avg, w_map = self.strategy.group_hosts_by_cpu_util()
|
h1, h2, avg, w_map = self.strategy.group_hosts_by_cpu_util()
|
||||||
vm_to_mig = self.strategy.choose_vm_to_migrate(h1, avg, w_map)
|
vm_to_mig = self.strategy.choose_vm_to_migrate(h1, avg, w_map)
|
||||||
dest_hosts = self.strategy.filter_destination_hosts(
|
dest_hosts = self.strategy.filter_destination_hosts(
|
||||||
@@ -137,23 +134,17 @@ class TestWorkloadBalance(base.BaseTestCase):
|
|||||||
def test_execute_cluster_empty(self):
|
def test_execute_cluster_empty(self):
|
||||||
model = model_root.ModelRoot()
|
model = model_root.ModelRoot()
|
||||||
self.m_model.return_value = model
|
self.m_model.return_value = model
|
||||||
self.strategy.ceilometer = mock.MagicMock(
|
|
||||||
statistic_aggregation=self.fake_metrics.mock_get_statistics_wb)
|
|
||||||
self.assertRaises(exception.ClusterEmpty, self.strategy.execute)
|
self.assertRaises(exception.ClusterEmpty, self.strategy.execute)
|
||||||
|
|
||||||
def test_execute_no_workload(self):
|
def test_execute_no_workload(self):
|
||||||
model = self.fake_cluster.generate_scenario_4_with_1_hypervisor_no_vm()
|
model = self.fake_cluster.generate_scenario_4_with_1_hypervisor_no_vm()
|
||||||
self.m_model.return_value = model
|
self.m_model.return_value = model
|
||||||
self.strategy.ceilometer = mock.MagicMock(
|
|
||||||
statistic_aggregation=self.fake_metrics.mock_get_statistics_wb)
|
|
||||||
solution = self.strategy.execute()
|
solution = self.strategy.execute()
|
||||||
self.assertEqual([], solution.actions)
|
self.assertEqual([], solution.actions)
|
||||||
|
|
||||||
def test_execute(self):
|
def test_execute(self):
|
||||||
model = self.fake_cluster.generate_scenario_6_with_2_hypervisors()
|
model = self.fake_cluster.generate_scenario_6_with_2_hypervisors()
|
||||||
self.m_model.return_value = model
|
self.m_model.return_value = model
|
||||||
self.strategy.ceilometer = mock.MagicMock(
|
|
||||||
statistic_aggregation=self.fake_metrics.mock_get_statistics_wb)
|
|
||||||
solution = self.strategy.execute()
|
solution = self.strategy.execute()
|
||||||
actions_counter = collections.Counter(
|
actions_counter = collections.Counter(
|
||||||
[action.get('action_type') for action in solution.actions])
|
[action.get('action_type') for action in solution.actions])
|
||||||
@@ -164,8 +155,6 @@ class TestWorkloadBalance(base.BaseTestCase):
|
|||||||
def test_check_parameters(self):
|
def test_check_parameters(self):
|
||||||
model = self.fake_cluster.generate_scenario_6_with_2_hypervisors()
|
model = self.fake_cluster.generate_scenario_6_with_2_hypervisors()
|
||||||
self.m_model.return_value = model
|
self.m_model.return_value = model
|
||||||
self.strategy.ceilometer = mock.MagicMock(
|
|
||||||
statistic_aggregation=self.fake_metrics.mock_get_statistics_wb)
|
|
||||||
solution = self.strategy.execute()
|
solution = self.strategy.execute()
|
||||||
loader = default.DefaultActionLoader()
|
loader = default.DefaultActionLoader()
|
||||||
for action in solution.actions:
|
for action in solution.actions:
|
||||||
|
|||||||
Reference in New Issue
Block a user