Merge "Send Instance object to cells instance_update_at_top"

This commit is contained in:
Jenkins 2015-06-12 01:33:13 +00:00 committed by Gerrit Code Review
commit bf7e5873c5
24 changed files with 343 additions and 422 deletions

View File

@ -76,7 +76,7 @@ class CellsManager(manager.Manager):
Scheduling requests get passed to the scheduler class.
"""
target = oslo_messaging.Target(version='1.34')
target = oslo_messaging.Target(version='1.35')
def __init__(self, *args, **kwargs):
LOG.warning(_LW('The cells feature of Nova is considered experimental '
@ -179,7 +179,7 @@ class CellsManager(manager.Manager):
if not instance_uuid:
return
try:
instance = self.db.instance_get_by_uuid(rd_context,
instance = objects.Instance.get_by_uuid(rd_context,
instance_uuid)
except exception.InstanceNotFound:
continue
@ -190,7 +190,7 @@ class CellsManager(manager.Manager):
"""Broadcast an instance_update or instance_destroy message up to
parent cells.
"""
if instance['deleted']:
if instance.deleted:
self.instance_destroy_at_top(ctxt, instance)
else:
self.instance_update_at_top(ctxt, instance)
@ -428,11 +428,11 @@ class CellsManager(manager.Manager):
def validate_console_port(self, ctxt, instance_uuid, console_port,
console_type):
"""Validate console port with child cell compute node."""
instance = self.db.instance_get_by_uuid(ctxt, instance_uuid)
if not instance['cell_name']:
instance = objects.Instance.get_by_uuid(ctxt, instance_uuid)
if not instance.cell_name:
raise exception.InstanceUnknownCell(instance_uuid=instance_uuid)
response = self.msg_runner.validate_console_port(ctxt,
instance['cell_name'], instance_uuid, console_port,
instance.cell_name, instance_uuid, console_port,
console_type)
return response.value_or_raise()

View File

@ -53,7 +53,6 @@ from nova import context
from nova.db import base
from nova import exception
from nova.i18n import _, _LE, _LI, _LW
from nova.network import model as network_model
from nova import objects
from nova.objects import base as objects_base
from nova import rpc
@ -683,7 +682,8 @@ class _TargetedMessageMethods(_BaseMessageMethods):
# Must be a race condition. Let's try to resolve it by
# telling the top level cells that this instance doesn't
# exist.
instance = {'uuid': instance_uuid}
instance = objects.Instance(context=message.ctxt,
uuid=instance_uuid)
self.msg_runner.instance_destroy_at_top(message.ctxt,
instance)
return fn(message.ctxt, *args, **method_info['method_kwargs'])
@ -782,14 +782,15 @@ class _TargetedMessageMethods(_BaseMessageMethods):
# 1st arg is instance_uuid that we need to turn into the
# instance object.
try:
instance = self.db.instance_get_by_uuid(message.ctxt,
instance = objects.Instance.get_by_uuid(message.ctxt,
instance_uuid)
except exception.InstanceNotFound:
with excutils.save_and_reraise_exception():
# Must be a race condition. Let's try to resolve it by
# telling the top level cells that this instance doesn't
# exist.
instance = {'uuid': instance_uuid}
instance = objects.Instance(context=message.ctxt,
uuid=instance_uuid)
self.msg_runner.instance_destroy_at_top(message.ctxt,
instance)
return self.compute_rpcapi.validate_console_port(message.ctxt,
@ -826,7 +827,8 @@ class _TargetedMessageMethods(_BaseMessageMethods):
# Must be a race condition. Let's try to resolve it by
# telling the top level cells that this instance doesn't
# exist.
instance = {'uuid': instance.uuid}
instance = objects.Instance(context=ctxt,
uuid=instance.uuid)
self.msg_runner.instance_destroy_at_top(ctxt,
instance)
except exception.InstanceInfoCacheNotFound:
@ -953,11 +955,10 @@ class _BroadcastMessageMethods(_BaseMessageMethods):
"""Are we the API level?"""
return not self.state_manager.get_parent_cells()
def _apply_expected_states(self, instance_info):
def _get_expected_vm_state(self, instance):
"""To attempt to address out-of-order messages, do some sanity
checking on the VM and task states. Add some requirements for
vm_state and task_state to the instance_update() DB call if
necessary.
checking on the VM states. Add some requirements for
vm_state to the instance.save() call if necessary.
"""
expected_vm_state_map = {
# For updates containing 'vm_state' of 'building',
@ -967,6 +968,14 @@ class _BroadcastMessageMethods(_BaseMessageMethods):
# start out in 'building' anyway.. but just in case.
vm_states.BUILDING: [vm_states.BUILDING, None]}
if instance.obj_attr_is_set('vm_state'):
return expected_vm_state_map.get(instance.vm_state)
def _get_expected_task_state(self, instance):
"""To attempt to address out-of-order messages, do some sanity
checking on the task states. Add some requirements for
task_state to the instance.save() call if necessary.
"""
expected_task_state_map = {
# Always allow updates when task_state doesn't change,
# but also make sure we don't set resize/rebuild task
@ -994,20 +1003,13 @@ class _BroadcastMessageMethods(_BaseMessageMethods):
task_states.RESIZE_MIGRATING,
task_states.RESIZE_PREP]}
if 'vm_state' in instance_info:
expected = expected_vm_state_map.get(instance_info['vm_state'])
if expected is not None:
instance_info['expected_vm_state'] = expected
if 'task_state' in instance_info:
expected = expected_task_state_map.get(instance_info['task_state'])
if expected is not None:
instance_info['expected_task_state'] = expected
if instance.obj_attr_is_set('task_state'):
return expected_task_state_map.get(instance.task_state)
def instance_update_at_top(self, message, instance, **kwargs):
"""Update an instance in the DB if we're a top level cell."""
if not self._at_the_top():
return
instance_uuid = instance['uuid']
# Remove things that we can't update in the top level cells.
# 'metadata' is only updated in the API cell, so don't overwrite
@ -1015,63 +1017,40 @@ class _BroadcastMessageMethods(_BaseMessageMethods):
# 'cell_name' based on the routing path.
items_to_remove = ['id', 'security_groups', 'volumes', 'cell_name',
'name', 'metadata']
for key in items_to_remove:
instance.pop(key, None)
instance['cell_name'] = _reverse_path(message.routing_path)
# Fixup info_cache. We'll have to update this separately if
# it exists.
info_cache = instance.pop('info_cache', None)
if info_cache is not None:
info_cache.pop('id', None)
info_cache.pop('instance', None)
if 'system_metadata' in instance:
# Make sure we have the dict form that we need for
# instance_update.
instance['system_metadata'] = utils.instance_sys_meta(instance)
instance.obj_reset_changes(items_to_remove)
instance.cell_name = _reverse_path(message.routing_path)
LOG.debug("Got update for instance: %(instance)s",
{'instance': instance}, instance_uuid=instance_uuid)
{'instance': instance}, instance_uuid=instance.uuid)
self._apply_expected_states(instance)
expected_vm_state = self._get_expected_vm_state(instance)
expected_task_state = self._get_expected_task_state(instance)
# It's possible due to some weird condition that the instance
# was already set as deleted... so we'll attempt to update
# it with permissions that allows us to read deleted.
with utils.temporary_mutation(message.ctxt, read_deleted="yes"):
try:
self.db.instance_update(message.ctxt, instance_uuid,
instance, update_cells=False)
except exception.NotFound:
with instance.skip_cells_sync():
instance.save(expected_vm_state=expected_vm_state,
expected_task_state=expected_task_state)
except exception.InstanceNotFound:
# FIXME(comstud): Strange. Need to handle quotas here,
# if we actually want this code to remain..
self.db.instance_create(message.ctxt, instance)
if info_cache:
network_info = info_cache.get('network_info')
if isinstance(network_info, list):
if not isinstance(network_info, network_model.NetworkInfo):
network_info = network_model.NetworkInfo.hydrate(
network_info)
info_cache['network_info'] = network_info.json()
try:
self.db.instance_info_cache_update(
message.ctxt, instance_uuid, info_cache)
except exception.InstanceInfoCacheNotFound:
instance.create()
except exception.NotFound:
# Can happen if we try to update a deleted instance's
# network information.
# network information, for example.
pass
def instance_destroy_at_top(self, message, instance, **kwargs):
"""Destroy an instance from the DB if we're a top level cell."""
if not self._at_the_top():
return
instance_uuid = instance['uuid']
LOG.debug("Got update to delete instance",
instance_uuid=instance_uuid)
instance_uuid=instance.uuid)
try:
self.db.instance_destroy(message.ctxt, instance_uuid,
update_cells=False)
instance.destroy()
except exception.InstanceNotFound:
pass
@ -1108,7 +1087,7 @@ class _BroadcastMessageMethods(_BaseMessageMethods):
self.db.bw_usage_update(message.ctxt, **bw_update_info)
def _sync_instance(self, ctxt, instance):
if instance['deleted']:
if instance.deleted:
self.msg_runner.instance_destroy_at_top(ctxt, instance)
else:
self.msg_runner.instance_update_at_top(ctxt, instance)

