diff --git a/releasenotes/notes/compute-cdm-include-all-instances-f7506ded2d57732f.yaml b/releasenotes/notes/compute-cdm-include-all-instances-f7506ded2d57732f.yaml
new file mode 100644
index 000000000..e39f0e354
--- /dev/null
+++ b/releasenotes/notes/compute-cdm-include-all-instances-f7506ded2d57732f.yaml
@@ -0,0 +1,6 @@
+---
+features:
+ - Watcher has a whole scope of the cluster, when building
+ compute CDM which includes all instances.
+ It filters excluded instances when migration during the
+ audit.
\ No newline at end of file
diff --git a/watcher/decision_engine/model/model_root.py b/watcher/decision_engine/model/model_root.py
index 07dc4da8e..a72f41d4b 100644
--- a/watcher/decision_engine/model/model_root.py
+++ b/watcher/decision_engine/model/model_root.py
@@ -16,6 +16,7 @@
Openstack implementation of the cluster graph.
"""
+import ast
from lxml import etree
import networkx as nx
from oslo_concurrency import lockutils
@@ -225,6 +226,8 @@ class ModelRoot(nx.DiGraph, base.Model):
for inst in root.findall('.//Instance'):
instance = element.Instance(**inst.attrib)
+ instance.watcher_exclude = ast.literal_eval(
+ inst.attrib["watcher_exclude"])
model.add_instance(instance)
parent = inst.getparent()
diff --git a/watcher/decision_engine/strategy/strategies/basic_consolidation.py b/watcher/decision_engine/strategy/strategies/basic_consolidation.py
index c3fdcb4fa..5be5cf325 100644
--- a/watcher/decision_engine/strategy/strategies/basic_consolidation.py
+++ b/watcher/decision_engine/strategy/strategies/basic_consolidation.py
@@ -400,6 +400,11 @@ class BasicConsolidation(base.ServerConsolidationBaseStrategy):
sorted_score):
number_migrations = 0
for mig_instance, __ in sorted_instances:
+ # skip exclude instance when migrating
+ if mig_instance.watcher_exclude:
+ LOG.debug("Instance is excluded by scope, "
+ "skipped: %s", mig_instance.uuid)
+ continue
for node_uuid, __ in sorted_score:
mig_source_node = self.compute_model.get_node_by_uuid(
node_to_release)
diff --git a/watcher/decision_engine/strategy/strategies/outlet_temp_control.py b/watcher/decision_engine/strategy/strategies/outlet_temp_control.py
index 467a5c2c4..fdc2fd790 100644
--- a/watcher/decision_engine/strategy/strategies/outlet_temp_control.py
+++ b/watcher/decision_engine/strategy/strategies/outlet_temp_control.py
@@ -212,6 +212,11 @@ class OutletTempControl(base.ThermalOptimizationBaseStrategy):
mig_source_node)
for instance in instances_of_src:
try:
+ # NOTE: skip exclude instance when migrating
+ if instance.watcher_exclude:
+ LOG.debug("Instance is excluded by scope, "
+ "skipped: %s", instance.uuid)
+ continue
# select the first active instance to migrate
if (instance.state !=
element.InstanceState.ACTIVE.value):
diff --git a/watcher/decision_engine/strategy/strategies/uniform_airflow.py b/watcher/decision_engine/strategy/strategies/uniform_airflow.py
index 0a4a436a4..8dd439813 100644
--- a/watcher/decision_engine/strategy/strategies/uniform_airflow.py
+++ b/watcher/decision_engine/strategy/strategies/uniform_airflow.py
@@ -240,6 +240,11 @@ class UniformAirflow(base.BaseStrategy):
else:
# migrate the first active instance
for instance in source_instances:
+ # NOTE: skip exclude instance when migrating
+ if instance.watcher_exclude:
+ LOG.debug("Instance is excluded by scope, "
+ "skipped: %s", instance.uuid)
+ continue
if (instance.state !=
element.InstanceState.ACTIVE.value):
LOG.info(
diff --git a/watcher/decision_engine/strategy/strategies/vm_workload_consolidation.py b/watcher/decision_engine/strategy/strategies/vm_workload_consolidation.py
index 2af96bab4..3b2959b3e 100644
--- a/watcher/decision_engine/strategy/strategies/vm_workload_consolidation.py
+++ b/watcher/decision_engine/strategy/strategies/vm_workload_consolidation.py
@@ -504,6 +504,11 @@ class VMWorkloadConsolidation(base.ServerConsolidationBaseStrategy):
key=lambda x: self.get_instance_utilization(
x)['cpu']
):
+ # skip exclude instance when migrating
+ if instance.watcher_exclude:
+ LOG.debug("Instance is excluded by scope, "
+ "skipped: %s", instance.uuid)
+ continue
for destination_node in reversed(sorted_nodes):
if self.instance_fits(
instance, destination_node, cc):
@@ -536,6 +541,11 @@ class VMWorkloadConsolidation(base.ServerConsolidationBaseStrategy):
self.compute_model.get_node_instances(node),
key=lambda x: self.get_instance_utilization(x)['cpu'])
for instance in reversed(instances):
+ # skip exclude instance when migrating
+ if instance.watcher_exclude:
+ LOG.debug("Instance is excluded by scope, "
+ "skipped: %s", instance.uuid)
+ continue
dsc = len(sorted_nodes) - 1
for destination_node in reversed(sorted_nodes):
if asc >= dsc:
diff --git a/watcher/decision_engine/strategy/strategies/workload_balance.py b/watcher/decision_engine/strategy/strategies/workload_balance.py
index 426983df6..c0f0917d5 100644
--- a/watcher/decision_engine/strategy/strategies/workload_balance.py
+++ b/watcher/decision_engine/strategy/strategies/workload_balance.py
@@ -208,6 +208,11 @@ class WorkloadBalance(base.WorkloadStabilizationBaseStrategy):
instance_id = None
for instance in source_instances:
try:
+ # NOTE: skip exclude instance when migrating
+ if instance.watcher_exclude:
+ LOG.debug("Instance is excluded by scope, "
+ "skipped: %s", instance.uuid)
+ continue
# select the first active VM to migrate
if (instance.state !=
element.InstanceState.ACTIVE.value):
diff --git a/watcher/decision_engine/strategy/strategies/workload_stabilization.py b/watcher/decision_engine/strategy/strategies/workload_stabilization.py
index bf4d4edef..e657b8227 100644
--- a/watcher/decision_engine/strategy/strategies/workload_stabilization.py
+++ b/watcher/decision_engine/strategy/strategies/workload_stabilization.py
@@ -412,10 +412,15 @@ class WorkloadStabilization(base.WorkloadStabilizationBaseStrategy):
c_nodes.remove(src_host)
node_list = yield_nodes(c_nodes)
for instance in self.compute_model.get_node_instances(src_node):
- min_sd_case = {'value': current_weighted_sd}
+ # NOTE: skip exclude instance when migrating
+ if instance.watcher_exclude:
+ LOG.debug("Instance is excluded by scope, "
+ "skipped: %s", instance.uuid)
+ continue
if instance.state not in [element.InstanceState.ACTIVE.value,
element.InstanceState.PAUSED.value]:
continue
+ min_sd_case = {'value': current_weighted_sd}
for dst_host in next(node_list):
dst_node = self.compute_model.get_node_by_uuid(dst_host)
sd_case = self.calculate_migration_case(
diff --git a/watcher/tests/decision_engine/model/data/scenario_1.xml b/watcher/tests/decision_engine/model/data/scenario_1.xml
index 7476af277..95cba68a9 100644
--- a/watcher/tests/decision_engine/model/data/scenario_1.xml
+++ b/watcher/tests/decision_engine/model/data/scenario_1.xml
@@ -1,47 +1,47 @@
-
-
+
+
-
+
-
-
-
+
+
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/watcher/tests/decision_engine/model/data/scenario_1_with_1_node_unavailable.xml b/watcher/tests/decision_engine/model/data/scenario_1_with_1_node_unavailable.xml
index ad95c2fda..fb19025f1 100644
--- a/watcher/tests/decision_engine/model/data/scenario_1_with_1_node_unavailable.xml
+++ b/watcher/tests/decision_engine/model/data/scenario_1_with_1_node_unavailable.xml
@@ -1,50 +1,50 @@
-
-
+
+
-
+
-
-
-
+
+
+
-
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/watcher/tests/decision_engine/model/data/scenario_1_with_all_instances_exclude.xml b/watcher/tests/decision_engine/model/data/scenario_1_with_all_instances_exclude.xml
new file mode 100644
index 000000000..6b4f87012
--- /dev/null
+++ b/watcher/tests/decision_engine/model/data/scenario_1_with_all_instances_exclude.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/watcher/tests/decision_engine/model/data/scenario_1_with_metrics.xml b/watcher/tests/decision_engine/model/data/scenario_1_with_metrics.xml
index 17c084c40..fffa2fcc2 100644
--- a/watcher/tests/decision_engine/model/data/scenario_1_with_metrics.xml
+++ b/watcher/tests/decision_engine/model/data/scenario_1_with_metrics.xml
@@ -1,8 +1,8 @@
-
+
-
+
diff --git a/watcher/tests/decision_engine/model/data/scenario_2_with_metrics.xml b/watcher/tests/decision_engine/model/data/scenario_2_with_metrics.xml
index 668ef1985..6e94543f4 100644
--- a/watcher/tests/decision_engine/model/data/scenario_2_with_metrics.xml
+++ b/watcher/tests/decision_engine/model/data/scenario_2_with_metrics.xml
@@ -1,11 +1,11 @@
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/watcher/tests/decision_engine/model/data/scenario_3_with_2_nodes.xml b/watcher/tests/decision_engine/model/data/scenario_3_with_2_nodes.xml
index 189d81ee9..209a83684 100644
--- a/watcher/tests/decision_engine/model/data/scenario_3_with_2_nodes.xml
+++ b/watcher/tests/decision_engine/model/data/scenario_3_with_2_nodes.xml
@@ -1,8 +1,8 @@
-
+
-
+
diff --git a/watcher/tests/decision_engine/model/data/scenario_3_with_metrics.xml b/watcher/tests/decision_engine/model/data/scenario_3_with_metrics.xml
index 5c6079916..e734d3595 100644
--- a/watcher/tests/decision_engine/model/data/scenario_3_with_metrics.xml
+++ b/watcher/tests/decision_engine/model/data/scenario_3_with_metrics.xml
@@ -1,9 +1,9 @@
-
-
-
-
+
+
+
+
diff --git a/watcher/tests/decision_engine/model/data/scenario_5_with_instance_disk_0.xml b/watcher/tests/decision_engine/model/data/scenario_5_with_instance_disk_0.xml
index a8bffab30..0d71f90f8 100644
--- a/watcher/tests/decision_engine/model/data/scenario_5_with_instance_disk_0.xml
+++ b/watcher/tests/decision_engine/model/data/scenario_5_with_instance_disk_0.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/watcher/tests/decision_engine/model/data/scenario_6_with_2_nodes.xml b/watcher/tests/decision_engine/model/data/scenario_6_with_2_nodes.xml
index 636827c63..a75be0abe 100644
--- a/watcher/tests/decision_engine/model/data/scenario_6_with_2_nodes.xml
+++ b/watcher/tests/decision_engine/model/data/scenario_6_with_2_nodes.xml
@@ -1,10 +1,10 @@
-
-
+
+
-
-
+
+
diff --git a/watcher/tests/decision_engine/model/data/scenario_7_with_2_nodes.xml b/watcher/tests/decision_engine/model/data/scenario_7_with_2_nodes.xml
index cf86c00e2..2e9e2a134 100644
--- a/watcher/tests/decision_engine/model/data/scenario_7_with_2_nodes.xml
+++ b/watcher/tests/decision_engine/model/data/scenario_7_with_2_nodes.xml
@@ -1,10 +1,10 @@
-
-
+
+
-
-
+
+
diff --git a/watcher/tests/decision_engine/model/data/scenario_8_with_4_nodes.xml b/watcher/tests/decision_engine/model/data/scenario_8_with_4_nodes.xml
index a646c6e90..dac56c1bf 100644
--- a/watcher/tests/decision_engine/model/data/scenario_8_with_4_nodes.xml
+++ b/watcher/tests/decision_engine/model/data/scenario_8_with_4_nodes.xml
@@ -1,16 +1,16 @@
-
-
-
+
+
+
-
+
-
+
-
+
diff --git a/watcher/tests/decision_engine/model/data/scenario_9_with_3_active_plus_1_disabled_nodes.xml b/watcher/tests/decision_engine/model/data/scenario_9_with_3_active_plus_1_disabled_nodes.xml
index 488f1c7f0..c66239edb 100644
--- a/watcher/tests/decision_engine/model/data/scenario_9_with_3_active_plus_1_disabled_nodes.xml
+++ b/watcher/tests/decision_engine/model/data/scenario_9_with_3_active_plus_1_disabled_nodes.xml
@@ -1,16 +1,16 @@
-
-
-
+
+
+
-
+
-
+
-
+
diff --git a/watcher/tests/decision_engine/model/faker_cluster_state.py b/watcher/tests/decision_engine/model/faker_cluster_state.py
index 043d4e11b..0e05714dc 100644
--- a/watcher/tests/decision_engine/model/faker_cluster_state.py
+++ b/watcher/tests/decision_engine/model/faker_cluster_state.py
@@ -121,6 +121,9 @@ class FakerModelCollector(base.BaseClusterDataModelCollector):
def generate_scenario_1_with_1_node_unavailable(self):
return self.load_model('scenario_1_with_1_node_unavailable.xml')
+ def generate_scenario_1_with_all_instances_exclude(self):
+ return self.load_model('scenario_1_with_all_instances_exclude.xml')
+
def generate_scenario_3_with_2_nodes(self):
return self.load_model('scenario_3_with_2_nodes.xml')
diff --git a/watcher/tests/decision_engine/strategy/strategies/test_workload_stabilization.py b/watcher/tests/decision_engine/strategy/strategies/test_workload_stabilization.py
index f3be6c7ed..961edc92e 100644
--- a/watcher/tests/decision_engine/strategy/strategies/test_workload_stabilization.py
+++ b/watcher/tests/decision_engine/strategy/strategies/test_workload_stabilization.py
@@ -195,6 +195,15 @@ class TestWorkloadStabilization(base.TestCase):
10,
len(self.strategy.simulate_migrations(self.hosts_load_assert)))
+ def test_simulate_migrations_with_all_instances_exclude(self):
+ model = \
+ self.fake_cluster.generate_scenario_1_with_all_instances_exclude()
+ self.m_model.return_value = model
+ self.strategy.host_choice = 'fullsearch'
+ self.assertEqual(
+ 0,
+ len(self.strategy.simulate_migrations(self.hosts_load_assert)))
+
def test_check_threshold(self):
self.m_model.return_value = self.fake_cluster.generate_scenario_1()
self.strategy.thresholds = {'cpu_util': 0.001, 'memory.resident': 0.2}