Add Voluptuous to validate the action parameters

We want a simplest way to validate the input parameters of an
Action through a schema.

APIImpact
DocImpact
Partially implements: blueprint watcher-add-actions-via-conf

Change-Id: I139775f467fe7778c7354b0cfacf796fc27ffcb2
This commit is contained in:
Jean-Emile DARTOIS
2016-01-26 15:31:18 +01:00
committed by Vincent Françoise
parent 33ee575936
commit e3198d25a5
32 changed files with 771 additions and 503 deletions

View File

@@ -0,0 +1,54 @@
# -*- encoding: utf-8 -*-
# Copyright (c) 2016 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.
#
import voluptuous
from watcher.applier.actions import base as baction
from watcher.applier.actions import change_nova_service_state
from watcher.decision_engine.model import hypervisor_state as hstate
from watcher.tests import base
class TestChangeNovaServiceState(base.TestCase):
def setUp(self):
super(TestChangeNovaServiceState, self).setUp()
self.a = change_nova_service_state.ChangeNovaServiceState()
def test_parameters_down(self):
self.a.input_parameters = {
baction.BaseAction.RESOURCE_ID: "compute-1",
self.a.STATE: hstate.HypervisorState.OFFLINE.value}
self.assertEqual(True, self.a.validate_parameters())
def test_parameters_up(self):
self.a.input_parameters = {
baction.BaseAction.RESOURCE_ID: "compute-1",
self.a.STATE: hstate.HypervisorState.ONLINE.value}
self.assertEqual(True, self.a.validate_parameters())
def test_parameters_exception_wrong_state(self):
self.a.input_parameters = {
baction.BaseAction.RESOURCE_ID: "compute-1",
self.a.STATE: 'error'}
self.assertRaises(voluptuous.Invalid, self.a.validate_parameters)
def test_parameters_resource_id_empty(self):
self.a.input_parameters = {
self.a.STATE: None}
self.assertRaises(voluptuous.Invalid, self.a.validate_parameters)
def test_parameters_applies_add_extra(self):
self.a.input_parameters = {"extra": "failed"}
self.assertRaises(voluptuous.Invalid, self.a.validate_parameters)

View File

@@ -0,0 +1,78 @@
# -*- encoding: utf-8 -*-
# Copyright (c) 2016 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.
#
import voluptuous
from watcher.applier.actions import base as baction
from watcher.applier.actions import migration
from watcher.tests import base
class TestMigration(base.TestCase):
def setUp(self):
super(TestMigration, self).setUp()
self.mig = migration.Migrate()
def test_parameters(self):
params = {baction.BaseAction.RESOURCE_ID:
"45a37aeb-95ab-4ddb-a305-7d9f62c2f5ba",
self.mig.MIGRATION_TYPE: 'live',
self.mig.DST_HYPERVISOR: 'compute-2',
self.mig.SRC_HYPERVISOR: 'compute3'}
self.mig.input_parameters = params
self.assertEqual(True, self.mig.validate_parameters())
def test_parameters_exception_resource_id(self):
parameters = {baction.BaseAction.RESOURCE_ID: "EFEF",
'migration_type': 'live',
'src_hypervisor': 'compute-2',
'dst_hypervisor': 'compute3'}
self.mig.input_parameters = parameters
self.assertRaises(voluptuous.Invalid, self.mig.validate_parameters)
def test_parameters_exception_migration_type(self):
parameters = {baction.BaseAction.RESOURCE_ID:
"45a37aeb-95ab-4ddb-a305-7d9f62c2f5ba",
'migration_type': 'cold',
'src_hypervisor': 'compute-2',
'dst_hypervisor': 'compute3'}
self.mig.input_parameters = parameters
self.assertRaises(voluptuous.Invalid, self.mig.validate_parameters)
def test_parameters_exception_src_hypervisor(self):
parameters = {baction.BaseAction.RESOURCE_ID:
"45a37aeb-95ab-4ddb-a305-7d9f62c2f5ba",
'migration_type': 'cold',
'src_hypervisor': None,
'dst_hypervisor': 'compute3'}
self.mig.input_parameters = parameters
self.assertRaises(voluptuous.Invalid, self.mig.validate_parameters)
def test_parameters_exception_dst_hypervisor(self):
parameters = {baction.BaseAction.RESOURCE_ID:
"45a37aeb-95ab-4ddb-a305-7d9f62c2f5ba",
'migration_type': 'cold',
'src_hypervisor': 'compute-1',
'dst_hypervisor': None}
self.mig.input_parameters = parameters
self.assertRaises(voluptuous.Invalid, self.mig.validate_parameters)
def test_parameters_exception_empty_fields(self):
parameters = {baction.BaseAction.RESOURCE_ID: None,
'migration_type': None,
'src_hypervisor': None,
'dst_hypervisor': None}
self.mig.input_parameters = parameters
self.assertRaises(voluptuous.Invalid, self.mig.validate_parameters)

View File

@@ -0,0 +1,42 @@
# -*- encoding: utf-8 -*-
# Copyright (c) 2016 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.
#
import voluptuous
from watcher.applier.actions import sleep
from watcher.tests import base
class TestSleep(base.TestCase):
def setUp(self):
super(TestSleep, self).setUp()
self.s = sleep.Sleep()
def test_parameters_duration(self):
self.s.input_parameters = {self.s.DURATION: 1.0}
self.assertEqual(True, self.s.validate_parameters())
def test_parameters_duration_empty(self):
self.s.input_parameters = {self.s.DURATION: None}
self.assertRaises(voluptuous.Invalid, self.s.validate_parameters)
def test_parameters_wrong_parameter(self):
self.s.input_parameters = {self.s.DURATION: "ef"}
self.assertRaises(voluptuous.Invalid, self.s.validate_parameters)
def test_parameters_add_field(self):
self.s.input_parameters = {self.s.DURATION: 1.0, "not_required": "nop"}
self.assertRaises(voluptuous.Invalid, self.s.validate_parameters)

