initial version
Change-Id: I699e0ab082657880998d8618fe29eb7f56c6c661
This commit is contained in:
1
watcher/tests/decision_engine/__init__.py
Normal file
1
watcher/tests/decision_engine/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
__author__ = 'Jean-Emile DARTOIS <jean-emile.dartois@b-com.com>'
|
||||
0
watcher/tests/decision_engine/demo/__init__.py
Normal file
0
watcher/tests/decision_engine/demo/__init__.py
Normal file
103
watcher/tests/decision_engine/demo/plot_consolidation_basic.py
Normal file
103
watcher/tests/decision_engine/demo/plot_consolidation_basic.py
Normal file
@@ -0,0 +1,103 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Copyright (c) 2015 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.
|
||||
#
|
||||
|
||||
# FIXME(jed): remove this class due jenkins build failed
|
||||
# The following librairies are removed from requirement.txt :
|
||||
# - numpy
|
||||
# - matplotlib
|
||||
# These dependencies required a server x, jenkin's server has no
|
||||
# server x
|
||||
|
||||
# import matplotlib.pyplot as plt
|
||||
# import numpy as np
|
||||
|
||||
|
||||
from watcher.decision_engine.strategies.basic_consolidation import \
|
||||
BasicConsolidation
|
||||
from watcher.tests.decision_engine.faker_cluster_state import \
|
||||
FakerStateCollector
|
||||
from watcher.tests.decision_engine.faker_metrics_collector import \
|
||||
FakerMetricsCollector
|
||||
|
||||
|
||||
class PlotConsolidationBasic(object):
|
||||
def plot(self, sercon, orign_model, solution):
|
||||
pass
|
||||
|
||||
# cluster_size = len(orign_model._hypervisors)
|
||||
# labels = []
|
||||
# before_score = []
|
||||
# after_score = []
|
||||
# for hypevisor_id in orign_model.get_all_hypervisors():
|
||||
# labels.append(hypevisor_id)
|
||||
# hypevisor = orign_model.get_hypervisor_from_id(hypevisor_id)
|
||||
# result_before = sercon.calculate_score_node(hypevisor,
|
||||
# orign_model)
|
||||
# result_after = sercon.calculate_score_node(hypevisor,
|
||||
# solution.get_model())
|
||||
# before_score.append(float(result_before * 100))
|
||||
# if result_after == 0:
|
||||
# result_after = 0
|
||||
# after_score.append(float(result_after * 100))
|
||||
#
|
||||
# ind = np.arange(cluster_size) # the x locations for the groups
|
||||
# width = 0.35 # the width of the bars
|
||||
#
|
||||
# fig, ax = plt.subplots()
|
||||
#
|
||||
# rects1 = ax.bar(ind, before_score, width, color='b')
|
||||
#
|
||||
# rects2 = ax.bar(ind + width, after_score, width, color='r')
|
||||
#
|
||||
# # add some text for labels, title and axes ticks
|
||||
# ax.set_ylabel(
|
||||
# 'Score of each hypervisor that represent their \
|
||||
# utilization level')
|
||||
# ax.set_title('Watcher Basic Server consolidation (efficiency ' + str(
|
||||
# sercon.get_solution().get_efficiency()) + " %)")
|
||||
#
|
||||
# ax.set_xticks(ind + width)
|
||||
# ax.set_xticklabels(labels)
|
||||
# ax.set_ylim([0, 140])
|
||||
|
||||
# ax.legend((rects1[0], rects2[0]),
|
||||
# ('Before Consolidation', 'After Consolidation'))
|
||||
|
||||
# def autolabel(rects):
|
||||
# # attach some text labels
|
||||
# for rect in rects:
|
||||
# height = rect.get_height()
|
||||
# ax.text(rect.get_x() + rect.get_width() / 2., 1.05 * height,
|
||||
# '%d' % int(height),
|
||||
# ha='center', va='bottom')
|
||||
#
|
||||
# autolabel(rects1)
|
||||
# autolabel(rects2)
|
||||
|
||||
# plt.show()
|
||||
|
||||
|
||||
cluster = FakerStateCollector()
|
||||
metrics = FakerMetricsCollector()
|
||||
sercon = BasicConsolidation()
|
||||
sercon.set_metrics_resource_collector(metrics)
|
||||
# try overbooking ? :) 150 % cpu
|
||||
sercon.set_threshold_cores(1)
|
||||
model_cluster = cluster.generate_scenario_1()
|
||||
solution = sercon.execute(model_cluster)
|
||||
plot = PlotConsolidationBasic()
|
||||
plot.plot(sercon, cluster.generate_scenario_1(), solution)
|
||||
45
watcher/tests/decision_engine/demo/test_context_strategy.py
Normal file
45
watcher/tests/decision_engine/demo/test_context_strategy.py
Normal file
@@ -0,0 +1,45 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Copyright (c) 2015 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.
|
||||
from oslo_config import cfg
|
||||
import time
|
||||
from watcher.decision_engine.strategies.basic_consolidation import \
|
||||
BasicConsolidation
|
||||
|
||||
from watcher.openstack.common import log
|
||||
|
||||
from watcher.tests.decision_engine.faker_cluster_state import \
|
||||
FakerStateCollector
|
||||
from watcher.tests.decision_engine.faker_metrics_collector import \
|
||||
FakerMetricsCollector
|
||||
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
cfg.CONF.debug = True
|
||||
log.setup('metering-controller')
|
||||
|
||||
metrics = FakerMetricsCollector()
|
||||
current_state_cluster = FakerStateCollector()
|
||||
|
||||
sercon = BasicConsolidation("basic", "Basic offline consolidation")
|
||||
sercon.set_metrics_resource_collector(metrics)
|
||||
|
||||
start_time = time.clock()
|
||||
solution = sercon.execute(current_state_cluster.generate_scenario_1())
|
||||
print(time.clock() - start_time, "seconds")
|
||||
print(solution)
|
||||
# planner = DefaultPlanner()
|
||||
# planner.schedule(solution)
|
||||
43
watcher/tests/decision_engine/demo/test_sercon.py
Normal file
43
watcher/tests/decision_engine/demo/test_sercon.py
Normal file
@@ -0,0 +1,43 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Copyright (c) 2015 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.
|
||||
from oslo_config import cfg
|
||||
import time
|
||||
from watcher.decision_engine.strategies.basic_consolidation import \
|
||||
BasicConsolidation
|
||||
|
||||
from watcher.openstack.common import log
|
||||
|
||||
from watcher.tests.decision_engine.faker_cluster_state import \
|
||||
FakerStateCollector
|
||||
from watcher.tests.decision_engine.faker_metrics_collector import \
|
||||
FakerMetricsCollector
|
||||
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
# debug on
|
||||
cfg.CONF.debug = True
|
||||
log.setup('metering-controller')
|
||||
|
||||
metrics = FakerMetricsCollector()
|
||||
current_state_cluster = FakerStateCollector()
|
||||
|
||||
sercon = BasicConsolidation()
|
||||
sercon.set_metrics_resource_collector(metrics)
|
||||
|
||||
start_time = time.clock()
|
||||
solution = sercon.execute(current_state_cluster.generate_scenario_1())
|
||||
print("duration =" + str((time.clock() - start_time)), "seconds")
|
||||
LOG.debug(solution)
|
||||
255
watcher/tests/decision_engine/faker_cluster_state.py
Normal file
255
watcher/tests/decision_engine/faker_cluster_state.py
Normal file
@@ -0,0 +1,255 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Copyright (c) 2015 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 random
|
||||
|
||||
from watcher.decision_engine.api.collector.cluster_state_collector import \
|
||||
ClusterStateCollector
|
||||
from watcher.decision_engine.framework.model.hypervisor import Hypervisor
|
||||
from watcher.decision_engine.framework.model.model_root import ModelRoot
|
||||
from watcher.decision_engine.framework.model.resource import Resource
|
||||
from watcher.decision_engine.framework.model.resource import ResourceType
|
||||
from watcher.decision_engine.framework.model.vm import VM
|
||||
|
||||
|
||||
class FakerStateCollector(ClusterStateCollector):
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def get_latest_state_cluster(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_" + str(i)
|
||||
hypervisor = Hypervisor()
|
||||
hypervisor.set_uuid(node_uuid)
|
||||
mem.set_capacity(hypervisor, 132)
|
||||
disk.set_capacity(hypervisor, 250)
|
||||
num_cores.set_capacity(hypervisor, 40)
|
||||
# print("create "+str(hypervisor))
|
||||
current_state_cluster.add_hypervisor(hypervisor)
|
||||
|
||||
for i in range(0, count_vm):
|
||||
vm_uuid = "VM_" + str(i)
|
||||
vm = VM()
|
||||
vm.set_uuid(vm_uuid)
|
||||
# print("create "+str(vm))
|
||||
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()
|
||||
# number of nodes
|
||||
count_node = 5
|
||||
# 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_" + str(i)
|
||||
node = Hypervisor()
|
||||
node.set_uuid(node_uuid)
|
||||
|
||||
mem.set_capacity(node, 132)
|
||||
disk.set_capacity(node, 250)
|
||||
num_cores.set_capacity(node, 40)
|
||||
# print("create "+str(node))
|
||||
current_state_cluster.add_hypervisor(node)
|
||||
|
||||
for i in range(0, count_vm):
|
||||
vm_uuid = "VM_" + str(i)
|
||||
vm = VM()
|
||||
vm.set_uuid(vm_uuid)
|
||||
# print("create "+str(vm))
|
||||
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)
|
||||
|
||||
current_state_cluster.get_mapping().map(
|
||||
current_state_cluster.get_hypervisor_from_id("Node_0"),
|
||||
current_state_cluster.get_vm_from_id("VM_0"))
|
||||
|
||||
current_state_cluster.get_mapping().map(
|
||||
current_state_cluster.get_hypervisor_from_id("Node_0"),
|
||||
current_state_cluster.get_vm_from_id("VM_1"))
|
||||
|
||||
current_state_cluster.get_mapping().map(
|
||||
current_state_cluster.get_hypervisor_from_id("Node_1"),
|
||||
current_state_cluster.get_vm_from_id("VM_2"))
|
||||
|
||||
current_state_cluster.get_mapping().map(
|
||||
current_state_cluster.get_hypervisor_from_id("Node_2"),
|
||||
current_state_cluster.get_vm_from_id("VM_3"))
|
||||
|
||||
current_state_cluster.get_mapping().map(
|
||||
current_state_cluster.get_hypervisor_from_id("Node_2"),
|
||||
current_state_cluster.get_vm_from_id("VM_4"))
|
||||
|
||||
current_state_cluster.get_mapping().map(
|
||||
current_state_cluster.get_hypervisor_from_id("Node_2"),
|
||||
current_state_cluster.get_vm_from_id("VM_5"))
|
||||
|
||||
current_state_cluster.get_mapping().map(
|
||||
current_state_cluster.get_hypervisor_from_id("Node_3"),
|
||||
current_state_cluster.get_vm_from_id("VM_6"))
|
||||
|
||||
current_state_cluster.get_mapping().map(
|
||||
current_state_cluster.get_hypervisor_from_id("Node_4"),
|
||||
current_state_cluster.get_vm_from_id("VM_7"))
|
||||
|
||||
return current_state_cluster
|
||||
|
||||
def generate_scenario_2(self):
|
||||
current_state_cluster = ModelRoot()
|
||||
# number of nodes
|
||||
count_node = 5
|
||||
|
||||
# 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_" + str(i)
|
||||
node = Hypervisor()
|
||||
node.set_uuid(node_uuid)
|
||||
mem.set_capacity(node, 132)
|
||||
disk.set_capacity(node, 250)
|
||||
num_cores.set_capacity(node, 40)
|
||||
# print("create "+str(node))
|
||||
current_state_cluster.add_hypervisor(node)
|
||||
return current_state_cluster
|
||||
|
||||
def map(self, model, h_id, vm_id):
|
||||
model.get_mapping().map(
|
||||
model.get_hypervisor_from_id(h_id),
|
||||
model.get_vm_from_id(vm_id))
|
||||
|
||||
def generate_scenario_3(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_" + str(i)
|
||||
node = Hypervisor()
|
||||
node.set_uuid(node_uuid)
|
||||
mem.set_capacity(node, 132)
|
||||
disk.set_capacity(node, 250)
|
||||
num_cores.set_capacity(node, 40)
|
||||
# print("create "+str(node))
|
||||
current_state_cluster.add_hypervisor(node)
|
||||
|
||||
for i in range(0, count_vm):
|
||||
vm_uuid = "VM_" + str(i)
|
||||
vm = VM()
|
||||
vm.set_uuid(vm_uuid)
|
||||
# print("create "+str(vm))
|
||||
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)
|
||||
print(count_vm)
|
||||
indice = 0
|
||||
for j in range(0, 2):
|
||||
node_uuid = "Node_" + str(j)
|
||||
for i in range(indice, 3):
|
||||
vm_uuid = "VM_" + str(i)
|
||||
self.map(current_state_cluster, node_uuid, vm_uuid)
|
||||
|
||||
for j in range(2, 5):
|
||||
node_uuid = "Node_" + str(j)
|
||||
for i in range(indice, 4):
|
||||
vm_uuid = "VM_" + str(i)
|
||||
self.map(current_state_cluster, node_uuid, vm_uuid)
|
||||
|
||||
for j in range(5, 10):
|
||||
node_uuid = "Node_" + str(j)
|
||||
for i in range(indice, 4):
|
||||
vm_uuid = "VM_" + str(i)
|
||||
self.map(current_state_cluster, node_uuid, vm_uuid)
|
||||
|
||||
return current_state_cluster
|
||||
113
watcher/tests/decision_engine/faker_metrics_collector.py
Normal file
113
watcher/tests/decision_engine/faker_metrics_collector.py
Normal file
@@ -0,0 +1,113 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Copyright (c) 2015 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 random
|
||||
from watcher.decision_engine.api.collector.metrics_resource_collector import \
|
||||
MetricsResourceCollector
|
||||
|
||||
|
||||
class FakerMetricsCollector(MetricsResourceCollector):
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def get_average_usage_vm_cpu(self, uuid):
|
||||
"""The last VM CPU usage values to average
|
||||
|
||||
:param uuid:00
|
||||
:return:
|
||||
"""
|
||||
# query influxdb stream
|
||||
|
||||
# compute in stream
|
||||
|
||||
# Normalize
|
||||
mock = {}
|
||||
# node 0
|
||||
mock['VM_0'] = 7
|
||||
mock['VM_1'] = 7
|
||||
# node 1
|
||||
mock['VM_2'] = 10
|
||||
# node 2
|
||||
mock['VM_3'] = 5
|
||||
mock['VM_4'] = 5
|
||||
mock['VM_5'] = 10
|
||||
|
||||
# node 3
|
||||
mock['VM_6'] = 8
|
||||
|
||||
# node 4
|
||||
mock['VM_7'] = 4
|
||||
if uuid not in mock.keys():
|
||||
# mock[uuid] = random.randint(1, 4)
|
||||
mock[uuid] = 8
|
||||
|
||||
return mock[str(uuid)]
|
||||
|
||||
def get_average_usage_vm_memory(self, uuid):
|
||||
mock = {}
|
||||
# node 0
|
||||
mock['VM_0'] = 2
|
||||
mock['VM_1'] = 5
|
||||
# node 1
|
||||
mock['VM_2'] = 5
|
||||
# node 2
|
||||
mock['VM_3'] = 8
|
||||
mock['VM_4'] = 5
|
||||
mock['VM_5'] = 16
|
||||
|
||||
# node 3
|
||||
mock['VM_6'] = 8
|
||||
|
||||
# node 4
|
||||
mock['VM_7'] = 4
|
||||
if uuid not in mock.keys():
|
||||
# mock[uuid] = random.randint(1, 4)
|
||||
mock[uuid] = 10
|
||||
|
||||
return mock[str(uuid)]
|
||||
|
||||
def get_average_usage_vm_disk(self, uuid):
|
||||
mock = {}
|
||||
# node 0
|
||||
mock['VM_0'] = 2
|
||||
mock['VM_1'] = 2
|
||||
# node 1
|
||||
mock['VM_2'] = 2
|
||||
# node 2
|
||||
mock['VM_3'] = 10
|
||||
mock['VM_4'] = 15
|
||||
mock['VM_5'] = 20
|
||||
|
||||
# node 3
|
||||
mock['VM_6'] = 8
|
||||
|
||||
# node 4
|
||||
mock['VM_7'] = 4
|
||||
|
||||
if uuid not in mock.keys():
|
||||
# mock[uuid] = random.randint(1, 4)
|
||||
mock[uuid] = 4
|
||||
|
||||
return mock[str(uuid)]
|
||||
|
||||
def get_virtual_machine_capacity(self, vm_uuid):
|
||||
return random.randint(1, 4)
|
||||
|
||||
def get_average_network_incomming(self, node):
|
||||
pass
|
||||
|
||||
def get_average_network_outcomming(self, node):
|
||||
pass
|
||||
0
watcher/tests/decision_engine/framework/__init__.py
Normal file
0
watcher/tests/decision_engine/framework/__init__.py
Normal file
@@ -0,0 +1,32 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Copyright (c) 2015 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 exceptions
|
||||
|
||||
from watcher.decision_engine.framework.events.event_consumer_factory import \
|
||||
EventConsumerFactory
|
||||
from watcher.decision_engine.framework.messaging.events import Events
|
||||
from watcher.tests import base
|
||||
|
||||
|
||||
class TestEventConsumerFactory(base.TestCase):
|
||||
|
||||
event_consumer_factory = EventConsumerFactory()
|
||||
|
||||
def test_factory_with_unknown_type(self):
|
||||
self.assertRaises(exceptions.AssertionError,
|
||||
self.event_consumer_factory.factory,
|
||||
Events.ALL)
|
||||
@@ -0,0 +1,75 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Copyright (c) 2015 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.
|
||||
|
||||
from mock import call
|
||||
from mock import MagicMock
|
||||
from watcher.decision_engine.framework.command.trigger_audit_command import \
|
||||
TriggerAuditCommand
|
||||
from watcher.decision_engine.framework.messaging.events import Events
|
||||
from watcher.objects.audit import Audit
|
||||
from watcher.objects.audit import AuditStatus
|
||||
from watcher.tests.db.base import DbTestCase
|
||||
from watcher.tests.decision_engine.faker_cluster_state import \
|
||||
FakerStateCollector
|
||||
from watcher.tests.decision_engine.faker_metrics_collector import \
|
||||
FakerMetricsCollector
|
||||
from watcher.tests.objects import utils as obj_utils
|
||||
|
||||
|
||||
class TestTriggerAuditCommand(DbTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestTriggerAuditCommand, self).setUp()
|
||||
self.audit_template = obj_utils.create_test_audit_template(
|
||||
self.context)
|
||||
self.audit = obj_utils.create_test_audit(
|
||||
self.context,
|
||||
audit_template_id=self.audit_template.id)
|
||||
|
||||
def test_trigger_audit_wihout_errors(self):
|
||||
try:
|
||||
statedb = FakerStateCollector()
|
||||
ressourcedb = FakerMetricsCollector()
|
||||
command = TriggerAuditCommand(MagicMock(), statedb, ressourcedb)
|
||||
command.execute(self.audit.uuid, self.context)
|
||||
except Exception:
|
||||
self.fail("The audit should be trigged wihtour error")
|
||||
|
||||
def test_trigger_audit_state_succes(self):
|
||||
statedb = FakerStateCollector()
|
||||
ressourcedb = FakerMetricsCollector()
|
||||
command = TriggerAuditCommand(MagicMock(), statedb, ressourcedb)
|
||||
command.execute(self.audit.uuid, self.context)
|
||||
audit = Audit.get_by_uuid(self.context, self.audit.uuid)
|
||||
self.assertEqual(AuditStatus.SUCCESS, audit.state)
|
||||
|
||||
def test_trigger_audit_send_notification(self):
|
||||
messaging = MagicMock()
|
||||
statedb = FakerStateCollector()
|
||||
ressourcedb = FakerMetricsCollector()
|
||||
command = TriggerAuditCommand(messaging, statedb, ressourcedb)
|
||||
command.execute(self.audit.uuid, self.context)
|
||||
|
||||
call_on_going = call(Events.TRIGGER_AUDIT.name, {
|
||||
'audit_status': AuditStatus.ONGOING,
|
||||
'audit_uuid': self.audit.uuid})
|
||||
call_success = call(Events.TRIGGER_AUDIT.name, {
|
||||
'audit_status': AuditStatus.SUCCESS,
|
||||
'audit_uuid': self.audit.uuid})
|
||||
|
||||
calls = [call_on_going, call_success]
|
||||
messaging.topic_status.publish_event.assert_has_calls(calls)
|
||||
self.assertEqual(2, messaging.topic_status.publish_event.call_count)
|
||||
@@ -0,0 +1,42 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Copyright (c) 2015 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 mock
|
||||
from mock import MagicMock
|
||||
from watcher.common import utils
|
||||
from watcher.decision_engine.framework.command.trigger_audit_command import \
|
||||
TriggerAuditCommand
|
||||
from watcher.decision_engine.framework.messaging.audit_endpoint import \
|
||||
AuditEndpoint
|
||||
from watcher.tests import base
|
||||
|
||||
|
||||
class TestAuditEndpoint(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestAuditEndpoint, self).setUp()
|
||||
self.endpoint = AuditEndpoint(MagicMock())
|
||||
|
||||
def test_trigger_audit(self):
|
||||
audit_uuid = utils.generate_uuid()
|
||||
# todo() add
|
||||
|
||||
with mock.patch.object(TriggerAuditCommand, 'execute') as mock_call:
|
||||
expected_uuid = self.endpoint.trigger_audit(
|
||||
self.context, audit_uuid)
|
||||
self.assertEqual(audit_uuid, expected_uuid)
|
||||
mock_call.assert_called_once_with(audit_uuid, self.context)
|
||||
"""
|
||||
@@ -0,0 +1,36 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Copyright (c) 2015 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.
|
||||
from watcher.decision_engine.framework.strategy.strategy_loader import \
|
||||
StrategyLoader
|
||||
from watcher.tests import base
|
||||
|
||||
|
||||
class TestStrategySelector(base.BaseTestCase):
|
||||
|
||||
strategy_loader = StrategyLoader()
|
||||
|
||||
def test_load_strategy_with_empty_model(self):
|
||||
selected_strategy = self.strategy_loader.load(None)
|
||||
self.assertIsNotNone(selected_strategy,
|
||||
'The default strategy be must not none')
|
||||
|
||||
def test_load_strategy_is_basic(self):
|
||||
exptected_strategy = 'basic'
|
||||
selected_strategy = self.strategy_loader.load(exptected_strategy)
|
||||
self.assertEqual(
|
||||
selected_strategy.get_name(),
|
||||
exptected_strategy,
|
||||
'The default strategy should be basic')
|
||||
@@ -0,0 +1,47 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Copyright (c) 2015 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 mock
|
||||
from oslo_config import cfg
|
||||
from watcher.decision_engine.framework.strategy.strategy_loader import \
|
||||
StrategyLoader
|
||||
from watcher.decision_engine.framework.strategy.strategy_selector import \
|
||||
StrategySelector
|
||||
from watcher.objects.audit_template import Goal
|
||||
from watcher.tests import base
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
class TestStrategySelector(base.BaseTestCase):
|
||||
|
||||
strategy_selector = StrategySelector()
|
||||
|
||||
def test_define_from_with_empty(self):
|
||||
expected_goal = None
|
||||
expected_strategy = \
|
||||
CONF.watcher_goals.goals[Goal.SERVERS_CONSOLIDATION]
|
||||
with mock.patch.object(StrategyLoader, 'load') as \
|
||||
mock_call:
|
||||
self.strategy_selector.define_from_goal(expected_goal)
|
||||
mock_call.assert_called_once_with(expected_strategy)
|
||||
|
||||
def test_define_from_goal(self):
|
||||
expected_goal = Goal.BALANCE_LOAD
|
||||
expected_strategy = CONF.watcher_goals.goals[expected_goal]
|
||||
with mock.patch.object(StrategyLoader, 'load') as \
|
||||
mock_call:
|
||||
self.strategy_selector.define_from_goal(expected_goal)
|
||||
mock_call.assert_called_once_with(expected_strategy)
|
||||
@@ -0,0 +1,75 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Copyright (c) 2015 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 mock
|
||||
from watcher.common import utils
|
||||
from watcher.db import api as db_api
|
||||
from watcher.decision_engine.framework.default_planner import DefaultPlanner
|
||||
from watcher.decision_engine.strategies.basic_consolidation import \
|
||||
BasicConsolidation
|
||||
from watcher.tests.db import base
|
||||
from watcher.tests.db import utils as db_utils
|
||||
from watcher.tests.decision_engine.faker_cluster_state import \
|
||||
FakerStateCollector
|
||||
from watcher.tests.decision_engine.faker_metrics_collector import \
|
||||
FakerMetricsCollector
|
||||
from watcher.tests.objects import utils as obj_utils
|
||||
|
||||
|
||||
class SolutionFaker(object):
|
||||
@staticmethod
|
||||
def build():
|
||||
metrics = FakerMetricsCollector()
|
||||
current_state_cluster = FakerStateCollector()
|
||||
sercon = BasicConsolidation("basic", "Basic offline consolidation")
|
||||
sercon.set_metrics_resource_collector(metrics)
|
||||
return sercon.execute(current_state_cluster.generate_scenario_1())
|
||||
|
||||
|
||||
class TestDefaultPlanner(base.DbTestCase):
|
||||
default_planner = DefaultPlanner()
|
||||
|
||||
def setUp(self):
|
||||
super(TestDefaultPlanner, self).setUp()
|
||||
obj_utils.create_test_audit_template(self.context)
|
||||
|
||||
p = mock.patch.object(db_api.Connection, 'create_action_plan')
|
||||
self.mock_create_action_plan = p.start()
|
||||
self.mock_create_action_plan.side_effect = (
|
||||
self._simulate_action_plan_create)
|
||||
self.addCleanup(p.stop)
|
||||
|
||||
q = mock.patch.object(db_api.Connection, 'create_action')
|
||||
self.mock_create_action = q.start()
|
||||
self.mock_create_action.side_effect = (
|
||||
self._simulate_action_create)
|
||||
self.addCleanup(q.stop)
|
||||
|
||||
def _simulate_action_plan_create(self, action_plan):
|
||||
action_plan.create()
|
||||
return action_plan
|
||||
|
||||
def _simulate_action_create(self, action):
|
||||
action.create()
|
||||
return action
|
||||
|
||||
def test_scheduler_w(self):
|
||||
audit = db_utils.create_test_audit(uuid=utils.generate_uuid())
|
||||
fake_solution = SolutionFaker.build()
|
||||
action_plan = self.default_planner.schedule(self.context,
|
||||
audit.id, fake_solution)
|
||||
|
||||
self.assertIsNotNone(action_plan.uuid)
|
||||
45
watcher/tests/decision_engine/framework/test_manager.py
Normal file
45
watcher/tests/decision_engine/framework/test_manager.py
Normal file
@@ -0,0 +1,45 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Copyright (c) 2015 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 mock
|
||||
|
||||
from watcher.common import utils
|
||||
|
||||
from watcher.decision_engine.framework.events.event_consumer_factory import \
|
||||
EventConsumerFactory
|
||||
|
||||
from watcher.common.messaging.events.event import Event
|
||||
from watcher.decision_engine.framework.manager_decision_engine import \
|
||||
DecisionEngineManager
|
||||
|
||||
from watcher.decision_engine.framework.messaging.events import Events
|
||||
from watcher.tests import base
|
||||
|
||||
|
||||
class TestDecisionEngineManager(base.TestCase):
|
||||
def setUp(self):
|
||||
super(TestDecisionEngineManager, self).setUp()
|
||||
self.manager = DecisionEngineManager()
|
||||
|
||||
def test_event_receive(self):
|
||||
# todo(jed) remove useless
|
||||
with mock.patch.object(EventConsumerFactory, 'factory') as mock_call:
|
||||
data = {"key1": "value"}
|
||||
request_id = utils.generate_uuid()
|
||||
event_type = Events.TRIGGER_AUDIT
|
||||
event = Event(event_type, data, request_id)
|
||||
self.manager.event_receive(event)
|
||||
mock_call.assert_called_once_with(event_type)
|
||||
57
watcher/tests/decision_engine/framework/test_rpcapi.py
Normal file
57
watcher/tests/decision_engine/framework/test_rpcapi.py
Normal file
@@ -0,0 +1,57 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Copyright (c) 2015 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 mock
|
||||
import oslo.messaging as om
|
||||
from watcher.common import exception
|
||||
from watcher.common import utils
|
||||
from watcher.decision_engine.framework.rpcapi import DecisionEngineAPI
|
||||
from watcher.tests import base
|
||||
|
||||
|
||||
class TestDecisionEngineAPI(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestDecisionEngineAPI, self).setUp()
|
||||
|
||||
api = DecisionEngineAPI()
|
||||
|
||||
def test_get_version(self):
|
||||
expected_version = self.api.API_VERSION
|
||||
self.assertEqual(expected_version, self.api.get_version())
|
||||
|
||||
def test_get_api_version(self):
|
||||
with mock.patch.object(om.RPCClient, 'call') as mock_call:
|
||||
expected_context = self.context
|
||||
self.api.check_api_version(expected_context)
|
||||
mock_call.assert_called_once_with(
|
||||
expected_context.to_dict(),
|
||||
'check_api_version',
|
||||
api_version=DecisionEngineAPI().API_VERSION)
|
||||
|
||||
def test_execute_audit_throw_exception(self):
|
||||
audit_uuid = "uuid"
|
||||
self.assertRaises(exception.InvalidUuidOrName,
|
||||
self.api.trigger_audit,
|
||||
audit_uuid)
|
||||
|
||||
def test_execute_audit_without_error(self):
|
||||
with mock.patch.object(om.RPCClient, 'call') as mock_call:
|
||||
audit_uuid = utils.generate_uuid()
|
||||
self.api.trigger_audit(self.context, audit_uuid)
|
||||
mock_call.assert_called_once_with(self.context.to_dict(),
|
||||
'trigger_audit',
|
||||
audit_uuid=audit_uuid)
|
||||
184
watcher/tests/decision_engine/test_basic_consolidation.py
Normal file
184
watcher/tests/decision_engine/test_basic_consolidation.py
Normal file
@@ -0,0 +1,184 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Copyright (c) 2015 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.
|
||||
#
|
||||
from watcher.common import exception
|
||||
|
||||
from watcher.decision_engine.framework.meta_actions.hypervisor_state import \
|
||||
ChangeHypervisorState
|
||||
from watcher.decision_engine.framework.meta_actions.power_state import \
|
||||
ChangePowerState
|
||||
|
||||
from watcher.decision_engine.framework.meta_actions.migrate import Migrate
|
||||
from watcher.decision_engine.framework.model.model_root import ModelRoot
|
||||
from watcher.decision_engine.strategies.basic_consolidation import \
|
||||
BasicConsolidation
|
||||
|
||||
from watcher.tests import base
|
||||
from watcher.tests.decision_engine.faker_cluster_state import \
|
||||
FakerStateCollector
|
||||
from watcher.tests.decision_engine.faker_metrics_collector import \
|
||||
FakerMetricsCollector
|
||||
|
||||
|
||||
class TestBasicConsolidation(base.BaseTestCase):
|
||||
# fake metrics
|
||||
fake_metrics = FakerMetricsCollector()
|
||||
|
||||
# fake cluster
|
||||
fake_cluster = FakerStateCollector()
|
||||
|
||||
def test_cluster_size(self):
|
||||
size_cluster = len(
|
||||
self.fake_cluster.generate_scenario_1().get_all_hypervisors())
|
||||
size_cluster_assert = 5
|
||||
self.assertEqual(size_cluster, size_cluster_assert)
|
||||
|
||||
def test_basic_consolidation_score_hypervisor(self):
|
||||
cluster = self.fake_cluster.generate_scenario_1()
|
||||
sercon = BasicConsolidation()
|
||||
sercon.set_metrics_resource_collector(self.fake_metrics)
|
||||
node_1_score = 0.09862626262626262
|
||||
self.assertEqual(
|
||||
sercon.calculate_score_node(
|
||||
cluster.get_hypervisor_from_id("Node_1"),
|
||||
cluster), node_1_score)
|
||||
node_2_score = 0.29989898989898994
|
||||
self.assertEqual(
|
||||
sercon.calculate_score_node(
|
||||
cluster.get_hypervisor_from_id("Node_2"),
|
||||
cluster), node_2_score)
|
||||
node_0_score = 0.13967676767676765
|
||||
self.assertEqual(
|
||||
sercon.calculate_score_node(
|
||||
cluster.get_hypervisor_from_id("Node_0"),
|
||||
cluster), node_0_score)
|
||||
|
||||
def test_basic_consolidation_score_vm(self):
|
||||
cluster = self.fake_cluster.generate_scenario_1()
|
||||
sercon = BasicConsolidation()
|
||||
sercon.set_metrics_resource_collector(self.fake_metrics)
|
||||
vm_0 = cluster.get_vm_from_id("VM_0")
|
||||
vm_0_score = 0.6
|
||||
self.assertEqual(sercon.calculate_score_vm(vm_0, cluster), vm_0_score)
|
||||
|
||||
vm_1 = cluster.get_vm_from_id("VM_1")
|
||||
vm_1_score = 1.0999999999999999
|
||||
self.assertEqual(sercon.calculate_score_vm(vm_1, cluster),
|
||||
vm_1_score)
|
||||
vm_2 = cluster.get_vm_from_id("VM_2")
|
||||
vm_2_score = 1.2
|
||||
self.assertEqual(sercon.calculate_score_vm(vm_2, cluster), vm_2_score)
|
||||
|
||||
def test_basic_consolidation_weight(self):
|
||||
cluster = self.fake_cluster.generate_scenario_1()
|
||||
sercon = BasicConsolidation()
|
||||
sercon.set_metrics_resource_collector(self.fake_metrics)
|
||||
vm_0 = cluster.get_vm_from_id("VM_0")
|
||||
cores = 16
|
||||
# 80 Go
|
||||
disk = 80
|
||||
# mem 8 Go
|
||||
mem = 8
|
||||
vm_0_weight_assert = 3.1999999999999997
|
||||
self.assertEqual(sercon.calculate_weight(cluster, vm_0, cores, disk,
|
||||
mem),
|
||||
vm_0_weight_assert)
|
||||
|
||||
def test_basic_consolidation_efficiency(self):
|
||||
sercon = BasicConsolidation()
|
||||
sercon.set_metrics_resource_collector(self.fake_metrics)
|
||||
efficient_assert = 100
|
||||
solution = sercon.execute(self.fake_cluster.generate_scenario_1())
|
||||
self.assertEqual(solution.get_efficiency(), efficient_assert)
|
||||
|
||||
def test_exception_model(self):
|
||||
sercon = BasicConsolidation()
|
||||
self.assertRaises(exception.ClusteStateNotDefined, sercon.execute,
|
||||
None)
|
||||
|
||||
def test_exception_cluster_empty(self):
|
||||
sercon = BasicConsolidation()
|
||||
model = ModelRoot()
|
||||
self.assertRaises(exception.ClusterEmpty, sercon.execute,
|
||||
model)
|
||||
|
||||
def test_exception_metric_collector(self):
|
||||
sercon = BasicConsolidation()
|
||||
self.assertRaises(exception.MetricCollectorNotDefined,
|
||||
sercon.calculate_score_vm, "VM_1", None)
|
||||
|
||||
def check_migration(self, array, indice, vm, src, dest):
|
||||
"""Helper to check migration
|
||||
|
||||
:param array:
|
||||
:param indice:
|
||||
:param vm:
|
||||
:param src:
|
||||
:param dest:
|
||||
:return:
|
||||
"""
|
||||
self.assertEqual(array[indice].get_vm().get_uuid(), vm)
|
||||
self.assertEqual(array[indice].get_source_hypervisor().get_uuid(), src)
|
||||
self.assertEqual(array[indice].get_dest_hypervisor().get_uuid(), dest)
|
||||
|
||||
def test_basic_consolidation_migration(self):
|
||||
sercon = BasicConsolidation()
|
||||
sercon.set_metrics_resource_collector(self.fake_metrics)
|
||||
|
||||
solution = sercon.execute(self.fake_cluster.generate_scenario_1())
|
||||
|
||||
count_migration = 0
|
||||
change_hypervisor_state = 0
|
||||
change_power_state = 0
|
||||
migrate = []
|
||||
for action in solution.meta_actions:
|
||||
if isinstance(action, Migrate):
|
||||
count_migration += 1
|
||||
migrate.append(action)
|
||||
if isinstance(action, ChangeHypervisorState):
|
||||
change_hypervisor_state += 1
|
||||
if isinstance(action, ChangePowerState):
|
||||
change_power_state += 1
|
||||
|
||||
self.assertEqual(change_hypervisor_state, 3)
|
||||
self.assertEqual(count_migration, 3)
|
||||
# check migration
|
||||
self.check_migration(migrate, 0, "VM_7", "Node_4", "Node_2")
|
||||
self.check_migration(migrate, 1, "VM_6", "Node_3", "Node_0")
|
||||
self.check_migration(migrate, 2, "VM_2", "Node_1", "Node_0")
|
||||
|
||||
def test_basic_consolidation_random(self):
|
||||
metrics = FakerMetricsCollector()
|
||||
current_state_cluster = FakerStateCollector()
|
||||
|
||||
sercon = BasicConsolidation("sercon", "Basic offline consolidation")
|
||||
sercon.set_metrics_resource_collector(metrics)
|
||||
|
||||
solution = sercon.execute(
|
||||
current_state_cluster.generate_random(25, 2))
|
||||
|
||||
count_migration = 0
|
||||
change_hypervisor_state = 0
|
||||
change_power_state = 0
|
||||
migrate = []
|
||||
for action in solution.meta_actions:
|
||||
if isinstance(action, Migrate):
|
||||
count_migration += 1
|
||||
migrate.append(action)
|
||||
if isinstance(action, ChangeHypervisorState):
|
||||
change_hypervisor_state += 1
|
||||
if isinstance(action, ChangePowerState):
|
||||
change_power_state += 1
|
||||
22
watcher/tests/decision_engine/test_loader.py
Normal file
22
watcher/tests/decision_engine/test_loader.py
Normal file
@@ -0,0 +1,22 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Copyright (c) 2015 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.
|
||||
from watcher.tests import base
|
||||
|
||||
|
||||
class TestLoader(base.BaseTestCase):
|
||||
|
||||
def test_loader(self):
|
||||
pass
|
||||
54
watcher/tests/decision_engine/test_model.py
Normal file
54
watcher/tests/decision_engine/test_model.py
Normal file
@@ -0,0 +1,54 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Copyright (c) 2015 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 uuid
|
||||
from watcher.common import exception
|
||||
|
||||
from watcher.decision_engine.framework.model.hypervisor import Hypervisor
|
||||
from watcher.decision_engine.framework.model.model_root import ModelRoot
|
||||
|
||||
from watcher.tests.decision_engine.faker_cluster_state import \
|
||||
FakerStateCollector
|
||||
|
||||
from watcher.tests import base
|
||||
|
||||
|
||||
class TestModel(base.BaseTestCase):
|
||||
def test_model(self):
|
||||
fake_cluster = FakerStateCollector()
|
||||
model = fake_cluster.generate_scenario_1()
|
||||
|
||||
self.assertEqual(len(model._hypervisors), 5)
|
||||
self.assertEqual(len(model._vms), 35)
|
||||
self.assertEqual(len(model.get_mapping().get_mapping()), 5)
|
||||
|
||||
def test_add_hypervisor(self):
|
||||
model = ModelRoot()
|
||||
id = str(uuid.uuid4())
|
||||
hypervisor = Hypervisor()
|
||||
hypervisor.set_uuid(id)
|
||||
model.add_hypervisor(hypervisor)
|
||||
self.assertEqual(model.get_hypervisor_from_id(id), hypervisor)
|
||||
|
||||
def test_delete_hypervisor(self):
|
||||
model = ModelRoot()
|
||||
id = str(uuid.uuid4())
|
||||
hypervisor = Hypervisor()
|
||||
hypervisor.set_uuid(id)
|
||||
model.add_hypervisor(hypervisor)
|
||||
self.assertEqual(model.get_hypervisor_from_id(id), hypervisor)
|
||||
model.remove_hypervisor(hypervisor)
|
||||
self.assertRaises(exception.HypervisorNotFound,
|
||||
model.get_hypervisor_from_id, id)
|
||||
21
watcher/tests/decision_engine/test_planner.py
Normal file
21
watcher/tests/decision_engine/test_planner.py
Normal file
@@ -0,0 +1,21 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Copyright (c) 2015 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.
|
||||
from watcher.tests import base
|
||||
|
||||
|
||||
class TestPlanner(base.BaseTestCase):
|
||||
def test_planner(self):
|
||||
pass
|
||||
Reference in New Issue
Block a user