Skip to content

Commit

Permalink
Transform scheduler.select_destinations notification
Browse files Browse the repository at this point in the history
Transform the scheduler.select_destinations.start and
scheduler.select_destinations.end notifications to the
versioned notification framework.

Change-Id: I019e88fabd1d386c0d6395a7b1969315873485fd
Implements: bp versioned-notification-transformation-stein
  • Loading branch information
Előd Illés committed Nov 30, 2018
1 parent fe4e47d commit 70c7ba7
Show file tree
Hide file tree
Showing 16 changed files with 462 additions and 63 deletions.
16 changes: 15 additions & 1 deletion doc/notification_samples/common_payloads/ComputeTaskPayload.json
Expand Up @@ -5,7 +5,21 @@
"nova_object.data": {
"instance_uuid": "d5e6a7b7-80e5-4166-85a3-cd6115201082",
"reason": {"$ref": "ExceptionPayload.json#"},
"request_spec": {"$ref": "RequestSpecPayload.json#"},
"request_spec": {
"$ref": "RequestSpecPayload.json#",
"nova_object.data": {
"flavor": {
"nova_object.data": {
"extra_specs": {
"hw:numa_cpus.0": "0",
"hw:numa_mem.0": "512",
"hw:numa_nodes": "1"
}
}
},
"numa_topology": {"$ref": "InstanceNUMATopologyPayload.json#"}
}
},
"state": "error"
}
}
23 changes: 11 additions & 12 deletions doc/notification_samples/common_payloads/RequestSpecPayload.json
Expand Up @@ -2,24 +2,23 @@
"nova_object.namespace": "nova",
"nova_object.data": {
"availability_zone": null,
"flavor": {
"$ref": "FlavorPayload.json#",
"nova_object.data": {
"extra_specs": {
"hw:numa_cpus.0": "0",
"hw:numa_mem.0": "512",
"hw:numa_nodes": "1"
}
}
},
"flavor": {"$ref": "FlavorPayload.json#"},
"ignore_hosts": null,
"image": {"$ref": "ImageMetaPayload.json#"},
"instance_uuid": "d5e6a7b7-80e5-4166-85a3-cd6115201082",
"num_instances": 1,
"numa_topology": {"$ref": "InstanceNUMATopologyPayload.json#"},
"numa_topology": null,
"pci_requests": {"$ref": "InstancePCIRequestsPayload.json#"},
"project_id": "6f70656e737461636b20342065766572",
"scheduler_hints": {},
"security_groups": ["default"],
"force_hosts": null,
"force_nodes": null,
"instance_group": null,
"requested_destination": null,
"retry": null,
"user_id": "fake"
},
"nova_object.name": "RequestSpecPayload",
"nova_object.version": "1.0"
"nova_object.version": "1.1"
}
@@ -0,0 +1,6 @@
{
"priority": "INFO",
"payload": {"$ref": "common_payloads/RequestSpecPayload.json#"},
"event_type": "scheduler.select_destinations.end",
"publisher_id": "nova-scheduler:fake-mini"
}
@@ -0,0 +1,6 @@
{
"priority": "INFO",
"payload": {"$ref": "common_payloads/RequestSpecPayload.json#"},
"event_type": "scheduler.select_destinations.start",
"publisher_id": "nova-scheduler:fake-mini"
}
27 changes: 27 additions & 0 deletions nova/compute/utils.py
Expand Up @@ -43,6 +43,8 @@
from nova.notifications.objects import keypair as keypair_notification
from nova.notifications.objects import libvirt as libvirt_notification
from nova.notifications.objects import metrics as metrics_notification
from nova.notifications.objects import request_spec as reqspec_notification
from nova.notifications.objects import scheduler as scheduler_notification
from nova.notifications.objects import server_group as sg_notification
from nova.notifications.objects import volume as volume_notification
from nova import objects
Expand Down Expand Up @@ -471,6 +473,31 @@ def notify_about_instance_create(context, instance, host, phase=None,
notification.emit(context)


@rpc.if_notifications_enabled
def notify_about_scheduler_action(context, request_spec, action, phase=None,
source=fields.NotificationSource.SCHEDULER):
"""Send versioned notification about the action made by the scheduler
:param context: the RequestContext object
:param request_spec: the RequestSpec object
:param action: the name of the action
:param phase: the phase of the action
:param source: the source of the notification
"""
payload = reqspec_notification.RequestSpecPayload(
request_spec=request_spec)
notification = scheduler_notification.SelectDestinationsNotification(
context=context,
priority=fields.NotificationPriority.INFO,
publisher=notification_base.NotificationPublisher(
host=CONF.host, source=source),
event_type=notification_base.EventType(
object='scheduler',
action=action,
phase=phase),
payload=payload)
notification.emit(context)


@rpc.if_notifications_enabled
def notify_about_volume_attach_detach(context, instance, host, action, phase,
volume_id=None, exception=None, tb=None):
Expand Down
4 changes: 3 additions & 1 deletion nova/notifications/objects/base.py
Expand Up @@ -69,7 +69,9 @@ class EventType(NotificationObject):
# Version 1.17: USAGE is added to NotificationActionField enum
# Version 1.18: ComputeTask related values have been added to
# NotificationActionField enum
VERSION = '1.18'
# Version 1.19: SELECT_DESTINATIONS is added to the NotificationActionField
# enum
VERSION = '1.19'

fields = {
'object': fields.StringField(nullable=False),
Expand Down
128 changes: 125 additions & 3 deletions nova/notifications/objects/request_spec.py
Expand Up @@ -15,21 +15,27 @@
from nova.notifications.objects import base
from nova.notifications.objects import flavor as flavor_payload
from nova.notifications.objects import image as image_payload
from nova.notifications.objects import server_group as server_group_payload
from nova.objects import base as nova_base
from nova.objects import fields


@nova_base.NovaObjectRegistry.register_notification
class RequestSpecPayload(base.NotificationPayloadBase):
# Version 1.0: Initial version
VERSION = '1.0'
# Version 1.1: Add force_hosts, force_nodes, ignore_hosts, image_meta,
# instance_group, requested_destination, retry,
# scheduler_hints and security_groups fields
VERSION = '1.1'

SCHEMA = {
'ignore_hosts': ('request_spec', 'ignore_hosts'),
'instance_uuid': ('request_spec', 'instance_uuid'),
'project_id': ('request_spec', 'project_id'),
'user_id': ('request_spec', 'user_id'),
'availability_zone': ('request_spec', 'availability_zone'),
'num_instances': ('request_spec', 'num_instances')
'num_instances': ('request_spec', 'num_instances'),
'scheduler_hints': ('request_spec', 'scheduler_hints'),
}

fields = {
Expand All @@ -38,12 +44,23 @@ class RequestSpecPayload(base.NotificationPayloadBase):
'user_id': fields.StringField(nullable=True),
'availability_zone': fields.StringField(nullable=True),
'flavor': fields.ObjectField('FlavorPayload', nullable=True),
'force_hosts': fields.StringField(nullable=True),
'force_nodes': fields.StringField(nullable=True),
'ignore_hosts': fields.ListOfStringsField(nullable=True),
'image_meta': fields.ObjectField('ImageMetaPayload', nullable=True),
'instance_group': fields.ObjectField('ServerGroupPayload',
nullable=True),
'image': fields.ObjectField('ImageMetaPayload', nullable=True),
'numa_topology': fields.ObjectField('InstanceNUMATopologyPayload',
nullable=True),
'pci_requests': fields.ObjectField('InstancePCIRequestsPayload',
nullable=True),
'num_instances': fields.IntegerField(default=1)
'num_instances': fields.IntegerField(default=1),
'requested_destination': fields.ObjectField('DestinationPayload',
nullable=True),
'retry': fields.ObjectField('SchedulerRetriesPayload', nullable=True),
'scheduler_hints': fields.DictOfListOfStringsField(nullable=True),
'security_groups': fields.ListOfStringsField(),
}

def __init__(self, request_spec):
Expand All @@ -69,6 +86,32 @@ def __init__(self, request_spec):
request_spec.pci_requests)
else:
self.pci_requests = None
if 'requested_destination' in request_spec \
and request_spec.requested_destination:
self.requested_destination = DestinationPayload(
destination=request_spec.requested_destination)
else:
self.requested_destination = None
if 'retry' in request_spec and request_spec.retry:
self.retry = SchedulerRetriesPayload(
retry=request_spec.retry)
else:
self.retry = None
self.security_groups = [
sec_group.identifier for sec_group in request_spec.security_groups]
if 'instance_group' in request_spec and request_spec.instance_group:
self.instance_group = server_group_payload.ServerGroupPayload(
group=request_spec.instance_group)
else:
self.instance_group = None
if 'force_hosts' in request_spec and request_spec.force_hosts:
self.force_hosts = request_spec.force_hosts[0]
else:
self.force_hosts = None
if 'force_nodes' in request_spec and request_spec.force_nodes:
self.force_nodes = request_spec.force_nodes[0]
else:
self.force_nodes = None
self.populate_schema(request_spec=request_spec)


Expand Down Expand Up @@ -224,3 +267,82 @@ def from_pci_request_list_obj(cls, pci_request_list):
for pci_request in pci_request_list:
payloads.append(cls(pci_request))
return payloads


@nova_base.NovaObjectRegistry.register_notification
class DestinationPayload(base.NotificationPayloadBase):
# Version 1.0: Initial version
VERSION = '1.0'

SCHEMA = {
'aggregates': ('destination', 'aggregates'),
}

fields = {
'host': fields.StringField(),
'node': fields.StringField(nullable=True),
'cell': fields.ObjectField('CellMappingPayload', nullable=True),
'aggregates': fields.ListOfStringsField(nullable=True,
default=None),
}

def __init__(self, destination):
super(DestinationPayload, self).__init__()
if (destination.obj_attr_is_set('host') and
destination.host is not None):
self.host = destination.host
if (destination.obj_attr_is_set('node') and
destination.node is not None):
self.node = destination.node
if (destination.obj_attr_is_set('cell') and
destination.cell is not None):
self.cell = CellMappingPayload(destination.cell)
self.populate_schema(destination=destination)


@nova_base.NovaObjectRegistry.register_notification
class SchedulerRetriesPayload(base.NotificationPayloadBase):
# Version 1.0: Initial version
VERSION = '1.0'

SCHEMA = {
'num_attempts': ('retry', 'num_attempts'),
}

fields = {
'num_attempts': fields.IntegerField(),
'hosts': fields.ListOfStringsField(),
}

def __init__(self, retry):
super(SchedulerRetriesPayload, self).__init__()
self.hosts = []
for compute_node in retry.hosts:
self.hosts.append(compute_node.hypervisor_hostname)
self.populate_schema(retry=retry)


@nova_base.NovaObjectRegistry.register_notification
class CellMappingPayload(base.NotificationPayloadBase):
# Version 1.0: Initial version
VERSION = '1.0'

SCHEMA = {
'uuid': ('cell', 'uuid'),
'name': ('cell', 'name'),
'transport_url': ('cell', 'transport_url'),
'database_connection': ('cell', 'database_connection'),
'disabled': ('cell', 'disabled'),
}

fields = {
'uuid': fields.UUIDField(),
'name': fields.StringField(nullable=True),
'transport_url': fields.StringField(),
'database_connection': fields.StringField(),
'disabled': fields.BooleanField(default=False),
}

def __init__(self, cell):
super(CellMappingPayload, self).__init__()
self.populate_schema(cell=cell)
29 changes: 29 additions & 0 deletions nova/notifications/objects/scheduler.py
@@ -0,0 +1,29 @@
# Copyright 2017 Ericsson
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from nova.notifications.objects import base
from nova.objects import base as nova_base
from nova.objects import fields


@base.notification_sample('scheduler-select_destinations-start.json')
@base.notification_sample('scheduler-select_destinations-end.json')
@nova_base.NovaObjectRegistry.register_notification
class SelectDestinationsNotification(base.NotificationBase):
# Version 1.0: Initial version
VERSION = '1.0'

fields = {
'payload': fields.ObjectField('RequestSpecPayload')
}
4 changes: 3 additions & 1 deletion nova/objects/fields.py
Expand Up @@ -819,6 +819,7 @@ class NotificationAction(BaseNovaEnum):
RESIZE_CONFIRM = 'resize_confirm'
RESIZE_PREP = 'resize_prep'
RESIZE_REVERT = 'resize_revert'
SELECT_DESTINATIONS = 'select_destinations'
SHELVE_OFFLOAD = 'shelve_offload'
SOFT_DELETE = 'soft_delete'
TRIGGER_CRASH_DUMP = 'trigger_crash_dump'
Expand Down Expand Up @@ -848,7 +849,8 @@ class NotificationAction(BaseNovaEnum):
SOFT_DELETE, TRIGGER_CRASH_DUMP, UNRESCUE, UNSHELVE, ADD_HOST,
REMOVE_HOST, ADD_MEMBER, UPDATE_METADATA, LOCK, UNLOCK,
REBUILD_SCHEDULED, UPDATE_PROP, LIVE_MIGRATION_FORCE_COMPLETE,
CONNECT, USAGE, BUILD_INSTANCES, MIGRATE_SERVER, REBUILD_SERVER)
CONNECT, USAGE, BUILD_INSTANCES, MIGRATE_SERVER, REBUILD_SERVER,
SELECT_DESTINATIONS)