View File

@@ -32,6 +32,12 @@ from watcher.tests.db import base
@six.add_metaclass(abc.ABCMeta)
class FakeAction(abase.BaseAction):
def schema(self):
pass
def postcondition(self):
pass
def precondition(self):
pass
@@ -62,12 +68,11 @@ class TestDefaultWorkFlowEngine(base.DbTestCase):
result = self.engine.execute(actions)
self.assertEqual(result, True)
def create_action(self, action_type, applies_to, parameters, next):
def create_action(self, action_type, parameters, next):
action = {
'uuid': utils.generate_uuid(),
'action_plan_id': 0,
'action_type': action_type,
'applies_to': applies_to,
'input_parameters': parameters,
'state': objects.action.State.PENDING,
'alarm': None,
@@ -92,15 +97,15 @@ class TestDefaultWorkFlowEngine(base.DbTestCase):
self.assertEqual(result, True)
def test_execute_with_one_action(self):
actions = [self.create_action("nop", "", {'message': 'test'}, None)]
actions = [self.create_action("nop", {'message': 'test'}, None)]
result = self.engine.execute(actions)
self.assertEqual(result, True)
self.check_actions_state(actions, objects.action.State.SUCCEEDED)
def test_execute_with_two_actions(self):
actions = []
next = self.create_action("sleep", "", {'duration': '0'}, None)
first = self.create_action("nop", "", {'message': 'test'}, next.id)
next = self.create_action("sleep", {'duration': 0.0}, None)
first = self.create_action("nop", {'message': 'test'}, next.id)
actions.append(first)
actions.append(next)
@@ -111,9 +116,9 @@ class TestDefaultWorkFlowEngine(base.DbTestCase):
def test_execute_with_three_actions(self):
actions = []
next2 = self.create_action("nop", "vm1", {'message': 'next'}, None)
next = self.create_action("sleep", "vm1", {'duration': '0'}, next2.id)
first = self.create_action("nop", "vm1", {'message': 'hello'}, next.id)
next2 = self.create_action("nop", {'message': 'next'}, None)
next = self.create_action("sleep", {'duration': 0.0}, next2.id)
first = self.create_action("nop", {'message': 'hello'}, next.id)
self.check_action_state(first, objects.action.State.PENDING)
self.check_action_state(next, objects.action.State.PENDING)
self.check_action_state(next2, objects.action.State.PENDING)
@@ -128,12 +133,9 @@ class TestDefaultWorkFlowEngine(base.DbTestCase):
def test_execute_with_exception(self):
actions = []
next2 = self.create_action("no_exist",
"vm1", {'message': 'next'}, None)
next = self.create_action("sleep", "vm1",
{'duration': '0'}, next2.id)
first = self.create_action("nop", "vm1",
{'message': 'hello'}, next.id)
next2 = self.create_action("no_exist", {'message': 'next'}, None)
next = self.create_action("sleep", {'duration': 0.0}, next2.id)
first = self.create_action("nop", {'message': 'hello'}, next.id)
self.check_action_state(first, objects.action.State.PENDING)
self.check_action_state(next, objects.action.State.PENDING)
@@ -158,7 +160,7 @@ class TestDefaultWorkFlowEngine(base.DbTestCase):
plugin=FakeAction,
obj=None),
namespace=FakeAction.namespace())
actions = [self.create_action("dontcare", "vm1", {}, None)]
actions = [self.create_action("dontcare", {}, None)]
result = self.engine.execute(actions)
self.assertEqual(result, False)
self.check_action_state(actions[0], objects.action.State.FAILED)

View File

@@ -84,10 +84,12 @@ def get_test_action(**kwargs):
'uuid': kwargs.get('uuid', '10a47dd1-4874-4298-91cf-eff046dbdb8d'),
'action_plan_id': kwargs.get('action_plan_id', 1),
'action_type': kwargs.get('action_type', 'nop'),
'applies_to': kwargs.get('applies_to',
'10a47dd1-4874-4298-91cf-eff046dbdb8d'),
'input_parameters': kwargs.get('input_parameters', {'key1': 'val1',
'key2': 'val2'}),
'input_parameters':
kwargs.get('input_parameters',
{'key1': 'val1',
'key2': 'val2',
'resource_id':
'10a47dd1-4874-4298-91cf-eff046dbdb8d'}),
'state': kwargs.get('state', 'PENDING'),
'alarm': kwargs.get('alarm', None),
'next': kwargs.get('next', 2),

View File

