Fixed Tempest test due to notification issues

Change-Id: I33a0764060600b8e3d6bec757669490b9003b345
This commit is contained in:
Vincent Françoise
2016-09-06 15:11:48 +02:00
parent 74989fe94e
commit 72e6564549
27 changed files with 965 additions and 514 deletions

View File

@@ -83,7 +83,7 @@ class NovaClusterDataModelCollector(base.BaseClusterDataModelCollector):
for n in nodes:
service = self.wrapper.nova.services.find(id=n.service['id'])
# create node in cluster_model_collector
node = element.ComputeNode()
node = element.ComputeNode(n.id)
node.uuid = service.host
node.hostname = n.hypervisor_hostname
# set capacity
@@ -105,7 +105,10 @@ class NovaClusterDataModelCollector(base.BaseClusterDataModelCollector):
# set capacity
self.wrapper.get_flavor_instance(v, flavor_cache)
mem.set_capacity(instance, v.flavor['ram'])
# FIXME: update all strategies to use disk_capacity
# for instances instead of disk
disk.set_capacity(instance, v.flavor['disk'])
disk_capacity.set_capacity(instance, v.flavor['disk'])
num_cores.set_capacity(instance, v.flavor['vcpus'])
model.map_instance(instance, node)

View File

@@ -28,8 +28,9 @@ class ServiceState(enum.Enum):
class ComputeNode(compute_resource.ComputeResource):
def __init__(self):
def __init__(self, id):
super(ComputeNode, self).__init__()
self.id = id
self._state = ServiceState.ONLINE.value
self._status = ServiceState.ENABLED.value

View File

@@ -16,6 +16,8 @@
import enum
from watcher.common import exception
class ResourceType(enum.Enum):
cpu_cores = 'num_cores'
@@ -50,12 +52,12 @@ class Resource(object):
def unset_capacity(self, element):
del self.mapping[element.uuid]
def get_capacity_from_id(self, uuid):
if str(uuid) in self.mapping.keys():
def get_capacity_by_uuid(self, uuid):
try:
return self.mapping[str(uuid)]
else:
# TODO(jed) throw exception
return None
except KeyError:
raise exception.CapacityNotDefined(
capacity=self.name.value, resource=str(uuid))
def get_capacity(self, element):
return self.get_capacity_from_id(element.uuid)
return self.get_capacity_by_uuid(element.uuid)

View File