# TODO(rlrossit): These should be changed over to be a StateMachine enum from
Expand Down
10 changes: 10 additions & 0 deletions nova/scheduler/filter_scheduler.py
Expand Up @@ -24,10 +24,12 @@
from oslo_log import log as logging
from six.moves import range

from nova.compute import utils as compute_utils
import nova.conf
from nova import exception
from nova.i18n import _
from nova import objects
from nova.objects import fields as fields_obj
from nova import rpc
from nova.scheduler import client
from nova.scheduler import driver
Expand Down Expand Up @@ -85,13 +87,21 @@ def select_destinations(self, context, spec_obj, instance_uuids,
self.notifier.info(
context, 'scheduler.select_destinations.start',
dict(request_spec=spec_obj.to_legacy_request_spec_dict()))
compute_utils.notify_about_scheduler_action(
context=context, request_spec=spec_obj,
action=fields_obj.NotificationAction.SELECT_DESTINATIONS,
phase=fields_obj.NotificationPhase.START)

host_selections = self._schedule(context, spec_obj, instance_uuids,
alloc_reqs_by_rp_uuid, provider_summaries,
allocation_request_version, return_alternates)
self.notifier.info(
context, 'scheduler.select_destinations.end',
dict(request_spec=spec_obj.to_legacy_request_spec_dict()))
compute_utils.notify_about_scheduler_action(
context=context, request_spec=spec_obj,
action=fields_obj.NotificationAction.SELECT_DESTINATIONS,
phase=fields_obj.NotificationPhase.END)
return host_selections

def _schedule(self, context, spec_obj, instance_uuids,
Expand Down

0 comments on commit 70c7ba7

Please sign in to comment.