@@ -18,55 +18,60 @@
#
import uuid
from watcher.decision_engine.model.hypervisor import Hypervisor
from watcher.decision_engine.model.vm_state import VMState
from watcher.decision_engine.model import hypervisor as modelhyp
from watcher.decision_engine.model import vm_state
from watcher.tests import base
from watcher.tests.decision_engine.strategy.strategies.faker_cluster_state import \
FakerModelCollector
from watcher.tests.decision_engine.strategy.strategies import \
faker_cluster_state
class TestMapping(base.BaseTestCase):
VM1_UUID = "73b09e16-35b7-4922-804e-e8f5d9b740fc"
VM2_UUID = "a4cab39b-9828-413a-bf88-f76921bf1517"
def test_get_node_from_vm(self):
fake_cluster = FakerModelCollector()
fake_cluster = faker_cluster_state.FakerModelCollector()
model = fake_cluster.generate_scenario_3_with_2_hypervisors()
vms = model.get_all_vms()
keys = list(vms.keys())
vm = vms[keys[0]]
if vm.uuid != 'VM_0':
if vm.uuid != self.VM1_UUID:
vm = vms[keys[1]]
node = model.mapping.get_node_from_vm(vm)
self.assertEqual(node.uuid, 'Node_0')
def test_get_node_from_vm_id(self):
fake_cluster = FakerModelCollector()
fake_cluster = faker_cluster_state.FakerModelCollector()
model = fake_cluster.generate_scenario_3_with_2_hypervisors()
hyps = model.mapping.get_node_vms_from_id("BLABLABLA")
self.assertEqual(hyps.__len__(), 0)
def test_get_all_vms(self):
fake_cluster = FakerModelCollector()
fake_cluster = faker_cluster_state.FakerModelCollector()
model = fake_cluster.generate_scenario_3_with_2_hypervisors()
vms = model.get_all_vms()
self.assertEqual(vms.__len__(), 2)
self.assertEqual(vms['VM_0'].state, VMState.ACTIVE.value)
self.assertEqual(vms['VM_0'].uuid, 'VM_0')
self.assertEqual(vms['VM_1'].state, VMState.ACTIVE.value)
self.assertEqual(vms['VM_1'].uuid, 'VM_1')
self.assertEqual(vms[self.VM1_UUID].state,
vm_state.VMState.ACTIVE.value)
self.assertEqual(vms[self.VM1_UUID].uuid, self.VM1_UUID)
self.assertEqual(vms[self.VM2_UUID].state,
vm_state.VMState.ACTIVE.value)
self.assertEqual(vms[self.VM2_UUID].uuid, self.VM2_UUID)
def test_get_mapping(self):
fake_cluster = FakerModelCollector()
fake_cluster = faker_cluster_state.FakerModelCollector()
model = fake_cluster.generate_scenario_3_with_2_hypervisors()
mapping_vm = model.mapping.get_mapping_vm()
self.assertEqual(mapping_vm.__len__(), 2)
self.assertEqual(mapping_vm['VM_0'], 'Node_0')
self.assertEqual(mapping_vm['VM_1'], 'Node_1')
self.assertEqual(mapping_vm[self.VM1_UUID], 'Node_0')
self.assertEqual(mapping_vm[self.VM2_UUID], 'Node_1')
def test_migrate_vm(self):
fake_cluster = FakerModelCollector()
fake_cluster = faker_cluster_state.FakerModelCollector()
model = fake_cluster.generate_scenario_3_with_2_hypervisors()
vms = model.get_all_vms()
keys = list(vms.keys())
@@ -81,13 +86,13 @@ class TestMapping(base.BaseTestCase):
self.assertEqual(model.mapping.migrate_vm(vm1, hyp0, hyp1), True)
def test_unmap_from_id_log_warning(self):
fake_cluster = FakerModelCollector()
fake_cluster = faker_cluster_state.FakerModelCollector()
model = fake_cluster.generate_scenario_3_with_2_hypervisors()
vms = model.get_all_vms()
keys = list(vms.keys())
vm0 = vms[keys[0]]
id = "{0}".format(uuid.uuid4())
hypervisor = Hypervisor()
hypervisor = modelhyp.Hypervisor()
hypervisor.uuid = id
model.mapping.unmap_from_id(hypervisor.uuid, vm0.uuid)
@@ -95,7 +100,7 @@ class TestMapping(base.BaseTestCase):
# hypervisor.uuid)), 1)
def test_unmap_from_id(self):
fake_cluster = FakerModelCollector()
fake_cluster = faker_cluster_state.FakerModelCollector()
model = fake_cluster.generate_scenario_3_with_2_hypervisors()
vms = model.get_all_vms()
keys = list(vms.keys())

View File

