Compare commits
10 Commits
1.6.0
...
newton-eol
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1c38637dff | ||
|
|
1eb2b517ef | ||
|
|
3e030618fa | ||
|
|
f823345424 | ||
|
|
19fdd1557e | ||
|
|
641989b424 | ||
|
|
8814c09087 | ||
|
|
eb4f46b703 | ||
|
|
2f33dd10c0 | ||
|
|
1a197ab801 |
@@ -2,3 +2,4 @@
|
|||||||
host=review.openstack.org
|
host=review.openstack.org
|
||||||
port=29418
|
port=29418
|
||||||
project=openstack/watcher.git
|
project=openstack/watcher.git
|
||||||
|
defaultbranch=stable/newton
|
||||||
|
|||||||
@@ -10,10 +10,8 @@ Watcher
|
|||||||
|
|
||||||
OpenStack Watcher provides a flexible and scalable resource optimization
|
OpenStack Watcher provides a flexible and scalable resource optimization
|
||||||
service for multi-tenant OpenStack-based clouds.
|
service for multi-tenant OpenStack-based clouds.
|
||||||
Watcher provides a complete optimization loop-including everything from a
|
Watcher provides a robust framework to realize a wide range of cloud
|
||||||
metrics receiver, complex event processor and profiler, optimization processor
|
optimization goals, including the reduction of data center
|
||||||
and an action plan applier. This provides a robust framework to realize a wide
|
|
||||||
range of cloud optimization goals, including the reduction of data center
|
|
||||||
operating costs, increased system performance via intelligent virtual machine
|
operating costs, increased system performance via intelligent virtual machine
|
||||||
migration, increased energy efficiency-and more!
|
migration, increased energy efficiency-and more!
|
||||||
|
|
||||||
|
|||||||
@@ -171,12 +171,12 @@ This component is responsible for computing a set of potential optimization
|
|||||||
:ref:`Actions <action_definition>` in order to fulfill
|
:ref:`Actions <action_definition>` in order to fulfill
|
||||||
the :ref:`Goal <goal_definition>` of an :ref:`Audit <audit_definition>`.
|
the :ref:`Goal <goal_definition>` of an :ref:`Audit <audit_definition>`.
|
||||||
|
|
||||||
It first reads the parameters of the :ref:`Audit <audit_definition>` from the
|
It first reads the parameters of the :ref:`Audit <audit_definition>` to know
|
||||||
associated :ref:`Audit Template <audit_template_definition>` and knows the
|
the :ref:`Goal <goal_definition>` to achieve.
|
||||||
:ref:`Goal <goal_definition>` to achieve.
|
|
||||||
|
|
||||||
It then selects the most appropriate :ref:`Strategy <strategy_definition>`
|
Unless specified, it then selects the most appropriate :ref:`strategy
|
||||||
from the list of available strategies achieving this goal.
|
<strategy_definition>` from the list of available strategies achieving this
|
||||||
|
goal.
|
||||||
|
|
||||||
The :ref:`Strategy <strategy_definition>` is then dynamically loaded (via
|
The :ref:`Strategy <strategy_definition>` is then dynamically loaded (via
|
||||||
`stevedore <http://docs.openstack.org/developer/stevedore/>`_). The
|
`stevedore <http://docs.openstack.org/developer/stevedore/>`_). The
|
||||||
@@ -290,7 +290,7 @@ the Audit parameters from the
|
|||||||
:ref:`Watcher Database <watcher_database_definition>`. It instantiates the
|
:ref:`Watcher Database <watcher_database_definition>`. It instantiates the
|
||||||
appropriate :ref:`strategy <strategy_definition>` (using entry points)
|
appropriate :ref:`strategy <strategy_definition>` (using entry points)
|
||||||
given both the :ref:`goal <goal_definition>` and the strategy associated to the
|
given both the :ref:`goal <goal_definition>` and the strategy associated to the
|
||||||
parent :ref:`audit template <audit_template_definition>` of the :ref:`Audit
|
parent :ref:`audit template <audit_template_definition>` of the :ref:`audit
|
||||||
<audit_definition>`. If no strategy is associated to the audit template, the
|
<audit_definition>`. If no strategy is associated to the audit template, the
|
||||||
strategy is dynamically selected by the Decision Engine.
|
strategy is dynamically selected by the Decision Engine.
|
||||||
|
|
||||||
|
|||||||
@@ -5,11 +5,12 @@
|
|||||||
hide methods
|
hide methods
|
||||||
hide stereotypes
|
hide stereotypes
|
||||||
|
|
||||||
table(goal) {
|
table(goals) {
|
||||||
primary_key(id: Integer)
|
primary_key(id: Integer)
|
||||||
uuid : String[36]
|
uuid : String[36]
|
||||||
name : String[63]
|
name : String[63]
|
||||||
display_name : String[63]
|
display_name : String[63]
|
||||||
|
efficacy_specification : JSONEncodedList, nullable
|
||||||
|
|
||||||
created_at : DateTime
|
created_at : DateTime
|
||||||
updated_at : DateTime
|
updated_at : DateTime
|
||||||
@@ -18,12 +19,13 @@ table(goal) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
table(strategy) {
|
table(strategies) {
|
||||||
primary_key(id: Integer)
|
primary_key(id: Integer)
|
||||||
foreign_key(goal_id : Integer)
|
foreign_key(goal_id : Integer)
|
||||||
uuid : String[36]
|
uuid : String[36]
|
||||||
name : String[63]
|
name : String[63]
|
||||||
display_name : String[63]
|
display_name : String[63]
|
||||||
|
parameters_spec : JSONEncodedDict, nullable
|
||||||
|
|
||||||
created_at : DateTime
|
created_at : DateTime
|
||||||
updated_at : DateTime
|
updated_at : DateTime
|
||||||
@@ -32,7 +34,7 @@ table(strategy) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
table(audit_template) {
|
table(audit_templates) {
|
||||||
primary_key(id: Integer)
|
primary_key(id: Integer)
|
||||||
foreign_key("goal_id : Integer")
|
foreign_key("goal_id : Integer")
|
||||||
foreign_key("strategy_id : Integer, nullable")
|
foreign_key("strategy_id : Integer, nullable")
|
||||||
@@ -50,14 +52,17 @@ table(audit_template) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
table(audit) {
|
table(audits) {
|
||||||
primary_key(id: Integer)
|
primary_key(id: Integer)
|
||||||
foreign_key("audit_template_id : Integer")
|
foreign_key("goal_id : Integer")
|
||||||
|
foreign_key("strategy_id : Integer, nullable")
|
||||||
uuid : String[36]
|
uuid : String[36]
|
||||||
audit_type : String[20]
|
audit_type : String[20]
|
||||||
state : String[20], nullable
|
state : String[20], nullable
|
||||||
deadline :DateTime, nullable
|
deadline : DateTime, nullable
|
||||||
interval : Integer, nullable
|
interval : Integer, nullable
|
||||||
|
parameters : JSONEncodedDict, nullable
|
||||||
|
host_aggregate : Integer, nullable
|
||||||
|
|
||||||
created_at : DateTime
|
created_at : DateTime
|
||||||
updated_at : DateTime
|
updated_at : DateTime
|
||||||
@@ -66,9 +71,10 @@ table(audit) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
table(action_plan) {
|
table(action_plans) {
|
||||||
primary_key(id: Integer)
|
primary_key(id: Integer)
|
||||||
foreign_key("audit_id : Integer, nullable")
|
foreign_key("audit_id : Integer, nullable")
|
||||||
|
foreign_key("strategy_id : Integer")
|
||||||
uuid : String[36]
|
uuid : String[36]
|
||||||
first_action_id : Integer
|
first_action_id : Integer
|
||||||
state : String[20], nullable
|
state : String[20], nullable
|
||||||
@@ -81,7 +87,7 @@ table(action_plan) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
table(action) {
|
table(actions) {
|
||||||
primary_key(id: Integer)
|
primary_key(id: Integer)
|
||||||
foreign_key("action_plan_id : Integer")
|
foreign_key("action_plan_id : Integer")
|
||||||
uuid : String[36]
|
uuid : String[36]
|
||||||
@@ -97,7 +103,7 @@ table(action) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
table(efficacy_indicator) {
|
table(efficacy_indicators) {
|
||||||
primary_key(id: Integer)
|
primary_key(id: Integer)
|
||||||
foreign_key("action_plan_id : Integer")
|
foreign_key("action_plan_id : Integer")
|
||||||
uuid : String[36]
|
uuid : String[36]
|
||||||
@@ -112,12 +118,27 @@ table(efficacy_indicator) {
|
|||||||
deleted : Integer
|
deleted : Integer
|
||||||
}
|
}
|
||||||
|
|
||||||
"goal" <.. "strategy" : Foreign Key
|
table(scoring_engines) {
|
||||||
"goal" <.. "audit_template" : Foreign Key
|
primary_key(id: Integer)
|
||||||
"strategy" <.. "audit_template" : Foreign Key
|
uuid : String[36]
|
||||||
"audit_template" <.. "audit" : Foreign Key
|
name : String[63]
|
||||||
"action_plan" <.. "action" : Foreign Key
|
description : String[255], nullable
|
||||||
"action_plan" <.. "efficacy_indicator" : Foreign Key
|
metainfo : Text, nullable
|
||||||
"audit" <.. "action_plan" : Foreign Key
|
|
||||||
|
created_at : DateTime
|
||||||
|
updated_at : DateTime
|
||||||
|
deleted_at : DateTime
|
||||||
|
deleted : Integer
|
||||||
|
}
|
||||||
|
|
||||||
|
"goals" <.. "strategies" : Foreign Key
|
||||||
|
"goals" <.. "audit_templates" : Foreign Key
|
||||||
|
"strategies" <.. "audit_templates" : Foreign Key
|
||||||
|
"goals" <.. "audits" : Foreign Key
|
||||||
|
"strategies" <.. "audits" : Foreign Key
|
||||||
|
"action_plans" <.. "actions" : Foreign Key
|
||||||
|
"action_plans" <.. "efficacy_indicators" : Foreign Key
|
||||||
|
"strategies" <.. "action_plans" : Foreign Key
|
||||||
|
"audits" <.. "action_plans" : Foreign Key
|
||||||
|
|
||||||
@enduml
|
@enduml
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 56 KiB |
@@ -12,7 +12,7 @@ oslo.concurrency>=3.8.0 # Apache-2.0
|
|||||||
oslo.cache>=1.5.0 # Apache-2.0
|
oslo.cache>=1.5.0 # Apache-2.0
|
||||||
oslo.config>=3.14.0 # Apache-2.0
|
oslo.config>=3.14.0 # Apache-2.0
|
||||||
oslo.context>=2.9.0 # Apache-2.0
|
oslo.context>=2.9.0 # Apache-2.0
|
||||||
oslo.db>=4.10.0 # Apache-2.0
|
oslo.db!=4.13.1,!=4.13.2,>=4.10.0 # Apache-2.0
|
||||||
oslo.i18n>=2.1.0 # Apache-2.0
|
oslo.i18n>=2.1.0 # Apache-2.0
|
||||||
oslo.log>=1.14.0 # Apache-2.0
|
oslo.log>=1.14.0 # Apache-2.0
|
||||||
oslo.messaging>=5.2.0 # Apache-2.0
|
oslo.messaging>=5.2.0 # Apache-2.0
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[metadata]
|
[metadata]
|
||||||
name = python-watcher
|
name = python-watcher
|
||||||
summary = Watcher takes advantage of CEP and ML algorithms/metaheuristics to improve physical resources usage through better VM placement. Watcher can improve your cloud optimization by reducing energy footprint and increasing profits.
|
summary = OpenStack Watcher provides a flexible and scalable resource optimization service for multi-tenant OpenStack-based clouds.
|
||||||
description-file =
|
description-file =
|
||||||
README.rst
|
README.rst
|
||||||
author = OpenStack
|
author = OpenStack
|
||||||
|
|||||||
13
tox.ini
13
tox.ini
@@ -1,16 +1,17 @@
|
|||||||
[tox]
|
[tox]
|
||||||
minversion = 1.6
|
minversion = 1.8
|
||||||
envlist = py35,py34,py27,pep8
|
envlist = py35,py34,py27,pep8
|
||||||
skipsdist = True
|
skipsdist = True
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
usedevelop = True
|
usedevelop = True
|
||||||
whitelist_externals = find
|
whitelist_externals = find
|
||||||
install_command = pip install -U {opts} {packages}
|
install_command =
|
||||||
|
constraints: pip install -U --force-reinstall -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt?h=stable/newton} {opts} {packages}
|
||||||
|
pip install -U {opts} {packages}
|
||||||
setenv =
|
setenv =
|
||||||
VIRTUAL_ENV={envdir}
|
VIRTUAL_ENV={envdir}
|
||||||
deps = -r{toxinidir}/requirements.txt
|
deps = -r{toxinidir}/test-requirements.txt
|
||||||
-r{toxinidir}/test-requirements.txt
|
|
||||||
commands =
|
commands =
|
||||||
find . -type f -name "*.pyc" -delete
|
find . -type f -name "*.pyc" -delete
|
||||||
find . -type d -name "__pycache__" -delete
|
find . -type d -name "__pycache__" -delete
|
||||||
@@ -20,7 +21,7 @@ commands =
|
|||||||
commands =
|
commands =
|
||||||
doc8 doc/source/ CONTRIBUTING.rst HACKING.rst README.rst
|
doc8 doc/source/ CONTRIBUTING.rst HACKING.rst README.rst
|
||||||
flake8
|
flake8
|
||||||
bandit -r watcher -x tests -n5 -ll
|
bandit -r watcher -x tests -n5 -ll -s B320
|
||||||
|
|
||||||
[testenv:venv]
|
[testenv:venv]
|
||||||
setenv = PYTHONHASHSEED=0
|
setenv = PYTHONHASHSEED=0
|
||||||
@@ -66,4 +67,4 @@ commands = sphinx-build -a -W -E -d releasenotes/build/doctrees -b html releasen
|
|||||||
|
|
||||||
[testenv:bandit]
|
[testenv:bandit]
|
||||||
deps = -r{toxinidir}/test-requirements.txt
|
deps = -r{toxinidir}/test-requirements.txt
|
||||||
commands = bandit -r watcher -x tests -n5 -ll
|
commands = bandit -r watcher -x tests -n5 -ll -s B320
|
||||||
|
|||||||
@@ -272,4 +272,4 @@ def prepare_service(argv=(), conf=cfg.CONF):
|
|||||||
conf.log_opt_values(LOG, logging.DEBUG)
|
conf.log_opt_values(LOG, logging.DEBUG)
|
||||||
|
|
||||||
gmr.TextGuruMeditation.register_section(_('Plugins'), opts.show_plugins)
|
gmr.TextGuruMeditation.register_section(_('Plugins'), opts.show_plugins)
|
||||||
gmr.TextGuruMeditation.setup_autorun(version)
|
gmr.TextGuruMeditation.setup_autorun(version, conf=conf)
|
||||||
|
|||||||
@@ -223,3 +223,53 @@ class ModelRoot(object):
|
|||||||
root.append(self._build_instance_element(instance))
|
root.append(self._build_instance_element(instance))
|
||||||
|
|
||||||
return etree.tostring(root, pretty_print=True).decode('utf-8')
|
return etree.tostring(root, pretty_print=True).decode('utf-8')
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_xml(cls, data):
|
||||||
|
model = cls()
|
||||||
|
root = etree.fromstring(data)
|
||||||
|
|
||||||
|
mem = element.Resource(element.ResourceType.memory)
|
||||||
|
num_cores = element.Resource(element.ResourceType.cpu_cores)
|
||||||
|
disk = element.Resource(element.ResourceType.disk)
|
||||||
|
disk_capacity = element.Resource(element.ResourceType.disk_capacity)
|
||||||
|
model.create_resource(mem)
|
||||||
|
model.create_resource(num_cores)
|
||||||
|
model.create_resource(disk)
|
||||||
|
model.create_resource(disk_capacity)
|
||||||
|
|
||||||
|
for cn in root.findall('.//ComputeNode'):
|
||||||
|
node = element.ComputeNode(cn.get('id'))
|
||||||
|
node.uuid = cn.get('uuid')
|
||||||
|
node.hostname = cn.get('hostname')
|
||||||
|
# set capacity
|
||||||
|
mem.set_capacity(node, int(cn.get(str(mem.name))))
|
||||||
|
disk.set_capacity(node, int(cn.get(str(disk.name))))
|
||||||
|
disk_capacity.set_capacity(
|
||||||
|
node, int(cn.get(str(disk_capacity.name))))
|
||||||
|
num_cores.set_capacity(node, int(cn.get(str(num_cores.name))))
|
||||||
|
node.state = cn.get('state')
|
||||||
|
node.status = cn.get('status')
|
||||||
|
|
||||||
|
model.add_node(node)
|
||||||
|
|
||||||
|
for inst in root.findall('.//Instance'):
|
||||||
|
instance = element.Instance()
|
||||||
|
instance.uuid = inst.get('uuid')
|
||||||
|
instance.state = inst.get('state')
|
||||||
|
|
||||||
|
mem.set_capacity(instance, int(inst.get(str(mem.name))))
|
||||||
|
disk.set_capacity(instance, int(inst.get(str(disk.name))))
|
||||||
|
disk_capacity.set_capacity(
|
||||||
|
instance, int(inst.get(str(disk_capacity.name))))
|
||||||
|
num_cores.set_capacity(
|
||||||
|
instance, int(inst.get(str(num_cores.name))))
|
||||||
|
|
||||||
|
parent = inst.getparent()
|
||||||
|
if parent.tag == 'ComputeNode':
|
||||||
|
node = model.get_node_by_uuid(parent.get('uuid'))
|
||||||
|
model.map_instance(instance, node)
|
||||||
|
else:
|
||||||
|
model.add_instance(instance)
|
||||||
|
|
||||||
|
return model
|
||||||
|
|||||||
@@ -81,8 +81,6 @@ class BasicConsolidation(base.ServerConsolidationBaseStrategy):
|
|||||||
self.number_of_released_nodes = 0
|
self.number_of_released_nodes = 0
|
||||||
# set default value for the number of migrations
|
# set default value for the number of migrations
|
||||||
self.number_of_migrations = 0
|
self.number_of_migrations = 0
|
||||||
# set default value for number of allowed migration attempts
|
|
||||||
self.migration_attempts = 0
|
|
||||||
|
|
||||||
# set default value for the efficacy
|
# set default value for the efficacy
|
||||||
self.efficacy = 100
|
self.efficacy = 100
|
||||||
@@ -94,21 +92,14 @@ class BasicConsolidation(base.ServerConsolidationBaseStrategy):
|
|||||||
self.threshold_disk = 1
|
self.threshold_disk = 1
|
||||||
self.threshold_cores = 1
|
self.threshold_cores = 1
|
||||||
|
|
||||||
# TODO(jed): target efficacy
|
|
||||||
self.target_efficacy = 60
|
|
||||||
|
|
||||||
# TODO(jed): weight
|
|
||||||
self.weight_cpu = 1
|
|
||||||
self.weight_mem = 1
|
|
||||||
self.weight_disk = 1
|
|
||||||
|
|
||||||
# TODO(jed): bound migration attempts (80 %)
|
|
||||||
self.bound_migration = 0.80
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_name(cls):
|
def get_name(cls):
|
||||||
return "basic"
|
return "basic"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def migration_attempts(self):
|
||||||
|
return self.input_parameters.get('migration_attempts', 0)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_display_name(cls):
|
def get_display_name(cls):
|
||||||
return _("Basic offline consolidation")
|
return _("Basic offline consolidation")
|
||||||
@@ -117,6 +108,22 @@ class BasicConsolidation(base.ServerConsolidationBaseStrategy):
|
|||||||
def get_translatable_display_name(cls):
|
def get_translatable_display_name(cls):
|
||||||
return "Basic offline consolidation"
|
return "Basic offline consolidation"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_schema(cls):
|
||||||
|
# Mandatory default setting for each element
|
||||||
|
return {
|
||||||
|
"properties": {
|
||||||
|
"migration_attempts": {
|
||||||
|
"description": "Maximum number of combinations to be "
|
||||||
|
"tried by the strategy while searching "
|
||||||
|
"for potential candidates. To remove the "
|
||||||
|
"limit, set it to 0 (by default)",
|
||||||
|
"type": "number",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def ceilometer(self):
|
def ceilometer(self):
|
||||||
if self._ceilometer is None:
|
if self._ceilometer is None:
|
||||||
@@ -127,13 +134,6 @@ class BasicConsolidation(base.ServerConsolidationBaseStrategy):
|
|||||||
def ceilometer(self, ceilometer):
|
def ceilometer(self, ceilometer):
|
||||||
self._ceilometer = ceilometer
|
self._ceilometer = ceilometer
|
||||||
|
|
||||||
def compute_attempts(self, size_cluster):
|
|
||||||
"""Upper bound of the number of migration
|
|
||||||
|
|
||||||
:param size_cluster: The size of the cluster
|
|
||||||
"""
|
|
||||||
self.migration_attempts = size_cluster * self.bound_migration
|
|
||||||
|
|
||||||
def check_migration(self, source_node, destination_node,
|
def check_migration(self, source_node, destination_node,
|
||||||
instance_to_migrate):
|
instance_to_migrate):
|
||||||
"""Check if the migration is possible
|
"""Check if the migration is possible
|
||||||
@@ -199,16 +199,6 @@ class BasicConsolidation(base.ServerConsolidationBaseStrategy):
|
|||||||
disk_capacity >= total_disk * self.threshold_disk and
|
disk_capacity >= total_disk * self.threshold_disk and
|
||||||
memory_capacity >= total_mem * self.threshold_mem)
|
memory_capacity >= total_mem * self.threshold_mem)
|
||||||
|
|
||||||
def get_allowed_migration_attempts(self):
|
|
||||||
"""Allowed migration
|
|
||||||
|
|
||||||
Maximum allowed number of migrations this allows us to fix
|
|
||||||
the upper bound of the number of migrations.
|
|
||||||
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
return self.migration_attempts
|
|
||||||
|
|
||||||
def calculate_weight(self, compute_resource, total_cores_used,
|
def calculate_weight(self, compute_resource, total_cores_used,
|
||||||
total_disk_used, total_memory_used):
|
total_disk_used, total_memory_used):
|
||||||
"""Calculate weight of every resource
|
"""Calculate weight of every resource
|
||||||
@@ -331,8 +321,9 @@ class BasicConsolidation(base.ServerConsolidationBaseStrategy):
|
|||||||
resource_id=resource_id,
|
resource_id=resource_id,
|
||||||
input_parameters=parameters)
|
input_parameters=parameters)
|
||||||
|
|
||||||
def score_of_nodes(self, score):
|
def compute_score_of_nodes(self):
|
||||||
"""Calculate score of nodes based on load by VMs"""
|
"""Calculate score of nodes based on load by VMs"""
|
||||||
|
score = []
|
||||||
for node in self.compute_model.get_all_compute_nodes().values():
|
for node in self.compute_model.get_all_compute_nodes().values():
|
||||||
count = self.compute_model.mapping.get_node_instances(node)
|
count = self.compute_model.mapping.get_node_instances(node)
|
||||||
if len(count) > 0:
|
if len(count) > 0:
|
||||||
@@ -344,9 +335,9 @@ class BasicConsolidation(base.ServerConsolidationBaseStrategy):
|
|||||||
score.append((node.uuid, result))
|
score.append((node.uuid, result))
|
||||||
return score
|
return score
|
||||||
|
|
||||||
def node_and_instance_score(self, sorted_score, score):
|
def node_and_instance_score(self, sorted_scores):
|
||||||
"""Get List of VMs from node"""
|
"""Get List of VMs from node"""
|
||||||
node_to_release = sorted_score[len(score) - 1][0]
|
node_to_release = sorted_scores[len(sorted_scores) - 1][0]
|
||||||
instances_to_migrate = self.compute_model.mapping.get_node_instances(
|
instances_to_migrate = self.compute_model.mapping.get_node_instances(
|
||||||
self.compute_model.get_node_by_uuid(node_to_release))
|
self.compute_model.get_node_by_uuid(node_to_release))
|
||||||
|
|
||||||
@@ -409,20 +400,14 @@ class BasicConsolidation(base.ServerConsolidationBaseStrategy):
|
|||||||
if not self.compute_model:
|
if not self.compute_model:
|
||||||
raise exception.ClusterStateNotDefined()
|
raise exception.ClusterStateNotDefined()
|
||||||
|
|
||||||
|
if len(self.compute_model.get_all_compute_nodes()) == 0:
|
||||||
|
raise exception.ClusterEmpty()
|
||||||
|
|
||||||
LOG.debug(self.compute_model.to_string())
|
LOG.debug(self.compute_model.to_string())
|
||||||
|
|
||||||
def do_execute(self):
|
def do_execute(self):
|
||||||
# todo(jed) clone model
|
|
||||||
self.efficacy = 100
|
|
||||||
unsuccessful_migration = 0
|
unsuccessful_migration = 0
|
||||||
|
|
||||||
first_migration = True
|
|
||||||
size_cluster = len(self.compute_model.get_all_compute_nodes())
|
|
||||||
if size_cluster == 0:
|
|
||||||
raise exception.ClusterEmpty()
|
|
||||||
|
|
||||||
self.compute_attempts(size_cluster)
|
|
||||||
|
|
||||||
for node_uuid, node in self.compute_model.get_all_compute_nodes(
|
for node_uuid, node in self.compute_model.get_all_compute_nodes(
|
||||||
).items():
|
).items():
|
||||||
node_instances = self.compute_model.mapping.get_node_instances(
|
node_instances = self.compute_model.mapping.get_node_instances(
|
||||||
@@ -432,44 +417,44 @@ class BasicConsolidation(base.ServerConsolidationBaseStrategy):
|
|||||||
self.add_change_service_state(
|
self.add_change_service_state(
|
||||||
node_uuid, element.ServiceState.DISABLED.value)
|
node_uuid, element.ServiceState.DISABLED.value)
|
||||||
|
|
||||||
while self.get_allowed_migration_attempts() >= unsuccessful_migration:
|
scores = self.compute_score_of_nodes()
|
||||||
if not first_migration:
|
# Sort compute nodes by Score decreasing
|
||||||
self.efficacy = self.calculate_migration_efficacy()
|
sorted_scores = sorted(scores, reverse=True, key=lambda x: (x[1]))
|
||||||
if self.efficacy < float(self.target_efficacy):
|
LOG.debug("Compute node(s) BFD %s", sorted_scores)
|
||||||
break
|
# Get Node to be released
|
||||||
first_migration = False
|
if len(scores) == 0:
|
||||||
score = []
|
LOG.warning(_LW(
|
||||||
|
"The workloads of the compute nodes"
|
||||||
score = self.score_of_nodes(score)
|
" of the cluster is zero"))
|
||||||
|
return
|
||||||
# Sort compute nodes by Score decreasing
|
|
||||||
sorted_score = sorted(score, reverse=True, key=lambda x: (x[1]))
|
|
||||||
LOG.debug("Compute node(s) BFD %s", sorted_score)
|
|
||||||
|
|
||||||
# Get Node to be released
|
|
||||||
if len(score) == 0:
|
|
||||||
LOG.warning(_LW(
|
|
||||||
"The workloads of the compute nodes"
|
|
||||||
" of the cluster is zero"))
|
|
||||||
break
|
|
||||||
|
|
||||||
|
while sorted_scores and (
|
||||||
|
not self.migration_attempts or
|
||||||
|
self.migration_attempts >= unsuccessful_migration):
|
||||||
node_to_release, instance_score = self.node_and_instance_score(
|
node_to_release, instance_score = self.node_and_instance_score(
|
||||||
sorted_score, score)
|
sorted_scores)
|
||||||
|
|
||||||
# Sort instances by Score
|
# Sort instances by Score
|
||||||
sorted_instances = sorted(
|
sorted_instances = sorted(
|
||||||
instance_score, reverse=True, key=lambda x: (x[1]))
|
instance_score, reverse=True, key=lambda x: (x[1]))
|
||||||
# BFD: Best Fit Decrease
|
# BFD: Best Fit Decrease
|
||||||
LOG.debug("VM(s) BFD %s", sorted_instances)
|
LOG.debug("Instance(s) BFD %s", sorted_instances)
|
||||||
|
|
||||||
migrations = self.calculate_num_migrations(
|
migrations = self.calculate_num_migrations(
|
||||||
sorted_instances, node_to_release, sorted_score)
|
sorted_instances, node_to_release, sorted_scores)
|
||||||
|
|
||||||
unsuccessful_migration = self.unsuccessful_migration_actualization(
|
unsuccessful_migration = self.unsuccessful_migration_actualization(
|
||||||
migrations, unsuccessful_migration)
|
migrations, unsuccessful_migration)
|
||||||
|
|
||||||
|
if not migrations:
|
||||||
|
# We don't have any possible migrations to perform on this node
|
||||||
|
# so we discard the node so we can try to migrate instances
|
||||||
|
# from the next one in the list
|
||||||
|
sorted_scores.pop()
|
||||||
|
|
||||||
infos = {
|
infos = {
|
||||||
"number_of_migrations": self.number_of_migrations,
|
"released_compute_nodes_count": self.number_of_released_nodes,
|
||||||
"number_of_nodes_released": self.number_of_released_nodes,
|
"instance_migrations_count": self.number_of_migrations,
|
||||||
"efficacy": self.efficacy
|
"efficacy": self.efficacy
|
||||||
}
|
}
|
||||||
LOG.debug(infos)
|
LOG.debug(infos)
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ class TestNoExceptionTracebackHook(base.FunctionalTest):
|
|||||||
p = mock.patch.object(root.Root, 'convert')
|
p = mock.patch.object(root.Root, 'convert')
|
||||||
self.root_convert_mock = p.start()
|
self.root_convert_mock = p.start()
|
||||||
self.addCleanup(p.stop)
|
self.addCleanup(p.stop)
|
||||||
|
cfg.CONF.set_override('debug', False, enforce_type=True)
|
||||||
|
|
||||||
def test_hook_exception_success(self):
|
def test_hook_exception_success(self):
|
||||||
self.root_convert_mock.side_effect = Exception(self.MSG_WITH_TRACE)
|
self.root_convert_mock.side_effect = Exception(self.MSG_WITH_TRACE)
|
||||||
|
|||||||
@@ -25,8 +25,7 @@ from watcher.decision_engine.messaging import events
|
|||||||
from watcher.decision_engine.model.collector import manager
|
from watcher.decision_engine.model.collector import manager
|
||||||
from watcher.objects import audit as audit_objects
|
from watcher.objects import audit as audit_objects
|
||||||
from watcher.tests.db import base
|
from watcher.tests.db import base
|
||||||
from watcher.tests.decision_engine.strategy.strategies import \
|
from watcher.tests.decision_engine.model import faker_cluster_state as faker
|
||||||
faker_cluster_state as faker
|
|
||||||
from watcher.tests.objects import utils as obj_utils
|
from watcher.tests.objects import utils as obj_utils
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -23,8 +23,7 @@ from watcher.common import exception
|
|||||||
from watcher.decision_engine.loading import default as default_loading
|
from watcher.decision_engine.loading import default as default_loading
|
||||||
from watcher.tests import base
|
from watcher.tests import base
|
||||||
from watcher.tests import conf_fixture
|
from watcher.tests import conf_fixture
|
||||||
from watcher.tests.decision_engine.strategy.strategies import \
|
from watcher.tests.decision_engine.model import faker_cluster_state
|
||||||
faker_cluster_state
|
|
||||||
|
|
||||||
|
|
||||||
class TestClusterDataModelCollectorLoader(base.TestCase):
|
class TestClusterDataModelCollectorLoader(base.TestCase):
|
||||||
|
|||||||
@@ -20,8 +20,7 @@ from watcher.decision_engine.audit import oneshot as oneshot_handler
|
|||||||
from watcher.decision_engine.messaging import audit_endpoint
|
from watcher.decision_engine.messaging import audit_endpoint
|
||||||
from watcher.decision_engine.model.collector import manager
|
from watcher.decision_engine.model.collector import manager
|
||||||
from watcher.tests.db import base
|
from watcher.tests.db import base
|
||||||
from watcher.tests.decision_engine.strategy.strategies \
|
from watcher.tests.decision_engine.model import faker_cluster_state
|
||||||
import faker_cluster_state
|
|
||||||
from watcher.tests.objects import utils as obj_utils
|
from watcher.tests.objects import utils as obj_utils
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
47
watcher/tests/decision_engine/model/data/scenario_1.xml
Normal file
47
watcher/tests/decision_engine/model/data/scenario_1.xml
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
<ModelRoot>
|
||||||
|
<ComputeNode human_id="" uuid="Node_0" status="enabled" state="up" id="0" hostname="hostname_0" ResourceType.cpu_cores="40" ResourceType.disk="250" ResourceType.disk_capacity="250" ResourceType.memory="132">
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_0" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_1" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
</ComputeNode>
|
||||||
|
<ComputeNode human_id="" uuid="Node_1" status="enabled" state="up" id="1" hostname="hostname_1" ResourceType.cpu_cores="40" ResourceType.disk="250" ResourceType.disk_capacity="250" ResourceType.memory="132">
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_2" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
</ComputeNode>
|
||||||
|
<ComputeNode human_id="" uuid="Node_2" status="enabled" state="up" id="2" hostname="hostname_2" ResourceType.cpu_cores="40" ResourceType.disk="250" ResourceType.disk_capacity="250" ResourceType.memory="132">
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_3" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_4" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_5" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
</ComputeNode>
|
||||||
|
<ComputeNode human_id="" uuid="Node_3" status="enabled" state="up" id="3" hostname="hostname_3" ResourceType.cpu_cores="40" ResourceType.disk="250" ResourceType.disk_capacity="250" ResourceType.memory="132">
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_6" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
</ComputeNode>
|
||||||
|
<ComputeNode human_id="" uuid="Node_4" status="enabled" state="up" id="4" hostname="hostname_4" ResourceType.cpu_cores="40" ResourceType.disk="250" ResourceType.disk_capacity="250" ResourceType.memory="132">
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_7" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
</ComputeNode>
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_10" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_11" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_12" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_13" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_14" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_15" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_16" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_17" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_18" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_19" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_20" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_21" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_22" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_23" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_24" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_25" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_26" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_27" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_28" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_29" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_30" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_31" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_32" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_33" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_34" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_8" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_9" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
</ModelRoot>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<ModelRoot>
|
||||||
|
<ComputeNode hostname="hostname_0" uuid="Node_0" id="0" state="enabled" human_id="" status="enabled" ResourceType.cpu_cores="40" ResourceType.disk="250" ResourceType.disk_capacity="250" ResourceType.memory="64">
|
||||||
|
<Instance hostname="" human_id="" state="active" uuid="INSTANCE_0" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
</ComputeNode>
|
||||||
|
<ComputeNode hostname="hostname_1" uuid="Node_1" id="1" state="enabled" human_id="" status="enabled" ResourceType.cpu_cores="40" ResourceType.disk="250" ResourceType.disk_capacity="250" ResourceType.memory="64">
|
||||||
|
<Instance hostname="" human_id="" state="active" uuid="INSTANCE_1" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
</ComputeNode>
|
||||||
|
</ModelRoot>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<ModelRoot>
|
||||||
|
<ComputeNode hostname="hostname_0" uuid="Node_0" id="0" state="up" human_id="" status="enabled" ResourceType.cpu_cores="16" ResourceType.disk="250" ResourceType.disk_capacity="250" ResourceType.memory="64">
|
||||||
|
<Instance hostname="" human_id="" state="active" uuid="INSTANCE_0" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance hostname="" human_id="" state="active" uuid="INSTANCE_1" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance hostname="" human_id="" state="active" uuid="INSTANCE_2" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance hostname="" human_id="" state="active" uuid="INSTANCE_3" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance hostname="" human_id="" state="active" uuid="INSTANCE_4" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance hostname="" human_id="" state="active" uuid="INSTANCE_5" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
</ComputeNode>
|
||||||
|
<ComputeNode hostname="hostname_1" uuid="Node_1" id="1" state="up" human_id="" status="enabled" ResourceType.cpu_cores="16" ResourceType.disk="250" ResourceType.disk_capacity="250" ResourceType.memory="64"/>
|
||||||
|
<ComputeNode hostname="hostname_2" uuid="Node_2" id="2" state="up" human_id="" status="enabled" ResourceType.cpu_cores="16" ResourceType.disk="250" ResourceType.disk_capacity="250" ResourceType.memory="64"/>
|
||||||
|
<ComputeNode hostname="hostname_3" uuid="Node_3" id="3" state="up" human_id="" status="enabled" ResourceType.cpu_cores="16" ResourceType.disk="250" ResourceType.disk_capacity="250" ResourceType.memory="64"/>
|
||||||
|
</ModelRoot>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<ModelRoot>
|
||||||
|
<ComputeNode human_id="" uuid="Node_0" status="enabled" state="up" id="0" hostname="hostname_0" ResourceType.cpu_cores="40" ResourceType.disk="250" ResourceType.disk_capacity="250" ResourceType.memory="132">
|
||||||
|
<Instance state="active" human_id="" uuid="73b09e16-35b7-4922-804e-e8f5d9b740fc" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
</ComputeNode>
|
||||||
|
<ComputeNode human_id="" uuid="Node_1" status="enabled" state="up" id="1" hostname="hostname_1" ResourceType.cpu_cores="40" ResourceType.disk="250" ResourceType.disk_capacity="250" ResourceType.memory="132">
|
||||||
|
<Instance state="active" human_id="" uuid="a4cab39b-9828-413a-bf88-f76921bf1517" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
</ComputeNode>
|
||||||
|
</ModelRoot>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<ModelRoot>
|
||||||
|
<ComputeNode hostname="hostname_0" uuid="Node_0" id="0" state="up" human_id="" status="enabled" ResourceType.cpu_cores="10" ResourceType.disk="250" ResourceType.disk_capacity="250" ResourceType.memory="64">
|
||||||
|
<Instance hostname="" human_id="" state="active" uuid="INSTANCE_6" ResourceType.cpu_cores="1" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance hostname="" human_id="" state="active" uuid="INSTANCE_7" ResourceType.cpu_cores="2" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance hostname="" human_id="" state="active" uuid="INSTANCE_8" ResourceType.cpu_cores="4" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance hostname="" human_id="" state="active" uuid="INSTANCE_9" ResourceType.cpu_cores="8" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
</ComputeNode>
|
||||||
|
<ComputeNode hostname="hostname_1" uuid="Node_1" id="1" state="up" human_id="" status="enabled" ResourceType.cpu_cores="10" ResourceType.disk="250" ResourceType.disk_capacity="250" ResourceType.memory="64"/>
|
||||||
|
</ModelRoot>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
<ModelRoot>
|
||||||
|
<ComputeNode human_id="" uuid="Node_0" status="enabled" state="up" id="0" hostname="hostname_0" ResourceType.cpu_cores="1" ResourceType.disk="1" ResourceType.disk_capacity="1" ResourceType.memory="1"/>
|
||||||
|
</ModelRoot>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<ModelRoot>
|
||||||
|
<ComputeNode human_id="" uuid="Node_0" status="enabled" state="up" id="0" hostname="hostname_0" ResourceType.cpu_cores="4" ResourceType.disk="4" ResourceType.disk_capacity="4" ResourceType.memory="4">
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_0" hostname="" ResourceType.cpu_cores="4" ResourceType.disk="0" ResourceType.disk_capacity="0" ResourceType.memory="2"/>
|
||||||
|
</ComputeNode>
|
||||||
|
</ModelRoot>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<ModelRoot>
|
||||||
|
<ComputeNode human_id="" uuid="Node_0" status="enabled" state="up" id="0" hostname="hostname_0" ResourceType.cpu_cores="40" ResourceType.disk="250" ResourceType.disk_capacity="250" ResourceType.memory="132">
|
||||||
|
<Instance state="active" human_id="" uuid="73b09e16-35b7-4922-804e-e8f5d9b740fc" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_1" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
</ComputeNode>
|
||||||
|
<ComputeNode human_id="" uuid="Node_1" status="enabled" state="up" id="1" hostname="hostname_1" ResourceType.cpu_cores="40" ResourceType.disk="250" ResourceType.disk_capacity="250" ResourceType.memory="132">
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_3" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_4" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
</ComputeNode>
|
||||||
|
</ModelRoot>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<ModelRoot>
|
||||||
|
<ComputeNode human_id="" uuid="Node_0" status="enabled" state="up" id="0" hostname="hostname_0" ResourceType.cpu_cores="50" ResourceType.disk="250" ResourceType.disk_capacity="250" ResourceType.memory="132">
|
||||||
|
<Instance state="active" human_id="" uuid="73b09e16-35b7-4922-804e-e8f5d9b740fc" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance state="active" human_id="" uuid="cae81432-1631-4d4e-b29c-6f3acdcde906" hostname="" ResourceType.cpu_cores="15" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
</ComputeNode>
|
||||||
|
<ComputeNode human_id="" uuid="Node_1" status="enabled" state="up" id="1" hostname="hostname_1" ResourceType.cpu_cores="50" ResourceType.disk="250" ResourceType.disk_capacity="250" ResourceType.memory="132">
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_3" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance state="active" human_id="" uuid="INSTANCE_4" hostname="" ResourceType.cpu_cores="10" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
</ComputeNode>
|
||||||
|
</ModelRoot>
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<ModelRoot>
|
||||||
|
<ComputeNode hostname="hostname_0" uuid="Node_0" id="0" state="up" human_id="" status="enabled" ResourceType.cpu_cores="16" ResourceType.disk="250" ResourceType.disk_capacity="250" ResourceType.memory="64">
|
||||||
|
<Instance hostname="" human_id="" state="active" uuid="INSTANCE_0" ResourceType.cpu_cores="2" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance hostname="" human_id="" state="active" uuid="INSTANCE_1" ResourceType.cpu_cores="2" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance hostname="" human_id="" state="active" uuid="INSTANCE_2" ResourceType.cpu_cores="2" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
</ComputeNode>
|
||||||
|
<ComputeNode hostname="hostname_1" uuid="Node_1" id="1" state="up" human_id="" status="enabled" ResourceType.cpu_cores="16" ResourceType.disk="250" ResourceType.disk_capacity="250" ResourceType.memory="64">
|
||||||
|
<Instance hostname="" human_id="" state="active" uuid="INSTANCE_3" ResourceType.cpu_cores="2" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
</ComputeNode>
|
||||||
|
<ComputeNode hostname="hostname_2" uuid="Node_2" id="2" state="up" human_id="" status="enabled" ResourceType.cpu_cores="16" ResourceType.disk="250" ResourceType.disk_capacity="250" ResourceType.memory="64">
|
||||||
|
<Instance hostname="" human_id="" state="active" uuid="INSTANCE_4" ResourceType.cpu_cores="2" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
</ComputeNode>
|
||||||
|
<ComputeNode hostname="hostname_3" uuid="Node_3" id="3" state="up" human_id="" status="enabled" ResourceType.cpu_cores="16" ResourceType.disk="250" ResourceType.disk_capacity="250" ResourceType.memory="64">
|
||||||
|
<Instance hostname="" human_id="" state="active" uuid="INSTANCE_5" ResourceType.cpu_cores="2" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
</ComputeNode>
|
||||||
|
</ModelRoot>
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<ModelRoot>
|
||||||
|
<ComputeNode hostname="hostname_0" uuid="Node_0" id="0" state="up" human_id="" status="enabled" ResourceType.cpu_cores="16" ResourceType.disk="250" ResourceType.disk_capacity="250" ResourceType.memory="64">
|
||||||
|
<Instance hostname="" human_id="" state="active" uuid="INSTANCE_0" ResourceType.cpu_cores="2" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance hostname="" human_id="" state="active" uuid="INSTANCE_1" ResourceType.cpu_cores="2" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
<Instance hostname="" human_id="" state="active" uuid="INSTANCE_2" ResourceType.cpu_cores="2" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
</ComputeNode>
|
||||||
|
<ComputeNode hostname="hostname_1" uuid="Node_1" id="1" state="up" human_id="" status="enabled" ResourceType.cpu_cores="16" ResourceType.disk="250" ResourceType.disk_capacity="250" ResourceType.memory="64">
|
||||||
|
<Instance hostname="" human_id="" state="active" uuid="INSTANCE_3" ResourceType.cpu_cores="2" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
</ComputeNode>
|
||||||
|
<ComputeNode hostname="hostname_2" uuid="Node_2" id="2" state="up" human_id="" status="enabled" ResourceType.cpu_cores="16" ResourceType.disk="250" ResourceType.disk_capacity="250" ResourceType.memory="64">
|
||||||
|
<Instance hostname="" human_id="" state="active" uuid="INSTANCE_4" ResourceType.cpu_cores="2" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
</ComputeNode>
|
||||||
|
<ComputeNode hostname="hostname_3" uuid="Node_3" id="3" state="up" human_id="" status="disabled" ResourceType.cpu_cores="16" ResourceType.disk="250" ResourceType.disk_capacity="250" ResourceType.memory="64">
|
||||||
|
<Instance hostname="" human_id="" state="active" uuid="INSTANCE_5" ResourceType.cpu_cores="2" ResourceType.disk="20" ResourceType.disk_capacity="20" ResourceType.memory="2"/>
|
||||||
|
</ComputeNode>
|
||||||
|
</ModelRoot>
|
||||||
161
watcher/tests/decision_engine/model/faker_cluster_and_metrics.py
Normal file
161
watcher/tests/decision_engine/model/faker_cluster_and_metrics.py
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
# -*- encoding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Authors: Vojtech CIMA <cima@zhaw.ch>
|
||||||
|
# Bruno GRAZIOLI <gaea@zhaw.ch>
|
||||||
|
# Sean MURPHY <murp@zhaw.ch>
|
||||||
|
#
|
||||||
|
# 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 os
|
||||||
|
|
||||||
|
import mock
|
||||||
|
|
||||||
|
from watcher.decision_engine.model.collector import base
|
||||||
|
from watcher.decision_engine.model import element
|
||||||
|
from watcher.decision_engine.model import model_root as modelroot
|
||||||
|
|
||||||
|
|
||||||
|
class FakerModelCollector(base.BaseClusterDataModelCollector):
|
||||||
|
|
||||||
|
def __init__(self, config=None, osc=None):
|
||||||
|
if config is None:
|
||||||
|
config = mock.Mock()
|
||||||
|
super(FakerModelCollector, self).__init__(config)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def notification_endpoints(self):
|
||||||
|
return []
|
||||||
|
|
||||||
|
def execute(self):
|
||||||
|
return self.generate_scenario_1()
|
||||||
|
|
||||||
|
def load_data(self, filename):
|
||||||
|
cwd = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
data_folder = os.path.join(cwd, "data")
|
||||||
|
|
||||||
|
with open(os.path.join(data_folder, filename), 'rb') as xml_file:
|
||||||
|
xml_data = xml_file.read()
|
||||||
|
|
||||||
|
return xml_data
|
||||||
|
|
||||||
|
def load_model(self, filename):
|
||||||
|
return modelroot.ModelRoot.from_xml(self.load_data(filename))
|
||||||
|
|
||||||
|
def generate_scenario_1(self):
|
||||||
|
"""Simulates cluster with 2 nodes and 2 instances using 1:1 mapping"""
|
||||||
|
return self.load_model('scenario_1_with_metrics.xml')
|
||||||
|
|
||||||
|
def generate_scenario_2(self):
|
||||||
|
"""Simulates a cluster
|
||||||
|
|
||||||
|
With 4 nodes and 6 instances all mapped to a single node
|
||||||
|
"""
|
||||||
|
return self.load_model('scenario_2_with_metrics.xml')
|
||||||
|
|
||||||
|
def generate_scenario_3(self):
|
||||||
|
"""Simulates a cluster
|
||||||
|
|
||||||
|
With 4 nodes and 6 instances all mapped to one node
|
||||||
|
"""
|
||||||
|
return self.load_model('scenario_3_with_metrics.xml')
|
||||||
|
|
||||||
|
def generate_scenario_4(self):
|
||||||
|
"""Simulates a cluster
|
||||||
|
|
||||||
|
With 4 nodes and 6 instances spread on all nodes
|
||||||
|
"""
|
||||||
|
return self.load_model('scenario_4_with_metrics.xml')
|
||||||
|
|
||||||
|
|
||||||
|
class FakeCeilometerMetrics(object):
|
||||||
|
def __init__(self, model):
|
||||||
|
self.model = model
|
||||||
|
|
||||||
|
def mock_get_statistics(self, resource_id, meter_name, period=3600,
|
||||||
|
aggregate='avg'):
|
||||||
|
if meter_name == "compute.node.cpu.percent":
|
||||||
|
return self.get_node_cpu_util(resource_id)
|
||||||
|
elif meter_name == "cpu_util":
|
||||||
|
return self.get_instance_cpu_util(resource_id)
|
||||||
|
elif meter_name == "memory.usage":
|
||||||
|
return self.get_instance_ram_util(resource_id)
|
||||||
|
elif meter_name == "disk.root.size":
|
||||||
|
return self.get_instance_disk_root_size(resource_id)
|
||||||
|
|
||||||
|
def get_node_cpu_util(self, r_id):
|
||||||
|
"""Calculates node utilization dynamicaly.
|
||||||
|
|
||||||
|
node CPU utilization should consider
|
||||||
|
and corelate with actual instance-node mappings
|
||||||
|
provided within a cluster model.
|
||||||
|
Returns relative node CPU utilization <0, 100>.
|
||||||
|
:param r_id: resource id
|
||||||
|
"""
|
||||||
|
|
||||||
|
id = '%s_%s' % (r_id.split('_')[0], r_id.split('_')[1])
|
||||||
|
instances = self.model.get_mapping().get_node_instances_by_uuid(id)
|
||||||
|
util_sum = 0.0
|
||||||
|
node_cpu_cores = self.model.get_resource_by_uuid(
|
||||||
|
element.ResourceType.cpu_cores).get_capacity_by_uuid(id)
|
||||||
|
for instance_uuid in instances:
|
||||||
|
instance_cpu_cores = self.model.get_resource_by_uuid(
|
||||||
|
element.ResourceType.cpu_cores).\
|
||||||
|
get_capacity(self.model.get_instance_by_uuid(instance_uuid))
|
||||||
|
total_cpu_util = instance_cpu_cores * self.get_instance_cpu_util(
|
||||||
|
instance_uuid)
|
||||||
|
util_sum += total_cpu_util / 100.0
|
||||||
|
util_sum /= node_cpu_cores
|
||||||
|
return util_sum * 100.0
|
||||||
|
|
||||||
|
def get_instance_cpu_util(self, r_id):
|
||||||
|
instance_cpu_util = dict()
|
||||||
|
instance_cpu_util['INSTANCE_0'] = 10
|
||||||
|
instance_cpu_util['INSTANCE_1'] = 30
|
||||||
|
instance_cpu_util['INSTANCE_2'] = 60
|
||||||
|
instance_cpu_util['INSTANCE_3'] = 20
|
||||||
|
instance_cpu_util['INSTANCE_4'] = 40
|
||||||
|
instance_cpu_util['INSTANCE_5'] = 50
|
||||||
|
instance_cpu_util['INSTANCE_6'] = 100
|
||||||
|
instance_cpu_util['INSTANCE_7'] = 100
|
||||||
|
instance_cpu_util['INSTANCE_8'] = 100
|
||||||
|
instance_cpu_util['INSTANCE_9'] = 100
|
||||||
|
return instance_cpu_util[str(r_id)]
|
||||||
|
|
||||||
|
def get_instance_ram_util(self, r_id):
|
||||||
|
instance_ram_util = dict()
|
||||||
|
instance_ram_util['INSTANCE_0'] = 1
|
||||||
|
instance_ram_util['INSTANCE_1'] = 2
|
||||||
|
instance_ram_util['INSTANCE_2'] = 4
|
||||||
|
instance_ram_util['INSTANCE_3'] = 8
|
||||||
|
instance_ram_util['INSTANCE_4'] = 3
|
||||||
|
instance_ram_util['INSTANCE_5'] = 2
|
||||||
|
instance_ram_util['INSTANCE_6'] = 1
|
||||||
|
instance_ram_util['INSTANCE_7'] = 2
|
||||||
|
instance_ram_util['INSTANCE_8'] = 4
|
||||||
|
instance_ram_util['INSTANCE_9'] = 8
|
||||||
|
return instance_ram_util[str(r_id)]
|
||||||
|
|
||||||
|
def get_instance_disk_root_size(self, r_id):
|
||||||
|
instance_disk_util = dict()
|
||||||
|
instance_disk_util['INSTANCE_0'] = 10
|
||||||
|
instance_disk_util['INSTANCE_1'] = 15
|
||||||
|
instance_disk_util['INSTANCE_2'] = 30
|
||||||
|
instance_disk_util['INSTANCE_3'] = 35
|
||||||
|
instance_disk_util['INSTANCE_4'] = 20
|
||||||
|
instance_disk_util['INSTANCE_5'] = 25
|
||||||
|
instance_disk_util['INSTANCE_6'] = 25
|
||||||
|
instance_disk_util['INSTANCE_7'] = 25
|
||||||
|
instance_disk_util['INSTANCE_8'] = 25
|
||||||
|
instance_disk_util['INSTANCE_9'] = 25
|
||||||
|
return instance_disk_util[str(r_id)]
|
||||||
157
watcher/tests/decision_engine/model/faker_cluster_state.py
Normal file
157
watcher/tests/decision_engine/model/faker_cluster_state.py
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
# -*- encoding: utf-8 -*-
|
||||||
|
# Copyright (c) 2015 b<>com
|
||||||
|
#
|
||||||
|
# Authors: Jean-Emile DARTOIS <jean-emile.dartois@b-com.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 os
|
||||||
|
|
||||||
|
import mock
|
||||||
|
|
||||||
|
from watcher.decision_engine.model.collector import base
|
||||||
|
from watcher.decision_engine.model import element
|
||||||
|
from watcher.decision_engine.model import model_root as modelroot
|
||||||
|
|
||||||
|
|
||||||
|
class FakerModelCollector(base.BaseClusterDataModelCollector):
|
||||||
|
|
||||||
|
def __init__(self, config=None, osc=None):
|
||||||
|
if config is None:
|
||||||
|
config = mock.Mock(period=777)
|
||||||
|
super(FakerModelCollector, self).__init__(config)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def notification_endpoints(self):
|
||||||
|
return []
|
||||||
|
|
||||||
|
def load_data(self, filename):
|
||||||
|
cwd = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
data_folder = os.path.join(cwd, "data")
|
||||||
|
|
||||||
|
with open(os.path.join(data_folder, filename), 'rb') as xml_file:
|
||||||
|
xml_data = xml_file.read()
|
||||||
|
|
||||||
|
return xml_data
|
||||||
|
|
||||||
|
def load_model(self, filename):
|
||||||
|
return modelroot.ModelRoot.from_xml(self.load_data(filename))
|
||||||
|
|
||||||
|
def execute(self):
|
||||||
|
return self._cluster_data_model or self.build_scenario_1()
|
||||||
|
|
||||||
|
def build_scenario_1(self):
|
||||||
|
instances = []
|
||||||
|
|
||||||
|
current_state_cluster = modelroot.ModelRoot()
|
||||||
|
# number of nodes
|
||||||
|
node_count = 5
|
||||||
|
# number max of instance per node
|
||||||
|
node_instance_count = 7
|
||||||
|
# total number of virtual machine
|
||||||
|
instance_count = (node_count * node_instance_count)
|
||||||
|
|
||||||
|
# define ressouce ( CPU, MEM disk, ... )
|
||||||
|
mem = element.Resource(element.ResourceType.memory)
|
||||||
|
# 2199.954 Mhz
|
||||||
|
num_cores = element.Resource(element.ResourceType.cpu_cores)
|
||||||
|
disk = element.Resource(element.ResourceType.disk)
|
||||||
|
disk_capacity = element.Resource(element.ResourceType.disk_capacity)
|
||||||
|
|
||||||
|
current_state_cluster.create_resource(mem)
|
||||||
|
current_state_cluster.create_resource(num_cores)
|
||||||
|
current_state_cluster.create_resource(disk)
|
||||||
|
current_state_cluster.create_resource(disk_capacity)
|
||||||
|
|
||||||
|
for id_ in range(0, node_count):
|
||||||
|
node_uuid = "Node_{0}".format(id_)
|
||||||
|
node = element.ComputeNode(id_)
|
||||||
|
node.uuid = node_uuid
|
||||||
|
node.hostname = "hostname_{0}".format(id_)
|
||||||
|
|
||||||
|
mem.set_capacity(node, 132)
|
||||||
|
disk.set_capacity(node, 250)
|
||||||
|
disk_capacity.set_capacity(node, 250)
|
||||||
|
num_cores.set_capacity(node, 40)
|
||||||
|
current_state_cluster.add_node(node)
|
||||||
|
|
||||||
|
for i in range(0, instance_count):
|
||||||
|
instance_uuid = "INSTANCE_{0}".format(i)
|
||||||
|
instance = element.Instance()
|
||||||
|
instance.uuid = instance_uuid
|
||||||
|
mem.set_capacity(instance, 2)
|
||||||
|
disk.set_capacity(instance, 20)
|
||||||
|
disk_capacity.set_capacity(instance, 20)
|
||||||
|
num_cores.set_capacity(instance, 10)
|
||||||
|
instances.append(instance)
|
||||||
|
current_state_cluster.add_instance(instance)
|
||||||
|
|
||||||
|
current_state_cluster.mapping.map(
|
||||||
|
current_state_cluster.get_node_by_uuid("Node_0"),
|
||||||
|
current_state_cluster.get_instance_by_uuid("INSTANCE_0"))
|
||||||
|
|
||||||
|
current_state_cluster.mapping.map(
|
||||||
|
current_state_cluster.get_node_by_uuid("Node_0"),
|
||||||
|
current_state_cluster.get_instance_by_uuid("INSTANCE_1"))
|
||||||
|
|
||||||
|
current_state_cluster.mapping.map(
|
||||||
|
current_state_cluster.get_node_by_uuid("Node_1"),
|
||||||
|
current_state_cluster.get_instance_by_uuid("INSTANCE_2"))
|
||||||
|
|
||||||
|
current_state_cluster.mapping.map(
|
||||||
|
current_state_cluster.get_node_by_uuid("Node_2"),
|
||||||
|
current_state_cluster.get_instance_by_uuid("INSTANCE_3"))
|
||||||
|
|
||||||
|
current_state_cluster.mapping.map(
|
||||||
|
current_state_cluster.get_node_by_uuid("Node_2"),
|
||||||
|
current_state_cluster.get_instance_by_uuid("INSTANCE_4"))
|
||||||
|
|
||||||
|
current_state_cluster.mapping.map(
|
||||||
|
current_state_cluster.get_node_by_uuid("Node_2"),
|
||||||
|
current_state_cluster.get_instance_by_uuid("INSTANCE_5"))
|
||||||
|
|
||||||
|
current_state_cluster.mapping.map(
|
||||||
|
current_state_cluster.get_node_by_uuid("Node_3"),
|
||||||
|
current_state_cluster.get_instance_by_uuid("INSTANCE_6"))
|
||||||
|
|
||||||
|
current_state_cluster.mapping.map(
|
||||||
|
current_state_cluster.get_node_by_uuid("Node_4"),
|
||||||
|
current_state_cluster.get_instance_by_uuid("INSTANCE_7"))
|
||||||
|
|
||||||
|
return current_state_cluster
|
||||||
|
|
||||||
|
def generate_scenario_1(self):
|
||||||
|
return self.load_model('scenario_1.xml')
|
||||||
|
|
||||||
|
def generate_scenario_3_with_2_nodes(self):
|
||||||
|
return self.load_model('scenario_3_with_2_nodes.xml')
|
||||||
|
|
||||||
|
def generate_scenario_4_with_1_node_no_instance(self):
|
||||||
|
return self.load_model('scenario_4_with_1_node_no_instance.xml')
|
||||||
|
|
||||||
|
def generate_scenario_5_with_instance_disk_0(self):
|
||||||
|
return self.load_model('scenario_5_with_instance_disk_0.xml')
|
||||||
|
|
||||||
|
def generate_scenario_6_with_2_nodes(self):
|
||||||
|
return self.load_model('scenario_6_with_2_nodes.xml')
|
||||||
|
|
||||||
|
def generate_scenario_7_with_2_nodes(self):
|
||||||
|
return self.load_model('scenario_7_with_2_nodes.xml')
|
||||||
|
|
||||||
|
def generate_scenario_8_with_4_nodes(self):
|
||||||
|
return self.load_model('scenario_8_with_4_nodes.xml')
|
||||||
|
|
||||||
|
def generate_scenario_9_with_3_active_plus_1_disabled_nodes(self):
|
||||||
|
return self.load_model(
|
||||||
|
'scenario_9_with_3_active_plus_1_disabled_nodes.xml')
|
||||||
@@ -250,9 +250,3 @@ class FakerMetricsCollector(object):
|
|||||||
|
|
||||||
def get_virtual_machine_capacity(self, instance_uuid):
|
def get_virtual_machine_capacity(self, instance_uuid):
|
||||||
return random.randint(1, 4)
|
return random.randint(1, 4)
|
||||||
|
|
||||||
def get_average_network_incomming(self, node):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def get_average_network_outcomming(self, node):
|
|
||||||
pass
|
|
||||||
@@ -17,8 +17,7 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from watcher.decision_engine.model.notification import nova as novanotification
|
from watcher.decision_engine.model.notification import nova as novanotification
|
||||||
from watcher.tests.decision_engine.strategy.strategies \
|
from watcher.tests.decision_engine.model import faker_cluster_state
|
||||||
import faker_cluster_state
|
|
||||||
|
|
||||||
|
|
||||||
class FakeManager(object):
|
class FakeManager(object):
|
||||||
|
|||||||
@@ -29,9 +29,8 @@ from watcher.decision_engine.model import element
|
|||||||
from watcher.decision_engine.model import model_root
|
from watcher.decision_engine.model import model_root
|
||||||
from watcher.decision_engine.model.notification import nova as novanotification
|
from watcher.decision_engine.model.notification import nova as novanotification
|
||||||
from watcher.tests import base as base_test
|
from watcher.tests import base as base_test
|
||||||
|
from watcher.tests.decision_engine.model import faker_cluster_state
|
||||||
from watcher.tests.decision_engine.model.notification import fake_managers
|
from watcher.tests.decision_engine.model.notification import fake_managers
|
||||||
from watcher.tests.decision_engine.strategy.strategies \
|
|
||||||
import faker_cluster_state
|
|
||||||
|
|
||||||
|
|
||||||
class NotificationTestCase(base_test.TestCase):
|
class NotificationTestCase(base_test.TestCase):
|
||||||
|
|||||||
@@ -20,8 +20,7 @@ import uuid
|
|||||||
|
|
||||||
from watcher.decision_engine.model import element
|
from watcher.decision_engine.model import element
|
||||||
from watcher.tests import base
|
from watcher.tests import base
|
||||||
from watcher.tests.decision_engine.strategy.strategies import \
|
from watcher.tests.decision_engine.model import faker_cluster_state
|
||||||
faker_cluster_state
|
|
||||||
|
|
||||||
|
|
||||||
class TestMapping(base.TestCase):
|
class TestMapping(base.TestCase):
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
from oslo_utils import uuidutils
|
from oslo_utils import uuidutils
|
||||||
import six
|
import six
|
||||||
@@ -24,154 +26,32 @@ from watcher.common import exception
|
|||||||
from watcher.decision_engine.model import element
|
from watcher.decision_engine.model import element
|
||||||
from watcher.decision_engine.model import model_root
|
from watcher.decision_engine.model import model_root
|
||||||
from watcher.tests import base
|
from watcher.tests import base
|
||||||
from watcher.tests.decision_engine.strategy.strategies \
|
from watcher.tests.decision_engine.model import faker_cluster_state
|
||||||
import faker_cluster_state
|
|
||||||
|
|
||||||
|
|
||||||
class TestModel(base.TestCase):
|
class TestModel(base.TestCase):
|
||||||
|
|
||||||
|
def load_data(self, filename):
|
||||||
|
cwd = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
data_folder = os.path.join(cwd, "data")
|
||||||
|
|
||||||
|
with open(os.path.join(data_folder, filename), 'rb') as xml_file:
|
||||||
|
xml_data = xml_file.read()
|
||||||
|
|
||||||
|
return xml_data
|
||||||
|
|
||||||
|
def load_model(self, filename):
|
||||||
|
return model_root.ModelRoot.from_xml(self.load_data(filename))
|
||||||
|
|
||||||
def test_model_structure(self):
|
def test_model_structure(self):
|
||||||
fake_cluster = faker_cluster_state.FakerModelCollector()
|
fake_cluster = faker_cluster_state.FakerModelCollector()
|
||||||
model = fake_cluster.generate_scenario_1()
|
model = fake_cluster.build_scenario_1()
|
||||||
|
|
||||||
self.assertEqual(5, len(model._nodes))
|
self.assertEqual(5, len(model._nodes))
|
||||||
self.assertEqual(35, len(model._instances))
|
self.assertEqual(35, len(model._instances))
|
||||||
self.assertEqual(5, len(model.mapping.get_mapping()))
|
self.assertEqual(5, len(model.mapping.get_mapping()))
|
||||||
|
|
||||||
expected_struct_str = """
|
expected_struct_str = self.load_data('scenario_1.xml')
|
||||||
<ModelRoot>
|
|
||||||
<ComputeNode ResourceType.cpu_cores="40" ResourceType.disk="250"
|
|
||||||
ResourceType.disk_capacity="250" ResourceType.memory="132"
|
|
||||||
hostname="hostname_0" human_id="" id="0" state="up"
|
|
||||||
status="enabled" uuid="Node_0">
|
|
||||||
<Instance ResourceType.cpu_cores="10" ResourceType.disk="20"
|
|
||||||
ResourceType.disk_capacity="20" ResourceType.memory="2"
|
|
||||||
hostname="" human_id="" state="active" uuid="INSTANCE_0"/>
|
|
||||||
<Instance ResourceType.cpu_cores="10" ResourceType.disk="20"
|
|
||||||
ResourceType.disk_capacity="20" ResourceType.memory="2"
|
|
||||||
hostname="" human_id="" state="active" uuid="INSTANCE_1"/>
|
|
||||||
</ComputeNode>
|
|
||||||
<ComputeNode ResourceType.cpu_cores="40" ResourceType.disk="250"
|
|
||||||
ResourceType.disk_capacity="250" ResourceType.memory="132"
|
|
||||||
hostname="hostname_1" human_id="" id="1" state="up"
|
|
||||||
status="enabled" uuid="Node_1">
|
|
||||||
<Instance ResourceType.cpu_cores="10" ResourceType.disk="20"
|
|
||||||
ResourceType.disk_capacity="20" ResourceType.memory="2"
|
|
||||||
hostname="" human_id="" state="active" uuid="INSTANCE_2"/>
|
|
||||||
</ComputeNode>
|
|
||||||
<ComputeNode ResourceType.cpu_cores="40" ResourceType.disk="250"
|
|
||||||
ResourceType.disk_capacity="250" ResourceType.memory="132"
|
|
||||||
hostname="hostname_2" human_id="" id="2" state="up"
|
|
||||||
status="enabled" uuid="Node_2">
|
|
||||||
<Instance ResourceType.cpu_cores="10" ResourceType.disk="20"
|
|
||||||
ResourceType.disk_capacity="20" ResourceType.memory="2"
|
|
||||||
hostname="" human_id="" state="active" uuid="INSTANCE_3"/>
|
|
||||||
<Instance ResourceType.cpu_cores="10" ResourceType.disk="20"
|
|
||||||
ResourceType.disk_capacity="20" ResourceType.memory="2"
|
|
||||||
hostname="" human_id="" state="active" uuid="INSTANCE_4"/>
|
|
||||||
<Instance ResourceType.cpu_cores="10" ResourceType.disk="20"
|
|
||||||
ResourceType.disk_capacity="20" ResourceType.memory="2"
|
|
||||||
hostname="" human_id="" state="active" uuid="INSTANCE_5"/>
|
|
||||||
</ComputeNode>
|
|
||||||
<ComputeNode ResourceType.cpu_cores="40" ResourceType.disk="250"
|
|
||||||
ResourceType.disk_capacity="250" ResourceType.memory="132"
|
|
||||||
hostname="hostname_3" human_id="" id="3" state="up"
|
|
||||||
status="enabled" uuid="Node_3">
|
|
||||||
<Instance ResourceType.cpu_cores="10" ResourceType.disk="20"
|
|
||||||
ResourceType.disk_capacity="20" ResourceType.memory="2"
|
|
||||||
hostname="" human_id="" state="active" uuid="INSTANCE_6"/>
|
|
||||||
</ComputeNode>
|
|
||||||
<ComputeNode ResourceType.cpu_cores="40" ResourceType.disk="250"
|
|
||||||
ResourceType.disk_capacity="250" ResourceType.memory="132"
|
|
||||||
hostname="hostname_4" human_id="" id="4" state="up"
|
|
||||||
status="enabled" uuid="Node_4">
|
|
||||||
<Instance ResourceType.cpu_cores="10" ResourceType.disk="20"
|
|
||||||
ResourceType.disk_capacity="20" ResourceType.memory="2"
|
|
||||||
hostname="" human_id="" state="active" uuid="INSTANCE_7"/>
|
|
||||||
</ComputeNode>
|
|
||||||
<Instance ResourceType.cpu_cores="10" ResourceType.disk="20"
|
|
||||||
ResourceType.disk_capacity="20" ResourceType.memory="2"
|
|
||||||
hostname="" human_id="" state="active" uuid="INSTANCE_10"/>
|
|
||||||
<Instance ResourceType.cpu_cores="10" ResourceType.disk="20"
|
|
||||||
ResourceType.disk_capacity="20" ResourceType.memory="2"
|
|
||||||
hostname="" human_id="" state="active" uuid="INSTANCE_11"/>
|
|
||||||
<Instance ResourceType.cpu_cores="10" ResourceType.disk="20"
|
|
||||||
ResourceType.disk_capacity="20" ResourceType.memory="2"
|
|
||||||
hostname="" human_id="" state="active" uuid="INSTANCE_12"/>
|
|
||||||
<Instance ResourceType.cpu_cores="10" ResourceType.disk="20"
|
|
||||||
ResourceType.disk_capacity="20" ResourceType.memory="2"
|
|
||||||
hostname="" human_id="" state="active" uuid="INSTANCE_13"/>
|
|
||||||
<Instance ResourceType.cpu_cores="10" ResourceType.disk="20"
|
|
||||||
ResourceType.disk_capacity="20" ResourceType.memory="2"
|
|
||||||
hostname="" human_id="" state="active" uuid="INSTANCE_14"/>
|
|
||||||
<Instance ResourceType.cpu_cores="10" ResourceType.disk="20"
|
|
||||||
ResourceType.disk_capacity="20" ResourceType.memory="2"
|
|
||||||
hostname="" human_id="" state="active" uuid="INSTANCE_15"/>
|
|
||||||
<Instance ResourceType.cpu_cores="10" ResourceType.disk="20"
|
|
||||||
ResourceType.disk_capacity="20" ResourceType.memory="2"
|
|
||||||
hostname="" human_id="" state="active" uuid="INSTANCE_16"/>
|
|
||||||
<Instance ResourceType.cpu_cores="10" ResourceType.disk="20"
|
|
||||||
ResourceType.disk_capacity="20" ResourceType.memory="2"
|
|
||||||
hostname="" human_id="" state="active" uuid="INSTANCE_17"/>
|
|
||||||
<Instance ResourceType.cpu_cores="10" ResourceType.disk="20"
|
|
||||||
ResourceType.disk_capacity="20" ResourceType.memory="2"
|
|
||||||
hostname="" human_id="" state="active" uuid="INSTANCE_18"/>
|
|
||||||
<Instance ResourceType.cpu_cores="10" ResourceType.disk="20"
|
|
||||||
ResourceType.disk_capacity="20" ResourceType.memory="2"
|
|
||||||
hostname="" human_id="" state="active" uuid="INSTANCE_19"/>
|
|
||||||
<Instance ResourceType.cpu_cores="10" ResourceType.disk="20"
|
|
||||||
ResourceType.disk_capacity="20" ResourceType.memory="2"
|
|
||||||
hostname="" human_id="" state="active" uuid="INSTANCE_20"/>
|
|
||||||
<Instance ResourceType.cpu_cores="10" ResourceType.disk="20"
|
|
||||||
ResourceType.disk_capacity="20" ResourceType.memory="2"
|
|
||||||
hostname="" human_id="" state="active" uuid="INSTANCE_21"/>
|
|
||||||
<Instance ResourceType.cpu_cores="10" ResourceType.disk="20"
|
|
||||||
ResourceType.disk_capacity="20" ResourceType.memory="2"
|
|
||||||
hostname="" human_id="" state="active" uuid="INSTANCE_22"/>
|
|
||||||
<Instance ResourceType.cpu_cores="10" ResourceType.disk="20"
|
|
||||||
ResourceType.disk_capacity="20" ResourceType.memory="2"
|
|
||||||
hostname="" human_id="" state="active" uuid="INSTANCE_23"/>
|
|
||||||
<Instance ResourceType.cpu_cores="10" ResourceType.disk="20"
|
|
||||||
ResourceType.disk_capacity="20" ResourceType.memory="2"
|
|
||||||
hostname="" human_id="" state="active" uuid="INSTANCE_24"/>
|
|
||||||
<Instance ResourceType.cpu_cores="10" ResourceType.disk="20"
|
|
||||||
ResourceType.disk_capacity="20" ResourceType.memory="2"
|
|
||||||
hostname="" human_id="" state="active" uuid="INSTANCE_25"/>
|
|
||||||
<Instance ResourceType.cpu_cores="10" ResourceType.disk="20"
|
|
||||||
ResourceType.disk_capacity="20" ResourceType.memory="2"
|
|
||||||
hostname="" human_id="" state="active" uuid="INSTANCE_26"/>
|
|
||||||
<Instance ResourceType.cpu_cores="10" ResourceType.disk="20"
|
|
||||||
ResourceType.disk_capacity="20" ResourceType.memory="2"
|
|
||||||
hostname="" human_id="" state="active" uuid="INSTANCE_27"/>
|
|
||||||
<Instance ResourceType.cpu_cores="10" ResourceType.disk="20"
|
|
||||||
ResourceType.disk_capacity="20" ResourceType.memory="2"
|
|
||||||
hostname="" human_id="" state="active" uuid="INSTANCE_28"/>
|
|
||||||
<Instance ResourceType.cpu_cores="10" ResourceType.disk="20"
|
|
||||||
ResourceType.disk_capacity="20" ResourceType.memory="2"
|
|
||||||
hostname="" human_id="" state="active" uuid="INSTANCE_29"/>
|
|
||||||
<Instance ResourceType.cpu_cores="10" ResourceType.disk="20"
|
|
||||||
ResourceType.disk_capacity="20" ResourceType.memory="2"
|
|
||||||
hostname="" human_id="" state="active" uuid="INSTANCE_30"/>
|
|
||||||
<Instance ResourceType.cpu_cores="10" ResourceType.disk="20"
|
|
||||||
ResourceType.disk_capacity="20" ResourceType.memory="2"
|
|
||||||
hostname="" human_id="" state="active" uuid="INSTANCE_31"/>
|
|
||||||
<Instance ResourceType.cpu_cores="10" ResourceType.disk="20"
|
|
||||||
ResourceType.disk_capacity="20" ResourceType.memory="2"
|
|
||||||
hostname="" human_id="" state="active" uuid="INSTANCE_32"/>
|
|
||||||
<Instance ResourceType.cpu_cores="10" ResourceType.disk="20"
|
|
||||||
ResourceType.disk_capacity="20" ResourceType.memory="2"
|
|
||||||
hostname="" human_id="" state="active" uuid="INSTANCE_33"/>
|
|
||||||
<Instance ResourceType.cpu_cores="10" ResourceType.disk="20"
|
|
||||||
ResourceType.disk_capacity="20" ResourceType.memory="2"
|
|
||||||
hostname="" human_id="" state="active" uuid="INSTANCE_34"/>
|
|
||||||
<Instance ResourceType.cpu_cores="10" ResourceType.disk="20"
|
|
||||||
ResourceType.disk_capacity="20" ResourceType.memory="2"
|
|
||||||
hostname="" human_id="" state="active" uuid="INSTANCE_8"/>
|
|
||||||
<Instance ResourceType.cpu_cores="10" ResourceType.disk="20"
|
|
||||||
ResourceType.disk_capacity="20" ResourceType.memory="2"
|
|
||||||
hostname="" human_id="" state="active" uuid="INSTANCE_9"/>
|
|
||||||
</ModelRoot>
|
|
||||||
"""
|
|
||||||
parser = etree.XMLParser(remove_blank_text=True)
|
parser = etree.XMLParser(remove_blank_text=True)
|
||||||
expected_struct = etree.fromstring(expected_struct_str, parser)
|
expected_struct = etree.fromstring(expected_struct_str, parser)
|
||||||
model_structure = etree.fromstring(model.to_string(), parser)
|
model_structure = etree.fromstring(model.to_string(), parser)
|
||||||
@@ -186,6 +66,15 @@ class TestModel(base.TestCase):
|
|||||||
|
|
||||||
self.assertEqual(normalized_expected_struct, normalized_model_struct)
|
self.assertEqual(normalized_expected_struct, normalized_model_struct)
|
||||||
|
|
||||||
|
def test_build_model_from_xml(self):
|
||||||
|
fake_cluster = faker_cluster_state.FakerModelCollector()
|
||||||
|
|
||||||
|
expected_model = fake_cluster.generate_scenario_1()
|
||||||
|
struct_str = self.load_data('scenario_1.xml')
|
||||||
|
|
||||||
|
model = model_root.ModelRoot.from_xml(struct_str)
|
||||||
|
self.assertEqual(expected_model.to_string(), model.to_string())
|
||||||
|
|
||||||
def test_add_node(self):
|
def test_add_node(self):
|
||||||
model = model_root.ModelRoot()
|
model = model_root.ModelRoot()
|
||||||
uuid_ = "{0}".format(uuidutils.generate_uuid())
|
uuid_ = "{0}".format(uuidutils.generate_uuid())
|
||||||
|
|||||||
@@ -24,10 +24,8 @@ from watcher.decision_engine.strategy import strategies
|
|||||||
from watcher import objects
|
from watcher import objects
|
||||||
from watcher.tests.db import base
|
from watcher.tests.db import base
|
||||||
from watcher.tests.db import utils as db_utils
|
from watcher.tests.db import utils as db_utils
|
||||||
from watcher.tests.decision_engine.strategy.strategies \
|
from watcher.tests.decision_engine.model import faker_cluster_state
|
||||||
import faker_cluster_state
|
from watcher.tests.decision_engine.model import faker_metrics_collector as fake
|
||||||
from watcher.tests.decision_engine.strategy.strategies \
|
|
||||||
import faker_metrics_collector as fake
|
|
||||||
from watcher.tests.objects import utils as obj_utils
|
from watcher.tests.objects import utils as obj_utils
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,270 +0,0 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
|
||||||
#
|
|
||||||
# Authors: Vojtech CIMA <cima@zhaw.ch>
|
|
||||||
# Bruno GRAZIOLI <gaea@zhaw.ch>
|
|
||||||
# Sean MURPHY <murp@zhaw.ch>
|
|
||||||
#
|
|
||||||
# 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.decision_engine.model.collector import base
|
|
||||||
from watcher.decision_engine.model import element
|
|
||||||
from watcher.decision_engine.model import model_root as modelroot
|
|
||||||
|
|
||||||
|
|
||||||
class FakerModelCollector(base.BaseClusterDataModelCollector):
|
|
||||||
|
|
||||||
def __init__(self, config=None, osc=None):
|
|
||||||
if config is None:
|
|
||||||
config = mock.Mock()
|
|
||||||
super(FakerModelCollector, self).__init__(config)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def notification_endpoints(self):
|
|
||||||
return []
|
|
||||||
|
|
||||||
def execute(self):
|
|
||||||
return self.generate_scenario_1()
|
|
||||||
|
|
||||||
def generate_scenario_1(self):
|
|
||||||
"""Simulates cluster with 2 nodes and 2 instances using 1:1 mapping"""
|
|
||||||
|
|
||||||
current_state_cluster = modelroot.ModelRoot()
|
|
||||||
count_node = 2
|
|
||||||
count_instance = 2
|
|
||||||
|
|
||||||
mem = element.Resource(element.ResourceType.memory)
|
|
||||||
num_cores = element.Resource(element.ResourceType.cpu_cores)
|
|
||||||
disk = element.Resource(element.ResourceType.disk)
|
|
||||||
disk_capacity =\
|
|
||||||
element.Resource(element.ResourceType.disk_capacity)
|
|
||||||
|
|
||||||
current_state_cluster.create_resource(mem)
|
|
||||||
current_state_cluster.create_resource(num_cores)
|
|
||||||
current_state_cluster.create_resource(disk)
|
|
||||||
current_state_cluster.create_resource(disk_capacity)
|
|
||||||
|
|
||||||
for id_ in range(0, count_node):
|
|
||||||
node_uuid = "Node_{0}".format(id_)
|
|
||||||
node = element.ComputeNode(id_)
|
|
||||||
node.uuid = node_uuid
|
|
||||||
node.hostname = "hostname_{0}".format(id_)
|
|
||||||
node.state = 'enabled'
|
|
||||||
|
|
||||||
mem.set_capacity(node, 64)
|
|
||||||
disk_capacity.set_capacity(node, 250)
|
|
||||||
num_cores.set_capacity(node, 40)
|
|
||||||
current_state_cluster.add_node(node)
|
|
||||||
|
|
||||||
for i in range(0, count_instance):
|
|
||||||
instance_uuid = "INSTANCE_{0}".format(i)
|
|
||||||
instance = element.Instance()
|
|
||||||
instance.uuid = instance_uuid
|
|
||||||
instance.state = element.InstanceState.ACTIVE.value
|
|
||||||
mem.set_capacity(instance, 2)
|
|
||||||
disk.set_capacity(instance, 20)
|
|
||||||
num_cores.set_capacity(instance, 10)
|
|
||||||
current_state_cluster.add_instance(instance)
|
|
||||||
|
|
||||||
current_state_cluster.get_mapping().map(
|
|
||||||
current_state_cluster.get_node_by_uuid("Node_0"),
|
|
||||||
current_state_cluster.get_instance_by_uuid("INSTANCE_0"))
|
|
||||||
|
|
||||||
current_state_cluster.get_mapping().map(
|
|
||||||
current_state_cluster.get_node_by_uuid("Node_1"),
|
|
||||||
current_state_cluster.get_instance_by_uuid("INSTANCE_1"))
|
|
||||||
|
|
||||||
return current_state_cluster
|
|
||||||
|
|
||||||
def generate_scenario_2(self):
|
|
||||||
"""Simulates a cluster
|
|
||||||
|
|
||||||
With 4 nodes and 6 instances all mapped to a single node
|
|
||||||
"""
|
|
||||||
|
|
||||||
current_state_cluster = modelroot.ModelRoot()
|
|
||||||
count_node = 4
|
|
||||||
count_instance = 6
|
|
||||||
|
|
||||||
mem = element.Resource(element.ResourceType.memory)
|
|
||||||
num_cores = element.Resource(element.ResourceType.cpu_cores)
|
|
||||||
disk = element.Resource(element.ResourceType.disk)
|
|
||||||
disk_capacity =\
|
|
||||||
element.Resource(element.ResourceType.disk_capacity)
|
|
||||||
|
|
||||||
current_state_cluster.create_resource(mem)
|
|
||||||
current_state_cluster.create_resource(num_cores)
|
|
||||||
current_state_cluster.create_resource(disk)
|
|
||||||
current_state_cluster.create_resource(disk_capacity)
|
|
||||||
|
|
||||||
for id_ in range(0, count_node):
|
|
||||||
node_uuid = "Node_{0}".format(id_)
|
|
||||||
node = element.ComputeNode(id_)
|
|
||||||
node.uuid = node_uuid
|
|
||||||
node.hostname = "hostname_{0}".format(id_)
|
|
||||||
node.state = 'up'
|
|
||||||
|
|
||||||
mem.set_capacity(node, 64)
|
|
||||||
disk_capacity.set_capacity(node, 250)
|
|
||||||
num_cores.set_capacity(node, 16)
|
|
||||||
current_state_cluster.add_node(node)
|
|
||||||
|
|
||||||
for i in range(0, count_instance):
|
|
||||||
instance_uuid = "INSTANCE_{0}".format(i)
|
|
||||||
instance = element.Instance()
|
|
||||||
instance.uuid = instance_uuid
|
|
||||||
instance.state = element.InstanceState.ACTIVE.value
|
|
||||||
mem.set_capacity(instance, 2)
|
|
||||||
disk.set_capacity(instance, 20)
|
|
||||||
num_cores.set_capacity(instance, 10)
|
|
||||||
current_state_cluster.add_instance(instance)
|
|
||||||
|
|
||||||
current_state_cluster.get_mapping().map(
|
|
||||||
current_state_cluster.get_node_by_uuid("Node_0"),
|
|
||||||
current_state_cluster.get_instance_by_uuid("INSTANCE_%s" % i))
|
|
||||||
|
|
||||||
return current_state_cluster
|
|
||||||
|
|
||||||
def generate_scenario_3(self):
|
|
||||||
"""Simulates a cluster
|
|
||||||
|
|
||||||
With 4 nodes and 6 instances all mapped to one node
|
|
||||||
"""
|
|
||||||
|
|
||||||
current_state_cluster = modelroot.ModelRoot()
|
|
||||||
count_node = 2
|
|
||||||
count_instance = 4
|
|
||||||
|
|
||||||
mem = element.Resource(element.ResourceType.memory)
|
|
||||||
num_cores = element.Resource(element.ResourceType.cpu_cores)
|
|
||||||
disk = element.Resource(element.ResourceType.disk)
|
|
||||||
disk_capacity =\
|
|
||||||
element.Resource(element.ResourceType.disk_capacity)
|
|
||||||
|
|
||||||
current_state_cluster.create_resource(mem)
|
|
||||||
current_state_cluster.create_resource(num_cores)
|
|
||||||
current_state_cluster.create_resource(disk)
|
|
||||||
current_state_cluster.create_resource(disk_capacity)
|
|
||||||
|
|
||||||
for id_ in range(0, count_node):
|
|
||||||
node_uuid = "Node_{0}".format(id_)
|
|
||||||
node = element.ComputeNode(id_)
|
|
||||||
node.uuid = node_uuid
|
|
||||||
node.hostname = "hostname_{0}".format(id_)
|
|
||||||
node.state = 'up'
|
|
||||||
|
|
||||||
mem.set_capacity(node, 64)
|
|
||||||
disk_capacity.set_capacity(node, 250)
|
|
||||||
num_cores.set_capacity(node, 10)
|
|
||||||
current_state_cluster.add_node(node)
|
|
||||||
|
|
||||||
for i in range(6, 6 + count_instance):
|
|
||||||
instance_uuid = "INSTANCE_{0}".format(i)
|
|
||||||
instance = element.Instance()
|
|
||||||
instance.uuid = instance_uuid
|
|
||||||
instance.state = element.InstanceState.ACTIVE.value
|
|
||||||
mem.set_capacity(instance, 2)
|
|
||||||
disk.set_capacity(instance, 20)
|
|
||||||
num_cores.set_capacity(instance, 2 ** (i - 6))
|
|
||||||
current_state_cluster.add_instance(instance)
|
|
||||||
|
|
||||||
current_state_cluster.get_mapping().map(
|
|
||||||
current_state_cluster.get_node_by_uuid("Node_0"),
|
|
||||||
current_state_cluster.get_instance_by_uuid("INSTANCE_%s" % i))
|
|
||||||
|
|
||||||
return current_state_cluster
|
|
||||||
|
|
||||||
|
|
||||||
class FakeCeilometerMetrics(object):
|
|
||||||
def __init__(self, model):
|
|
||||||
self.model = model
|
|
||||||
|
|
||||||
def mock_get_statistics(self, resource_id, meter_name, period=3600,
|
|
||||||
aggregate='avg'):
|
|
||||||
if meter_name == "compute.node.cpu.percent":
|
|
||||||
return self.get_node_cpu_util(resource_id)
|
|
||||||
elif meter_name == "cpu_util":
|
|
||||||
return self.get_instance_cpu_util(resource_id)
|
|
||||||
elif meter_name == "memory.usage":
|
|
||||||
return self.get_instance_ram_util(resource_id)
|
|
||||||
elif meter_name == "disk.root.size":
|
|
||||||
return self.get_instance_disk_root_size(resource_id)
|
|
||||||
|
|
||||||
def get_node_cpu_util(self, r_id):
|
|
||||||
"""Calculates node utilization dynamicaly.
|
|
||||||
|
|
||||||
node CPU utilization should consider
|
|
||||||
and corelate with actual instance-node mappings
|
|
||||||
provided within a cluster model.
|
|
||||||
Returns relative node CPU utilization <0, 100>.
|
|
||||||
:param r_id: resource id
|
|
||||||
"""
|
|
||||||
|
|
||||||
id = '%s_%s' % (r_id.split('_')[0], r_id.split('_')[1])
|
|
||||||
instances = self.model.get_mapping().get_node_instances_by_uuid(id)
|
|
||||||
util_sum = 0.0
|
|
||||||
node_cpu_cores = self.model.get_resource_by_uuid(
|
|
||||||
element.ResourceType.cpu_cores).get_capacity_by_uuid(id)
|
|
||||||
for instance_uuid in instances:
|
|
||||||
instance_cpu_cores = self.model.get_resource_by_uuid(
|
|
||||||
element.ResourceType.cpu_cores).\
|
|
||||||
get_capacity(self.model.get_instance_by_uuid(instance_uuid))
|
|
||||||
total_cpu_util = instance_cpu_cores * self.get_instance_cpu_util(
|
|
||||||
instance_uuid)
|
|
||||||
util_sum += total_cpu_util / 100.0
|
|
||||||
util_sum /= node_cpu_cores
|
|
||||||
return util_sum * 100.0
|
|
||||||
|
|
||||||
def get_instance_cpu_util(self, r_id):
|
|
||||||
instance_cpu_util = dict()
|
|
||||||
instance_cpu_util['INSTANCE_0'] = 10
|
|
||||||
instance_cpu_util['INSTANCE_1'] = 30
|
|
||||||
instance_cpu_util['INSTANCE_2'] = 60
|
|
||||||
instance_cpu_util['INSTANCE_3'] = 20
|
|
||||||
instance_cpu_util['INSTANCE_4'] = 40
|
|
||||||
instance_cpu_util['INSTANCE_5'] = 50
|
|
||||||
instance_cpu_util['INSTANCE_6'] = 100
|
|
||||||
instance_cpu_util['INSTANCE_7'] = 100
|
|
||||||
instance_cpu_util['INSTANCE_8'] = 100
|
|
||||||
instance_cpu_util['INSTANCE_9'] = 100
|
|
||||||
return instance_cpu_util[str(r_id)]
|
|
||||||
|
|
||||||
def get_instance_ram_util(self, r_id):
|
|
||||||
instance_ram_util = dict()
|
|
||||||
instance_ram_util['INSTANCE_0'] = 1
|
|
||||||
instance_ram_util['INSTANCE_1'] = 2
|
|
||||||
instance_ram_util['INSTANCE_2'] = 4
|
|
||||||
instance_ram_util['INSTANCE_3'] = 8
|
|
||||||
instance_ram_util['INSTANCE_4'] = 3
|
|
||||||
instance_ram_util['INSTANCE_5'] = 2
|
|
||||||
instance_ram_util['INSTANCE_6'] = 1
|
|
||||||
instance_ram_util['INSTANCE_7'] = 2
|
|
||||||
instance_ram_util['INSTANCE_8'] = 4
|
|
||||||
instance_ram_util['INSTANCE_9'] = 8
|
|
||||||
return instance_ram_util[str(r_id)]
|
|
||||||
|
|
||||||
def get_instance_disk_root_size(self, r_id):
|
|
||||||
instance_disk_util = dict()
|
|
||||||
instance_disk_util['INSTANCE_0'] = 10
|
|
||||||
instance_disk_util['INSTANCE_1'] = 15
|
|
||||||
instance_disk_util['INSTANCE_2'] = 30
|
|
||||||
instance_disk_util['INSTANCE_3'] = 35
|
|
||||||
instance_disk_util['INSTANCE_4'] = 20
|
|
||||||
instance_disk_util['INSTANCE_5'] = 25
|
|
||||||
instance_disk_util['INSTANCE_6'] = 25
|
|
||||||
instance_disk_util['INSTANCE_7'] = 25
|
|
||||||
instance_disk_util['INSTANCE_8'] = 25
|
|
||||||
instance_disk_util['INSTANCE_9'] = 25
|
|
||||||
return instance_disk_util[str(r_id)]
|
|
||||||
@@ -1,414 +0,0 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
|
||||||
# Copyright (c) 2015 b<>com
|
|
||||||
#
|
|
||||||
# Authors: Jean-Emile DARTOIS <jean-emile.dartois@b-com.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.decision_engine.model.collector import base
|
|
||||||
from watcher.decision_engine.model import element
|
|
||||||
from watcher.decision_engine.model import model_root as modelroot
|
|
||||||
|
|
||||||
|
|
||||||
class FakerModelCollector(base.BaseClusterDataModelCollector):
|
|
||||||
|
|
||||||
def __init__(self, config=None, osc=None):
|
|
||||||
if config is None:
|
|
||||||
config = mock.Mock(period=777)
|
|
||||||
super(FakerModelCollector, self).__init__(config)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def notification_endpoints(self):
|
|
||||||
return []
|
|
||||||
|
|
||||||
def execute(self):
|
|
||||||
return self._cluster_data_model or self.generate_scenario_1()
|
|
||||||
|
|
||||||
def generate_scenario_1(self):
|
|
||||||
instances = []
|
|
||||||
|
|
||||||
current_state_cluster = modelroot.ModelRoot()
|
|
||||||
# number of nodes
|
|
||||||
node_count = 5
|
|
||||||
# number max of instance per node
|
|
||||||
node_instance_count = 7
|
|
||||||
# total number of virtual machine
|
|
||||||
instance_count = (node_count * node_instance_count)
|
|
||||||
|
|
||||||
# define ressouce ( CPU, MEM disk, ... )
|
|
||||||
mem = element.Resource(element.ResourceType.memory)
|
|
||||||
# 2199.954 Mhz
|
|
||||||
num_cores = element.Resource(element.ResourceType.cpu_cores)
|
|
||||||
disk = element.Resource(element.ResourceType.disk)
|
|
||||||
disk_capacity = element.Resource(element.ResourceType.disk_capacity)
|
|
||||||
|
|
||||||
current_state_cluster.create_resource(mem)
|
|
||||||
current_state_cluster.create_resource(num_cores)
|
|
||||||
current_state_cluster.create_resource(disk)
|
|
||||||
current_state_cluster.create_resource(disk_capacity)
|
|
||||||
|
|
||||||
for id_ in range(0, node_count):
|
|
||||||
node_uuid = "Node_{0}".format(id_)
|
|
||||||
node = element.ComputeNode(id_)
|
|
||||||
node.uuid = node_uuid
|
|
||||||
node.hostname = "hostname_{0}".format(id_)
|
|
||||||
|
|
||||||
mem.set_capacity(node, 132)
|
|
||||||
disk.set_capacity(node, 250)
|
|
||||||
disk_capacity.set_capacity(node, 250)
|
|
||||||
num_cores.set_capacity(node, 40)
|
|
||||||
current_state_cluster.add_node(node)
|
|
||||||
|
|
||||||
for i in range(0, instance_count):
|
|
||||||
instance_uuid = "INSTANCE_{0}".format(i)
|
|
||||||
instance = element.Instance()
|
|
||||||
instance.uuid = instance_uuid
|
|
||||||
mem.set_capacity(instance, 2)
|
|
||||||
disk.set_capacity(instance, 20)
|
|
||||||
disk_capacity.set_capacity(instance, 20)
|
|
||||||
num_cores.set_capacity(instance, 10)
|
|
||||||
instances.append(instance)
|
|
||||||
current_state_cluster.add_instance(instance)
|
|
||||||
|
|
||||||
current_state_cluster.get_mapping().map(
|
|
||||||
current_state_cluster.get_node_by_uuid("Node_0"),
|
|
||||||
current_state_cluster.get_instance_by_uuid("INSTANCE_0"))
|
|
||||||
|
|
||||||
current_state_cluster.get_mapping().map(
|
|
||||||
current_state_cluster.get_node_by_uuid("Node_0"),
|
|
||||||
current_state_cluster.get_instance_by_uuid("INSTANCE_1"))
|
|
||||||
|
|
||||||
current_state_cluster.get_mapping().map(
|
|
||||||
current_state_cluster.get_node_by_uuid("Node_1"),
|
|
||||||
current_state_cluster.get_instance_by_uuid("INSTANCE_2"))
|
|
||||||
|
|
||||||
current_state_cluster.get_mapping().map(
|
|
||||||
current_state_cluster.get_node_by_uuid("Node_2"),
|
|
||||||
current_state_cluster.get_instance_by_uuid("INSTANCE_3"))
|
|
||||||
|
|
||||||
current_state_cluster.get_mapping().map(
|
|
||||||
current_state_cluster.get_node_by_uuid("Node_2"),
|
|
||||||
current_state_cluster.get_instance_by_uuid("INSTANCE_4"))
|
|
||||||
|
|
||||||
current_state_cluster.get_mapping().map(
|
|
||||||
current_state_cluster.get_node_by_uuid("Node_2"),
|
|
||||||
current_state_cluster.get_instance_by_uuid("INSTANCE_5"))
|
|
||||||
|
|
||||||
current_state_cluster.get_mapping().map(
|
|
||||||
current_state_cluster.get_node_by_uuid("Node_3"),
|
|
||||||
current_state_cluster.get_instance_by_uuid("INSTANCE_6"))
|
|
||||||
|
|
||||||
current_state_cluster.get_mapping().map(
|
|
||||||
current_state_cluster.get_node_by_uuid("Node_4"),
|
|
||||||
current_state_cluster.get_instance_by_uuid("INSTANCE_7"))
|
|
||||||
|
|
||||||
return current_state_cluster
|
|
||||||
|
|
||||||
def map(self, model, h_id, instance_id):
|
|
||||||
model.get_mapping().map(
|
|
||||||
model.get_node_by_uuid(h_id),
|
|
||||||
model.get_instance_by_uuid(instance_id))
|
|
||||||
|
|
||||||
def generate_scenario_3_with_2_nodes(self):
|
|
||||||
instances = []
|
|
||||||
|
|
||||||
root = modelroot.ModelRoot()
|
|
||||||
# number of nodes
|
|
||||||
node_count = 2
|
|
||||||
|
|
||||||
# define ressouce ( CPU, MEM disk, ... )
|
|
||||||
mem = element.Resource(element.ResourceType.memory)
|
|
||||||
# 2199.954 Mhz
|
|
||||||
num_cores = element.Resource(element.ResourceType.cpu_cores)
|
|
||||||
disk = element.Resource(element.ResourceType.disk)
|
|
||||||
disk_capacity = element.Resource(element.ResourceType.disk_capacity)
|
|
||||||
|
|
||||||
root.create_resource(mem)
|
|
||||||
root.create_resource(num_cores)
|
|
||||||
root.create_resource(disk)
|
|
||||||
root.create_resource(disk_capacity)
|
|
||||||
|
|
||||||
for id_ in range(0, node_count):
|
|
||||||
node_uuid = "Node_{0}".format(id_)
|
|
||||||
node = element.ComputeNode(id_)
|
|
||||||
node.uuid = node_uuid
|
|
||||||
node.hostname = "hostname_{0}".format(id_)
|
|
||||||
|
|
||||||
mem.set_capacity(node, 132)
|
|
||||||
disk.set_capacity(node, 250)
|
|
||||||
disk_capacity.set_capacity(node, 250)
|
|
||||||
num_cores.set_capacity(node, 40)
|
|
||||||
root.add_node(node)
|
|
||||||
|
|
||||||
instance1 = element.Instance()
|
|
||||||
instance1.uuid = "73b09e16-35b7-4922-804e-e8f5d9b740fc"
|
|
||||||
mem.set_capacity(instance1, 2)
|
|
||||||
disk.set_capacity(instance1, 20)
|
|
||||||
disk_capacity.set_capacity(instance1, 20)
|
|
||||||
num_cores.set_capacity(instance1, 10)
|
|
||||||
instances.append(instance1)
|
|
||||||
root.add_instance(instance1)
|
|
||||||
|
|
||||||
instance2 = element.Instance()
|
|
||||||
instance2.uuid = "a4cab39b-9828-413a-bf88-f76921bf1517"
|
|
||||||
mem.set_capacity(instance2, 2)
|
|
||||||
disk.set_capacity(instance2, 20)
|
|
||||||
disk_capacity.set_capacity(instance2, 20)
|
|
||||||
num_cores.set_capacity(instance2, 10)
|
|
||||||
instances.append(instance2)
|
|
||||||
root.add_instance(instance2)
|
|
||||||
|
|
||||||
root.get_mapping().map(root.get_node_by_uuid("Node_0"),
|
|
||||||
root.get_instance_by_uuid(str(instance1.uuid)))
|
|
||||||
|
|
||||||
root.get_mapping().map(root.get_node_by_uuid("Node_1"),
|
|
||||||
root.get_instance_by_uuid(str(instance2.uuid)))
|
|
||||||
|
|
||||||
return root
|
|
||||||
|
|
||||||
def generate_scenario_4_with_1_node_no_instance(self):
|
|
||||||
current_state_cluster = modelroot.ModelRoot()
|
|
||||||
# number of nodes
|
|
||||||
node_count = 1
|
|
||||||
|
|
||||||
# define ressouce ( CPU, MEM disk, ... )
|
|
||||||
mem = element.Resource(element.ResourceType.memory)
|
|
||||||
# 2199.954 Mhz
|
|
||||||
num_cores = element.Resource(element.ResourceType.cpu_cores)
|
|
||||||
disk = element.Resource(element.ResourceType.disk)
|
|
||||||
disk_capacity = element.Resource(element.ResourceType.disk_capacity)
|
|
||||||
|
|
||||||
current_state_cluster.create_resource(mem)
|
|
||||||
current_state_cluster.create_resource(num_cores)
|
|
||||||
current_state_cluster.create_resource(disk)
|
|
||||||
current_state_cluster.create_resource(disk_capacity)
|
|
||||||
|
|
||||||
for id_ in range(0, node_count):
|
|
||||||
node_uuid = "Node_{0}".format(id_)
|
|
||||||
node = element.ComputeNode(id_)
|
|
||||||
node.uuid = node_uuid
|
|
||||||
node.hostname = "hostname_{0}".format(id_)
|
|
||||||
|
|
||||||
mem.set_capacity(node, 1)
|
|
||||||
disk.set_capacity(node, 1)
|
|
||||||
disk_capacity.set_capacity(node, 1)
|
|
||||||
num_cores.set_capacity(node, 1)
|
|
||||||
current_state_cluster.add_node(node)
|
|
||||||
|
|
||||||
return current_state_cluster
|
|
||||||
|
|
||||||
def generate_scenario_5_with_instance_disk_0(self):
|
|
||||||
instances = []
|
|
||||||
current_state_cluster = modelroot.ModelRoot()
|
|
||||||
# number of nodes
|
|
||||||
node_count = 1
|
|
||||||
# number of instances
|
|
||||||
instance_count = 1
|
|
||||||
|
|
||||||
# define ressouce ( CPU, MEM disk, ... )
|
|
||||||
mem = element.Resource(element.ResourceType.memory)
|
|
||||||
# 2199.954 Mhz
|
|
||||||
num_cores = element.Resource(element.ResourceType.cpu_cores)
|
|
||||||
disk = element.Resource(element.ResourceType.disk)
|
|
||||||
disk_capacity = element.Resource(element.ResourceType.disk_capacity)
|
|
||||||
|
|
||||||
current_state_cluster.create_resource(mem)
|
|
||||||
current_state_cluster.create_resource(num_cores)
|
|
||||||
current_state_cluster.create_resource(disk)
|
|
||||||
current_state_cluster.create_resource(disk_capacity)
|
|
||||||
|
|
||||||
for id_ in range(0, node_count):
|
|
||||||
node_uuid = "Node_{0}".format(id_)
|
|
||||||
node = element.ComputeNode(id_)
|
|
||||||
node.uuid = node_uuid
|
|
||||||
node.hostname = "hostname_{0}".format(id_)
|
|
||||||
|
|
||||||
mem.set_capacity(node, 4)
|
|
||||||
disk.set_capacity(node, 4)
|
|
||||||
disk_capacity.set_capacity(node, 4)
|
|
||||||
num_cores.set_capacity(node, 4)
|
|
||||||
current_state_cluster.add_node(node)
|
|
||||||
|
|
||||||
for i in range(0, instance_count):
|
|
||||||
instance_uuid = "INSTANCE_{0}".format(i)
|
|
||||||
instance = element.Instance()
|
|
||||||
instance.uuid = instance_uuid
|
|
||||||
mem.set_capacity(instance, 2)
|
|
||||||
disk.set_capacity(instance, 0)
|
|
||||||
disk_capacity.set_capacity(instance, 0)
|
|
||||||
num_cores.set_capacity(instance, 4)
|
|
||||||
instances.append(instance)
|
|
||||||
current_state_cluster.add_instance(instance)
|
|
||||||
|
|
||||||
current_state_cluster.get_mapping().map(
|
|
||||||
current_state_cluster.get_node_by_uuid("Node_0"),
|
|
||||||
current_state_cluster.get_instance_by_uuid("INSTANCE_0"))
|
|
||||||
|
|
||||||
return current_state_cluster
|
|
||||||
|
|
||||||
def generate_scenario_6_with_2_nodes(self):
|
|
||||||
instances = []
|
|
||||||
root = modelroot.ModelRoot()
|
|
||||||
# number of nodes
|
|
||||||
node_count = 2
|
|
||||||
|
|
||||||
# define ressouce ( CPU, MEM disk, ... )
|
|
||||||
mem = element.Resource(element.ResourceType.memory)
|
|
||||||
# 2199.954 Mhz
|
|
||||||
num_cores = element.Resource(element.ResourceType.cpu_cores)
|
|
||||||
disk = element.Resource(element.ResourceType.disk)
|
|
||||||
disk_capacity = element.Resource(element.ResourceType.disk_capacity)
|
|
||||||
|
|
||||||
root.create_resource(mem)
|
|
||||||
root.create_resource(num_cores)
|
|
||||||
root.create_resource(disk)
|
|
||||||
root.create_resource(disk_capacity)
|
|
||||||
|
|
||||||
for id_ in range(0, node_count):
|
|
||||||
node_uuid = "Node_{0}".format(id_)
|
|
||||||
node = element.ComputeNode(id_)
|
|
||||||
node.uuid = node_uuid
|
|
||||||
node.hostname = "hostname_{0}".format(id_)
|
|
||||||
|
|
||||||
mem.set_capacity(node, 132)
|
|
||||||
disk.set_capacity(node, 250)
|
|
||||||
disk_capacity.set_capacity(node, 250)
|
|
||||||
num_cores.set_capacity(node, 40)
|
|
||||||
root.add_node(node)
|
|
||||||
|
|
||||||
instance1 = element.Instance()
|
|
||||||
instance1.uuid = "INSTANCE_1"
|
|
||||||
mem.set_capacity(instance1, 2)
|
|
||||||
disk.set_capacity(instance1, 20)
|
|
||||||
disk_capacity.set_capacity(instance1, 20)
|
|
||||||
num_cores.set_capacity(instance1, 10)
|
|
||||||
instances.append(instance1)
|
|
||||||
root.add_instance(instance1)
|
|
||||||
|
|
||||||
instance11 = element.Instance()
|
|
||||||
instance11.uuid = "73b09e16-35b7-4922-804e-e8f5d9b740fc"
|
|
||||||
mem.set_capacity(instance11, 2)
|
|
||||||
disk.set_capacity(instance11, 20)
|
|
||||||
disk_capacity.set_capacity(instance11, 20)
|
|
||||||
num_cores.set_capacity(instance11, 10)
|
|
||||||
instances.append(instance11)
|
|
||||||
root.add_instance(instance11)
|
|
||||||
|
|
||||||
instance2 = element.Instance()
|
|
||||||
instance2.uuid = "INSTANCE_3"
|
|
||||||
mem.set_capacity(instance2, 2)
|
|
||||||
disk.set_capacity(instance2, 20)
|
|
||||||
disk_capacity.set_capacity(instance2, 20)
|
|
||||||
num_cores.set_capacity(instance2, 10)
|
|
||||||
instances.append(instance2)
|
|
||||||
root.add_instance(instance2)
|
|
||||||
|
|
||||||
instance21 = element.Instance()
|
|
||||||
instance21.uuid = "INSTANCE_4"
|
|
||||||
mem.set_capacity(instance21, 2)
|
|
||||||
disk.set_capacity(instance21, 20)
|
|
||||||
disk_capacity.set_capacity(instance21, 20)
|
|
||||||
num_cores.set_capacity(instance21, 10)
|
|
||||||
instances.append(instance21)
|
|
||||||
root.add_instance(instance21)
|
|
||||||
|
|
||||||
root.get_mapping().map(root.get_node_by_uuid("Node_0"),
|
|
||||||
root.get_instance_by_uuid(str(instance1.uuid)))
|
|
||||||
root.get_mapping().map(root.get_node_by_uuid("Node_0"),
|
|
||||||
root.get_instance_by_uuid(str(instance11.uuid)))
|
|
||||||
|
|
||||||
root.get_mapping().map(root.get_node_by_uuid("Node_1"),
|
|
||||||
root.get_instance_by_uuid(str(instance2.uuid)))
|
|
||||||
root.get_mapping().map(root.get_node_by_uuid("Node_1"),
|
|
||||||
root.get_instance_by_uuid(str(instance21.uuid)))
|
|
||||||
return root
|
|
||||||
|
|
||||||
def generate_scenario_7_with_2_nodes(self):
|
|
||||||
instances = []
|
|
||||||
root = modelroot.ModelRoot()
|
|
||||||
# number of nodes
|
|
||||||
count_node = 2
|
|
||||||
|
|
||||||
# define ressouce ( CPU, MEM disk, ... )
|
|
||||||
mem = element.Resource(element.ResourceType.memory)
|
|
||||||
# 2199.954 Mhz
|
|
||||||
num_cores = element.Resource(element.ResourceType.cpu_cores)
|
|
||||||
disk = element.Resource(element.ResourceType.disk)
|
|
||||||
disk_capacity = element.Resource(element.ResourceType.disk_capacity)
|
|
||||||
|
|
||||||
root.create_resource(mem)
|
|
||||||
root.create_resource(num_cores)
|
|
||||||
root.create_resource(disk)
|
|
||||||
root.create_resource(disk_capacity)
|
|
||||||
|
|
||||||
for id_ in range(0, count_node):
|
|
||||||
node_uuid = "Node_{0}".format(id_)
|
|
||||||
node = element.ComputeNode(id_)
|
|
||||||
node.uuid = node_uuid
|
|
||||||
node.hostname = "hostname_{0}".format(id_)
|
|
||||||
|
|
||||||
mem.set_capacity(node, 132)
|
|
||||||
disk.set_capacity(node, 250)
|
|
||||||
disk_capacity.set_capacity(node, 250)
|
|
||||||
num_cores.set_capacity(node, 50)
|
|
||||||
root.add_node(node)
|
|
||||||
|
|
||||||
instance1 = element.Instance()
|
|
||||||
instance1.uuid = "cae81432-1631-4d4e-b29c-6f3acdcde906"
|
|
||||||
mem.set_capacity(instance1, 2)
|
|
||||||
disk.set_capacity(instance1, 20)
|
|
||||||
disk_capacity.set_capacity(instance1, 20)
|
|
||||||
num_cores.set_capacity(instance1, 15)
|
|
||||||
instances.append(instance1)
|
|
||||||
root.add_instance(instance1)
|
|
||||||
|
|
||||||
instance11 = element.Instance()
|
|
||||||
instance11.uuid = "73b09e16-35b7-4922-804e-e8f5d9b740fc"
|
|
||||||
mem.set_capacity(instance11, 2)
|
|
||||||
disk.set_capacity(instance11, 20)
|
|
||||||
disk_capacity.set_capacity(instance11, 20)
|
|
||||||
num_cores.set_capacity(instance11, 10)
|
|
||||||
instances.append(instance11)
|
|
||||||
root.add_instance(instance11)
|
|
||||||
|
|
||||||
instance2 = element.Instance()
|
|
||||||
instance2.uuid = "INSTANCE_3"
|
|
||||||
mem.set_capacity(instance2, 2)
|
|
||||||
disk.set_capacity(instance2, 20)
|
|
||||||
disk_capacity.set_capacity(instance2, 20)
|
|
||||||
num_cores.set_capacity(instance2, 10)
|
|
||||||
instances.append(instance2)
|
|
||||||
root.add_instance(instance2)
|
|
||||||
|
|
||||||
instance21 = element.Instance()
|
|
||||||
instance21.uuid = "INSTANCE_4"
|
|
||||||
mem.set_capacity(instance21, 2)
|
|
||||||
disk.set_capacity(instance21, 20)
|
|
||||||
disk_capacity.set_capacity(instance21, 20)
|
|
||||||
num_cores.set_capacity(instance21, 10)
|
|
||||||
instances.append(instance21)
|
|
||||||
root.add_instance(instance21)
|
|
||||||
|
|
||||||
root.get_mapping().map(root.get_node_by_uuid("Node_0"),
|
|
||||||
root.get_instance_by_uuid(str(instance1.uuid)))
|
|
||||||
root.get_mapping().map(root.get_node_by_uuid("Node_0"),
|
|
||||||
root.get_instance_by_uuid(str(instance11.uuid)))
|
|
||||||
|
|
||||||
root.get_mapping().map(root.get_node_by_uuid("Node_1"),
|
|
||||||
root.get_instance_by_uuid(str(instance2.uuid)))
|
|
||||||
root.get_mapping().map(root.get_node_by_uuid("Node_1"),
|
|
||||||
root.get_instance_by_uuid(str(instance21.uuid)))
|
|
||||||
return root
|
|
||||||
@@ -26,10 +26,8 @@ from watcher.decision_engine.model.collector import nova
|
|||||||
from watcher.decision_engine.model import model_root
|
from watcher.decision_engine.model import model_root
|
||||||
from watcher.decision_engine.strategy import strategies
|
from watcher.decision_engine.strategy import strategies
|
||||||
from watcher.tests import base
|
from watcher.tests import base
|
||||||
from watcher.tests.decision_engine.strategy.strategies \
|
from watcher.tests.decision_engine.model import faker_cluster_state
|
||||||
import faker_cluster_state
|
from watcher.tests.decision_engine.model import faker_metrics_collector
|
||||||
from watcher.tests.decision_engine.strategy.strategies \
|
|
||||||
import faker_metrics_collector
|
|
||||||
|
|
||||||
|
|
||||||
class TestBasicConsolidation(base.TestCase):
|
class TestBasicConsolidation(base.TestCase):
|
||||||
@@ -186,14 +184,37 @@ class TestBasicConsolidation(base.TestCase):
|
|||||||
[action.get('action_type') for action in solution.actions])
|
[action.get('action_type') for action in solution.actions])
|
||||||
|
|
||||||
expected_num_migrations = 1
|
expected_num_migrations = 1
|
||||||
expected_power_state = 0
|
expected_power_state = 1
|
||||||
|
|
||||||
num_migrations = actions_counter.get("migrate", 0)
|
num_migrations = actions_counter.get("migrate", 0)
|
||||||
num_node_state_change = actions_counter.get(
|
num_node_state_change = actions_counter.get(
|
||||||
"change_node_state", 0)
|
"change_nova_service_state", 0)
|
||||||
self.assertEqual(expected_num_migrations, num_migrations)
|
self.assertEqual(expected_num_migrations, num_migrations)
|
||||||
self.assertEqual(expected_power_state, num_node_state_change)
|
self.assertEqual(expected_power_state, num_node_state_change)
|
||||||
|
|
||||||
|
def test_basic_consolidation_execute_scenario_8_with_4_nodes(self):
|
||||||
|
model = self.fake_cluster.generate_scenario_8_with_4_nodes()
|
||||||
|
self.m_model.return_value = model
|
||||||
|
|
||||||
|
solution = self.strategy.execute()
|
||||||
|
|
||||||
|
actions_counter = collections.Counter(
|
||||||
|
[action.get('action_type') for action in solution.actions])
|
||||||
|
|
||||||
|
expected_num_migrations = 5
|
||||||
|
expected_power_state = 3
|
||||||
|
expected_global_efficacy = 60
|
||||||
|
|
||||||
|
num_migrations = actions_counter.get("migrate", 0)
|
||||||
|
num_node_state_change = actions_counter.get(
|
||||||
|
"change_nova_service_state", 0)
|
||||||
|
|
||||||
|
global_efficacy_value = solution.global_efficacy.get("value", 0)
|
||||||
|
|
||||||
|
self.assertEqual(expected_num_migrations, num_migrations)
|
||||||
|
self.assertEqual(expected_power_state, num_node_state_change)
|
||||||
|
self.assertEqual(expected_global_efficacy, global_efficacy_value)
|
||||||
|
|
||||||
def test_exception_stale_cdm(self):
|
def test_exception_stale_cdm(self):
|
||||||
self.fake_cluster.set_cluster_data_model_as_stale()
|
self.fake_cluster.set_cluster_data_model_as_stale()
|
||||||
self.m_model.return_value = self.fake_cluster.cluster_data_model
|
self.m_model.return_value = self.fake_cluster.cluster_data_model
|
||||||
|
|||||||
@@ -21,8 +21,7 @@ from watcher.common import utils
|
|||||||
from watcher.decision_engine.model import model_root
|
from watcher.decision_engine.model import model_root
|
||||||
from watcher.decision_engine.strategy import strategies
|
from watcher.decision_engine.strategy import strategies
|
||||||
from watcher.tests import base
|
from watcher.tests import base
|
||||||
from watcher.tests.decision_engine.strategy.strategies import \
|
from watcher.tests.decision_engine.model import faker_cluster_state
|
||||||
faker_cluster_state
|
|
||||||
|
|
||||||
|
|
||||||
class TestDummyStrategy(base.TestCase):
|
class TestDummyStrategy(base.TestCase):
|
||||||
|
|||||||
@@ -21,8 +21,7 @@ from watcher.common import utils
|
|||||||
from watcher.decision_engine.model import model_root
|
from watcher.decision_engine.model import model_root
|
||||||
from watcher.decision_engine.strategy import strategies
|
from watcher.decision_engine.strategy import strategies
|
||||||
from watcher.tests import base
|
from watcher.tests import base
|
||||||
from watcher.tests.decision_engine.strategy.strategies import \
|
from watcher.tests.decision_engine.model import faker_cluster_state
|
||||||
faker_cluster_state
|
|
||||||
|
|
||||||
|
|
||||||
class TestDummyWithScorer(base.TestCase):
|
class TestDummyWithScorer(base.TestCase):
|
||||||
|
|||||||
@@ -26,10 +26,8 @@ from watcher.decision_engine.model import element
|
|||||||
from watcher.decision_engine.model import model_root
|
from watcher.decision_engine.model import model_root
|
||||||
from watcher.decision_engine.strategy import strategies
|
from watcher.decision_engine.strategy import strategies
|
||||||
from watcher.tests import base
|
from watcher.tests import base
|
||||||
from watcher.tests.decision_engine.strategy.strategies \
|
from watcher.tests.decision_engine.model import faker_cluster_state
|
||||||
import faker_cluster_state
|
from watcher.tests.decision_engine.model import faker_metrics_collector
|
||||||
from watcher.tests.decision_engine.strategy.strategies \
|
|
||||||
import faker_metrics_collector
|
|
||||||
|
|
||||||
|
|
||||||
class TestOutletTempControl(base.TestCase):
|
class TestOutletTempControl(base.TestCase):
|
||||||
|
|||||||
@@ -26,10 +26,8 @@ from watcher.decision_engine.model import element
|
|||||||
from watcher.decision_engine.model import model_root
|
from watcher.decision_engine.model import model_root
|
||||||
from watcher.decision_engine.strategy import strategies
|
from watcher.decision_engine.strategy import strategies
|
||||||
from watcher.tests import base
|
from watcher.tests import base
|
||||||
from watcher.tests.decision_engine.strategy.strategies \
|
from watcher.tests.decision_engine.model import faker_cluster_state
|
||||||
import faker_cluster_state
|
from watcher.tests.decision_engine.model import faker_metrics_collector
|
||||||
from watcher.tests.decision_engine.strategy.strategies \
|
|
||||||
import faker_metrics_collector
|
|
||||||
|
|
||||||
|
|
||||||
class TestUniformAirflow(base.TestCase):
|
class TestUniformAirflow(base.TestCase):
|
||||||
|
|||||||
@@ -24,8 +24,7 @@ from watcher.common import exception
|
|||||||
from watcher.decision_engine.model import model_root
|
from watcher.decision_engine.model import model_root
|
||||||
from watcher.decision_engine.strategy import strategies
|
from watcher.decision_engine.strategy import strategies
|
||||||
from watcher.tests import base
|
from watcher.tests import base
|
||||||
from watcher.tests.decision_engine.strategy.strategies \
|
from watcher.tests.decision_engine.model import faker_cluster_and_metrics
|
||||||
import faker_cluster_and_metrics
|
|
||||||
|
|
||||||
|
|
||||||
class TestVMWorkloadConsolidation(base.TestCase):
|
class TestVMWorkloadConsolidation(base.TestCase):
|
||||||
|
|||||||
@@ -26,10 +26,8 @@ from watcher.decision_engine.model import element
|
|||||||
from watcher.decision_engine.model import model_root
|
from watcher.decision_engine.model import model_root
|
||||||
from watcher.decision_engine.strategy import strategies
|
from watcher.decision_engine.strategy import strategies
|
||||||
from watcher.tests import base
|
from watcher.tests import base
|
||||||
from watcher.tests.decision_engine.strategy.strategies \
|
from watcher.tests.decision_engine.model import faker_cluster_state
|
||||||
import faker_cluster_state
|
from watcher.tests.decision_engine.model import faker_metrics_collector
|
||||||
from watcher.tests.decision_engine.strategy.strategies \
|
|
||||||
import faker_metrics_collector
|
|
||||||
|
|
||||||
|
|
||||||
class TestWorkloadBalance(base.TestCase):
|
class TestWorkloadBalance(base.TestCase):
|
||||||
|
|||||||
@@ -23,10 +23,8 @@ from watcher.common import utils
|
|||||||
from watcher.decision_engine.model import model_root
|
from watcher.decision_engine.model import model_root
|
||||||
from watcher.decision_engine.strategy import strategies
|
from watcher.decision_engine.strategy import strategies
|
||||||
from watcher.tests import base
|
from watcher.tests import base
|
||||||
from watcher.tests.decision_engine.strategy.strategies \
|
from watcher.tests.decision_engine.model import faker_cluster_state
|
||||||
import faker_cluster_state
|
from watcher.tests.decision_engine.model import faker_metrics_collector
|
||||||
from watcher.tests.decision_engine.strategy.strategies \
|
|
||||||
import faker_metrics_collector
|
|
||||||
|
|
||||||
|
|
||||||
class TestWorkloadStabilization(base.TestCase):
|
class TestWorkloadStabilization(base.TestCase):
|
||||||
|
|||||||
@@ -24,8 +24,7 @@ import mock
|
|||||||
from watcher.decision_engine.loading import default as default_loading
|
from watcher.decision_engine.loading import default as default_loading
|
||||||
from watcher.decision_engine import scheduling
|
from watcher.decision_engine import scheduling
|
||||||
from watcher.tests import base
|
from watcher.tests import base
|
||||||
from watcher.tests.decision_engine.strategy.strategies import \
|
from watcher.tests.decision_engine.model import faker_cluster_state
|
||||||
faker_cluster_state
|
|
||||||
|
|
||||||
|
|
||||||
class TestDecisionEngineSchedulingService(base.TestCase):
|
class TestDecisionEngineSchedulingService(base.TestCase):
|
||||||
|
|||||||
Reference in New Issue
Block a user