View File

@ -30,6 +30,7 @@ from oslo_serialization import jsonutils
from nova import exception
from nova.i18n import _LE
from nova import objects
from nova.objects import base as objects_base
from nova import rpc
@ -112,6 +113,9 @@ class CellsAPI(object):
... Kilo supports message version 1.34. So, any changes to
existing methods in 1.x after that point should be done such that they
can handle the version_cap being set to 1.34.
* 1.35 - Make instance_update_at_top, instance_destroy_at_top
and instance_info_cache_update_at_top use instance objects
'''
VERSION_ALIASES = {
@ -191,16 +195,23 @@ class CellsAPI(object):
"""Update instance at API level."""
if not CONF.cells.enable:
return
# Make sure we have a dict, not a SQLAlchemy model
instance_p = jsonutils.to_primitive(instance)
self.client.cast(ctxt, 'instance_update_at_top', instance=instance_p)
version = '1.35'
if not self.client.can_send_version('1.35'):
instance = objects_base.obj_to_primitive(instance)
version = '1.34'
cctxt = self.client.prepare(version=version)
cctxt.cast(ctxt, 'instance_update_at_top', instance=instance)
def instance_destroy_at_top(self, ctxt, instance):
"""Destroy instance at API level."""
if not CONF.cells.enable:
return
instance_p = jsonutils.to_primitive(instance)
self.client.cast(ctxt, 'instance_destroy_at_top', instance=instance_p)
version = '1.35'
if not self.client.can_send_version('1.35'):
instance = objects_base.obj_to_primitive(instance)
version = '1.34'
cctxt = self.client.prepare(version=version)
cctxt.cast(ctxt, 'instance_destroy_at_top', instance=instance)
def instance_delete_everywhere(self, ctxt, instance, delete_type):
"""Delete instance everywhere. delete_type may be 'soft'
@ -246,10 +257,14 @@ class CellsAPI(object):
"""Broadcast up that an instance's info_cache has changed."""
if not CONF.cells.enable:
return
iicache = jsonutils.to_primitive(instance_info_cache)
instance = {'uuid': iicache['instance_uuid'],
'info_cache': iicache}
self.client.cast(ctxt, 'instance_update_at_top', instance=instance)
version = '1.35'
instance = objects.Instance(uuid=instance_info_cache.instance_uuid,
info_cache=instance_info_cache)
if not self.client.can_send_version('1.35'):
instance = objects_base.obj_to_primitive(instance)
version = '1.34'
cctxt = self.client.prepare(version=version)
cctxt.cast(ctxt, 'instance_update_at_top', instance=instance)
def get_cell_info_for_neighbors(self, ctxt):
"""Get information about our neighbor cells from the manager."""

View File

@ -121,8 +121,7 @@ class CellsScheduler(base.Base):
num_instances, i)
instances.append(instance)
instance_p = obj_base.obj_to_primitive(instance)
self.msg_runner.instance_update_at_top(ctxt, instance_p)
self.msg_runner.instance_update_at_top(ctxt, instance)
return instances
def _create_action_here(self, ctxt, instance_uuids):
@ -247,12 +246,11 @@ class CellsScheduler(base.Base):
{'instance_uuids': instance_uuids})
ctxt = message.ctxt
for instance_uuid in instance_uuids:
self.msg_runner.instance_update_at_top(ctxt,
{'uuid': instance_uuid,
'vm_state': vm_states.ERROR})
instance = objects.Instance(context=ctxt, uuid=instance_uuid,
vm_state=vm_states.ERROR)
self.msg_runner.instance_update_at_top(ctxt, instance)
try:
self.db.instance_update(ctxt,
instance_uuid,
{'vm_state': vm_states.ERROR})
instance.vm_state = vm_states.ERROR
instance.save()
except Exception:
pass

View File

@ -21,7 +21,6 @@ import sys
import six
from nova import db
from nova import exception
from nova import objects
from nova.objects import base as obj_base
@ -141,13 +140,15 @@ def get_instances_to_sync(context, updated_since=None, project_id=None,
if not deleted:
filters['deleted'] = False
# Active instances first.
instances = db.instance_get_all_by_filters(
context, filters, 'deleted', 'asc')
instances = objects.InstanceList.get_by_filters(
context, filters, sort_key='deleted', sort_dir='asc')
if shuffle:
# NOTE(melwitt): Need a list that supports assignment for shuffle.
instances = [instance for instance in instances]
random.shuffle(instances)
for instance in instances:
if uuids_only:
yield instance['uuid']
yield instance.uuid
else:
yield instance

View File

@ -40,7 +40,6 @@ from nova import image
from nova import manager
from nova import network
from nova.network.security_group import openstack_driver
from nova import notifications
from nova import objects
from nova.objects import base as nova_object
from nova import quota
@ -122,17 +121,11 @@ class ConductorManager(manager.Manager):
if key in datetime_fields and isinstance(value, six.string_types):
updates[key] = timeutils.parse_strtime(value)
# NOTE(danms): the send_update() call below is going to want to know
# about the flavor, so we need to join the appropriate things here,
# and objectify the result.
old_ref, instance_ref = self.db.instance_update_and_get_original(
context, instance_uuid, updates,
columns_to_join=['system_metadata'])
inst_obj = objects.Instance._from_db_object(
context, objects.Instance(),
instance_ref, expected_attrs=['system_metadata'])
notifications.send_update(context, old_ref, inst_obj, service)
return jsonutils.to_primitive(instance_ref)
instance = objects.Instance(context=context, uuid=instance_uuid,
**updates)
instance.obj_reset_changes(['uuid'])
instance.save()
return nova_object.obj_to_primitive(instance)
# NOTE(hanlind): This can be removed in version 3.0 of the RPC API
@messaging.expected_exceptions(exception.InstanceNotFound)
@ -245,8 +238,12 @@ class ConductorManager(manager.Manager):
# NOTE(hanlind): This can be removed in version 3.0 of the RPC API
def instance_destroy(self, context, instance):
result = self.db.instance_destroy(context, instance['uuid'])
return jsonutils.to_primitive(result)
if not isinstance(instance, objects.Instance):
instance = objects.Instance._from_db_object(context,
objects.Instance(),
instance)
instance.destroy()
return nova_object.obj_to_primitive(instance)
# NOTE(hanlind): This can be removed in version 3.0 of the RPC API
def instance_fault_create(self, context, values):

View File

@ -633,16 +633,9 @@ def instance_create(context, values):
return IMPL.instance_create(context, values)
def instance_destroy(context, instance_uuid, constraint=None,
update_cells=True):
def instance_destroy(context, instance_uuid, constraint=None):
"""Destroy the instance or raise if it does not exist."""
rv = IMPL.instance_destroy(context, instance_uuid, constraint)
if update_cells:
try:
cells_rpcapi.CellsAPI().instance_destroy_at_top(context, rv)
except Exception:
LOG.exception(_LE("Failed to notify cells of instance destroy"))
return rv
return IMPL.instance_destroy(context, instance_uuid, constraint)
def instance_get_by_uuid(context, uuid, columns_to_join=None, use_slave=False):
@ -737,26 +730,16 @@ def instance_get_all_hung_in_rebooting(context, reboot_window):
return IMPL.instance_get_all_hung_in_rebooting(context, reboot_window)
def instance_update(context, instance_uuid, values, update_cells=True):
def instance_update(context, instance_uuid, values):
"""Set the given properties on an instance and update it.
Raises NotFound if instance does not exist.
"""
rv = IMPL.instance_update(context, instance_uuid, values)
if update_cells:
try:
cells_rpcapi.CellsAPI().instance_update_at_top(context, rv)
except Exception:
LOG.exception(_LE("Failed to notify cells of instance update"))
return rv
return IMPL.instance_update(context, instance_uuid, values)
# FIXME(comstud): 'update_cells' is temporary as we transition to using
# objects. When everything is using Instance.save(), we can remove the
# argument and the RPC to nova-cells.
def instance_update_and_get_original(context, instance_uuid, values,
update_cells=True,
columns_to_join=None):
"""Set the given properties on an instance and update it. Return
a shallow copy of the original instance reference, as well as the
@ -772,11 +755,6 @@ def instance_update_and_get_original(context, instance_uuid, values,
"""
rv = IMPL.instance_update_and_get_original(context, instance_uuid, values,
columns_to_join=columns_to_join)
if update_cells:
try:
cells_rpcapi.CellsAPI().instance_update_at_top(context, rv[1])
except Exception:
LOG.exception(_LE("Failed to notify cells of instance update"))
return rv

View File

@ -659,6 +659,10 @@ class Instance(base.NovaPersistentObject, base.NovaObject,
else:
constraint = None
cell_type = cells_opts.get_cell_type()
if cell_type is not None:
stale_instance = self.obj_clone()
try:
db_inst = db.instance_destroy(self._context, self.uuid,
constraint=constraint)
@ -666,6 +670,9 @@ class Instance(base.NovaPersistentObject, base.NovaObject,
except exception.ConstraintNotMet:
raise exception.ObjectActionError(action='destroy',
reason='host changed')
if cell_type == 'compute':
cells_api = cells_rpcapi.CellsAPI()
cells_api.instance_destroy_at_top(self._context, stale_instance)
delattr(self, base.get_attrname('id'))
def _save_info_cache(self, context):
@ -793,7 +800,8 @@ class Instance(base.NovaPersistentObject, base.NovaObject,
context = self._context
cell_type = cells_opts.get_cell_type()
if cell_type == 'api' and self.cell_name:
if cell_type is not None:
# NOTE(comstud): We need to stash a copy of ourselves
# before any updates are applied. When we call the save
# methods on nested objects, we will lose any changes to
@ -805,15 +813,16 @@ class Instance(base.NovaPersistentObject, base.NovaObject,
# authoritative for their view of vm_state and task_state.
stale_instance = self.obj_clone()
cells_update_from_api = (cell_type == 'api' and self.cell_name and
self._sync_cells)
if cells_update_from_api:
def _handle_cell_update_from_api():
if self._sync_cells:
cells_api = cells_rpcapi.CellsAPI()
cells_api.instance_update_from_api(context, stale_instance,
cells_api = cells_rpcapi.CellsAPI()
cells_api.instance_update_from_api(context, stale_instance,
expected_vm_state,
expected_task_state,
admin_state_reset)
else:
stale_instance = None
self._maybe_upgrade_flavor()
updates = {}
@ -845,7 +854,7 @@ class Instance(base.NovaPersistentObject, base.NovaObject,
updates[field] = self[field]
if not updates:
if stale_instance:
if cells_update_from_api:
_handle_cell_update_from_api()
return
@ -883,24 +892,23 @@ class Instance(base.NovaPersistentObject, base.NovaObject,
expected_attrs.append('system_metadata')
expected_attrs.append('flavor')
old_ref, inst_ref = db.instance_update_and_get_original(
context, self.uuid, updates, update_cells=False,
context, self.uuid, updates,
columns_to_join=_expected_cols(expected_attrs))
self._from_db_object(context, self, inst_ref,
expected_attrs=expected_attrs)
# NOTE(danms): We have to be super careful here not to trigger
# any lazy-loads that will unmigrate or unbackport something. So,
# make a copy of the instance for notifications first.
new_ref = self.obj_clone()
if stale_instance:
if cells_update_from_api:
_handle_cell_update_from_api()
elif cell_type == 'compute':
if self._sync_cells:
cells_api = cells_rpcapi.CellsAPI()
cells_api.instance_update_at_top(context,
base.obj_to_primitive(new_ref))
cells_api.instance_update_at_top(context, stale_instance)
# NOTE(danms): We have to be super careful here not to trigger
# any lazy-loads that will unmigrate or unbackport something. So,
# make a copy of the instance for notifications first.
new_ref = self.obj_clone()
notifications.send_update(context, old_ref, new_ref)
self.obj_reset_changes()

View File

@ -89,14 +89,18 @@ class InstanceInfoCache(base.NovaPersistentObject, base.NovaObject,
@base.remotable
def save(self, update_cells=True):
if 'network_info' in self.obj_what_changed():
if update_cells:
stale_instance = self.obj_clone()
nw_info_json = self.fields['network_info'].to_primitive(
self, 'network_info', self.network_info)
rv = db.instance_info_cache_update(self._context,
self.instance_uuid,
{'network_info': nw_info_json})
self._from_db_object(self._context, self, rv)
if update_cells and rv:
self._info_cache_cells_update(self._context, rv)
if update_cells:
# Send a copy of ourselves before updates are applied so
# that cells can tell what changed.
self._info_cache_cells_update(self._context, stale_instance)
self.obj_reset_changes()
@base.remotable

View File

@ -27,7 +27,6 @@ from nova.compute import flavors
from nova.compute import utils as compute_utils
from nova import exception
from nova.i18n import _, _LE, _LW
from nova import notifications
from nova import objects
from nova.objects import base as obj_base
from nova.objects import instance as instance_obj
@ -92,19 +91,12 @@ def set_vm_state_and_notify(context, instance_uuid, service, method, updates,
LOG.warning(_LW('Setting instance to %s state.'), state,
instance_uuid=instance_uuid)
# update instance state and notify on the transition
# NOTE(hanlind): the send_update() call below is going to want to
# know about the flavor, so we need to join the appropriate things
# here and objectify the results.
(old_ref, new_ref) = db.instance_update_and_get_original(
context, instance_uuid, updates,
columns_to_join=['system_metadata'])
inst_obj = objects.Instance._from_db_object(
context, objects.Instance(), new_ref,
expected_attrs=['system_metadata'])
notifications.send_update(context, old_ref, inst_obj, service=service)
instance = objects.Instance(context=context, uuid=instance_uuid,
**updates)
instance.obj_reset_changes(['uuid'])
instance.save()
compute_utils.add_instance_fault_from_exc(context,
inst_obj, ex, sys.exc_info())
instance, ex, sys.exc_info())
payload = dict(request_spec=request_spec,
instance_properties=properties,

View File

@ -110,7 +110,7 @@ class MultiCreateExtensionTestV21(test.TestCase):
instance.update(values)
return instance
def server_update(context, instance_uuid, params, update_cells=True,
def server_update(context, instance_uuid, params,
columns_to_join=None):
inst = self.instance_cache_by_uuid[instance_uuid]
inst.update(params)

View File

@ -85,7 +85,6 @@ def return_servers_empty(context, *args, **kwargs):
def instance_update_and_get_original(context, instance_uuid, values,
update_cells=True,
columns_to_join=None,
):
inst = fakes.stub_instance(INSTANCE_IDS.get(instance_uuid),
@ -94,7 +93,7 @@ def instance_update_and_get_original(context, instance_uuid, values,
return (inst, inst)
def instance_update(context, instance_uuid, values, update_cells=True):
def instance_update(context, instance_uuid, values):
inst = fakes.stub_instance(INSTANCE_IDS.get(instance_uuid),
name=values.get('display_name'))
inst = dict(inst, **values)
@ -1938,8 +1937,7 @@ class ServersControllerCreateTest(test.TestCase):
return instance
def server_update_and_get_original(
context, instance_uuid, params, update_cells=False,
columns_to_join=None):
context, instance_uuid, params, columns_to_join=None):
inst = self.instance_cache_by_uuid[instance_uuid]
inst.update(params)
return (inst, inst)

View File

@ -51,7 +51,6 @@ def return_server_not_found(*arg, **kwarg):
def instance_update_and_get_original(context, instance_uuid, values,
update_cells=True,
columns_to_join=None,
):
inst = fakes.stub_instance(INSTANCE_IDS[instance_uuid], host='fake_host')
@ -59,7 +58,7 @@ def instance_update_and_get_original(context, instance_uuid, values,
return (inst, inst)
def instance_update(context, instance_uuid, kwargs, update_cells=True):
def instance_update(context, instance_uuid, kwargs):
inst = fakes.stub_instance(INSTANCE_IDS[instance_uuid], host='fake_host')
return inst

View File

@ -89,7 +89,6 @@ def return_security_group(context, instance_id, security_group_id):
def instance_update_and_get_original(context, instance_uuid, values,
update_cells=True,
columns_to_join=None,
):
inst = fakes.stub_instance(INSTANCE_IDS.get(instance_uuid),
@ -98,7 +97,7 @@ def instance_update_and_get_original(context, instance_uuid, values,
return (inst, inst)
def instance_update(context, instance_uuid, values, update_cells=True):
def instance_update(context, instance_uuid, values):
inst = fakes.stub_instance(INSTANCE_IDS.get(instance_uuid),
name=values.get('display_name'))
inst = dict(inst, **values)
@ -1900,8 +1899,7 @@ class ServersControllerCreateTest(test.TestCase):
return instance
def server_update_and_get_original(
context, instance_uuid, params, update_cells=False,
columns_to_join=None):
context, instance_uuid, params, columns_to_join=None):
inst = self.instance_cache_by_uuid[instance_uuid]
inst.update(params)
return (inst, inst)

View File

@ -230,6 +230,7 @@ class CellsManagerClassTestCase(test.NoDBTestCase):
call_info['get_instances'] += 1
return iter(instances)
@staticmethod
def instance_get_by_uuid(context, uuid):
return instances[int(uuid[-1]) - 1]
@ -239,7 +240,7 @@ class CellsManagerClassTestCase(test.NoDBTestCase):
self.stubs.Set(cells_utils, 'get_instances_to_sync',
get_instances_to_sync)
self.stubs.Set(self.cells_manager.db, 'instance_get_by_uuid',
self.stubs.Set(objects.Instance, 'get_by_uuid',
instance_get_by_uuid)
self.stubs.Set(self.cells_manager, '_sync_instance',
sync_instance)
@ -608,17 +609,16 @@ class CellsManagerClassTestCase(test.NoDBTestCase):
def test_validate_console_port(self):
instance_uuid = 'fake-instance-uuid'
cell_name = 'fake-cell-name'
instance = {'cell_name': cell_name}
instance = objects.Instance(cell_name=cell_name)
console_port = 'fake-console-port'
console_type = 'fake-console-type'
self.mox.StubOutWithMock(self.msg_runner,
'validate_console_port')
self.mox.StubOutWithMock(self.cells_manager.db,
'instance_get_by_uuid')
self.mox.StubOutWithMock(objects.Instance, 'get_by_uuid')
fake_response = self._get_fake_response()
self.cells_manager.db.instance_get_by_uuid(self.ctxt,
objects.Instance.get_by_uuid(self.ctxt,
instance_uuid).AndReturn(instance)
self.msg_runner.validate_console_port(self.ctxt, cell_name,
instance_uuid, console_port,

View File

@ -36,7 +36,6 @@ from nova.compute import vm_states
from nova import context
from nova import db
from nova import exception
from nova.network import model as network_model
from nova import objects
from nova.objects import base as objects_base
from nova.objects import fields as objects_fields
@ -740,7 +739,7 @@ class CellsTargetedMethodsTestCase(test.TestCase):
'security_groups', 'info_cache']).AndRaise(
exception.InstanceNotFound(instance_id=instance_uuid))
self.tgt_msg_runner.instance_destroy_at_top(self.ctxt,
{'uuid': instance.uuid})
mox.IsA(objects.Instance))
self.mox.ReplayAll()
@ -1011,25 +1010,24 @@ class CellsTargetedMethodsTestCase(test.TestCase):
def test_validate_console_port(self):
instance_uuid = 'fake_instance_uuid'
instance = {'uuid': instance_uuid}
instance = objects.Instance(uuid=instance_uuid)
console_port = 'fake-port'
console_type = 'fake-type'
self.mox.StubOutWithMock(self.tgt_c_rpcapi, 'validate_console_port')
self.mox.StubOutWithMock(self.tgt_db_inst, 'instance_get_by_uuid')
self.tgt_db_inst.instance_get_by_uuid(self.ctxt,
instance_uuid).AndReturn(instance)
self.tgt_c_rpcapi.validate_console_port(self.ctxt,
instance, console_port, console_type).AndReturn('fake_result')
self.mox.ReplayAll()
response = self.src_msg_runner.validate_console_port(self.ctxt,
self.tgt_cell_name, instance_uuid, console_port,
console_type)
result = response.value_or_raise()
self.assertEqual('fake_result', result)
@mock.patch.object(objects.Instance, 'get_by_uuid',
return_value=instance)
@mock.patch.object(self.tgt_c_rpcapi, 'validate_console_port',
return_value='fake_result')
def do_test(mock_validate, mock_get):
response = self.src_msg_runner.validate_console_port(self.ctxt,
self.tgt_cell_name, instance_uuid, console_port,
console_type)
result = response.value_or_raise()
self.assertEqual('fake_result', result)
mock_get.assert_called_once_with(self.ctxt, instance_uuid)
mock_validate.assert_called_once_with(self.ctxt, instance,
console_port, console_type)
do_test()
def test_get_migrations_for_a_given_cell(self):
filters = {'cell_name': 'child-cell2', 'status': 'confirmed'}
@ -1112,7 +1110,7 @@ class CellsTargetedMethodsTestCase(test.TestCase):
exception.InstanceNotFound(instance_id=instance.uuid))
self.tgt_msg_runner.instance_destroy_at_top(self.ctxt,
{'uuid': instance.uuid})
mox.IsA(objects.Instance))
self.mox.ReplayAll()
self.assertRaises(exception.InstanceNotFound,
@ -1465,152 +1463,105 @@ class CellsBroadcastMethodsTestCase(test.TestCase):
self.assertFalse(self.src_methods_cls._at_the_top())
def test_apply_expected_states_building(self):
instance_info = {'vm_state': vm_states.BUILDING}
expected = dict(instance_info,
expected_vm_state=[vm_states.BUILDING, None])
self.src_methods_cls._apply_expected_states(instance_info)
self.assertEqual(expected, instance_info)
instance_info = objects.Instance(vm_state=vm_states.BUILDING)
expected = instance_info.obj_clone()
expected.expected_vm_state = [vm_states.BUILDING, None]
expected_vm_state = self.src_methods_cls._get_expected_vm_state(
instance_info)
self.assertEqual(expected.expected_vm_state, expected_vm_state)
def test_apply_expected_states_resize_finish(self):
instance_info = {'task_state': task_states.RESIZE_FINISH}
instance_info = objects.Instance(task_state=task_states.RESIZE_FINISH)
exp_states = [task_states.RESIZE_FINISH,
task_states.RESIZE_MIGRATED,
task_states.RESIZE_MIGRATING,
task_states.RESIZE_PREP]
expected = dict(instance_info, expected_task_state=exp_states)
self.src_methods_cls._apply_expected_states(instance_info)
self.assertEqual(expected, instance_info)
expected = instance_info.obj_clone()
expected.expected_task_state = exp_states
expected_task_state = self.src_methods_cls._get_expected_task_state(
instance_info)
self.assertEqual(expected.expected_task_state, expected_task_state)
def _test_instance_update_at_top(self, net_info, exists=True):
fake_info_cache = {'id': 1,
'instance': 'fake_instance',
'network_info': net_info}
fake_sys_metadata = [{'id': 1,
'key': 'key1',
'value': 'value1'},
{'id': 2,
'key': 'key2',
'value': 'value2'}]
fake_instance = {'id': 2,
'uuid': 'fake_uuid',
'security_groups': 'fake',
'volumes': 'fake',
'cell_name': 'fake',
'name': 'fake',
'metadata': 'fake',
'info_cache': fake_info_cache,
'system_metadata': fake_sys_metadata,
'other': 'meow'}
expected_sys_metadata = {'key1': 'value1',
'key2': 'value2'}
expected_info_cache = {'network_info': "[]"}
def _test_instance_update_at_top(self, exists=True):
fake_uuid = fake_server_actions.FAKE_UUID
fake_info_cache = objects.InstanceInfoCache(instance_uuid='fake-uuid')
fake_sys_metadata = {'key1': 'value1',
'key2': 'value2'}
fake_attrs = {'uuid': fake_uuid,
'cell_name': 'fake',
'info_cache': fake_info_cache,
'system_metadata': fake_sys_metadata}
fake_instance = objects.Instance(**fake_attrs)
expected_cell_name = 'api-cell!child-cell2!grandchild-cell1'
expected_instance = {'system_metadata': expected_sys_metadata,
'cell_name': expected_cell_name,
'other': 'meow',
'uuid': 'fake_uuid'}
# To show these should not be called in src/mid-level cell
self.mox.StubOutWithMock(self.src_db_inst, 'instance_update')
self.mox.StubOutWithMock(self.src_db_inst,
'instance_info_cache_update')
self.mox.StubOutWithMock(self.mid_db_inst, 'instance_update')
self.mox.StubOutWithMock(self.mid_db_inst,
'instance_info_cache_update')
def fake_save(instance):
self.assertEqual(fake_uuid, instance.uuid)
self.assertEqual(expected_cell_name, instance.cell_name)
self.assertEqual(fake_info_cache, instance.info_cache)
self.assertEqual(fake_sys_metadata, instance.system_metadata)
self.mox.StubOutWithMock(self.tgt_db_inst, 'instance_update')
self.mox.StubOutWithMock(self.tgt_db_inst, 'instance_create')
self.mox.StubOutWithMock(self.tgt_db_inst,
'instance_info_cache_update')
mock = self.tgt_db_inst.instance_update(self.ctxt, 'fake_uuid',
expected_instance,
update_cells=False)
if not exists:
mock.AndRaise(exception.InstanceNotFound(instance_id='fake_uuid'))
self.tgt_db_inst.instance_create(self.ctxt,
expected_instance)
self.tgt_db_inst.instance_info_cache_update(self.ctxt, 'fake_uuid',
expected_info_cache)
self.mox.ReplayAll()
@mock.patch.object(objects.Instance, 'save')
@mock.patch.object(objects.Instance, 'create')
def do_test(mock_create, mock_save):
if exists:
mock_save.side_effect = fake_save
else:
error = exception.InstanceNotFound(instance_id='fake_uuid')
mock_save.side_effect = error
self.src_msg_runner.instance_update_at_top(self.ctxt, fake_instance)
self.src_msg_runner.instance_update_at_top(self.ctxt,
fake_instance)
if exists:
mock_save.assert_called_once_with(expected_vm_state=None,
expected_task_state=None)
self.assertFalse(mock_create.called)
else:
mock_save.assert_called_once_with(expected_vm_state=None,
expected_task_state=None)
mock_create.assert_called_once_with()
do_test()
def test_instance_update_at_top(self):
self._test_instance_update_at_top("[]")
def test_instance_update_at_top_netinfo_list(self):
self._test_instance_update_at_top([])
def test_instance_update_at_top_netinfo_model(self):
self._test_instance_update_at_top(network_model.NetworkInfo())
self._test_instance_update_at_top()
def test_instance_update_at_top_does_not_already_exist(self):
self._test_instance_update_at_top([], exists=False)
self._test_instance_update_at_top(exists=False)
def test_instance_update_at_top_with_building_state(self):
fake_info_cache = {'id': 1,
'instance': 'fake_instance',
'other': 'moo'}
fake_sys_metadata = [{'id': 1,
'key': 'key1',
'value': 'value1'},
{'id': 2,
'key': 'key2',
'value': 'value2'}]
fake_instance = {'id': 2,
'uuid': 'fake_uuid',
'security_groups': 'fake',
'volumes': 'fake',
'cell_name': 'fake',
'name': 'fake',
'metadata': 'fake',
'info_cache': fake_info_cache,
'system_metadata': fake_sys_metadata,
'vm_state': vm_states.BUILDING,
'other': 'meow'}
expected_sys_metadata = {'key1': 'value1',
'key2': 'value2'}
expected_info_cache = {'other': 'moo'}
fake_uuid = fake_server_actions.FAKE_UUID
fake_info_cache = objects.InstanceInfoCache(instance_uuid='fake-uuid')
fake_sys_metadata = {'key1': 'value1',
'key2': 'value2'}
fake_attrs = {'uuid': fake_uuid,
'cell_name': 'fake',
'info_cache': fake_info_cache,
'system_metadata': fake_sys_metadata,
'vm_state': vm_states.BUILDING}
fake_instance = objects.Instance(**fake_attrs)
expected_cell_name = 'api-cell!child-cell2!grandchild-cell1'
expected_instance = {'system_metadata': expected_sys_metadata,
'cell_name': expected_cell_name,
'other': 'meow',
'vm_state': vm_states.BUILDING,
'expected_vm_state': [vm_states.BUILDING, None],
'uuid': 'fake_uuid'}
expected_vm_state = [vm_states.BUILDING, None]
# To show these should not be called in src/mid-level cell
self.mox.StubOutWithMock(self.src_db_inst, 'instance_update')
self.mox.StubOutWithMock(self.src_db_inst,
'instance_info_cache_update')
self.mox.StubOutWithMock(self.mid_db_inst, 'instance_update')
self.mox.StubOutWithMock(self.mid_db_inst,
'instance_info_cache_update')
def fake_save(instance):
self.assertEqual(fake_uuid, instance.uuid)
self.assertEqual(expected_cell_name, instance.cell_name)
self.assertEqual(fake_info_cache, instance.info_cache)
self.assertEqual(fake_sys_metadata, instance.system_metadata)
self.mox.StubOutWithMock(self.tgt_db_inst, 'instance_update')
self.mox.StubOutWithMock(self.tgt_db_inst,
'instance_info_cache_update')
self.tgt_db_inst.instance_update(self.ctxt, 'fake_uuid',
expected_instance,
update_cells=False)
self.tgt_db_inst.instance_info_cache_update(self.ctxt, 'fake_uuid',
expected_info_cache)
self.mox.ReplayAll()
self.src_msg_runner.instance_update_at_top(self.ctxt, fake_instance)
with mock.patch.object(objects.Instance, 'save',
side_effect=fake_save) as mock_save:
self.src_msg_runner.instance_update_at_top(self.ctxt,
fake_instance)
# Check that save is called with the right expected states.
mock_save.assert_called_once_with(
expected_vm_state=expected_vm_state, expected_task_state=None)
def test_instance_destroy_at_top(self):
fake_instance = {'uuid': 'fake_uuid'}
fake_instance = objects.Instance(uuid='fake_uuid')
# To show these should not be called in src/mid-level cell
self.mox.StubOutWithMock(self.src_db_inst, 'instance_destroy')
self.mox.StubOutWithMock(self.tgt_db_inst, 'instance_destroy')
self.tgt_db_inst.instance_destroy(self.ctxt, 'fake_uuid',
update_cells=False)
self.mox.ReplayAll()
self.src_msg_runner.instance_destroy_at_top(self.ctxt, fake_instance)
with mock.patch.object(objects.Instance, 'destroy') as mock_destroy:
self.src_msg_runner.instance_destroy_at_top(self.ctxt,
fake_instance)
mock_destroy.assert_called_once_with()
def test_instance_hard_delete_everywhere(self):
# Reset this, as this is a broadcast down.
@ -1703,8 +1654,8 @@ class CellsBroadcastMethodsTestCase(test.TestCase):
updated_since_parsed = 'fake_updated_since_parsed'
deleted = 'fake_deleted'
instance1 = dict(uuid='fake_uuid1', deleted=False)
instance2 = dict(uuid='fake_uuid2', deleted=True)
instance1 = objects.Instance(uuid='fake_uuid1', deleted=False)
instance2 = objects.Instance(uuid='fake_uuid2', deleted=True)
fake_instances = [instance1, instance2]
self.mox.StubOutWithMock(self.tgt_msg_runner,

View File

@ -152,25 +152,15 @@ class CellsAPITestCase(test.NoDBTestCase):
self.assertEqual(capacity_info, result)
def test_instance_update_at_top(self):
fake_info_cache = {'id': 1,
'instance': 'fake_instance',
'other': 'moo'}
fake_sys_metadata = [{'id': 1,
'key': 'key1',
'value': 'value1'},
{'id': 2,
'key': 'key2',
'value': 'value2'}]
fake_instance = {'id': 2,
'security_groups': 'fake',
'instance_type': 'fake',
'volumes': 'fake',
'cell_name': 'fake',
'name': 'fake',
'metadata': 'fake',
'info_cache': fake_info_cache,
'system_metadata': fake_sys_metadata,
'other': 'meow'}
fake_info_cache = objects.InstanceInfoCache(instance_uuid='fake-uuid')
fake_sys_metadata = {'key1': 'value1',
'key2': 'value2'}
fake_attrs = {'id': 2,
'cell_name': 'fake',
'metadata': {'fake': 'fake'},
'info_cache': fake_info_cache,
'system_metadata': fake_sys_metadata}
fake_instance = objects.Instance(**fake_attrs)
call_info = self._stub_rpc_method('cast', None)
@ -179,10 +169,10 @@ class CellsAPITestCase(test.NoDBTestCase):
expected_args = {'instance': fake_instance}
self._check_result(call_info, 'instance_update_at_top',
expected_args)
expected_args, version='1.35')
def test_instance_destroy_at_top(self):
fake_instance = {'uuid': 'fake-uuid'}
fake_instance = objects.Instance(uuid='fake-uuid')
call_info = self._stub_rpc_method('cast', None)
@ -191,7 +181,7 @@ class CellsAPITestCase(test.NoDBTestCase):
expected_args = {'instance': fake_instance}
self._check_result(call_info, 'instance_destroy_at_top',
expected_args)
expected_args, version='1.35')
def test_instance_delete_everywhere(self):
instance = fake_instance.fake_instance_obj(self.fake_context)

View File

@ -254,9 +254,9 @@ class CellsSchedulerTestCase(test.TestCase):
def fake_sleep(_secs):
return
def fake_instance_update(ctxt, instance_uuid, values):
self.assertEqual(vm_states.ERROR, values['vm_state'])
call_info['errored_uuids'].append(instance_uuid)
def fake_instance_save(inst):
self.assertEqual(vm_states.ERROR, inst.vm_state)
call_info['errored_uuids'].append(inst.uuid)
def fake_build_request_spec(ctxt, image, instances):
request_spec = {
@ -267,7 +267,7 @@ class CellsSchedulerTestCase(test.TestCase):
self.stubs.Set(self.scheduler, '_grab_target_cells',
fake_grab_target_cells)
self.stubs.Set(time, 'sleep', fake_sleep)
self.stubs.Set(db, 'instance_update', fake_instance_update)
self.stubs.Set(objects.Instance, 'save', fake_instance_save)
self.stubs.Set(scheduler_utils, 'build_request_spec',
fake_build_request_spec)
@ -280,7 +280,8 @@ class CellsSchedulerTestCase(test.TestCase):
def test_schedule_method_on_random_exception(self):
self.flags(scheduler_retries=7, group='cells')
instances = [{'uuid': uuid} for uuid in self.instance_uuids]
instances = [objects.Instance(uuid=uuid) for uuid in
self.instance_uuids]
method_kwargs = {
'image': 'fake_image',
'instances': instances,
@ -294,9 +295,9 @@ class CellsSchedulerTestCase(test.TestCase):
call_info['num_tries'] += 1
raise test.TestingException()
def fake_instance_update(ctxt, instance_uuid, values):
self.assertEqual(vm_states.ERROR, values['vm_state'])
call_info['errored_uuids1'].append(instance_uuid)
def fake_instance_save(inst):
self.assertEqual(vm_states.ERROR, inst.vm_state)
call_info['errored_uuids1'].append(inst.uuid)
def fake_instance_update_at_top(ctxt, instance):
self.assertEqual(vm_states.ERROR, instance['vm_state'])
@ -310,7 +311,7 @@ class CellsSchedulerTestCase(test.TestCase):
self.stubs.Set(self.scheduler, '_grab_target_cells',
fake_grab_target_cells)
self.stubs.Set(db, 'instance_update', fake_instance_update)
self.stubs.Set(objects.Instance, 'save', fake_instance_save)
self.stubs.Set(self.msg_runner, 'instance_update_at_top',
fake_instance_update_at_top)
self.stubs.Set(scheduler_utils, 'build_request_spec',

View File

@ -20,7 +20,6 @@ import mock
import random
from nova.cells import utils as cells_utils
from nova import db
from nova import exception
from nova import objects
from nova import test
@ -36,16 +35,17 @@ class CellsUtilsTestCase(test.NoDBTestCase):
def random_shuffle(_list):
call_info['shuffle'] += 1
@staticmethod
def instance_get_all_by_filters(context, filters,
sort_key, sort_order):
sort_key, sort_dir):
self.assertEqual(context, fake_context)
self.assertEqual(sort_key, 'deleted')
self.assertEqual(sort_order, 'asc')
self.assertEqual(sort_dir, 'asc')
call_info['got_filters'] = filters
call_info['get_all'] += 1
return ['fake_instance1', 'fake_instance2', 'fake_instance3']
self.stubs.Set(db, 'instance_get_all_by_filters',
self.stubs.Set(objects.InstanceList, 'get_by_filters',
instance_get_all_by_filters)
self.stubs.Set(random, 'shuffle', random_shuffle)

View File

@ -2666,7 +2666,6 @@ class ComputeTestCase(BaseTestCase):
{'task_state': task_pending,
'expected_task_state': expected_tasks,
'power_state': fake_power_state1},
update_cells=False,
columns_to_join=['system_metadata',
'extra',
'extra.flavor']
@ -2677,7 +2676,6 @@ class ComputeTestCase(BaseTestCase):
updated_dbinstance1['uuid'],
{'task_state': task_started,
'expected_task_state': task_pending},
update_cells=False,
columns_to_join=['system_metadata',
'extra',
'extra.flavor']
@ -2726,7 +2724,6 @@ class ComputeTestCase(BaseTestCase):
{'power_state': new_power_state,
'task_state': None,
'vm_state': vm_states.ACTIVE},
update_cells=False,
columns_to_join=['system_metadata', 'extra', 'extra.flavor'],
).AndRaise(fault)
self.compute._notify_about_instance_usage(
@ -2737,7 +2734,6 @@ class ComputeTestCase(BaseTestCase):
db.instance_update_and_get_original(
econtext, updated_dbinstance1['uuid'],
{'vm_state': vm_states.ERROR},
update_cells=False,
columns_to_join=['system_metadata', 'extra', 'extra.flavor'],
).AndRaise(fault)
else:
@ -2746,7 +2742,6 @@ class ComputeTestCase(BaseTestCase):
{'power_state': new_power_state,
'task_state': None,
'vm_state': vm_states.ACTIVE},
update_cells=False,
columns_to_join=['system_metadata', 'extra', 'extra.flavor'],
).AndReturn((None, updated_dbinstance2))
if fail_running:
@ -6461,14 +6456,14 @@ class ComputeTestCase(BaseTestCase):
self.stubs.Set(self.compute, '_get_resource_tracker', fail_get)
instance = self._create_fake_instance_obj({'host': 'someotherhost'})
self.compute._instance_update(self.context, instance.uuid)
self.compute._instance_update(self.context, instance.uuid, vcpus=4)
instance = self._create_fake_instance_obj({'node': 'someothernode'})
self.compute._instance_update(self.context, instance.uuid)
self.compute._instance_update(self.context, instance.uuid, vcpus=4)
params = {'host': 'someotherhost', 'node': 'someothernode'}
instance = self._create_fake_instance_obj(params)
self.compute._instance_update(self.context, instance.uuid)
self.compute._instance_update(self.context, instance.uuid, vcpus=4)
def test_destroy_evacuated_instance_on_shared_storage(self):
fake_context = context.get_admin_context()

View File

@ -584,12 +584,17 @@ class ConductorTestCase(_BaseTestCase, test.TestCase):
'migration')
def test_instance_destroy(self):
self.mox.StubOutWithMock(db, 'instance_destroy')
db.instance_destroy(self.context, 'fake-uuid').AndReturn('fake-result')
self.mox.ReplayAll()
result = self.conductor.instance_destroy(self.context,
{'uuid': 'fake-uuid'})
self.assertEqual(result, 'fake-result')
instance = objects.Instance(id=1, uuid='fake-uuid')
@mock.patch.object(instance, 'destroy')
@mock.patch.object(obj_base, 'obj_to_primitive',
return_value='fake-result')
def do_test(mock_to_primitive, mock_destroy):
result = self.conductor.instance_destroy(self.context, instance)
mock_destroy.assert_called_once_with()
mock_to_primitive.assert_called_once_with(instance)
self.assertEqual(result, 'fake-result')
do_test()
def test_compute_unrescue(self):
self.mox.StubOutWithMock(self.conductor_manager.compute_api,
@ -856,23 +861,33 @@ class ConductorImportTest(test.TestCase):
class ConductorPolicyTest(test.TestCase):
def test_all_allowed_keys(self):
def fake_db_instance_update(self, *args, **kwargs):
return None, None
self.stubs.Set(db, 'instance_update_and_get_original',
fake_db_instance_update)
ctxt = context.RequestContext('fake-user', 'fake-project')
conductor = conductor_api.LocalAPI()
updates = {}
for key in conductor_manager.allowed_updates:
if key in conductor_manager.datetime_fields:
updates[key] = timeutils.utcnow()
elif key == 'access_ip_v4':
updates[key] = '10.0.0.2'
elif key == 'access_ip_v6':
updates[key] = '2001:db8:0:1::1'
elif key in ('instance_type_id', 'memory_mb', 'ephemeral_gb',
'root_gb', 'vcpus', 'power_state', 'progress'):
updates[key] = 5
elif key == 'system_metadata':
updates[key] = {'foo': 'foo'}
else:
updates[key] = 'foo'
with mock.patch('nova.objects.Instance._from_db_object'):
def fake_save(inst):
# id that comes back from db after updating
inst.id = 1
with mock.patch.object(objects.Instance, 'save',
side_effect=fake_save,
autospec=True) as mock_save:
conductor.instance_update(ctxt, 'fake-instance', **updates)
mock_save.assert_called_once_with(mock.ANY)
def test_allowed_keys_are_real(self):
instance = models.Instance()

View File

@ -2210,12 +2210,10 @@ class TestNeutronv2(TestNeutronv2Base):
api.release_floating_ip, self.context, address)
def _setup_mock_for_refresh_cache(self, api, instances):
nw_info = self.mox.CreateMock(model.NetworkInfo)
nw_info = model.NetworkInfo()
self.mox.StubOutWithMock(api, '_get_instance_nw_info')
self.mox.StubOutWithMock(api.db, 'instance_info_cache_update')
for instance in instances:
nw_info.__str__().AndReturn('')
nw_info.json().AndReturn({})
api._get_instance_nw_info(mox.IgnoreArg(), instance).\
AndReturn(nw_info)
api.db.instance_info_cache_update(mox.IgnoreArg(),

View File

@ -314,7 +314,6 @@ class _TestInstanceObject(object):
).AndReturn(old_ref)
db.instance_update_and_get_original(
self.context, fake_uuid, expected_updates,
update_cells=False,
columns_to_join=['info_cache', 'security_groups',
'system_metadata', 'extra', 'extra.flavor']
).AndReturn((old_ref, new_ref))
@ -325,12 +324,8 @@ class _TestInstanceObject(object):
exp_vm_state, exp_task_state, admin_reset)
elif cell_type == 'compute':
cells_rpcapi.CellsAPI().AndReturn(cells_api_mock)
expected = ['info_cache', 'security_groups', 'system_metadata',
'flavor', 'new_flavor', 'old_flavor']
new_ref_obj = objects.Instance._from_db_object(self.context,
objects.Instance(), new_ref, expected_attrs=expected)
instance_ref_p = base.obj_to_primitive(new_ref_obj)
cells_api_mock.instance_update_at_top(self.context, instance_ref_p)
cells_api_mock.instance_update_at_top(self.context,
mox.IsA(instance.Instance))
notifications.send_update(self.context, mox.IgnoreArg(),
mox.IgnoreArg())
@ -400,7 +395,7 @@ class _TestInstanceObject(object):
use_slave=False
).AndReturn(old_ref)
db.instance_update_and_get_original(
self.context, fake_uuid, expected_updates, update_cells=False,
self.context, fake_uuid, expected_updates,
columns_to_join=['info_cache', 'security_groups',
'system_metadata', 'extra', 'extra.flavor']
).AndReturn((old_ref, new_ref))
@ -543,8 +538,12 @@ class _TestInstanceObject(object):
self.assertEqual('foo!bar@baz', inst.cell_name)
if cell_type == 'compute':
mock_update_at_top.assert_called_once_with(self.context,
base.obj_to_primitive(inst))
mock_update_at_top.assert_called_once_with(self.context, mock.ANY)
# Compare primitives since we can't check instance object equality
expected_inst_p = base.obj_to_primitive(inst)
actual_inst = mock_update_at_top.call_args[0][1]
actual_inst_p = base.obj_to_primitive(actual_inst)
self.assertEqual(expected_inst_p, actual_inst_p)
self.assertFalse(fake_update_from_api.called)
elif cell_type == 'api':
self.assertFalse(mock_update_at_top.called)
@ -554,12 +553,12 @@ class _TestInstanceObject(object):
expected_calls = [
mock.call(self.context, inst.uuid,
{'vm_state': 'foo', 'task_state': 'bar',
'cell_name': 'foo!bar@baz'}, update_cells=False,
'cell_name': 'foo!bar@baz'},
columns_to_join=['system_metadata', 'extra',
'extra.flavor']),
mock.call(self.context, inst.uuid,
{'vm_state': 'bar', 'task_state': 'foo'},
update_cells=False, columns_to_join=['system_metadata',
columns_to_join=['system_metadata',
'extra', 'extra.flavor'])]
mock_db_update.assert_has_calls(expected_calls)
@ -952,6 +951,28 @@ class _TestInstanceObject(object):
self.assertRaises(exception.ObjectActionError,
inst.destroy)
@mock.patch.object(cells_rpcapi.CellsAPI, 'instance_destroy_at_top')
@mock.patch.object(db, 'instance_destroy')
def test_destroy_cell_sync_to_top(self, mock_destroy, mock_destroy_at_top):
self.flags(enable=True, cell_type='compute', group='cells')
fake_inst = fake_instance.fake_db_instance(deleted=True)
mock_destroy.return_value = fake_inst
inst = instance.Instance(context=self.context, id=1, uuid='fake-uuid')
inst.destroy()
mock_destroy_at_top.assert_called_once_with(self.context, mock.ANY)
actual_inst = mock_destroy_at_top.call_args[0][1]
self.assertIsInstance(actual_inst, objects.Instance)
@mock.patch.object(cells_rpcapi.CellsAPI, 'instance_destroy_at_top')
@mock.patch.object(db, 'instance_destroy')
def test_destroy_no_cell_sync_to_top(self, mock_destroy,
mock_destroy_at_top):
fake_inst = fake_instance.fake_db_instance(deleted=True)
mock_destroy.return_value = fake_inst
inst = instance.Instance(context=self.context, id=1, uuid='fake-uuid')
inst.destroy()
self.assertFalse(mock_destroy_at_top.called)
def test_name_does_not_trigger_lazy_loads(self):
values = {'user_id': self.context.user_id,
'project_id': self.context.project_id,

View File

@ -26,7 +26,6 @@ from nova.compute import flavors
from nova.compute import utils as compute_utils
from nova import db
from nova import exception
from nova import notifications
from nova import objects
from nova import rpc
from nova.scheduler import utils as scheduler_utils
@ -71,7 +70,10 @@ class SchedulerUtilsTestCase(test.NoDBTestCase):
mock_get.assert_called_once_with()
self.assertIsInstance(request_spec['instance_properties'], dict)
def test_set_vm_state_and_notify(self):
@mock.patch.object(rpc, 'get_notifier', return_value=mock.Mock())
@mock.patch.object(compute_utils, 'add_instance_fault_from_exc')
@mock.patch.object(objects.Instance, 'save')
def test_set_vm_state_and_notify(self, mock_save, mock_add, mock_get):
expected_uuid = 'fake-uuid'
request_spec = dict(instance_properties=dict(uuid='other-uuid'))
updates = dict(vm_state='fake-vm-state')
@ -79,28 +81,6 @@ class SchedulerUtilsTestCase(test.NoDBTestCase):
method = 'fake-method'
exc_info = 'exc_info'
self.mox.StubOutWithMock(compute_utils,
'add_instance_fault_from_exc')
self.mox.StubOutWithMock(notifications, 'send_update')
self.mox.StubOutWithMock(db, 'instance_update_and_get_original')
self.mox.StubOutWithMock(rpc, 'get_notifier')
notifier = self.mox.CreateMockAnything()
rpc.get_notifier(service).AndReturn(notifier)
old_ref = 'old_ref'
new_ref = 'new_ref'
inst_obj = 'inst_obj'
db.instance_update_and_get_original(
self.context, expected_uuid, updates,
columns_to_join=['system_metadata']).AndReturn((old_ref, new_ref))
notifications.send_update(self.context, old_ref, inst_obj,
service=service)
compute_utils.add_instance_fault_from_exc(
self.context,
inst_obj, exc_info, mox.IsA(tuple))
payload = dict(request_spec=request_spec,
instance_properties=request_spec.get(
'instance_properties', {}),
@ -109,20 +89,23 @@ class SchedulerUtilsTestCase(test.NoDBTestCase):
method=method,
reason=exc_info)
event_type = '%s.%s' % (service, method)
notifier.error(self.context, event_type, payload)
self.mox.ReplayAll()
with mock.patch.object(objects.Instance, '_from_db_object',
return_value=inst_obj):
scheduler_utils.set_vm_state_and_notify(self.context,
expected_uuid,
service,
method,
updates,
exc_info,
request_spec,
db)
scheduler_utils.set_vm_state_and_notify(self.context,
expected_uuid,
service,
method,
updates,
exc_info,
request_spec,
db)
mock_save.assert_called_once_with()
mock_add.assert_called_once_with(self.context, mock.ANY,
exc_info, mock.ANY)
self.assertIsInstance(mock_add.call_args[0][1], objects.Instance)
self.assertIsInstance(mock_add.call_args[0][3], tuple)
mock_get.return_value.error.assert_called_once_with(self.context,
event_type,
payload)
def _test_populate_filter_props(self, host_state_obj=True,
with_retry=True,