@@ -68,7 +68,7 @@ class TestActionScheduling(base.DbTestCase):
"dst_uuid_hypervisor": "server2",
}
solution.add_action(action_type="migrate",
applies_to="b199db0c-1408-4d52-b5a5-5ca14de0ff36",
resource_id="b199db0c-1408-4d52-b5a5-5ca14de0ff36",
input_parameters=parameters)
with mock.patch.object(
@@ -94,11 +94,11 @@ class TestActionScheduling(base.DbTestCase):
"dst_uuid_hypervisor": "server2",
}
solution.add_action(action_type="migrate",
applies_to="b199db0c-1408-4d52-b5a5-5ca14de0ff36",
resource_id="b199db0c-1408-4d52-b5a5-5ca14de0ff36",
input_parameters=parameters)
solution.add_action(action_type="nop",
applies_to="",
resource_id="",
input_parameters={})
with mock.patch.object(

View File

@@ -13,27 +13,29 @@
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from watcher.decision_engine.solution.default import DefaultSolution
from watcher.decision_engine.solution import default
from watcher.tests import base
class TestDefaultSolution(base.BaseTestCase):
def test_default_solution(self):
solution = DefaultSolution()
solution = default.DefaultSolution()
parameters = {
"src_uuid_hypervisor": "server1",
"dst_uuid_hypervisor": "server2",
}
solution.add_action(action_type="nop",
applies_to="b199db0c-1408-4d52-b5a5-5ca14de0ff36",
resource_id="b199db0c-1408-4d52-b5a5-5ca14de0ff36",
input_parameters=parameters)
self.assertEqual(len(solution.actions), 1)
expected_action_type = "nop"
expected_applies_to = "b199db0c-1408-4d52-b5a5-5ca14de0ff36"
expected_parameters = parameters
expected_parameters = {
"src_uuid_hypervisor": "server1",
"dst_uuid_hypervisor": "server2",
"resource_id": "b199db0c-1408-4d52-b5a5-5ca14de0ff36"
}
self.assertEqual(solution.actions[0].get('action_type'),
expected_action_type)
self.assertEqual(solution.actions[0].get('applies_to'),
expected_applies_to)
self.assertEqual(solution.actions[0].get('input_parameters'),
expected_parameters)

View File

@@ -16,81 +16,24 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
import random
from watcher.decision_engine.model.hypervisor import Hypervisor
from watcher.decision_engine.model.model_root import ModelRoot
from watcher.decision_engine.model.resource import Resource
from watcher.decision_engine.model.resource import ResourceType
from watcher.decision_engine.model.vm import VM
from watcher.metrics_engine.cluster_model_collector.api import \
BaseClusterModelCollector
from watcher.decision_engine.model import hypervisor
from watcher.decision_engine.model import model_root as modelroot
from watcher.decision_engine.model import resource
from watcher.decision_engine.model import vm as modelvm
from watcher.metrics_engine.cluster_model_collector import api
class FakerModelCollector(BaseClusterModelCollector):
class FakerModelCollector(api.BaseClusterModelCollector):
def __init__(self):
pass
def get_latest_cluster_data_model(self):
return self.generate_scenario_1()
def generate_random(self, count_nodes, number_of_vm_per_node):
vms = []
current_state_cluster = ModelRoot()
# number of nodes
count_node = count_nodes
# number max of vm per hypervisor
node_count_vm = number_of_vm_per_node
# total number of virtual machine
count_vm = (count_node * node_count_vm)
# 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)
hypervisor = Hypervisor()
hypervisor.uuid = node_uuid
hypervisor.hostname = "host_{0}".format(i)
mem.set_capacity(hypervisor, 132)
disk.set_capacity(hypervisor, 250)
num_cores.set_capacity(hypervisor, 40)
current_state_cluster.add_hypervisor(hypervisor)
for i in range(0, count_vm):
vm_uuid = "VM_{0}".format(i)
vm = VM()
vm.uuid = vm_uuid
mem.set_capacity(vm, 8)
disk.set_capacity(vm, 10)
num_cores.set_capacity(vm, 10)
vms.append(vm)
current_state_cluster.add_vm(vm)
j = 0
for node_id in current_state_cluster.get_all_hypervisors():
for i in range(0, random.randint(0, node_count_vm)):
# todo(jed) check if enough capacity
current_state_cluster.get_mapping().map(
current_state_cluster.get_hypervisor_from_id(node_id),
vms[j])
j += 1
return current_state_cluster
def generate_scenario_1(self):
vms = []
current_state_cluster = ModelRoot()
current_state_cluster = modelroot.ModelRoot()
# number of nodes
count_node = 5
# number max of vm per node
@@ -99,10 +42,10 @@ class FakerModelCollector(BaseClusterModelCollector):
count_vm = (count_node * node_count_vm)
# define ressouce ( CPU, MEM disk, ... )
mem = Resource(ResourceType.memory)
mem = resource.Resource(resource.ResourceType.memory)
# 2199.954 Mhz
num_cores = Resource(ResourceType.cpu_cores)
disk = Resource(ResourceType.disk)
num_cores = resource.Resource(resource.ResourceType.cpu_cores)
disk = resource.Resource(resource.ResourceType.disk)
current_state_cluster.create_resource(mem)
current_state_cluster.create_resource(num_cores)
@@ -110,7 +53,7 @@ class FakerModelCollector(BaseClusterModelCollector):
for i in range(0, count_node):
node_uuid = "Node_{0}".format(i)
node = Hypervisor()
node = hypervisor.Hypervisor()
node.uuid = node_uuid
node.hostname = "hostname_{0}".format(i)
@@ -121,7 +64,7 @@ class FakerModelCollector(BaseClusterModelCollector):
for i in range(0, count_vm):
vm_uuid = "VM_{0}".format(i)
vm = VM()
vm = modelvm.VM()
vm.uuid = vm_uuid
mem.set_capacity(vm, 2)
disk.set_capacity(vm, 20)
@@ -168,130 +111,68 @@ class FakerModelCollector(BaseClusterModelCollector):
model.get_hypervisor_from_id(h_id),
model.get_vm_from_id(vm_id))
def generate_scenario_2(self):
vms = []
current_state_cluster = ModelRoot()
# number of nodes
count_node = 10
# number max of vm per node
node_count_vm = 7
# total number of virtual machine
count_vm = (count_node * node_count_vm)
# 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)
current_state_cluster.add_hypervisor(node)
for i in range(0, count_vm):
vm_uuid = "VM_{0}".format(i)
vm = VM()
vm.uuid = vm_uuid
mem.set_capacity(vm, 10)
disk.set_capacity(vm, 25)
num_cores.set_capacity(vm, 16)
vms.append(vm)
current_state_cluster.add_vm(vm)
indice = 0
for j in range(0, 2):
node_uuid = "Node_{0}".format(j)
for i in range(indice, 3):
vm_uuid = "VM_{0}".format(i)
self.map(current_state_cluster, node_uuid, vm_uuid)
for j in range(2, 5):
node_uuid = "Node_{0}".format(j)
for i in range(indice, 4):
vm_uuid = "VM_{0}".format(i)
self.map(current_state_cluster, node_uuid, vm_uuid)
for j in range(5, 10):
node_uuid = "Node_{0}".format(j)
for i in range(indice, 4):
vm_uuid = "VM_{0}".format(i)
self.map(current_state_cluster, node_uuid, vm_uuid)
return current_state_cluster
def generate_scenario_3_with_2_hypervisors(self):
vms = []
current_state_cluster = ModelRoot()
root = modelroot.ModelRoot()
# number of nodes
count_node = 2
# number max of vm per node
node_count_vm = 1
# total number of virtual machine
count_vm = (count_node * node_count_vm)
# define ressouce ( CPU, MEM disk, ... )
mem = Resource(ResourceType.memory)
mem = resource.Resource(resource.ResourceType.memory)
# 2199.954 Mhz
num_cores = Resource(ResourceType.cpu_cores)
disk = Resource(ResourceType.disk)
num_cores = resource.Resource(resource.ResourceType.cpu_cores)
disk = resource.Resource(resource.ResourceType.disk)
current_state_cluster.create_resource(mem)
current_state_cluster.create_resource(num_cores)
current_state_cluster.create_resource(disk)
root.create_resource(mem)
root.create_resource(num_cores)
root.create_resource(disk)
for i in range(0, count_node):
node_uuid = "Node_{0}".format(i)
node = Hypervisor()
node = hypervisor.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)
current_state_cluster.add_hypervisor(node)
root.add_hypervisor(node)
for i in range(0, count_vm):
vm_uuid = "VM_{0}".format(i)
vm = VM()
vm.uuid = vm_uuid
mem.set_capacity(vm, 2)
disk.set_capacity(vm, 20)
num_cores.set_capacity(vm, 10)
vms.append(vm)
current_state_cluster.add_vm(vm)
vm1 = modelvm.VM()
vm1.uuid = "73b09e16-35b7-4922-804e-e8f5d9b740fc"
mem.set_capacity(vm1, 2)
disk.set_capacity(vm1, 20)
num_cores.set_capacity(vm1, 10)
vms.append(vm1)
root.add_vm(vm1)
current_state_cluster.get_mapping().map(
current_state_cluster.get_hypervisor_from_id("Node_0"),
current_state_cluster.get_vm_from_id("VM_0"))
vm2 = modelvm.VM()
vm2.uuid = "a4cab39b-9828-413a-bf88-f76921bf1517"
mem.set_capacity(vm2, 2)
disk.set_capacity(vm2, 20)
num_cores.set_capacity(vm2, 10)
vms.append(vm2)
root.add_vm(vm2)
current_state_cluster.get_mapping().map(
current_state_cluster.get_hypervisor_from_id("Node_1"),
current_state_cluster.get_vm_from_id("VM_1"))
root.get_mapping().map(root.get_hypervisor_from_id("Node_0"),
root.get_vm_from_id(str(vm1.uuid)))
return current_state_cluster
root.get_mapping().map(root.get_hypervisor_from_id("Node_1"),
root.get_vm_from_id(str(vm2.uuid)))
return root
def generate_scenario_4_with_1_hypervisor_no_vm(self):
current_state_cluster = ModelRoot()
current_state_cluster = modelroot.ModelRoot()
# number of nodes
count_node = 1
# define ressouce ( CPU, MEM disk, ... )
mem = Resource(ResourceType.memory)
mem = resource.Resource(resource.ResourceType.memory)
# 2199.954 Mhz
num_cores = Resource(ResourceType.cpu_cores)
disk = Resource(ResourceType.disk)
num_cores = resource.Resource(resource.ResourceType.cpu_cores)
disk = resource.Resource(resource.ResourceType.disk)
current_state_cluster.create_resource(mem)
current_state_cluster.create_resource(num_cores)
@@ -299,7 +180,7 @@ class FakerModelCollector(BaseClusterModelCollector):
for i in range(0, count_node):
node_uuid = "Node_{0}".format(i)
node = Hypervisor()
node = hypervisor.Hypervisor()
node.uuid = node_uuid
node.hostname = "hostname_{0}".format(i)
@@ -312,17 +193,17 @@ class FakerModelCollector(BaseClusterModelCollector):
def generate_scenario_5_with_vm_disk_0(self):
vms = []
current_state_cluster = ModelRoot()
current_state_cluster = modelroot.ModelRoot()
# number of nodes
count_node = 1
# number of vms
count_vm = 1
# define ressouce ( CPU, MEM disk, ... )
mem = Resource(ResourceType.memory)
mem = resource.Resource(resource.ResourceType.memory)
# 2199.954 Mhz
num_cores = Resource(ResourceType.cpu_cores)
disk = Resource(ResourceType.disk)
num_cores = resource.Resource(resource.ResourceType.cpu_cores)
disk = resource.Resource(resource.ResourceType.disk)
current_state_cluster.create_resource(mem)
current_state_cluster.create_resource(num_cores)
@@ -330,7 +211,7 @@ class FakerModelCollector(BaseClusterModelCollector):
for i in range(0, count_node):
node_uuid = "Node_{0}".format(i)
node = Hypervisor()
node = hypervisor.Hypervisor()
node.uuid = node_uuid
node.hostname = "hostname_{0}".format(i)
@@ -341,7 +222,7 @@ class FakerModelCollector(BaseClusterModelCollector):
for i in range(0, count_vm):
vm_uuid = "VM_{0}".format(i)
vm = VM()
vm = modelvm.VM()
vm.uuid = vm_uuid
mem.set_capacity(vm, 2)
disk.set_capacity(vm, 0)