@@ -58,9 +58,9 @@ class Mapping(object):
:param node: the node
:param instance: the virtual machine or instance
"""
self.unmap_from_id(node.uuid, instance.uuid)
self.unmap_by_uuid(node.uuid, instance.uuid)
def unmap_from_id(self, node_uuid, instance_uuid):
def unmap_by_uuid(self, node_uuid, instance_uuid):
"""Remove the instance (by id) from the node (by id)
:rtype : object
@@ -84,15 +84,15 @@ class Mapping(object):
return self.compute_node_mapping
def get_node_from_instance(self, instance):
return self.get_node_from_instance_id(instance.uuid)
return self.get_node_by_instance_uuid(instance.uuid)
def get_node_from_instance_id(self, instance_uuid):
def get_node_by_instance_uuid(self, instance_uuid):
"""Getting host information from the guest instance
:param instance: the uuid of the instance
:return: node
"""
return self.model.get_node_from_id(
return self.model.get_node_by_uuid(
self.instance_mapping[str(instance_uuid)])
def get_node_instances(self, node):
@@ -101,9 +101,9 @@ class Mapping(object):
:param node:
:return:
"""
return self.get_node_instances_from_id(node.uuid)
return self.get_node_instances_by_uuid(node.uuid)
def get_node_instances_from_id(self, node_uuid):
def get_node_instances_by_uuid(self, node_uuid):
if str(node_uuid) in self.compute_node_mapping.keys():
return self.compute_node_mapping[str(node_uuid)]
else:

View File

@@ -77,9 +77,9 @@ class ModelRoot(object):
:type node: str or :py:class:`~.Instance`
"""
if isinstance(instance, six.string_types):
instance = self.get_instance_from_id(instance)
instance = self.get_instance_by_uuid(instance)
if isinstance(node, six.string_types):
node = self.get_node_from_id(node)
node = self.get_node_by_uuid(node)
self.add_instance(instance)
self.mapping.map(node, instance)
@@ -93,17 +93,18 @@ class ModelRoot(object):
:type node: str or :py:class:`~.Instance`
"""
if isinstance(instance, six.string_types):
instance = self.get_instance_from_id(instance)
instance = self.get_instance_by_uuid(instance)
if isinstance(node, six.string_types):
node = self.get_node_from_id(node)
node = self.get_node_by_uuid(node)
self.add_instance(instance)
self.mapping.unmap(node, instance)
def delete_instance(self, instance, node):
self.remove_instance(instance)
def delete_instance(self, instance, node=None):
if node is not None:
self.mapping.unmap(node, instance)
self.mapping.unmap(node, instance)
self.remove_instance(instance)
for resource in self.resource.values():
try:
@@ -130,17 +131,17 @@ class ModelRoot(object):
def get_all_compute_nodes(self):
return self._nodes
def get_node_from_id(self, node_uuid):
def get_node_by_uuid(self, node_uuid):
if str(node_uuid) not in self._nodes:
raise exception.ComputeNodeNotFound(name=node_uuid)
return self._nodes[str(node_uuid)]
def get_instance_from_id(self, uuid):
def get_instance_by_uuid(self, uuid):
if str(uuid) not in self._instances:
raise exception.InstanceNotFound(name=uuid)
return self._instances[str(uuid)]
def get_node_from_instance_id(self, instance_uuid):
def get_node_by_instance_uuid(self, instance_uuid):
"""Getting host information from the guest instance
:param instance_uuid: the uuid of the instance
@@ -148,7 +149,7 @@ class ModelRoot(object):
"""
if str(instance_uuid) not in self.mapping.instance_mapping:
raise exception.InstanceNotFound(name=instance_uuid)
return self.get_node_from_id(
return self.get_node_by_uuid(
self.mapping.instance_mapping[str(instance_uuid)])
def get_all_instances(self):
@@ -160,7 +161,7 @@ class ModelRoot(object):
def create_resource(self, r):
self.resource[str(r.name)] = r
def get_resource_from_id(self, resource_id):
def get_resource_by_uuid(self, resource_id):
return self.resource[str(resource_id)]
def get_node_instances(self, node):
@@ -168,11 +169,12 @@ class ModelRoot(object):
def _build_compute_node_element(self, compute_node):
attrib = collections.OrderedDict(
uuid=compute_node.uuid, human_id=compute_node.human_id,
hostname=compute_node.hostname, state=compute_node.state,
status=compute_node.status)
id=six.text_type(compute_node.id), uuid=compute_node.uuid,
human_id=compute_node.human_id, hostname=compute_node.hostname,
state=compute_node.state, status=compute_node.status)
for resource_name, resource in self.resource.items():
for resource_name, resource in sorted(
self.resource.items(), key=lambda x: x[0]):
res_value = resource.get_capacity(compute_node)
if res_value is not None:
attrib[resource_name] = six.text_type(res_value)
@@ -186,7 +188,8 @@ class ModelRoot(object):
uuid=instance.uuid, human_id=instance.human_id,
hostname=instance.hostname, state=instance.state)
for resource_name, resource in self.resource.items():
for resource_name, resource in sorted(
self.resource.items(), key=lambda x: x[0]):
res_value = resource.get_capacity(instance)
if res_value is not None:
attrib[resource_name] = six.text_type(res_value)
@@ -205,7 +208,7 @@ class ModelRoot(object):
# Build mapped instance tree
node_instance_uuids = self.get_node_instances(cn)
for instance_uuid in sorted(node_instance_uuids):
instance = self.get_instance_from_id(instance_uuid)
instance = self.get_instance_by_uuid(instance_uuid)
instance_el = self._build_instance_element(instance)
compute_node_el.append(instance_el)
@@ -215,7 +218,7 @@ class ModelRoot(object):
for instance in sorted(self.get_all_instances().values(),
key=lambda inst: inst.uuid):
try:
self.get_node_from_instance_id(instance.uuid)
self.get_node_by_instance_uuid(instance.uuid)
except exception.InstanceNotFound:
root.append(self._build_instance_element(instance))

View File

@@ -20,6 +20,7 @@ from oslo_log import log
from watcher._i18n import _LI
from watcher.common import exception
from watcher.common import nova_helper
from watcher.decision_engine.model import element
from watcher.decision_engine.model.notification import base
from watcher.decision_engine.model.notification import filtering
@@ -29,9 +30,19 @@ LOG = log.getLogger(__name__)
class NovaNotification(base.NotificationEndpoint):
def __init__(self, collector):
super(NovaNotification, self).__init__(collector)
self._nova = None
@property
def nova(self):
if self._nova is None:
self._nova = nova_helper.NovaHelper()
return self._nova
def get_or_create_instance(self, uuid):
try:
instance = self.cluster_data_model.get_instance_from_id(uuid)
instance = self.cluster_data_model.get_instance_by_uuid(uuid)
except exception.InstanceNotFound:
# The instance didn't exist yet so we create a new instance object
LOG.debug("New instance created: %s", uuid)
@@ -59,13 +70,20 @@ class NovaNotification(base.NotificationEndpoint):
element.ResourceType.cpu_cores, instance, num_cores)
self.update_capacity(
element.ResourceType.disk, instance, disk_gb)
self.update_capacity(
element.ResourceType.disk_capacity, instance, disk_gb)
node = self.get_or_create_node(instance_data['host'])
try:
node = self.get_or_create_node(instance_data['host'])
except exception.ComputeNodeNotFound as exc:
LOG.exception(exc)
# If we can't create the node, we consider the instance as unmapped
node = None
self.update_instance_mapping(instance, node)
def update_capacity(self, resource_id, obj, value):
resource = self.cluster_data_model.get_resource_from_id(resource_id)
resource = self.cluster_data_model.get_resource_by_uuid(resource_id)
resource.set_capacity(obj, value)
def legacy_update_instance(self, instance, data):
@@ -82,34 +100,83 @@ class NovaNotification(base.NotificationEndpoint):
element.ResourceType.cpu_cores, instance, num_cores)
self.update_capacity(
element.ResourceType.disk, instance, disk_gb)
self.update_capacity(
element.ResourceType.disk_capacity, instance, disk_gb)
node = self.get_or_create_node(data['host'])
try:
node = self.get_or_create_node(data['host'])
except exception.ComputeNodeNotFound as exc:
LOG.exception(exc)
# If we can't create the node, we consider the instance as unmapped
node = None
self.update_instance_mapping(instance, node)
def update_compute_node(self, node, data):
"""Update the compute node using the notification data."""
node_data = data['nova_object.data']
node.hostname = node_data['host']
node.state = (
element.ServiceState.OFFLINE.value
if node_data['forced_down'] else element.ServiceState.ONLINE.value)
node.status = (
element.ServiceState.DISABLED.value
if node_data['host'] else element.ServiceState.ENABLED.value)
def create_compute_node(self, node_hostname):
"""Update the compute node by querying the Nova API."""
try:
_node = self.nova.get_compute_node_by_hostname(node_hostname)
node = element.ComputeNode(_node.id)
node.uuid = node_hostname
node.hostname = _node.hypervisor_hostname
node.state = _node.state
node.status = _node.status
self.update_capacity(
element.ResourceType.memory, node, _node.memory_mb)
self.update_capacity(
element.ResourceType.cpu_cores, node, _node.vcpus)
self.update_capacity(
element.ResourceType.disk, node, _node.free_disk_gb)
self.update_capacity(
element.ResourceType.disk_capacity, node, _node.local_gb)
return node
except Exception as exc:
LOG.exception(exc)
LOG.debug("Could not refresh the node %s.", node_hostname)
raise exception.ComputeNodeNotFound(name=node_hostname)
return False
def get_or_create_node(self, uuid):
if uuid is None:
LOG.debug("Compute node UUID not provided: skipping")
return
try:
node = self.cluster_data_model.get_node_from_id(uuid)
return self.cluster_data_model.get_node_by_uuid(uuid)
except exception.ComputeNodeNotFound:
# The node didn't exist yet so we create a new node object
node = self.create_compute_node(uuid)
LOG.debug("New compute node created: %s", uuid)
node = element.ComputeNode()
node.uuid = uuid
self.cluster_data_model.add_node(node)
return node
return node
def update_instance_mapping(self, instance, node):
if not node:
if node is None:
self.cluster_data_model.add_instance(instance)
LOG.debug("Instance %s not yet attached to any node: skipping",
instance.uuid)
return
try:
old_node = self.get_or_create_node(node.uuid)
try:
old_node = self.get_or_create_node(node.uuid)
except exception.ComputeNodeNotFound as exc:
LOG.exception(exc)
# If we can't create the node,
# we consider the instance as unmapped
old_node = None
LOG.debug("Mapped node %s found", node.uuid)
if node and node != old_node:
LOG.debug("Unmapping instance %s from %s",
@@ -126,8 +193,7 @@ class NovaNotification(base.NotificationEndpoint):
def delete_instance(self, instance, node):
try:
self.cluster_data_model.delete_instance(instance, node)
except Exception as exc:
LOG.exception(exc)
except Exception:
LOG.info(_LI("Instance %s already deleted"), instance.uuid)
@@ -150,19 +216,18 @@ class ServiceUpdated(VersionnedNotificationEndpoint):
)
def info(self, ctxt, publisher_id, event_type, payload, metadata):
LOG.info(_LI("Event '%(event)s' received from %(publisher)s") %
dict(event=event_type, publisher=publisher_id))
LOG.info(_LI("Event '%(event)s' received from %(publisher)s "
"with metadata %(metadata)s") %
dict(event=event_type,
publisher=publisher_id,
metadata=metadata))
node_data = payload['nova_object.data']
node_uuid = node_data['host']
node = self.get_or_create_node(node_uuid)
node.hostname = node_data['host']
node.state = (
element.ServiceState.OFFLINE.value
if node_data['forced_down'] else element.ServiceState.ONLINE.value)
node.status = (
element.ServiceState.DISABLED.value
if node_data['host'] else element.ServiceState.ENABLED.value)
try:
node = self.get_or_create_node(node_uuid)
self.update_compute_node(node, payload)
except exception.ComputeNodeNotFound as exc:
LOG.exception(exc)
class InstanceCreated(VersionnedNotificationEndpoint):
@@ -192,8 +257,11 @@ class InstanceCreated(VersionnedNotificationEndpoint):
)
def info(self, ctxt, publisher_id, event_type, payload, metadata):
LOG.info(_LI("Event '%(event)s' received from %(publisher)s") %
dict(event=event_type, publisher=publisher_id))
LOG.info(_LI("Event '%(event)s' received from %(publisher)s "
"with metadata %(metadata)s") %
dict(event=event_type,
publisher=publisher_id,
metadata=metadata))
instance_data = payload['nova_object.data']
instance_uuid = instance_data['uuid']
@@ -221,8 +289,11 @@ class InstanceUpdated(VersionnedNotificationEndpoint):
)
def info(self, ctxt, publisher_id, event_type, payload, metadata):
LOG.info(_LI("Event '%(event)s' received from %(publisher)s") %
dict(event=event_type, publisher=publisher_id))
LOG.info(_LI("Event '%(event)s' received from %(publisher)s "
"with metadata %(metadata)s") %
dict(event=event_type,
publisher=publisher_id,
metadata=metadata))
instance_data = payload['nova_object.data']
instance_uuid = instance_data['uuid']
instance = self.get_or_create_instance(instance_uuid)
@@ -241,14 +312,22 @@ class InstanceDeletedEnd(VersionnedNotificationEndpoint):
)
def info(self, ctxt, publisher_id, event_type, payload, metadata):
LOG.info(_LI("Event '%(event)s' received from %(publisher)s") %
dict(event=event_type, publisher=publisher_id))
LOG.info(_LI("Event '%(event)s' received from %(publisher)s "
"with metadata %(metadata)s") %
dict(event=event_type,
publisher=publisher_id,
metadata=metadata))
instance_data = payload['nova_object.data']
instance_uuid = instance_data['uuid']
instance = self.get_or_create_instance(instance_uuid)
node = self.get_or_create_node(instance_data['host'])
try:
node = self.get_or_create_node(instance_data['host'])
except exception.ComputeNodeNotFound as exc:
LOG.exception(exc)
# If we can't create the node, we consider the instance as unmapped
node = None
self.delete_instance(instance, node)
@@ -264,8 +343,11 @@ class LegacyInstanceUpdated(UnversionnedNotificationEndpoint):
)
def info(self, ctxt, publisher_id, event_type, payload, metadata):
LOG.info(_LI("Event '%(event)s' received from %(publisher)s") %
dict(event=event_type, publisher=publisher_id))
LOG.info(_LI("Event '%(event)s' received from %(publisher)s "
"with metadata %(metadata)s") %
dict(event=event_type,
publisher=publisher_id,
metadata=metadata))
instance_uuid = payload['instance_id']
instance = self.get_or_create_instance(instance_uuid)
@@ -284,8 +366,11 @@ class LegacyInstanceCreatedEnd(UnversionnedNotificationEndpoint):
)
def info(self, ctxt, publisher_id, event_type, payload, metadata):
LOG.info(_LI("Event '%(event)s' received from %(publisher)s") %
dict(event=event_type, publisher=publisher_id))
LOG.info(_LI("Event '%(event)s' received from %(publisher)s "
"with metadata %(metadata)s") %
dict(event=event_type,
publisher=publisher_id,
metadata=metadata))
instance_uuid = payload['instance_id']
instance = self.get_or_create_instance(instance_uuid)
@@ -304,12 +389,20 @@ class LegacyInstanceDeletedEnd(UnversionnedNotificationEndpoint):
)
def info(self, ctxt, publisher_id, event_type, payload, metadata):
LOG.info(_LI("Event '%(event)s' received from %(publisher)s") %
dict(event=event_type, publisher=publisher_id))
LOG.info(_LI("Event '%(event)s' received from %(publisher)s "
"with metadata %(metadata)s") %
dict(event=event_type,
publisher=publisher_id,
metadata=metadata))
instance_uuid = payload['instance_id']
instance = self.get_or_create_instance(instance_uuid)
node = self.get_or_create_node(payload['host'])
try:
node = self.get_or_create_node(payload['host'])
except exception.ComputeNodeNotFound as exc:
LOG.exception(exc)
# If we can't create the node, we consider the instance as unmapped
node = None
self.delete_instance(instance, node)
@@ -325,8 +418,11 @@ class LegacyLiveMigratedEnd(UnversionnedNotificationEndpoint):
)
def info(self, ctxt, publisher_id, event_type, payload, metadata):
LOG.info(_LI("Event '%(event)s' received from %(publisher)s") %
dict(event=event_type, publisher=publisher_id))
LOG.info(_LI("Event '%(event)s' received from %(publisher)s "
"with metadata %(metadata)s") %
dict(event=event_type,
publisher=publisher_id,
metadata=metadata))
instance_uuid = payload['instance_id']
instance = self.get_or_create_instance(instance_uuid)