node resource consolidation
This strategy is used to centralize VMs to as few nodes as possible by VM migration. User can set a input parameter to decide how to select the destination node. Implements: blueprint node-resource-consolidation Closes-Bug: #1843016 Change-Id: I104c864d532c2092f5dc6f0c8f756ebeae12f09e
This commit is contained in:
27
watcher/tests/decision_engine/model/data/scenario_10.xml
Normal file
27
watcher/tests/decision_engine/model/data/scenario_10.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<ModelRoot>
|
||||
<ComputeNode uuid="89dce55c-8e74-4402-b23f-32aaf216c97f" status="enabled" state="up" id="0" hostname="hostname_0" vcpus="40" vcpu_reserved="0" vcpu_ratio="1" disk="250" disk_gb_reserved="0" disk_ratio="1" disk_capacity="250" memory="132" memory_mb_reserved="0" memory_ratio="1">
|
||||
<Instance watcher_exclude="False" state="active" name="INSTANCE_0" uuid="6ae05517-a512-462d-9d83-90c313b5a8ff" vcpus="10" disk="20" disk_capacity="20" memory="20" metadata='{"optimize": true,"top": "floor", "nested": {"x": "y"}}' project_id="91FFFE30-78A0-4152-ACD2-8310FF274DC9"/>
|
||||
<Instance watcher_exclude="False" state="active" name="INSTANCE_1" uuid="6ae05517-a512-462d-9d83-90c313b5a8f1" vcpus="15" disk="20" disk_capacity="20" memory="20" metadata='{"optimize": true,"top": "floor", "nested": {"x": "y"}}' project_id="26F03131-32CB-4697-9D61-9123F87A8147"/>
|
||||
</ComputeNode>
|
||||
<ComputeNode uuid="89dce55c-8e74-4402-b23f-32aaf216c971" status="enabled" state="up" id="1" hostname="hostname_1" vcpus="40" vcpu_reserved="0" vcpu_ratio="1" disk="250" disk_gb_reserved="0" disk_ratio="1" disk_capacity="250" memory="132" memory_mb_reserved="0" memory_ratio="1">
|
||||
<Instance watcher_exclude="False" state="active" name="INSTANCE_2" uuid="6ae05517-a512-462d-9d83-90c313b5a8f2" vcpus="14" disk="20" disk_capacity="20" memory="20" metadata='{"optimize": true,"top": "floor", "nested": {"x": "y"}}' project_id="109F7909-0607-4712-B32C-5CC6D49D2F15"/>
|
||||
</ComputeNode>
|
||||
<ComputeNode uuid="89dce55c-8e74-4402-b23f-32aaf216c972" status="enabled" state="up" id="2" hostname="hostname_2" vcpus="40" vcpu_reserved="0" vcpu_ratio="1" disk="250" disk_gb_reserved="0" disk_ratio="1" disk_capacity="250" memory="132" memory_mb_reserved="0" memory_ratio="1">
|
||||
<Instance watcher_exclude="False" state="active" name="INSTANCE_3" uuid="6ae05517-a512-462d-9d83-90c313b5a8f3" vcpus="10" disk="20" disk_capacity="20" memory="20" metadata='{"optimize": true,"top": "floor", "nested": {"x": "y"}}' project_id="91FFFE30-78A0-4152-ACD2-8310FF274DC9"/>
|
||||
<Instance watcher_exclude="False" state="active" name="INSTANCE_4" uuid="6ae05517-a512-462d-9d83-90c313b5a8f4" vcpus="10" disk="20" disk_capacity="20" memory="20" metadata='{"optimize": true,"top": "floor", "nested": {"x": "y"}}' project_id="91FFFE30-78A0-4152-ACD2-8310FF274DC9"/>
|
||||
<Instance watcher_exclude="False" state="active" name="INSTANCE_5" uuid="6ae05517-a512-462d-9d83-90c313b5a8f5" vcpus="10" disk="20" disk_capacity="20" memory="20" metadata='{"optimize": true,"top": "floor", "nested": {"x": "y"}}' project_id="91FFFE30-78A0-4152-ACD2-8310FF274DC9"/>
|
||||
</ComputeNode>
|
||||
<ComputeNode uuid="89dce55c-8e74-4402-b23f-32aaf216c973" status="enabled" state="up" id="3" hostname="hostname_3" vcpus="40" vcpu_reserved="0" vcpu_ratio="1" disk="250" disk_gb_reserved="0" disk_ratio="1" disk_capacity="250" memory="132" memory_mb_reserved="0" memory_ratio="1">
|
||||
<Instance watcher_exclude="False" state="active" name="INSTANCE_6" uuid="6ae05517-a512-462d-9d83-90c313b5a8f6" vcpus="8" disk="20" disk_capacity="20" memory="20" metadata='{"optimize": true,"top": "floor", "nested": {"x": "y"}}' project_id="91FFFE30-78A0-4152-ACD2-8310FF274DC9"/>
|
||||
</ComputeNode>
|
||||
<ComputeNode uuid="89dce55c-8e74-4402-b23f-32aaf216c974" status="enabled" state="up" id="4" hostname="hostname_4" vcpus="40" vcpu_reserved="0" vcpu_ratio="1" disk="250" disk_gb_reserved="0" disk_ratio="1" disk_capacity="250" memory="132" memory_mb_reserved="0" memory_ratio="1">
|
||||
<Instance watcher_exclude="False" state="active" name="INSTANCE_7" uuid="6ae05517-a512-462d-9d83-90c313b5a8f7" vcpus="10" disk="20" disk_capacity="20" memory="20" metadata='{"optimize": true,"top": "floor", "nested": {"x": "y"}}' project_id="91FFFE30-78A0-4152-ACD2-8310FF274DC9"/>
|
||||
</ComputeNode>
|
||||
<ComputeNode uuid="89dce55c-8e74-4402-b23f-32aaf216c975" status="enabled" state="up" id="5" hostname="hostname_5" vcpus="40" vcpu_reserved="0" vcpu_ratio="1" disk="250" disk_gb_reserved="0" disk_ratio="1" disk_capacity="250" memory="132" memory_mb_reserved="0" memory_ratio="1">
|
||||
</ComputeNode>
|
||||
<ComputeNode uuid="89dce55c-8e74-4402-b23f-32aaf216c976" status="disabled" state="up" id="6" hostname="hostname_6" vcpus="40" vcpu_reserved="0" vcpu_ratio="1" disk="250" disk_gb_reserved="0" disk_ratio="1" disk_capacity="250" memory="132" memory_mb_reserved="0" memory_ratio="1">
|
||||
</ComputeNode>
|
||||
<ComputeNode uuid="89dce55c-8e74-4402-b23f-32aaf216c977" status="disabled" state="up" id="4" hostname="hostname_7" vcpus="40" vcpu_reserved="0" vcpu_ratio="1" disk="250" disk_gb_reserved="0" disk_ratio="1" disk_capacity="250" memory="132" memory_mb_reserved="0" memory_ratio="1">
|
||||
<Instance watcher_exclude="False" state="active" name="INSTANCE_8" uuid="6ae05517-a512-462d-9d83-90c313b5a8f8" vcpus="12" disk="20" disk_capacity="20" memory="20" metadata='{"optimize": true,"top": "floor", "nested": {"x": "y"}}' project_id="91FFFE30-78A0-4152-ACD2-8310FF274DC9"/>
|
||||
</ComputeNode>
|
||||
</ModelRoot>
|
||||
@@ -171,6 +171,9 @@ class FakerModelCollector(base.BaseClusterDataModelCollector):
|
||||
return self.load_model(
|
||||
'scenario_9_with_3_active_plus_1_disabled_nodes.xml')
|
||||
|
||||
def generate_scenario_10(self):
|
||||
return self.load_model('scenario_10.xml')
|
||||
|
||||
|
||||
class FakerStorageModelCollector(base.BaseClusterDataModelCollector):
|
||||
|
||||
|
||||
@@ -0,0 +1,334 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Copyright (c) 2019 ZTE Corporation
|
||||
#
|
||||
# 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 mock
|
||||
|
||||
from watcher.common import exception
|
||||
from watcher.decision_engine.model import element
|
||||
from watcher.decision_engine.strategy import strategies
|
||||
from watcher import objects
|
||||
from watcher.tests.decision_engine.strategy.strategies.test_base \
|
||||
import TestBaseStrategy
|
||||
from watcher.tests.objects import utils as obj_utils
|
||||
|
||||
|
||||
class TestNodeResourceConsolidation(TestBaseStrategy):
|
||||
|
||||
def setUp(self):
|
||||
super(TestNodeResourceConsolidation, self).setUp()
|
||||
self.strategy = strategies.NodeResourceConsolidation(
|
||||
config=mock.Mock())
|
||||
self.model = self.fake_c_cluster.generate_scenario_10()
|
||||
self.m_c_model.return_value = self.model
|
||||
|
||||
def test_check_resources(self):
|
||||
instance = [self.model.get_instance_by_uuid(
|
||||
"6ae05517-a512-462d-9d83-90c313b5a8ff")]
|
||||
dest = self.model.get_node_by_uuid(
|
||||
"89dce55c-8e74-4402-b23f-32aaf216c972")
|
||||
# test destination is null
|
||||
result = self.strategy.check_resources(instance, [])
|
||||
self.assertFalse(result)
|
||||
|
||||
result = self.strategy.check_resources(instance, dest)
|
||||
self.assertTrue(result)
|
||||
self.assertEqual([], instance)
|
||||
|
||||
def test_select_destination(self):
|
||||
instance0 = self.model.get_instance_by_uuid(
|
||||
"6ae05517-a512-462d-9d83-90c313b5a8ff")
|
||||
source = self.model.get_node_by_instance_uuid(
|
||||
"6ae05517-a512-462d-9d83-90c313b5a8ff")
|
||||
expected = self.model.get_node_by_uuid(
|
||||
"89dce55c-8e74-4402-b23f-32aaf216c972")
|
||||
# test destination is null
|
||||
result = self.strategy.select_destination(instance0, source, [])
|
||||
self.assertIsNone(result)
|
||||
|
||||
nodes = list(self.model.get_all_compute_nodes().values())
|
||||
nodes.remove(source)
|
||||
result = self.strategy.select_destination(instance0, source, nodes)
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
def test_add_migrate_actions_with_null(self):
|
||||
self.strategy.add_migrate_actions([], [])
|
||||
self.assertEqual([], self.strategy.solution.actions)
|
||||
self.strategy.add_migrate_actions(None, None)
|
||||
self.assertEqual([], self.strategy.solution.actions)
|
||||
|
||||
def test_add_migrate_actions_with_auto(self):
|
||||
self.strategy.host_choice = 'auto'
|
||||
source = self.model.get_node_by_instance_uuid(
|
||||
"6ae05517-a512-462d-9d83-90c313b5a8ff")
|
||||
nodes = list(self.model.get_all_compute_nodes().values())
|
||||
nodes.remove(source)
|
||||
self.strategy.add_migrate_actions([source], nodes)
|
||||
expected = [{'action_type': 'migrate',
|
||||
'input_parameters': {
|
||||
'migration_type': 'live',
|
||||
'resource_id': '6ae05517-a512-462d-9d83-90c313b5a8f1',
|
||||
'resource_name': 'INSTANCE_1',
|
||||
'source_node': 'hostname_0'}},
|
||||
{'action_type': 'migrate',
|
||||
'input_parameters': {
|
||||
'migration_type': 'live',
|
||||
'resource_id': '6ae05517-a512-462d-9d83-90c313b5a8ff',
|
||||
'resource_name': 'INSTANCE_0',
|
||||
'source_node': 'hostname_0'}}]
|
||||
self.assertEqual(expected, self.strategy.solution.actions)
|
||||
|
||||
def test_add_migrate_actions_with_specify(self):
|
||||
self.strategy.host_choice = 'specify'
|
||||
source = self.model.get_node_by_instance_uuid(
|
||||
"6ae05517-a512-462d-9d83-90c313b5a8ff")
|
||||
nodes = list(self.model.get_all_compute_nodes().values())
|
||||
nodes.remove(source)
|
||||
self.strategy.add_migrate_actions([source], nodes)
|
||||
expected = [{'action_type': 'migrate',
|
||||
'input_parameters': {
|
||||
'destination_node': 'hostname_1',
|
||||
'migration_type': 'live',
|
||||
'resource_id': '6ae05517-a512-462d-9d83-90c313b5a8f1',
|
||||
'resource_name': 'INSTANCE_1',
|
||||
'source_node': 'hostname_0'}},
|
||||
{'action_type': 'migrate',
|
||||
'input_parameters': {
|
||||
'destination_node': 'hostname_2',
|
||||
'migration_type': 'live',
|
||||
'resource_id': '6ae05517-a512-462d-9d83-90c313b5a8ff',
|
||||
'resource_name': 'INSTANCE_0',
|
||||
'source_node': 'hostname_0'}}]
|
||||
self.assertEqual(expected, self.strategy.solution.actions)
|
||||
|
||||
def test_add_migrate_actions_with_no_action(self):
|
||||
self.strategy.host_choice = 'specify'
|
||||
source = self.model.get_node_by_uuid(
|
||||
"89dce55c-8e74-4402-b23f-32aaf216c971")
|
||||
dest = self.model.get_node_by_uuid(
|
||||
"89dce55c-8e74-4402-b23f-32aaf216c972")
|
||||
self.strategy.add_migrate_actions([source], [dest])
|
||||
self.assertEqual([], self.strategy.solution.actions)
|
||||
|
||||
def test_add_change_node_state_actions_with_exeception(self):
|
||||
self.assertRaises(exception.IllegalArgumentException,
|
||||
self.strategy.add_change_node_state_actions,
|
||||
[], 'down')
|
||||
|
||||
def test_add_change_node_state_actions(self):
|
||||
node1 = self.model.get_node_by_uuid(
|
||||
"89dce55c-8e74-4402-b23f-32aaf216c972")
|
||||
node2 = self.model.get_node_by_uuid(
|
||||
"89dce55c-8e74-4402-b23f-32aaf216c97f")
|
||||
# disable two nodes
|
||||
status = element.ServiceState.DISABLED.value
|
||||
result = self.strategy.add_change_node_state_actions(
|
||||
[node1, node2], status)
|
||||
self.assertEqual([node1, node2], result)
|
||||
expected = [{
|
||||
'action_type': 'change_nova_service_state',
|
||||
'input_parameters': {
|
||||
'disabled_reason': 'Watcher node resource '
|
||||
'consolidation strategy',
|
||||
'resource_id': '89dce55c-8e74-4402-b23f-32aaf216c972',
|
||||
'resource_name': 'hostname_2',
|
||||
'state': 'disabled'}},
|
||||
{
|
||||
'action_type': 'change_nova_service_state',
|
||||
'input_parameters': {
|
||||
'disabled_reason': 'Watcher node resource consolidation '
|
||||
'strategy',
|
||||
'resource_id': '89dce55c-8e74-4402-b23f-32aaf216c97f',
|
||||
'resource_name': 'hostname_0',
|
||||
'state': 'disabled'}}]
|
||||
self.assertEqual(expected, self.strategy.solution.actions)
|
||||
|
||||
def test_add_change_node_state_actions_one_disabled(self):
|
||||
node1 = self.model.get_node_by_uuid(
|
||||
"89dce55c-8e74-4402-b23f-32aaf216c972")
|
||||
node2 = self.model.get_node_by_uuid(
|
||||
"89dce55c-8e74-4402-b23f-32aaf216c97f")
|
||||
# disable two nodes
|
||||
status = element.ServiceState.DISABLED.value
|
||||
|
||||
# one enable, one disable
|
||||
node1.status = element.ServiceState.DISABLED.value
|
||||
result = self.strategy.add_change_node_state_actions(
|
||||
[node1, node2], status)
|
||||
self.assertEqual([node2], result)
|
||||
expected = [{
|
||||
'action_type': 'change_nova_service_state',
|
||||
'input_parameters': {
|
||||
'disabled_reason': 'Watcher node resource consolidation '
|
||||
'strategy',
|
||||
'resource_id': '89dce55c-8e74-4402-b23f-32aaf216c97f',
|
||||
'resource_name': 'hostname_0',
|
||||
'state': 'disabled'}}]
|
||||
self.assertEqual(expected, self.strategy.solution.actions)
|
||||
|
||||
def test_get_nodes_migrate_failed_return_null(self):
|
||||
self.strategy.audit = None
|
||||
result = self.strategy.get_nodes_migrate_failed()
|
||||
self.assertEqual([], result)
|
||||
self.strategy.audit = mock.Mock(
|
||||
audit_type=objects.audit.AuditType.ONESHOT.value)
|
||||
result = self.strategy.get_nodes_migrate_failed()
|
||||
self.assertEqual([], result)
|
||||
|
||||
@mock.patch.object(objects.action.Action, 'list')
|
||||
def test_get_nodes_migrate_failed(self, mock_list):
|
||||
self.strategy.audit = mock.Mock(
|
||||
audit_type=objects.audit.AuditType.CONTINUOUS.value)
|
||||
fake_action = obj_utils.get_test_action(
|
||||
self.context,
|
||||
state=objects.action.State.FAILED,
|
||||
action_type='migrate',
|
||||
input_parameters={
|
||||
'resource_id': '6ae05517-a512-462d-9d83-90c313b5a8f1'})
|
||||
mock_list.return_value = [fake_action]
|
||||
result = self.strategy.get_nodes_migrate_failed()
|
||||
expected = self.model.get_node_by_uuid(
|
||||
'89dce55c-8e74-4402-b23f-32aaf216c97f')
|
||||
self.assertEqual([expected], result)
|
||||
|
||||
def test_group_nodes_with_ONESHOT(self):
|
||||
self.strategy.audit = mock.Mock(
|
||||
audit_type=objects.audit.AuditType.ONESHOT.value)
|
||||
nodes = list(self.model.get_all_compute_nodes().values())
|
||||
result = self.strategy.group_nodes(nodes)
|
||||
node0 = self.model.get_node_by_name('hostname_0')
|
||||
node1 = self.model.get_node_by_name('hostname_1')
|
||||
node2 = self.model.get_node_by_name('hostname_2')
|
||||
node3 = self.model.get_node_by_name('hostname_3')
|
||||
node4 = self.model.get_node_by_name('hostname_4')
|
||||
node5 = self.model.get_node_by_name('hostname_5')
|
||||
node6 = self.model.get_node_by_name('hostname_6')
|
||||
node7 = self.model.get_node_by_name('hostname_7')
|
||||
source_nodes = [node3, node4, node7]
|
||||
dest_nodes = [node2, node0, node1]
|
||||
self.assertIn(node5, result[0])
|
||||
self.assertIn(node6, result[0])
|
||||
self.assertEqual(source_nodes, result[1])
|
||||
self.assertEqual(dest_nodes, result[2])
|
||||
|
||||
@mock.patch.object(objects.action.Action, 'list')
|
||||
def test_group_nodes_with_CONTINUOUS(self, mock_list):
|
||||
self.strategy.audit = mock.Mock(
|
||||
audit_type=objects.audit.AuditType.CONTINUOUS.value)
|
||||
fake_action = obj_utils.get_test_action(
|
||||
self.context,
|
||||
state=objects.action.State.FAILED,
|
||||
action_type='migrate',
|
||||
input_parameters={
|
||||
'resource_id': '6ae05517-a512-462d-9d83-90c313b5a8f6'})
|
||||
mock_list.return_value = [fake_action]
|
||||
nodes = list(self.model.get_all_compute_nodes().values())
|
||||
result = self.strategy.group_nodes(nodes)
|
||||
node0 = self.model.get_node_by_name('hostname_0')
|
||||
node1 = self.model.get_node_by_name('hostname_1')
|
||||
node2 = self.model.get_node_by_name('hostname_2')
|
||||
node3 = self.model.get_node_by_name('hostname_3')
|
||||
node4 = self.model.get_node_by_name('hostname_4')
|
||||
node5 = self.model.get_node_by_name('hostname_5')
|
||||
node6 = self.model.get_node_by_name('hostname_6')
|
||||
node7 = self.model.get_node_by_name('hostname_7')
|
||||
source_nodes = [node4, node7]
|
||||
dest_nodes = [node3, node2, node0, node1]
|
||||
self.assertIn(node5, result[0])
|
||||
self.assertIn(node6, result[0])
|
||||
self.assertEqual(source_nodes, result[1])
|
||||
self.assertEqual(dest_nodes, result[2])
|
||||
|
||||
@mock.patch.object(objects.action.Action, 'list')
|
||||
def test_execute_with_auto(self, mock_list):
|
||||
fake_action = obj_utils.get_test_action(
|
||||
self.context,
|
||||
state=objects.action.State.FAILED,
|
||||
action_type='migrate',
|
||||
input_parameters={
|
||||
'resource_id': '6ae05517-a512-462d-9d83-90c313b5a8f6'})
|
||||
mock_list.return_value = [fake_action]
|
||||
mock_audit = mock.Mock(
|
||||
audit_type=objects.audit.AuditType.CONTINUOUS.value)
|
||||
self.strategy.host_choice = 'auto'
|
||||
self.strategy.do_execute(mock_audit)
|
||||
expected = [
|
||||
{'action_type': 'change_nova_service_state',
|
||||
'input_parameters': {
|
||||
'disabled_reason': 'Watcher node resource consolidation '
|
||||
'strategy',
|
||||
'resource_id': '89dce55c-8e74-4402-b23f-32aaf216c975',
|
||||
'resource_name': 'hostname_5',
|
||||
'state': 'disabled'}},
|
||||
{'action_type': 'change_nova_service_state',
|
||||
'input_parameters': {
|
||||
'disabled_reason': 'Watcher node resource consolidation '
|
||||
'strategy',
|
||||
'resource_id': '89dce55c-8e74-4402-b23f-32aaf216c974',
|
||||
'resource_name': 'hostname_4',
|
||||
'state': 'disabled'}},
|
||||
{'action_type': 'migrate',
|
||||
'input_parameters': {
|
||||
'migration_type': 'live',
|
||||
'resource_id': '6ae05517-a512-462d-9d83-90c313b5a8f7',
|
||||
'resource_name': 'INSTANCE_7',
|
||||
'source_node': 'hostname_4'}},
|
||||
{'action_type': 'migrate',
|
||||
'input_parameters': {
|
||||
'migration_type': 'live',
|
||||
'resource_id': '6ae05517-a512-462d-9d83-90c313b5a8f8',
|
||||
'resource_name': 'INSTANCE_8',
|
||||
'source_node': 'hostname_7'}},
|
||||
{'action_type': 'change_nova_service_state',
|
||||
'input_parameters': {
|
||||
'resource_id': '89dce55c-8e74-4402-b23f-32aaf216c975',
|
||||
'resource_name': 'hostname_5',
|
||||
'state': 'enabled'}},
|
||||
{'action_type': 'change_nova_service_state',
|
||||
'input_parameters': {
|
||||
'resource_id': '89dce55c-8e74-4402-b23f-32aaf216c974',
|
||||
'resource_name': 'hostname_4',
|
||||
'state': 'enabled'}}]
|
||||
self.assertEqual(expected, self.strategy.solution.actions)
|
||||
|
||||
def test_execute_with_specify(self):
|
||||
mock_audit = mock.Mock(
|
||||
audit_type=objects.audit.AuditType.ONESHOT.value)
|
||||
self.strategy.host_choice = 'specify'
|
||||
self.strategy.do_execute(mock_audit)
|
||||
expected = [
|
||||
{'action_type': 'migrate',
|
||||
'input_parameters': {
|
||||
'destination_node': 'hostname_2',
|
||||
'migration_type': 'live',
|
||||
'resource_id': '6ae05517-a512-462d-9d83-90c313b5a8f6',
|
||||
'resource_name': 'INSTANCE_6',
|
||||
'source_node': 'hostname_3'}},
|
||||
{'action_type': 'migrate',
|
||||
'input_parameters': {
|
||||
'destination_node': 'hostname_0',
|
||||
'migration_type': 'live',
|
||||
'resource_id': '6ae05517-a512-462d-9d83-90c313b5a8f7',
|
||||
'resource_name': 'INSTANCE_7',
|
||||
'source_node': 'hostname_4'}},
|
||||
{'action_type': 'migrate',
|
||||
'input_parameters': {
|
||||
'destination_node': 'hostname_1',
|
||||
'migration_type': 'live',
|
||||
'resource_id': '6ae05517-a512-462d-9d83-90c313b5a8f8',
|
||||
'resource_name': 'INSTANCE_8',
|
||||
'source_node': 'hostname_7'}}]
|
||||
self.assertEqual(expected, self.strategy.solution.actions)
|
||||
Reference in New Issue
Block a user