Transform scheduler.select_destinations notification
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
This commit is contained in:
parent
fe4e47d989
commit
70c7ba7324
@ -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"
|
||||
}
|
||||
}
|
||||
|
@ -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"
|
||||
}
|
@ -43,6 +43,8 @@ from nova.notifications.objects import instance as instance_notification
|
||||
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
|
||||
@ -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):
|
||||
|
@ -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),
|
||||
|
@ -15,6 +15,7 @@
|
||||
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
|
||||
|
||||
@ -22,14 +23,19 @@ 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 = {
|
||||
@ -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):
|
||||
@ -69,6 +86,32 @@ class RequestSpecPayload(base.NotificationPayloadBase):
|
||||
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)
|
||||
|
||||
|
||||
@ -224,3 +267,82 @@ class InstancePCIRequestPayload(base.NotificationPayloadBase):
|
||||
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
nova/notifications/objects/scheduler.py
Normal file
29
nova/notifications/objects/scheduler.py
Normal file
@ -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')
|
||||
}
|
@ -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'
|
||||
@ -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
|
||||
|
@ -24,10 +24,12 @@ import random
|
||||
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
|
||||
@ -85,6 +87,10 @@ class FilterScheduler(driver.Scheduler):
|
||||
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,
|
||||
@ -92,6 +98,10 @@ class FilterScheduler(driver.Scheduler):
|
||||
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,
|
||||
|
@ -156,6 +156,23 @@ class NotificationSampleTestBase(test.TestCase,
|
||||
|
||||
self.assertJsonEqual(sample_obj, notification)
|
||||
|
||||
def _pop_and_verify_dest_select_notification(self,
|
||||
server_id, replacements=None):
|
||||
replacements = replacements or {}
|
||||
replacements['instance_uuid'] = server_id
|
||||
replacements['pci_requests.instance_uuid'] = server_id
|
||||
replacements['flavor.extra_specs'] = self.ANY
|
||||
replacements['numa_topology'] = self.ANY
|
||||
scheduler_expected_notifications = [
|
||||
'scheduler-select_destinations-start',
|
||||
'scheduler-select_destinations-end']
|
||||
self.assertLessEqual(2, len(fake_notifier.VERSIONED_NOTIFICATIONS))
|
||||
for notification in scheduler_expected_notifications:
|
||||
self._verify_notification(
|
||||
notification,
|
||||
replacements=replacements,
|
||||
actual=fake_notifier.VERSIONED_NOTIFICATIONS.pop(0))
|
||||
|
||||
def _boot_a_server(self, expected_status='ACTIVE', extra_params=None,
|
||||
scheduler_hints=None, additional_extra_specs=None):
|
||||
|
||||
@ -227,6 +244,11 @@ class NotificationSampleTestBase(test.TestCase,
|
||||
expected_status)
|
||||
found_server['reservation_id'] = reservation_id
|
||||
|
||||
# Note(elod.illes): let's just pop and verify the dest_select
|
||||
# notifications if we don't have a special case
|
||||
if scheduler_hints is None and expected_status != 'ERROR':
|
||||
self._pop_and_verify_dest_select_notification(found_server['id'])
|
||||
|
||||
if found_server['status'] == 'ACTIVE':
|
||||
self.api.put_server_tags(found_server['id'], ['tag1'])
|
||||
return found_server
|
||||
|
@ -38,19 +38,22 @@ class TestComputeTaskNotificationSample(
|
||||
'hw:numa_cpus.0': '0',
|
||||
'hw:numa_mem.0': 512})
|
||||
self._wait_for_notification('compute_task.build_instances.error')
|
||||
self.assertEqual(1, len(fake_notifier.VERSIONED_NOTIFICATIONS))
|
||||
# 0. scheduler.select_destinations.start
|
||||
# 1. compute_task.rebuild_server.error
|
||||
self.assertEqual(2, len(fake_notifier.VERSIONED_NOTIFICATIONS))
|
||||
self._verify_notification(
|
||||
'compute_task-build_instances-error',
|
||||
replacements={
|
||||
'instance_uuid': server['id'],
|
||||
'request_spec.instance_uuid': server['id'],
|
||||
'request_spec.security_groups': [],
|
||||
'request_spec.numa_topology.instance_uuid': server['id'],
|
||||
'request_spec.pci_requests.instance_uuid': server['id'],
|
||||
'reason.function_name': self.ANY,
|
||||
'reason.module_name': self.ANY,
|
||||
'reason.traceback': self.ANY
|
||||
},
|
||||
actual=fake_notifier.VERSIONED_NOTIFICATIONS[0])
|
||||
actual=fake_notifier.VERSIONED_NOTIFICATIONS[1])
|
||||
|
||||
def test_rebuild_fault(self):
|
||||
server = self._boot_a_server(
|
||||
@ -72,20 +75,22 @@ class TestComputeTaskNotificationSample(
|
||||
self.admin_api.post_server_action(server['id'], post)
|
||||
self._wait_for_notification('compute_task.rebuild_server.error')
|
||||
# 0. instance.evacuate
|
||||
# 1. compute_task.rebuild_server.error
|
||||
self.assertEqual(2, len(fake_notifier.VERSIONED_NOTIFICATIONS))
|
||||
# 1. scheduler.select_destinations.start
|
||||
# 2. compute_task.rebuild_server.error
|
||||
self.assertEqual(3, len(fake_notifier.VERSIONED_NOTIFICATIONS))
|
||||
self._verify_notification(
|
||||
'compute_task-rebuild_server-error',
|
||||
replacements={
|
||||
'instance_uuid': server['id'],
|
||||
'request_spec.instance_uuid': server['id'],
|
||||
'request_spec.security_groups': [],
|
||||
'request_spec.numa_topology.instance_uuid': server['id'],
|
||||
'request_spec.pci_requests.instance_uuid': server['id'],
|
||||
'reason.function_name': self.ANY,
|
||||
'reason.module_name': self.ANY,
|
||||
'reason.traceback': self.ANY
|
||||
},
|
||||
actual=fake_notifier.VERSIONED_NOTIFICATIONS[1])
|
||||
actual=fake_notifier.VERSIONED_NOTIFICATIONS[2])
|
||||
|
||||
def test_migrate_fault(self):
|
||||
server = self._boot_a_server(
|
||||
@ -104,16 +109,19 @@ class TestComputeTaskNotificationSample(
|
||||
self.admin_api.post_server_action,
|
||||
server['id'], {'migrate': None})
|
||||
self._wait_for_notification('compute_task.migrate_server.error')
|
||||
self.assertEqual(1, len(fake_notifier.VERSIONED_NOTIFICATIONS))
|
||||
# 0. scheduler.select_destinations.start
|
||||
# 1. compute_task.migrate_server.error
|
||||
self.assertEqual(2, len(fake_notifier.VERSIONED_NOTIFICATIONS))
|
||||
self._verify_notification(
|
||||
'compute_task-migrate_server-error',
|
||||
replacements={
|
||||
'instance_uuid': server['id'],
|
||||
'request_spec.instance_uuid': server['id'],
|
||||
'request_spec.security_groups': [],
|
||||
'request_spec.numa_topology.instance_uuid': server['id'],
|
||||
'request_spec.pci_requests.instance_uuid': server['id'],
|
||||
'reason.function_name': self.ANY,
|
||||
'reason.module_name': self.ANY,
|
||||
'reason.traceback': self.ANY
|
||||
},
|
||||
actual=fake_notifier.VERSIONED_NOTIFICATIONS[0])
|
||||
actual=fake_notifier.VERSIONED_NOTIFICATIONS[1])
|
||||
|
@ -273,23 +273,25 @@ class TestInstanceNotificationSampleWithMultipleCompute(
|
||||
self._wait_for_notification(
|
||||
'instance.live_migration_force_complete.end')
|
||||
|
||||
# 0. instance.live_migration_pre.start
|
||||
# 1. instance.live_migration_pre.end
|
||||
# 2. instance.live_migration_force_complete.start
|
||||
# 3. instance.live_migration_force_complete.end
|
||||
self.assertEqual(4, len(fake_notifier.VERSIONED_NOTIFICATIONS))
|
||||
# 0. scheduler.select_destinations.start
|
||||
# 1. scheduler.select_destinations.end
|
||||
# 2. instance.live_migration_pre.start
|
||||
# 3. instance.live_migration_pre.end
|
||||
# 4. instance.live_migration_force_complete.start
|
||||
# 5. instance.live_migration_force_complete.end
|
||||
self.assertEqual(6, len(fake_notifier.VERSIONED_NOTIFICATIONS))
|
||||
self._verify_notification(
|
||||
'instance-live_migration_force_complete-start',
|
||||
replacements={
|
||||
'reservation_id': server['reservation_id'],
|
||||
'uuid': server['id']},
|
||||
actual=fake_notifier.VERSIONED_NOTIFICATIONS[2])
|
||||
actual=fake_notifier.VERSIONED_NOTIFICATIONS[4])
|
||||
self._verify_notification(
|
||||
'instance-live_migration_force_complete-end',
|
||||
replacements={
|
||||
'reservation_id': server['reservation_id'],
|
||||
'uuid': server['id']},
|
||||
actual=fake_notifier.VERSIONED_NOTIFICATIONS[3])
|
||||
actual=fake_notifier.VERSIONED_NOTIFICATIONS[5])
|
||||
|
||||
|
||||
class TestInstanceNotificationSampleWithMultipleComputeOldAttachFlow(
|
||||
@ -435,9 +437,13 @@ class TestInstanceNotificationSample(
|
||||
'tags': ['tag'],
|
||||
'trusted_image_certificates': fake_trusted_certs})
|
||||
|
||||
self.assertEqual(2, len(fake_notifier.VERSIONED_NOTIFICATIONS))
|
||||
# 0. scheduler.select_destinations.start
|
||||
# 1. scheduler.select_destinations.end
|
||||
# 2. instance-create-start
|
||||
# 3. instance-create-error
|
||||
self.assertEqual(4, len(fake_notifier.VERSIONED_NOTIFICATIONS))
|
||||
|
||||
tb = fake_notifier.VERSIONED_NOTIFICATIONS[1]['payload'][
|
||||
tb = fake_notifier.VERSIONED_NOTIFICATIONS[3]['payload'][
|
||||
'nova_object.data']['fault']['nova_object.data']['traceback']
|
||||
self.assertIn('raise exception.FlavorDiskTooSmall()', tb)
|
||||
|
||||
@ -446,14 +452,14 @@ class TestInstanceNotificationSample(
|
||||
replacements={
|
||||
'reservation_id': server['reservation_id'],
|
||||
'uuid': server['id']},
|
||||
actual=fake_notifier.VERSIONED_NOTIFICATIONS[0])
|
||||
actual=fake_notifier.VERSIONED_NOTIFICATIONS[2])
|
||||
self._verify_notification(
|
||||
'instance-create-error',
|
||||
replacements={
|
||||
'reservation_id': server['reservation_id'],
|
||||
'uuid': server['id'],
|
||||
'fault.traceback': self.ANY},
|
||||
actual=fake_notifier.VERSIONED_NOTIFICATIONS[1])
|
||||
actual=fake_notifier.VERSIONED_NOTIFICATIONS[3])
|
||||
|
||||
fake_notifier.reset()
|
||||
|
||||
@ -825,19 +831,19 @@ class TestInstanceNotificationSample(
|
||||
post = {'unshelve': None}
|
||||
self.api.post_server_action(server['id'], post)
|
||||
self._wait_for_state_change(self.admin_api, server, 'ACTIVE')
|
||||
self.assertEqual(7, len(fake_notifier.VERSIONED_NOTIFICATIONS))
|
||||
self.assertEqual(9, len(fake_notifier.VERSIONED_NOTIFICATIONS))
|
||||
self._verify_notification(
|
||||
'instance-unshelve-start',
|
||||
replacements={
|
||||
'reservation_id': server['reservation_id'],
|
||||
'uuid': server['id']},
|
||||
actual=fake_notifier.VERSIONED_NOTIFICATIONS[5])
|
||||
actual=fake_notifier.VERSIONED_NOTIFICATIONS[7])
|
||||
self._verify_notification(
|
||||
'instance-unshelve-end',
|
||||
replacements={
|
||||
'reservation_id': server['reservation_id'],
|
||||
'uuid': server['id']},
|
||||
actual=fake_notifier.VERSIONED_NOTIFICATIONS[6])
|
||||
actual=fake_notifier.VERSIONED_NOTIFICATIONS[8])
|
||||
|
||||
def _test_suspend_resume_server(self, server):
|
||||
post = {'suspend': {}}
|
||||
@ -920,6 +926,29 @@ class TestInstanceNotificationSample(
|
||||
'uuid': server['id']},
|
||||
actual=fake_notifier.VERSIONED_NOTIFICATIONS[3])
|
||||
|
||||
def _build_destination_payload(self):
|
||||
cell1 = self.cell_mappings.get('cell1')
|
||||
return {
|
||||
'nova_object.version': '1.0',
|
||||
'nova_object.namespace': 'nova',
|
||||
'nova_object.name': 'DestinationPayload',
|
||||
'nova_object.data': {
|
||||
'aggregates': None,
|
||||
'cell': {
|
||||
'nova_object.version': '1.0',
|
||||
'nova_object.namespace': 'nova',
|
||||
'nova_object.name': 'CellMappingPayload',
|
||||
'nova_object.data': {
|
||||
'database_connection': cell1.database_connection,
|
||||
'disabled': False,
|
||||
'name': u'cell1',
|
||||
'transport_url': u'fake://nowhere/',
|
||||
'uuid': cell1.uuid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def _test_resize_and_revert_server(self, server):
|
||||
self.flags(allow_resize_to_same_host=True)
|
||||
other_flavor_body = {
|
||||
@ -948,9 +977,19 @@ class TestInstanceNotificationSample(
|
||||
self.api.post_server_action(server['id'], post)
|
||||
self._wait_for_state_change(self.api, server, 'VERIFY_RESIZE')
|
||||
|
||||
self._pop_and_verify_dest_select_notification(server['id'],
|
||||
replacements={
|
||||
'ignore_hosts': [],
|
||||
'flavor.memory_mb': other_flavor_body['flavor']['ram'],
|
||||
'flavor.name': other_flavor_body['flavor']['name'],
|
||||
'flavor.flavorid': other_flavor_id,
|
||||
'flavor.extra_specs': extra_specs['extra_specs'],
|
||||
'requested_destination': self._build_destination_payload()})
|
||||
|
||||
self.assertEqual(7, len(fake_notifier.VERSIONED_NOTIFICATIONS))
|
||||
# ignore instance.exists
|
||||
fake_notifier.VERSIONED_NOTIFICATIONS.pop(0)
|
||||
|
||||
# This list needs to be in order.
|
||||
expected_notifications = [
|
||||
'instance-resize_prep-start',
|
||||
@ -1025,6 +1064,13 @@ class TestInstanceNotificationSample(
|
||||
mock_prep_resize.side_effect = _build_resources
|
||||
self.api.post_server_action(server['id'], post)
|
||||
self._wait_for_notification('instance.resize.error')
|
||||
self._pop_and_verify_dest_select_notification(server['id'],
|
||||
replacements={
|
||||
'ignore_hosts': [],
|
||||
'flavor.name': other_flavor_body['flavor']['name'],
|
||||
'flavor.flavorid': other_flavor_id,
|
||||
'flavor.extra_specs': {},
|
||||
'requested_destination': self._build_destination_payload()})
|
||||
# 0: instance-exists
|
||||
# 1: instance-resize_prep-start
|
||||
# 2: instance-resize-error
|
||||
@ -1089,7 +1135,8 @@ class TestInstanceNotificationSample(
|
||||
self.api.post_server_action(server['id'], post)
|
||||
self._wait_for_state_change(self.api, server, expected_status='ERROR')
|
||||
self._wait_for_notification('compute.exception')
|
||||
# There should be the following notifications.
|
||||
# There should be the following notifications after scheduler's
|
||||
# select_destination notifications:
|
||||
# 0: instance-exists
|
||||
# 1: instance-resize_prep-start
|
||||
# 2: instance-resize-error
|
||||
@ -1097,6 +1144,13 @@ class TestInstanceNotificationSample(
|
||||
# 4: compute.exception
|
||||
# (via the wrap_exception decorator on
|
||||
# the ComputeManager.prep_resize method.)
|
||||
self._pop_and_verify_dest_select_notification(server['id'],
|
||||
replacements={
|
||||
'ignore_hosts': [],
|
||||
'flavor.name': other_flavor_body['flavor']['name'],
|
||||
'flavor.flavorid': other_flavor_id,
|
||||
'flavor.extra_specs': {},
|
||||
'requested_destination': self._build_destination_payload()})
|
||||
self.assertEqual(5, len(fake_notifier.VERSIONED_NOTIFICATIONS),
|
||||
'Unexpected number of notifications: %s' %
|
||||
fake_notifier.VERSIONED_NOTIFICATIONS)
|
||||
@ -1146,10 +1200,11 @@ class TestInstanceNotificationSample(
|
||||
|
||||
fake_notifier.reset()
|
||||
|
||||
image_ref = 'a2459075-d96c-40d5-893e-577ff92e721c'
|
||||
post = {
|
||||
'rebuild': {
|
||||
'imageRef': 'a2459075-d96c-40d5-893e-577ff92e721c',
|
||||
'metadata': {},
|
||||
'imageRef': image_ref,
|
||||
'metadata': {}
|
||||
}
|
||||
}
|
||||
self.api.post_server_action(server['id'], post)
|
||||
@ -1160,6 +1215,22 @@ class TestInstanceNotificationSample(
|
||||
self._wait_for_state_change(self.api, server,
|
||||
expected_status='ACTIVE')
|
||||
|
||||
self._pop_and_verify_dest_select_notification(server['id'],
|
||||
replacements={
|
||||
'image.container_format': 'ami',
|
||||
'image.disk_format': 'ami',
|
||||
'image.id': image_ref,
|
||||
'image.properties': {
|
||||
'nova_object.data': {},
|
||||
'nova_object.name': 'ImageMetaPropsPayload',
|
||||
'nova_object.namespace': 'nova',
|
||||
'nova_object.version': u'1.0'},
|
||||
'image.size': 58145823,
|
||||
'image.tags': [],
|
||||
'scheduler_hints': {'_nova_check_type': ['rebuild']},
|
||||
'force_hosts': 'compute',
|
||||
'force_nodes': 'fake-mini'})
|
||||
|
||||
# 0. instance.rebuild_scheduled
|
||||
# 1. instance.exists
|
||||
# 2. instance.rebuild.start
|
||||
@ -1222,10 +1293,11 @@ class TestInstanceNotificationSample(
|
||||
|
||||
fake_notifier.reset()
|
||||
|
||||
image_ref = 'a2459075-d96c-40d5-893e-577ff92e721c'
|
||||
rebuild_trusted_certs = ['rebuild-cert-id-1', 'rebuild-cert-id-2']
|
||||
post = {
|
||||
'rebuild': {
|
||||
'imageRef': 'a2459075-d96c-40d5-893e-577ff92e721c',
|
||||
'imageRef': image_ref,
|
||||
'metadata': {},
|
||||
'trusted_image_certificates': rebuild_trusted_certs,
|
||||
}
|
||||
@ -1238,6 +1310,22 @@ class TestInstanceNotificationSample(
|
||||
self._wait_for_state_change(self.api, server,
|
||||
expected_status='ACTIVE')
|
||||
|
||||
self._pop_and_verify_dest_select_notification(server['id'],
|
||||
replacements={
|
||||
'image.container_format': 'ami',
|
||||
'image.disk_format': 'ami',
|
||||
'image.id': image_ref,
|
||||
'image.properties': {
|
||||
'nova_object.data': {},
|
||||
'nova_object.name': 'ImageMetaPropsPayload',
|
||||
'nova_object.namespace': 'nova',
|
||||
'nova_object.version': u'1.0'},
|
||||
'image.size': 58145823,
|
||||
'image.tags': [],
|
||||
'scheduler_hints': {'_nova_check_type': ['rebuild']},
|
||||
'force_hosts': 'compute',
|
||||
'force_nodes': 'fake-mini'})
|
||||
|
||||
# 0. instance.rebuild_scheduled
|
||||
# 1. instance.exists
|
||||
# 2. instance.rebuild.start
|
||||
|
@ -61,11 +61,13 @@ class TestServerGroupNotificationSample(
|
||||
scheduler_hints={"group": group['id']})
|
||||
self._wait_for_notification('instance.update')
|
||||
# 0: server_group.add_member
|
||||
# 1: instance.create.start
|
||||
# 2: instance.create.end
|
||||
# 3: instance.update
|
||||
# 1: scheduler-select_destinations-start
|
||||
# 2: scheduler-select_destinations-end
|
||||
# 3: instance.create.start
|
||||
# 4: instance.create.end
|
||||
# 5: instance.update
|
||||
# (Due to adding server tags in the '_boot_a_server' method.)
|
||||
self.assertEqual(4, len(fake_notifier.VERSIONED_NOTIFICATIONS))
|
||||
self.assertEqual(6, len(fake_notifier.VERSIONED_NOTIFICATIONS))
|
||||
self._verify_notification(
|
||||
'server_group-add_member',
|
||||
replacements={'uuid': group['id'],
|
||||
|
@ -370,9 +370,11 @@ notification_object_data = {
|
||||
'AuditPeriodPayload': '1.0-2b429dd307b8374636703b843fa3f9cb',
|
||||
'BandwidthPayload': '1.0-ee2616a7690ab78406842a2b68e34130',
|
||||
'BlockDevicePayload': '1.0-29751e1b6d41b1454e36768a1e764df8',
|
||||
'CellMappingPayload': '1.0-cf7faeb3cdd6b0c742ff74c80b88fb11',
|
||||
'ComputeTaskNotification': '1.0-a73147b93b520ff0061865849d3dfa56',
|
||||
'ComputeTaskPayload': '1.0-e3d34762c14d131c98337b72e8c600e1',
|
||||
'EventType': '1.18-44f33a06fd08fdba0b7dc266116c017b',
|
||||
'DestinationPayload': '1.0-4ccf26318dd18c4377dada2b1e74ec2e',
|
||||
'EventType': '1.19-000a76e83b06a9de11d365465a755a5e',
|
||||
'ExceptionNotification': '1.0-a73147b93b520ff0061865849d3dfa56',
|
||||
'ExceptionPayload': '1.1-6c43008bd81885a63bc7f7c629f0793b',
|
||||
'FlavorNotification': '1.0-a73147b93b520ff0061865849d3dfa56',
|
||||
@ -418,7 +420,9 @@ notification_object_data = {
|
||||
'MetricsNotification': '1.0-a73147b93b520ff0061865849d3dfa56',
|
||||
'MetricsPayload': '1.0-65c69b15b4de5a8c01971cb5bb9ab650',
|
||||
'NotificationPublisher': '2.2-b6ad48126247e10b46b6b0240e52e614',
|
||||
'RequestSpecPayload': '1.0-ef9936c8da44e442e397b02dec3f6914',
|
||||
'RequestSpecPayload': '1.1-64d30723a2e381d0cd6a16a877002c64',
|
||||
'SchedulerRetriesPayload': '1.0-03a07d09575ef52cced5b1b24301d0b4',
|
||||
'SelectDestinationsNotification': '1.0-a73147b93b520ff0061865849d3dfa56',
|
||||
'ServerGroupNotification': '1.0-a73147b93b520ff0061865849d3dfa56',
|
||||
'ServerGroupPayload': '1.1-4ded2997ea1b07038f7af33ef5c45f7f',
|
||||
'ServiceStatusNotification': '1.0-a73147b93b520ff0061865849d3dfa56',
|
||||
|
@ -83,7 +83,10 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
|
||||
root_gb=512,
|
||||
ephemeral_gb=0,
|
||||
swap=0,
|
||||
vcpus=1),
|
||||
vcpus=1,
|
||||
disabled=False,
|
||||
is_public=True,
|
||||
name="small_flavor"),
|
||||
project_id=uuids.project_id,
|
||||
instance_group=None, instance_uuid=uuids.instance)
|
||||
# Reset the RequestSpec changes so they don't interfere with the
|
||||
@ -149,7 +152,10 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
|
||||
root_gb=512,
|
||||
ephemeral_gb=0,
|
||||
swap=0,
|
||||
vcpus=1),
|
||||
vcpus=1,
|
||||
disabled=False,
|
||||
is_public=True,
|
||||
name="small_flavor"),
|
||||
project_id=uuids.project_id,
|
||||
instance_group=group)
|
||||
|
||||
@ -198,7 +204,10 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
|
||||
root_gb=512,
|
||||
ephemeral_gb=0,
|
||||
swap=0,
|
||||
vcpus=1),
|
||||
vcpus=1,
|
||||
disabled=False,
|
||||
is_public=True,
|
||||
name="small_flavor"),
|
||||
project_id=uuids.project_id,
|
||||
instance_group=None)
|
||||
|
||||
@ -268,7 +277,10 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
|
||||
root_gb=512,
|
||||
ephemeral_gb=0,
|
||||
swap=0,
|
||||
vcpus=1),
|
||||
vcpus=1,
|
||||
disabled=False,
|
||||
is_public=True,
|
||||
name="small_flavor"),
|
||||
project_id=uuids.project_id,
|
||||
instance_group=None)
|
||||
|
||||
@ -321,7 +333,10 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
|
||||
root_gb=512,
|
||||
ephemeral_gb=0,
|
||||
swap=0,
|
||||
vcpus=1),
|
||||
vcpus=1,
|
||||
disabled=False,
|
||||
is_public=True,
|
||||
name="small_flavor"),
|
||||
project_id=uuids.project_id,
|
||||
instance_group=None)
|
||||
|
||||
@ -500,7 +515,10 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
|
||||
root_gb=512,
|
||||
ephemeral_gb=0,
|
||||
swap=0,
|
||||
vcpus=1),
|
||||
vcpus=1,
|
||||
disabled=False,
|
||||
is_public=True,
|
||||
name="small_flavor"),
|
||||
project_id=uuids.project_id,
|
||||
instance_group=ig, instance_uuid=uuids.instance0)
|
||||
# Reset the RequestSpec changes so they don't interfere with the
|
||||
@ -765,9 +783,16 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
|
||||
root_gb=512,
|
||||
ephemeral_gb=0,
|
||||
swap=0,
|
||||
vcpus=1),
|
||||
vcpus=1,
|
||||
disabled=False,
|
||||
is_public=True,
|
||||
name="small_flavor"),
|
||||
project_id=uuids.project_id,
|
||||
num_instances=1)
|
||||
num_instances=1,
|
||||
image=None,
|
||||
numa_topology=None,
|
||||
pci_requests=None,
|
||||
instance_uuid=uuids.instance_id)
|
||||
|
||||
mock_schedule.return_value = [[fake_selection]]
|
||||
dests = self.driver.select_destinations(self.context, spec_obj,
|
||||
@ -793,9 +818,16 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
|
||||
root_gb=512,
|
||||
ephemeral_gb=0,
|
||||
swap=0,
|
||||
vcpus=1),
|
||||
vcpus=1,
|
||||
disabled=False,
|
||||
is_public=True,
|
||||
name="small_flavor"),
|
||||
project_id=uuids.project_id,
|
||||
num_instances=2)
|
||||
num_instances=2,
|
||||
image=None,
|
||||
numa_topology=None,
|
||||
pci_requests=None,
|
||||
instance_uuid=uuids.instance_id)
|
||||
|
||||
mock_schedule.return_value = [[fake_selection]]
|
||||
dests = self.driver.select_destinations(self.context, spec_obj,
|
||||
@ -824,8 +856,12 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
|
||||
root_gb=512,
|
||||
ephemeral_gb=0,
|
||||
swap=0,
|
||||
vcpus=1),
|
||||
vcpus=1,
|
||||
disabled=False,
|
||||
is_public=True,
|
||||
name="small_flavor"),
|
||||
project_id=uuids.project_id,
|
||||
instance_uuid=uuids.instance_id,
|
||||
instance_group=None)
|
||||
|
||||
host_state = mock.Mock(spec=host_manager.HostState, host="fake_host",
|
||||
@ -1020,16 +1056,32 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
|
||||
self._test_not_enough_alternates(num_hosts=3, max_attempts=5)
|
||||
self._test_not_enough_alternates(num_hosts=20, max_attempts=5)
|
||||
|
||||
@mock.patch('nova.compute.utils.notify_about_scheduler_action')
|
||||
@mock.patch.object(filter_scheduler.FilterScheduler, '_schedule')
|
||||
def test_select_destinations_notifications(self, mock_schedule):
|
||||
def test_select_destinations_notifications(self, mock_schedule,
|
||||
mock_notify):
|
||||
mock_schedule.return_value = ([[mock.Mock()]], [[mock.Mock()]])
|
||||
|
||||
with mock.patch.object(self.driver.notifier, 'info') as mock_info:
|
||||
flavor = objects.Flavor(memory_mb=512,
|
||||
root_gb=512,
|
||||
ephemeral_gb=0,
|
||||
swap=0,
|
||||
vcpus=1,
|
||||
disabled=False,
|
||||
is_public=True,
|
||||
name="small_flavor")
|
||||
expected = {'num_instances': 1,
|
||||
'instance_properties': {'uuid': uuids.instance},
|
||||
'instance_type': {},
|
||||
'instance_properties': {
|
||||
'uuid': uuids.instance,
|
||||
'ephemeral_gb': 0,
|
||||
'memory_mb': 512,
|
||||
'vcpus': 1,
|
||||
'root_gb': 512},
|
||||
'instance_type': flavor,
|
||||
'image': {}}
|
||||
spec_obj = objects.RequestSpec(num_instances=1,
|
||||
flavor=flavor,
|
||||
instance_uuid=uuids.instance)
|
||||
|
||||
self.driver.select_destinations(self.context, spec_obj,
|
||||
@ -1042,6 +1094,12 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
|
||||
dict(request_spec=expected))]
|
||||
self.assertEqual(expected, mock_info.call_args_list)
|
||||
|
||||
mock_notify.assert_has_calls([
|
||||
mock.call(context=self.context, request_spec=spec_obj,
|
||||
action='select_destinations', phase='start'),
|
||||
mock.call(context=self.context, request_spec=spec_obj,
|
||||
action='select_destinations', phase='end')])
|
||||
|
||||
def test_get_all_host_states_provider_summaries_is_none(self):
|
||||
"""Tests that HostManager.get_host_states_by_uuids is called with
|
||||
compute_uuids being None when the incoming provider_summaries is None.
|
||||
|
Loading…
Reference in New Issue
Block a user