From dc2c361d04211717ee97eb51747328b9aab17324 Mon Sep 17 00:00:00 2001 From: chenke Date: Mon, 20 May 2019 11:39:07 +0800 Subject: [PATCH] Add reource_name in action input parameter field (Partial implement) Implements: blueprint add-resource-name-in-action-input-parameter-field Depends-on: I51d879e31dee03652ee9d0d94a7f3168012cc060 Change-Id: I708cf63ff1d9a989604e1d5b834c8b7e5b087892 --- .../actions/change_nova_service_state.py | 4 ++ watcher/applier/actions/migration.py | 4 ++ .../decision_engine/model/element/instance.py | 1 + .../strategy/strategies/base.py | 3 +- .../strategies/basic_consolidation.py | 3 +- .../strategy/strategies/host_maintenance.py | 9 ++- .../strategy/strategies/noisy_neighbor.py | 3 +- .../strategies/outlet_temp_control.py | 3 +- .../strategies/vm_workload_consolidation.py | 6 +- .../decision_engine/cluster/test_nova_cdmc.py | 1 + .../decision_engine/model/data/scenario_1.xml | 70 +++++++++---------- .../model/faker_cluster_state.py | 1 + .../strategies/test_host_maintenance.py | 27 +++++-- .../test_vm_workload_consolidation.py | 48 +++++++++---- 14 files changed, 117 insertions(+), 66 deletions(-) diff --git a/watcher/applier/actions/change_nova_service_state.py b/watcher/applier/actions/change_nova_service_state.py index 166b449bf..ea302c099 100644 --- a/watcher/applier/actions/change_nova_service_state.py +++ b/watcher/applier/actions/change_nova_service_state.py @@ -60,6 +60,10 @@ class ChangeNovaServiceState(base.BaseAction): 'type': 'string', "minlength": 1 }, + 'resource_name': { + 'type': 'string', + "minlength": 1 + }, 'state': { 'type': 'string', 'enum': [element.ServiceState.ONLINE.value, diff --git a/watcher/applier/actions/migration.py b/watcher/applier/actions/migration.py index 2fe547460..781f378cd 100644 --- a/watcher/applier/actions/migration.py +++ b/watcher/applier/actions/migration.py @@ -87,6 +87,10 @@ class Migrate(base.BaseAction): "([a-fA-F0-9]){4}-([a-fA-F0-9]){4}-" "([a-fA-F0-9]){12}$") }, + 'resource_name': { + 'type': 'string', + "minlength": 1 + }, 'source_node': { 'type': 'string', "minLength": 1 diff --git a/watcher/decision_engine/model/element/instance.py b/watcher/decision_engine/model/element/instance.py index 3d3ffffd0..ae5631648 100644 --- a/watcher/decision_engine/model/element/instance.py +++ b/watcher/decision_engine/model/element/instance.py @@ -46,6 +46,7 @@ class Instance(compute_resource.ComputeResource): # If the resource is excluded by the scope, # 'watcher_exclude' property will be set True. "watcher_exclude": wfields.BooleanField(default=False), + "name": wfields.StringField(), "state": wfields.StringField(default=InstanceState.ACTIVE.value), "memory": wfields.NonNegativeIntegerField(), "disk": wfields.IntegerField(), diff --git a/watcher/decision_engine/strategy/strategies/base.py b/watcher/decision_engine/strategy/strategies/base.py index f730f438e..d19ce1564 100755 --- a/watcher/decision_engine/strategy/strategies/base.py +++ b/watcher/decision_engine/strategy/strategies/base.py @@ -450,7 +450,8 @@ class BaseStrategy(loadable.Loadable): destination_node): parameters = {'migration_type': migration_type, 'source_node': source_node.uuid, - 'destination_node': destination_node.uuid} + 'destination_node': destination_node.uuid, + 'resource_name': instance.name} self.solution.add_action(action_type=self.MIGRATION, resource_id=instance.uuid, input_parameters=parameters) diff --git a/watcher/decision_engine/strategy/strategies/basic_consolidation.py b/watcher/decision_engine/strategy/strategies/basic_consolidation.py index 82e042b0b..c84c3e9de 100644 --- a/watcher/decision_engine/strategy/strategies/basic_consolidation.py +++ b/watcher/decision_engine/strategy/strategies/basic_consolidation.py @@ -323,7 +323,8 @@ class BasicConsolidation(base.ServerConsolidationBaseStrategy): def add_action_disable_node(self, node): parameters = {'state': element.ServiceState.DISABLED.value, - 'disabled_reason': self.REASON_FOR_DISABLE} + 'disabled_reason': self.REASON_FOR_DISABLE, + 'resource_name': node.hostname} self.solution.add_action(action_type=self.CHANGE_NOVA_SERVICE_STATE, resource_id=node.uuid, input_parameters=parameters) diff --git a/watcher/decision_engine/strategy/strategies/host_maintenance.py b/watcher/decision_engine/strategy/strategies/host_maintenance.py index 1da8c9358..60cdd9eee 100644 --- a/watcher/decision_engine/strategy/strategies/host_maintenance.py +++ b/watcher/decision_engine/strategy/strategies/host_maintenance.py @@ -185,7 +185,8 @@ class HostMaintenance(base.HostMaintenanceBaseStrategy): def add_action_enable_compute_node(self, node): """Add an action for node enabler into the solution.""" - params = {'state': element.ServiceState.ENABLED.value} + params = {'state': element.ServiceState.ENABLED.value, + 'resource_name': node.hostname} self.solution.add_action( action_type=self.CHANGE_NOVA_SERVICE_STATE, resource_id=node.uuid, @@ -194,7 +195,8 @@ class HostMaintenance(base.HostMaintenanceBaseStrategy): def add_action_maintain_compute_node(self, node): """Add an action for node maintenance into the solution.""" params = {'state': element.ServiceState.DISABLED.value, - 'disabled_reason': self.REASON_FOR_MAINTAINING} + 'disabled_reason': self.REASON_FOR_MAINTAINING, + 'resource_name': node.hostname} self.solution.add_action( action_type=self.CHANGE_NOVA_SERVICE_STATE, resource_id=node.uuid, @@ -221,7 +223,8 @@ class HostMaintenance(base.HostMaintenanceBaseStrategy): migration_type = 'cold' params = {'migration_type': migration_type, - 'source_node': src_node.uuid} + 'source_node': src_node.uuid, + 'resource_name': instance.name} if des_node: params['destination_node'] = des_node.uuid self.solution.add_action(action_type=self.INSTANCE_MIGRATION, diff --git a/watcher/decision_engine/strategy/strategies/noisy_neighbor.py b/watcher/decision_engine/strategy/strategies/noisy_neighbor.py index b9e4c2480..b0ccd4e11 100644 --- a/watcher/decision_engine/strategy/strategies/noisy_neighbor.py +++ b/watcher/decision_engine/strategy/strategies/noisy_neighbor.py @@ -280,7 +280,8 @@ class NoisyNeighbor(base.NoisyNeighborBaseStrategy): mig_destination_node): parameters = {'migration_type': 'live', 'source_node': mig_source_node.uuid, - 'destination_node': mig_destination_node.uuid} + 'destination_node': mig_destination_node.uuid, + 'resource_name': instance_to_migrate.name} self.solution.add_action(action_type=self.MIGRATION, resource_id=instance_to_migrate.uuid, input_parameters=parameters) diff --git a/watcher/decision_engine/strategy/strategies/outlet_temp_control.py b/watcher/decision_engine/strategy/strategies/outlet_temp_control.py index 2e5a5821e..40a6a1a6f 100644 --- a/watcher/decision_engine/strategy/strategies/outlet_temp_control.py +++ b/watcher/decision_engine/strategy/strategies/outlet_temp_control.py @@ -282,7 +282,8 @@ class OutletTempControl(base.ThermalOptimizationBaseStrategy): instance_src, mig_source_node, mig_destination_node): parameters = {'migration_type': 'live', 'source_node': mig_source_node.uuid, - 'destination_node': mig_destination_node.uuid} + 'destination_node': mig_destination_node.uuid, + 'resource_name': instance_src.name} self.solution.add_action(action_type=self.MIGRATION, resource_id=instance_src.uuid, input_parameters=parameters) diff --git a/watcher/decision_engine/strategy/strategies/vm_workload_consolidation.py b/watcher/decision_engine/strategy/strategies/vm_workload_consolidation.py index 7b2777f54..626e6a66c 100644 --- a/watcher/decision_engine/strategy/strategies/vm_workload_consolidation.py +++ b/watcher/decision_engine/strategy/strategies/vm_workload_consolidation.py @@ -165,7 +165,8 @@ class VMWorkloadConsolidation(base.ServerConsolidationBaseStrategy): :param node: node object :return: None """ - params = {'state': element.ServiceState.ENABLED.value} + params = {'state': element.ServiceState.ENABLED.value, + 'resource_name': node.hostname} self.solution.add_action( action_type=self.CHANGE_NOVA_SERVICE_STATE, resource_id=node.uuid, @@ -179,7 +180,8 @@ class VMWorkloadConsolidation(base.ServerConsolidationBaseStrategy): :return: None """ params = {'state': element.ServiceState.DISABLED.value, - 'disabled_reason': self.REASON_FOR_DISABLE} + 'disabled_reason': self.REASON_FOR_DISABLE, + 'resource_name': node.hostname} self.solution.add_action( action_type=self.CHANGE_NOVA_SERVICE_STATE, resource_id=node.uuid, diff --git a/watcher/tests/decision_engine/cluster/test_nova_cdmc.py b/watcher/tests/decision_engine/cluster/test_nova_cdmc.py index 6d7de91d0..55df67aec 100644 --- a/watcher/tests/decision_engine/cluster/test_nova_cdmc.py +++ b/watcher/tests/decision_engine/cluster/test_nova_cdmc.py @@ -83,6 +83,7 @@ class TestNovaClusterDataModelCollector(base.TestCase): tenant_id='ff560f7e-dbc8-771f-960c-164482fce21b', ) setattr(fake_instance, 'OS-EXT-STS:vm_state', 'VM_STATE') + setattr(fake_instance, 'name', 'fake_instance') # Returns the hypervisors with details (service) but no servers. m_nova_helper.get_compute_node_list.return_value = [fake_compute_node] # Returns the hypervisor with servers and details (service). diff --git a/watcher/tests/decision_engine/model/data/scenario_1.xml b/watcher/tests/decision_engine/model/data/scenario_1.xml index 9d443d1d0..10c038e87 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/faker_cluster_state.py b/watcher/tests/decision_engine/model/faker_cluster_state.py index ee272ce45..a64f2a7bb 100644 --- a/watcher/tests/decision_engine/model/faker_cluster_state.py +++ b/watcher/tests/decision_engine/model/faker_cluster_state.py @@ -99,6 +99,7 @@ class FakerModelCollector(base.BaseClusterDataModelCollector): project_id = "91FFFE30-78A0-4152-ACD2-8310FF274DC9" instance_attributes = { "uuid": instance_uuid, + "name": instance_uuid, "memory": 2, "disk": 20, "disk_capacity": 20, diff --git a/watcher/tests/decision_engine/strategy/strategies/test_host_maintenance.py b/watcher/tests/decision_engine/strategy/strategies/test_host_maintenance.py index 2f5917022..8e36a3e6f 100755 --- a/watcher/tests/decision_engine/strategy/strategies/test_host_maintenance.py +++ b/watcher/tests/decision_engine/strategy/strategies/test_host_maintenance.py @@ -101,7 +101,8 @@ class TestHostMaintenance(TestBaseStrategy): expected = [{'action_type': 'change_nova_service_state', 'input_parameters': { 'state': 'enabled', - 'resource_id': 'Node_0'}}] + 'resource_id': 'Node_0', + 'resource_name': 'hostname_0'}}] self.assertEqual(expected, self.strategy.solution.actions) def test_add_action_maintain_compute_node(self): @@ -113,7 +114,8 @@ class TestHostMaintenance(TestBaseStrategy): 'input_parameters': { 'state': 'disabled', 'disabled_reason': 'watcher_maintaining', - 'resource_id': 'Node_0'}}] + 'resource_id': 'Node_0', + 'resource_name': 'hostname_0'}}] self.assertEqual(expected, self.strategy.solution.actions) def test_instance_migration(self): @@ -128,7 +130,9 @@ class TestHostMaintenance(TestBaseStrategy): 'input_parameters': {'destination_node': node_1.uuid, 'source_node': node_0.uuid, 'migration_type': 'live', - 'resource_id': instance_0.uuid}}] + 'resource_id': instance_0.uuid, + 'resource_name': instance_0.name + }}] self.assertEqual(expected, self.strategy.solution.actions) def test_instance_migration_without_dest_node(self): @@ -141,7 +145,9 @@ class TestHostMaintenance(TestBaseStrategy): expected = [{'action_type': 'migrate', 'input_parameters': {'source_node': node_0.uuid, 'migration_type': 'live', - 'resource_id': instance_0.uuid}}] + 'resource_id': instance_0.uuid, + 'resource_name': instance_0.name + }}] self.assertEqual(expected, self.strategy.solution.actions) def test_host_migration(self): @@ -157,12 +163,16 @@ class TestHostMaintenance(TestBaseStrategy): 'input_parameters': {'destination_node': node_1.uuid, 'source_node': node_0.uuid, 'migration_type': 'live', - 'resource_id': instance_0.uuid}}, + 'resource_id': instance_0.uuid, + 'resource_name': instance_0.name + }}, {'action_type': 'migrate', 'input_parameters': {'destination_node': node_1.uuid, 'source_node': node_0.uuid, 'migration_type': 'live', - 'resource_id': instance_1.uuid}}] + 'resource_id': instance_1.uuid, + 'resource_name': instance_1.name + }}] self.assertIn(expected[0], self.strategy.solution.actions) self.assertIn(expected[1], self.strategy.solution.actions) @@ -209,10 +219,12 @@ class TestHostMaintenance(TestBaseStrategy): expected = [{'action_type': 'change_nova_service_state', 'input_parameters': { 'resource_id': 'Node_3', + 'resource_name': 'hostname_3', 'state': 'enabled'}}, {'action_type': 'change_nova_service_state', 'input_parameters': { 'resource_id': 'Node_2', + 'resource_name': 'hostname_2', 'state': 'disabled', 'disabled_reason': 'watcher_maintaining'}}, {'action_type': 'migrate', @@ -220,7 +232,8 @@ class TestHostMaintenance(TestBaseStrategy): 'destination_node': node_3.uuid, 'source_node': node_2.uuid, 'migration_type': 'live', - 'resource_id': instance_4.uuid}}] + 'resource_id': instance_4.uuid, + 'resource_name': instance_4.name}}] self.assertEqual(expected, self.strategy.solution.actions) result = self.strategy.post_execute() diff --git a/watcher/tests/decision_engine/strategy/strategies/test_vm_workload_consolidation.py b/watcher/tests/decision_engine/strategy/strategies/test_vm_workload_consolidation.py index 370938fc6..31764357e 100644 --- a/watcher/tests/decision_engine/strategy/strategies/test_vm_workload_consolidation.py +++ b/watcher/tests/decision_engine/strategy/strategies/test_vm_workload_consolidation.py @@ -127,7 +127,8 @@ class TestVMWorkloadConsolidation(TestBaseStrategy): 'input_parameters': {'destination_node': n2.uuid, 'source_node': n1.uuid, 'migration_type': 'live', - 'resource_id': instance_uuid}} + 'resource_id': instance.uuid, + 'resource_name': instance.name}} self.assertEqual(expected, self.strategy.solution.actions[0]) def test_add_migration_with_paused_state(self): @@ -149,7 +150,8 @@ class TestVMWorkloadConsolidation(TestBaseStrategy): 'input_parameters': {'destination_node': n2.uuid, 'source_node': n1.uuid, 'migration_type': 'live', - 'resource_id': instance_uuid}} + 'resource_id': instance.uuid, + 'resource_name': instance.name}} self.assertEqual(expected, self.strategy.solution.actions[0]) def test_is_overloaded(self): @@ -191,7 +193,8 @@ class TestVMWorkloadConsolidation(TestBaseStrategy): self.strategy.add_action_enable_compute_node(n) expected = [{'action_type': 'change_nova_service_state', 'input_parameters': {'state': 'enabled', - 'resource_id': 'Node_0'}}] + 'resource_id': 'Node_0', + 'resource_name': 'hostname_0'}}] self.assertEqual(expected, self.strategy.solution.actions) def test_add_action_disable_node(self): @@ -204,7 +207,8 @@ class TestVMWorkloadConsolidation(TestBaseStrategy): 'input_parameters': { 'state': 'disabled', 'disabled_reason': 'watcher_disabled', - 'resource_id': 'Node_0'}}] + 'resource_id': 'Node_0', + 'resource_name': 'hostname_0'}}] self.assertEqual(expected, self.strategy.solution.actions) def test_disable_unused_nodes(self): @@ -226,7 +230,8 @@ class TestVMWorkloadConsolidation(TestBaseStrategy): 'input_parameters': { 'state': 'disabled', 'disabled_reason': 'watcher_disabled', - 'resource_id': 'Node_0'}} + 'resource_id': 'Node_0', + 'resource_name': 'hostname_0'}} self.assertEqual(2, len(self.strategy.solution.actions)) self.assertEqual(expected, self.strategy.solution.actions[1]) @@ -246,13 +251,15 @@ class TestVMWorkloadConsolidation(TestBaseStrategy): n1 = model.get_node_by_uuid('Node_0') n2 = model.get_node_by_uuid('Node_1') instance_uuid = 'INSTANCE_0' + instance = model.get_instance_by_uuid(instance_uuid) cc = {'cpu': 1.0, 'ram': 1.0, 'disk': 1.0} self.strategy.consolidation_phase(cc) expected = [{'action_type': 'migrate', 'input_parameters': {'destination_node': n2.uuid, 'source_node': n1.uuid, 'migration_type': 'live', - 'resource_id': instance_uuid}}] + 'resource_id': instance.uuid, + 'resource_name': instance.name}}] self.assertEqual(expected, self.strategy.solution.actions) def test_strategy(self): @@ -266,32 +273,39 @@ class TestVMWorkloadConsolidation(TestBaseStrategy): n1 = model.get_node_by_uuid('Node_0') self.strategy.get_relative_cluster_utilization = mock.MagicMock() self.strategy.do_execute() - n2 = self.strategy.solution.actions[0][ + n2_uuid = self.strategy.solution.actions[0][ 'input_parameters']['destination_node'] - n3 = self.strategy.solution.actions[2][ + n2 = model.get_node_by_uuid(n2_uuid) + n3_uuid = self.strategy.solution.actions[2][ 'input_parameters']['resource_id'] - n4 = self.strategy.solution.actions[3][ + n3 = model.get_node_by_uuid(n3_uuid) + n4_uuid = self.strategy.solution.actions[3][ 'input_parameters']['resource_id'] + n4 = model.get_node_by_uuid(n4_uuid) expected = [{'action_type': 'migrate', - 'input_parameters': {'destination_node': n2, + 'input_parameters': {'destination_node': n2.uuid, 'source_node': n1.uuid, 'migration_type': 'live', - 'resource_id': 'INSTANCE_3'}}, + 'resource_id': 'INSTANCE_3', + 'resource_name': ''}}, {'action_type': 'migrate', - 'input_parameters': {'destination_node': n2, + 'input_parameters': {'destination_node': n2.uuid, 'source_node': n1.uuid, 'migration_type': 'live', - 'resource_id': 'INSTANCE_1'}}, + 'resource_id': 'INSTANCE_1', + 'resource_name': ''}}, {'action_type': 'change_nova_service_state', 'input_parameters': {'state': 'disabled', 'disabled_reason': 'watcher_disabled', - 'resource_id': n3}}, + 'resource_id': n3.uuid, + 'resource_name': n3.hostname}}, {'action_type': 'change_nova_service_state', 'input_parameters': {'state': 'disabled', 'disabled_reason': 'watcher_disabled', - 'resource_id': n4}}] + 'resource_id': n4.uuid, + 'resource_name': n4.hostname}}] self.assertEqual(expected, self.strategy.solution.actions) compute_nodes_count = len(self.strategy.get_available_compute_nodes()) @@ -319,16 +333,19 @@ class TestVMWorkloadConsolidation(TestBaseStrategy): 'input_parameters': {'destination_node': n2.uuid, 'migration_type': 'live', 'resource_id': 'INSTANCE_6', + 'resource_name': '', 'source_node': n1.uuid}}, {'action_type': 'migrate', 'input_parameters': {'destination_node': n2.uuid, 'migration_type': 'live', 'resource_id': 'INSTANCE_7', + 'resource_name': '', 'source_node': n1.uuid}}, {'action_type': 'migrate', 'input_parameters': {'destination_node': n2.uuid, 'migration_type': 'live', 'resource_id': 'INSTANCE_8', + 'resource_name': '', 'source_node': n1.uuid}}] self.assertEqual(expected, self.strategy.solution.actions) self.strategy.consolidation_phase(cc) @@ -336,6 +353,7 @@ class TestVMWorkloadConsolidation(TestBaseStrategy): 'input_parameters': {'destination_node': n1.uuid, 'migration_type': 'live', 'resource_id': 'INSTANCE_7', + 'resource_name': '', 'source_node': n2.uuid}}) self.assertEqual(expected, self.strategy.solution.actions) self.strategy.optimize_solution()