View File

@@ -16,26 +16,26 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
from collections import Counter
import collections
import mock
from watcher.applier.actions.loading import default
from watcher.common import exception
from watcher.decision_engine.model.model_root import ModelRoot
from watcher.decision_engine.strategy.strategies.basic_consolidation import \
BasicConsolidation
from watcher.decision_engine.model import model_root
from watcher.decision_engine.strategy import strategies
from watcher.tests import base
from watcher.tests.decision_engine.strategy.strategies.faker_cluster_state \
import FakerModelCollector
from watcher.tests.decision_engine.strategy.strategies.faker_metrics_collector\
import FakerMetricsCollector
from watcher.tests.decision_engine.strategy.strategies \
import faker_cluster_state
from watcher.tests.decision_engine.strategy.strategies \
import faker_metrics_collector
class TestBasicConsolidation(base.BaseTestCase):
# fake metrics
fake_metrics = FakerMetricsCollector()
fake_metrics = faker_metrics_collector.FakerMetricsCollector()
# fake cluster
fake_cluster = FakerModelCollector()
fake_cluster = faker_cluster_state.FakerModelCollector()
def test_cluster_size(self):
size_cluster = len(
@@ -45,7 +45,7 @@ class TestBasicConsolidation(base.BaseTestCase):
def test_basic_consolidation_score_hypervisor(self):
cluster = self.fake_cluster.generate_scenario_1()
sercon = BasicConsolidation()
sercon = strategies.BasicConsolidation()
sercon.ceilometer = mock.MagicMock(
statistic_aggregation=self.fake_metrics.mock_get_statistics)
@@ -67,7 +67,7 @@ class TestBasicConsolidation(base.BaseTestCase):
def test_basic_consolidation_score_vm(self):
cluster = self.fake_cluster.generate_scenario_1()
sercon = BasicConsolidation()
sercon = strategies.BasicConsolidation()
sercon.ceilometer = mock.MagicMock(
statistic_aggregation=self.fake_metrics.mock_get_statistics)
vm_0 = cluster.get_vm_from_id("VM_0")
@@ -90,7 +90,7 @@ class TestBasicConsolidation(base.BaseTestCase):
def test_basic_consolidation_score_vm_disk(self):
cluster = self.fake_cluster.generate_scenario_5_with_vm_disk_0()
sercon = BasicConsolidation()
sercon = strategies.BasicConsolidation()
sercon.ceilometer = mock.MagicMock(
statistic_aggregation=self.fake_metrics.mock_get_statistics)
vm_0 = cluster.get_vm_from_id("VM_0")
@@ -99,7 +99,7 @@ class TestBasicConsolidation(base.BaseTestCase):
def test_basic_consolidation_weight(self):
cluster = self.fake_cluster.generate_scenario_1()
sercon = BasicConsolidation()
sercon = strategies.BasicConsolidation()
sercon.ceilometer = mock.MagicMock(
statistic_aggregation=self.fake_metrics.mock_get_statistics)
vm_0 = cluster.get_vm_from_id("VM_0")
@@ -114,24 +114,24 @@ class TestBasicConsolidation(base.BaseTestCase):
vm_0_weight_assert)
def test_calculate_migration_efficacy(self):
sercon = BasicConsolidation()
sercon = strategies.BasicConsolidation()
sercon.calculate_migration_efficacy()
def test_exception_model(self):
sercon = BasicConsolidation()
sercon = strategies.BasicConsolidation()
self.assertRaises(exception.ClusterStateNotDefined, sercon.execute,
None)
def test_exception_cluster_empty(self):
sercon = BasicConsolidation()
model = ModelRoot()
sercon = strategies.BasicConsolidation()
model = model_root.ModelRoot()
self.assertRaises(exception.ClusterEmpty, sercon.execute,
model)
def test_calculate_score_vm_raise_cluster_state_not_found(self):
metrics = FakerMetricsCollector()
metrics = faker_metrics_collector.FakerMetricsCollector()
metrics.empty_one_metric("CPU_COMPUTE")
sercon = BasicConsolidation()
sercon = strategies.BasicConsolidation()
sercon.ceilometer = mock.MagicMock(
statistic_aggregation=self.fake_metrics.mock_get_statistics)
@@ -139,8 +139,8 @@ class TestBasicConsolidation(base.BaseTestCase):
sercon.calculate_score_vm, "VM_1", None)
def test_check_migration(self):
sercon = BasicConsolidation()
fake_cluster = FakerModelCollector()
sercon = strategies.BasicConsolidation()
fake_cluster = faker_cluster_state.FakerModelCollector()
model = fake_cluster.generate_scenario_3_with_2_hypervisors()
all_vms = model.get_all_vms()
@@ -151,8 +151,8 @@ class TestBasicConsolidation(base.BaseTestCase):
sercon.check_migration(model, hyp0, hyp0, vm0)
def test_threshold(self):
sercon = BasicConsolidation()
fake_cluster = FakerModelCollector()
sercon = strategies.BasicConsolidation()
fake_cluster = faker_cluster_state.FakerModelCollector()
model = fake_cluster.generate_scenario_3_with_2_hypervisors()
all_hyps = model.get_all_hypervisors()
@@ -165,19 +165,19 @@ class TestBasicConsolidation(base.BaseTestCase):
self.assertEqual(sercon.get_threshold_cores(), threshold_cores + 1)
def test_number_of(self):
sercon = BasicConsolidation()
sercon = strategies.BasicConsolidation()
sercon.get_number_of_released_nodes()
sercon.get_number_of_migrations()
def test_basic_consolidation_migration(self):
sercon = BasicConsolidation()
sercon = strategies.BasicConsolidation()
sercon.ceilometer = mock.MagicMock(
statistic_aggregation=self.fake_metrics.mock_get_statistics)
solution = sercon.execute(
self.fake_cluster.generate_scenario_3_with_2_hypervisors())
actions_counter = Counter(
actions_counter = collections.Counter(
[action.get('action_type') for action in solution.actions])
expected_num_migrations = 1
@@ -189,26 +189,31 @@ class TestBasicConsolidation(base.BaseTestCase):
self.assertEqual(num_migrations, expected_num_migrations)
self.assertEqual(num_hypervisor_state_change, expected_power_state)
def test_execute_cluster_empty(self):
current_state_cluster = FakerModelCollector()
sercon = BasicConsolidation("sercon", "Basic offline consolidation")
sercon.ceilometer = mock.MagicMock(
statistic_aggregation=self.fake_metrics.mock_get_statistics)
model = current_state_cluster.generate_random(0, 0)
self.assertRaises(exception.ClusterEmpty, sercon.execute, model)
# calculate_weight
def test_execute_no_workload(self):
sercon = BasicConsolidation()
sercon = strategies.BasicConsolidation()
sercon.ceilometer = mock.MagicMock(
statistic_aggregation=self.fake_metrics.mock_get_statistics)
current_state_cluster = FakerModelCollector()
current_state_cluster = faker_cluster_state.FakerModelCollector()
model = current_state_cluster. \
generate_scenario_4_with_1_hypervisor_no_vm()
with mock.patch.object(BasicConsolidation, 'calculate_weight') \
with mock.patch.object(strategies.BasicConsolidation,
'calculate_weight') \
as mock_score_call:
mock_score_call.return_value = 0
solution = sercon.execute(model)
self.assertEqual(solution.efficacy, 100)
def test_check_parameters(self):
sercon = strategies.BasicConsolidation()
sercon.ceilometer = mock.MagicMock(
statistic_aggregation=self.fake_metrics.mock_get_statistics)
solution = sercon.execute(
self.fake_cluster.generate_scenario_3_with_2_hypervisors())
loader = default.DefaultActionLoader()
for action in solution.actions:
loaded_action = loader.load(action['action_type'])
loaded_action.input_parameters = action['input_parameters']
loaded_action.validate_parameters()

View File

@@ -13,16 +13,29 @@
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from watcher.decision_engine.strategy.strategies.dummy_strategy import \
DummyStrategy
from watcher.applier.actions.loading import default
from watcher.decision_engine.strategy import strategies
from watcher.tests import base
from watcher.tests.decision_engine.strategy.strategies.faker_cluster_state\
import FakerModelCollector
from watcher.tests.decision_engine.strategy.strategies import \
faker_cluster_state
class TestDummyStrategy(base.TestCase):
def test_dummy_strategy(self):
tactique = DummyStrategy("basic", "Basic offline consolidation")
fake_cluster = FakerModelCollector()
dummy = strategies.DummyStrategy("dummy", "Dummy strategy")
fake_cluster = faker_cluster_state.FakerModelCollector()
model = fake_cluster.generate_scenario_3_with_2_hypervisors()
tactique.execute(model)
solution = dummy.execute(model)
self.assertEqual(3, len(solution.actions))
def test_check_parameters(self):
dummy = strategies.DummyStrategy("dummy", "Dummy strategy")
fake_cluster = faker_cluster_state.FakerModelCollector()
model = fake_cluster.generate_scenario_3_with_2_hypervisors()
solution = dummy.execute(model)
loader = default.DefaultActionLoader()
for action in solution.actions:
loaded_action = loader.load(action['action_type'])
loaded_action.input_parameters = action['input_parameters']
loaded_action.validate_parameters()

View File

@@ -16,35 +16,35 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
from collections import Counter
import collections
import mock
from watcher.applier.actions.loading import default
from watcher.common import exception
from watcher.decision_engine.model.model_root import ModelRoot
from watcher.decision_engine.model.resource import ResourceType
from watcher.decision_engine.strategy.strategies.outlet_temp_control import \
OutletTempControl
from watcher.decision_engine.model import model_root
from watcher.decision_engine.model import resource
from watcher.decision_engine.strategy import strategies
from watcher.tests import base
from watcher.tests.decision_engine.strategy.strategies.faker_cluster_state \
import FakerModelCollector
from watcher.tests.decision_engine.strategy.strategies.faker_metrics_collector\
import FakerMetricsCollector
from watcher.tests.decision_engine.strategy.strategies \
import faker_cluster_state
from watcher.tests.decision_engine.strategy.strategies \
import faker_metrics_collector
class TestOutletTempControl(base.BaseTestCase):
# fake metrics
fake_metrics = FakerMetricsCollector()
fake_metrics = faker_metrics_collector.FakerMetricsCollector()
# fake cluster
fake_cluster = FakerModelCollector()
fake_cluster = faker_cluster_state.FakerModelCollector()
def test_calc_used_res(self):
model = self.fake_cluster.generate_scenario_3_with_2_hypervisors()
strategy = OutletTempControl()
strategy = strategies.OutletTempControl()
hypervisor = model.get_hypervisor_from_id('Node_0')
cap_cores = model.get_resource_from_id(ResourceType.cpu_cores)
cap_mem = model.get_resource_from_id(ResourceType.memory)
cap_disk = model.get_resource_from_id(ResourceType.disk)
cap_cores = model.get_resource_from_id(resource.ResourceType.cpu_cores)
cap_mem = model.get_resource_from_id(resource.ResourceType.memory)
cap_disk = model.get_resource_from_id(resource.ResourceType.disk)
cores_used, mem_used, disk_used = strategy.calc_used_res(model,
hypervisor,
cap_cores,
@@ -55,7 +55,7 @@ class TestOutletTempControl(base.BaseTestCase):
def test_group_hosts_by_outlet_temp(self):
model = self.fake_cluster.generate_scenario_3_with_2_hypervisors()
strategy = OutletTempControl()
strategy = strategies.OutletTempControl()
strategy.ceilometer = mock.MagicMock(
statistic_aggregation=self.fake_metrics.mock_get_statistics)
h1, h2 = strategy.group_hosts_by_outlet_temp(model)
@@ -64,17 +64,18 @@ class TestOutletTempControl(base.BaseTestCase):
def test_choose_vm_to_migrate(self):
model = self.fake_cluster.generate_scenario_3_with_2_hypervisors()
strategy = OutletTempControl()
strategy = strategies.OutletTempControl()
strategy.ceilometer = mock.MagicMock(
statistic_aggregation=self.fake_metrics.mock_get_statistics)
h1, h2 = strategy.group_hosts_by_outlet_temp(model)
vm_to_mig = strategy.choose_vm_to_migrate(model, h1)
self.assertEqual(vm_to_mig[0].uuid, 'Node_1')
self.assertEqual(vm_to_mig[1].uuid, 'VM_1')
self.assertEqual(vm_to_mig[1].uuid,
"a4cab39b-9828-413a-bf88-f76921bf1517")
def test_filter_dest_servers(self):
model = self.fake_cluster.generate_scenario_3_with_2_hypervisors()
strategy = OutletTempControl()
strategy = strategies.OutletTempControl()
strategy.ceilometer = mock.MagicMock(
statistic_aggregation=self.fake_metrics.mock_get_statistics)
h1, h2 = strategy.group_hosts_by_outlet_temp(model)
@@ -84,29 +85,28 @@ class TestOutletTempControl(base.BaseTestCase):
self.assertEqual(dest_hosts[0]['hv'].uuid, 'Node_0')
def test_exception_model(self):
strategy = OutletTempControl()
strategy = strategies.OutletTempControl()
self.assertRaises(exception.ClusterStateNotDefined, strategy.execute,
None)
def test_exception_cluster_empty(self):
strategy = OutletTempControl()
model = ModelRoot()
strategy = strategies.OutletTempControl()
model = model_root.ModelRoot()
self.assertRaises(exception.ClusterEmpty, strategy.execute, model)
def test_execute_cluster_empty(self):
current_state_cluster = FakerModelCollector()
strategy = OutletTempControl()
strategy = strategies.OutletTempControl()
strategy.ceilometer = mock.MagicMock(
statistic_aggregation=self.fake_metrics.mock_get_statistics)
model = current_state_cluster.generate_random(0, 0)
model = model_root.ModelRoot()
self.assertRaises(exception.ClusterEmpty, strategy.execute, model)
def test_execute_no_workload(self):
strategy = OutletTempControl()
strategy = strategies.OutletTempControl()
strategy.ceilometer = mock.MagicMock(
statistic_aggregation=self.fake_metrics.mock_get_statistics)
current_state_cluster = FakerModelCollector()
current_state_cluster = faker_cluster_state.FakerModelCollector()
model = current_state_cluster. \
generate_scenario_4_with_1_hypervisor_no_vm()
@@ -114,13 +114,25 @@ class TestOutletTempControl(base.BaseTestCase):
self.assertEqual(solution.actions, [])
def test_execute(self):
strategy = OutletTempControl()
strategy = strategies.OutletTempControl()
strategy.ceilometer = mock.MagicMock(
statistic_aggregation=self.fake_metrics.mock_get_statistics)
model = self.fake_cluster.generate_scenario_3_with_2_hypervisors()
solution = strategy.execute(model)
actions_counter = Counter(
actions_counter = collections.Counter(
[action.get('action_type') for action in solution.actions])
num_migrations = actions_counter.get("migrate", 0)
self.assertEqual(num_migrations, 1)
def test_check_parameters(self):
outlet = strategies.OutletTempControl()
outlet.ceilometer = mock.MagicMock(
statistic_aggregation=self.fake_metrics.mock_get_statistics)
model = self.fake_cluster.generate_scenario_3_with_2_hypervisors()
solution = outlet.execute(model)
loader = default.DefaultActionLoader()
for action in solution.actions:
loaded_action = loader.load(action['action_type'])
loaded_action.input_parameters = action['input_parameters']
loaded_action.validate_parameters()