summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--nova/api/ec2/apirequest.py4
-rw-r--r--nova/api/openstack/compute/servers.py10
-rw-r--r--nova/cmd/all.py10
-rw-r--r--nova/cmd/api.py4
-rw-r--r--nova/compute/api.py35
-rw-r--r--nova/compute/cells_api.py10
-rwxr-xr-xnova/compute/manager.py23
-rw-r--r--nova/openstack/common/rpc/common.py4
-rw-r--r--nova/openstack/common/rpc/dispatcher.py29
-rw-r--r--nova/openstack/common/rpc/proxy.py58
-rw-r--r--nova/openstack/common/rpc/serializer.py52
-rw-r--r--nova/service.py318
-rw-r--r--nova/servicegroup/drivers/db.py8
-rw-r--r--nova/servicegroup/drivers/mc.py8
-rw-r--r--nova/tests/api/openstack/compute/test_servers.py36
-rw-r--r--nova/tests/compute/test_compute.py157
-rw-r--r--nova/tests/compute/test_compute_cells.py3
-rw-r--r--nova/tests/integrated/test_api_samples.py2
-rw-r--r--nova/tests/integrated/test_multiprocess_api.py4
-rw-r--r--nova/tests/test_migrations.py2
-rw-r--r--nova/tests/test_service.py5
-rw-r--r--nova/tests/test_virt_drivers.py8
-rw-r--r--nova/tests/test_xenapi.py5
-rw-r--r--nova/tests/virt/baremetal/__init__.py (renamed from nova/tests/baremetal/__init__.py)2
-rw-r--r--nova/tests/virt/baremetal/db/__init__.py (renamed from nova/tests/baremetal/db/__init__.py)2
-rw-r--r--nova/tests/virt/baremetal/db/base.py (renamed from nova/tests/baremetal/db/base.py)0
-rw-r--r--nova/tests/virt/baremetal/db/test_bm_interface.py (renamed from nova/tests/baremetal/db/test_bm_interface.py)2
-rw-r--r--nova/tests/virt/baremetal/db/test_bm_node.py (renamed from nova/tests/baremetal/db/test_bm_node.py)4
-rw-r--r--nova/tests/virt/baremetal/db/test_bm_pxe_ip.py (renamed from nova/tests/baremetal/db/test_bm_pxe_ip.py)4
-rw-r--r--nova/tests/virt/baremetal/db/utils.py (renamed from nova/tests/baremetal/db/utils.py)0
-rw-r--r--nova/tests/virt/baremetal/test_baremetal_migrations.conf (renamed from nova/tests/test_baremetal_migrations.conf)0
-rw-r--r--nova/tests/virt/baremetal/test_driver.py (renamed from nova/tests/baremetal/test_driver.py)4
-rw-r--r--nova/tests/virt/baremetal/test_ipmi.py (renamed from nova/tests/baremetal/test_ipmi.py)2
-rw-r--r--nova/tests/virt/baremetal/test_nova_baremetal_deploy_helper.py (renamed from nova/tests/baremetal/test_nova_baremetal_deploy_helper.py)2
-rw-r--r--nova/tests/virt/baremetal/test_nova_baremetal_manage.py (renamed from nova/tests/baremetal/test_nova_baremetal_manage.py)2
-rw-r--r--nova/tests/virt/baremetal/test_pxe.py (renamed from nova/tests/baremetal/test_pxe.py)4
-rwxr-xr-xnova/tests/virt/baremetal/test_tilera.py (renamed from nova/tests/baremetal/test_tilera.py)4
-rwxr-xr-xnova/tests/virt/baremetal/test_tilera_pdu.py (renamed from nova/tests/baremetal/test_tilera_pdu.py)2
-rw-r--r--nova/tests/virt/baremetal/test_utils.py (renamed from nova/tests/baremetal/test_utils.py)0
-rw-r--r--nova/tests/virt/baremetal/test_virtual_power_driver.py (renamed from nova/tests/baremetal/test_virtual_power_driver.py)4
-rw-r--r--nova/tests/virt/baremetal/test_volume_driver.py (renamed from nova/tests/baremetal/test_volume_driver.py)0
-rw-r--r--nova/tests/virt/libvirt/__init__.py15
-rw-r--r--nova/tests/virt/libvirt/fake_imagebackend.py (renamed from nova/tests/fake_imagebackend.py)0
-rw-r--r--nova/tests/virt/libvirt/fake_libvirt_utils.py (renamed from nova/tests/fake_libvirt_utils.py)0
-rw-r--r--nova/tests/virt/libvirt/fakelibvirt.py (renamed from nova/tests/fakelibvirt.py)0
-rw-r--r--nova/tests/virt/libvirt/test_fakelibvirt.py (renamed from nova/tests/test_fakelibvirt.py)2
-rw-r--r--nova/tests/virt/libvirt/test_imagebackend.py (renamed from nova/tests/test_imagebackend.py)2
-rw-r--r--nova/tests/virt/libvirt/test_imagecache.py (renamed from nova/tests/test_imagecache.py)0
-rw-r--r--nova/tests/virt/libvirt/test_libvirt.py (renamed from nova/tests/test_libvirt.py)7
-rw-r--r--nova/tests/virt/libvirt/test_libvirt_blockinfo.py (renamed from nova/tests/test_libvirt_blockinfo.py)0
-rw-r--r--nova/tests/virt/libvirt/test_libvirt_config.py (renamed from nova/tests/test_libvirt_config.py)0
-rw-r--r--nova/tests/virt/libvirt/test_libvirt_utils.py (renamed from nova/tests/test_libvirt_utils.py)0
-rw-r--r--nova/tests/virt/libvirt/test_libvirt_vif.py (renamed from nova/tests/test_libvirt_vif.py)2
-rw-r--r--nova/tests/virt/libvirt/test_libvirt_volume.py (renamed from nova/tests/test_libvirt_volume.py)2
-rw-r--r--openstack-common.conf1
55 files changed, 459 insertions, 405 deletions
diff --git a/nova/api/ec2/apirequest.py b/nova/api/ec2/apirequest.py
index b43b63287..a2c20efc0 100644
--- a/nova/api/ec2/apirequest.py
+++ b/nova/api/ec2/apirequest.py
@@ -21,6 +21,7 @@ APIRequest class
"""
import datetime
+from lxml import etree
# TODO(termie): replace minidom with etree
from xml.dom import minidom
@@ -95,6 +96,9 @@ class APIRequest(object):
xml.appendChild(response_el)
response = xml.toxml()
+ root = etree.fromstring(response)
+ response = etree.tostring(root, pretty_print=True)
+
xml.unlink()
# Don't write private key to log
diff --git a/nova/api/openstack/compute/servers.py b/nova/api/openstack/compute/servers.py
index 166c8b10e..44d8dce3b 100644
--- a/nova/api/openstack/compute/servers.py
+++ b/nova/api/openstack/compute/servers.py
@@ -1282,18 +1282,16 @@ class Controller(wsgi.Controller):
except exception.InstanceNotFound:
msg = _("Instance could not be found")
raise exc.HTTPNotFound(explanation=msg)
- except exception.InvalidMetadata as error:
- raise exc.HTTPBadRequest(
- explanation=error.format_message())
except exception.InvalidMetadataSize as error:
raise exc.HTTPRequestEntityTooLarge(
explanation=error.format_message())
except exception.ImageNotFound:
msg = _("Cannot find image for rebuild")
raise exc.HTTPBadRequest(explanation=msg)
- except exception.InstanceTypeMemoryTooSmall as error:
- raise exc.HTTPBadRequest(explanation=error.format_message())
- except exception.InstanceTypeDiskTooSmall as error:
+ except (exception.InvalidMetadata,
+ exception.InstanceTypeMemoryTooSmall,
+ exception.InstanceTypeDiskTooSmall,
+ exception.ImageNotActive) as error:
raise exc.HTTPBadRequest(explanation=error.format_message())
instance = self._get_server(context, req, id)
diff --git a/nova/cmd/all.py b/nova/cmd/all.py
index f510069b6..517033d05 100644
--- a/nova/cmd/all.py
+++ b/nova/cmd/all.py
@@ -49,19 +49,19 @@ def main():
logging.setup("nova")
LOG = logging.getLogger('nova.all')
utils.monkey_patch()
- launcher = service.ProcessLauncher()
+ launcher = service.process_launcher()
# nova-api
for api in CONF.enabled_apis:
try:
server = service.WSGIService(api)
- launcher.launch_server(server, workers=server.workers or 1)
+ launcher.launch_service(server, workers=server.workers or 1)
except (Exception, SystemExit):
LOG.exception(_('Failed to load %s') % '%s-api' % api)
for mod in [s3server, xvp_proxy]:
try:
- launcher.launch_server(mod.get_wsgi_server())
+ launcher.launch_service(mod.get_wsgi_server())
except (Exception, SystemExit):
LOG.exception(_('Failed to load %s') % mod.__name__)
@@ -82,8 +82,8 @@ def main():
manager = None
try:
- launcher.launch_server(service.Service.create(binary=binary,
- topic=topic,
+ launcher.launch_service(service.Service.create(binary=binary,
+ topic=topic,
manager=manager))
except (Exception, SystemExit):
LOG.exception(_('Failed to load %s'), binary)
diff --git a/nova/cmd/api.py b/nova/cmd/api.py
index a7f6313b0..f838d988f 100644
--- a/nova/cmd/api.py
+++ b/nova/cmd/api.py
@@ -41,7 +41,7 @@ def main():
logging.setup("nova")
utils.monkey_patch()
- launcher = service.ProcessLauncher()
+ launcher = service.process_launcher()
for api in CONF.enabled_apis:
should_use_ssl = api in CONF.enabled_ssl_apis
if api == 'ec2':
@@ -49,5 +49,5 @@ def main():
max_url_len=16384)
else:
server = service.WSGIService(api, use_ssl=should_use_ssl)
- launcher.launch_server(server, workers=server.workers or 1)
+ launcher.launch_service(server, workers=server.workers or 1)
launcher.wait()
diff --git a/nova/compute/api.py b/nova/compute/api.py
index f31aefb9b..24d73ec0d 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -1757,25 +1757,13 @@ class API(base.Base):
block_device_info=block_info,
reboot_type=reboot_type)
- def _get_image(self, context, image_href):
- """Throws an ImageNotFound exception if image_href does not exist."""
- (image_service, image_id) = glance.get_remote_image_service(context,
- image_href)
- return image_service.show(context, image_id)
-
@wrap_check_policy
@check_instance_lock
@check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.STOPPED],
task_state=[None])
def rebuild(self, context, instance, image_href, admin_password, **kwargs):
"""Rebuild the given instance with the provided attributes."""
-
- if instance['image_ref']:
- orig_image_ref = instance['image_ref']
- image = self._get_image(context, image_href)
- else:
- orig_image_ref = ''
- image = {}
+ orig_image_ref = instance['image_ref'] or ''
files_to_inject = kwargs.pop('files_to_inject', [])
self._check_injected_file_quota(context, files_to_inject)
@@ -1783,18 +1771,21 @@ class API(base.Base):
metadata = kwargs.get('metadata', {})
self._check_metadata_properties_quota(context, metadata)
+ if image_href:
+ (image_service, image_id) = glance.get_remote_image_service(
+ context, image_href)
+ image = image_service.show(context, image_id)
+ if image['status'] != 'active':
+ raise exception.ImageNotActive(image_id=image_id)
+ else:
+ image = {}
+
instance_type = flavors.extract_instance_type(instance)
if instance_type['memory_mb'] < int(image.get('min_ram') or 0):
raise exception.InstanceTypeMemoryTooSmall()
if instance_type['root_gb'] < int(image.get('min_disk') or 0):
raise exception.InstanceTypeDiskTooSmall()
- if image_href:
- (image_service, image_id) = glance.get_remote_image_service(
- context, image_href)
- image = image_service.show(context, image_id)
- else:
- image = {}
kernel_id, ramdisk_id = self._handle_kernel_and_ramdisk(
context, None, None, image)
@@ -2020,7 +2011,11 @@ class API(base.Base):
raise exception.FlavorNotFound(flavor_id=flavor_id)
# NOTE(markwash): look up the image early to avoid auth problems later
- image = self.image_service.show(context, instance['image_ref'])
+ image_ref = instance.get('image_ref')
+ if image_ref:
+ image = self.image_service.show(context, image_ref)
+ else:
+ image = {}
if same_instance_type and flavor_id:
raise exception.CannotResizeToSameFlavor()
diff --git a/nova/compute/cells_api.py b/nova/compute/cells_api.py
index 7168313ec..4beeaeb3d 100644
--- a/nova/compute/cells_api.py
+++ b/nova/compute/cells_api.py
@@ -559,6 +559,16 @@ class ComputeCellsAPI(compute_api.API):
pass
return rv
+ @validate_cell
+ def live_migrate(self, context, instance, block_migration,
+ disk_over_commit, host_name):
+ """Migrate a server lively to a new host."""
+ super(ComputeCellsAPI, self).live_migrate(context,
+ instance, block_migration, disk_over_commit, host_name)
+
+ self._cast_to_cells(context, instance, 'live_migrate',
+ block_migration, disk_over_commit, host_name)
+
class HostAPI(compute_api.HostAPI):
"""HostAPI() class for cells.
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index b63ca10a1..91a814f98 100755
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -3188,6 +3188,7 @@ class ComputeManager(manager.SchedulerDependentManager):
return self.driver.check_can_live_migrate_source(ctxt, instance,
dest_check_data)
+ @exception.wrap_exception(notifier=notifier, publisher_id=publisher_id())
def pre_live_migration(self, context, instance,
block_migration=False, disk=None,
migrate_data=None):
@@ -3206,6 +3207,9 @@ class ComputeManager(manager.SchedulerDependentManager):
context, instance, bdms=bdms)
network_info = self._get_instance_nw_info(context, instance)
+ self._notify_about_instance_usage(
+ context, instance, "live_migration.pre.start",
+ network_info=network_info)
# TODO(tr3buchet): figure out how on the earth this is necessary
fixed_ips = network_info.fixed_ips()
@@ -3236,8 +3240,13 @@ class ComputeManager(manager.SchedulerDependentManager):
if block_migration:
self.driver.pre_block_migration(context, instance, disk)
+ self._notify_about_instance_usage(
+ context, instance, "live_migration.pre.end",
+ network_info=network_info)
+
return pre_live_migration_data
+ @exception.wrap_exception(notifier=notifier, publisher_id=publisher_id())
def live_migration(self, context, dest, instance,
block_migration=False, migrate_data=None):
"""Executing live migration.
@@ -3354,6 +3363,7 @@ class ComputeManager(manager.SchedulerDependentManager):
"This error can be safely ignored."),
instance=instance_ref)
+ @exception.wrap_exception(notifier=notifier, publisher_id=publisher_id())
def post_live_migration_at_destination(self, context, instance,
block_migration=False):
"""Post operations for live migration .
@@ -3379,6 +3389,9 @@ class ComputeManager(manager.SchedulerDependentManager):
migration)
network_info = self._get_instance_nw_info(context, instance)
+ self._notify_about_instance_usage(
+ context, instance, "live_migration.post.dest.start",
+ network_info=network_info)
block_device_info = self._get_instance_volume_block_device_info(
context, instance)
@@ -3402,6 +3415,9 @@ class ComputeManager(manager.SchedulerDependentManager):
# NOTE(vish): this is necessary to update dhcp
self.network_api.setup_networks_on_host(context, instance, self.host)
+ self._notify_about_instance_usage(
+ context, instance, "live_migration.post.dest.end",
+ network_info=network_info)
def _rollback_live_migration(self, context, instance,
dest, block_migration, migrate_data=None):
@@ -3445,6 +3461,7 @@ class ComputeManager(manager.SchedulerDependentManager):
self.compute_rpcapi.rollback_live_migration_at_destination(context,
instance, dest)
+ @exception.wrap_exception(notifier=notifier, publisher_id=publisher_id())
def rollback_live_migration_at_destination(self, context, instance):
"""Cleaning up image directory that is created pre_live_migration.
@@ -3452,6 +3469,9 @@ class ComputeManager(manager.SchedulerDependentManager):
:param instance: an Instance dict sent over rpc
"""
network_info = self._get_instance_nw_info(context, instance)
+ self._notify_about_instance_usage(
+ context, instance, "live_migration.rollback.dest.start",
+ network_info=network_info)
# NOTE(tr3buchet): tear down networks on destination host
self.network_api.setup_networks_on_host(context, instance,
@@ -3463,6 +3483,9 @@ class ComputeManager(manager.SchedulerDependentManager):
context, instance)
self.driver.destroy(instance, self._legacy_nw_info(network_info),
block_device_info)
+ self._notify_about_instance_usage(
+ context, instance, "live_migration.rollback.dest.end",
+ network_info=network_info)
@periodic_task.periodic_task
def _heal_instance_info_cache(self, context):
diff --git a/nova/openstack/common/rpc/common.py b/nova/openstack/common/rpc/common.py
index 4b2e5a71f..fcd954dd5 100644
--- a/nova/openstack/common/rpc/common.py
+++ b/nova/openstack/common/rpc/common.py
@@ -158,6 +158,10 @@ class UnsupportedRpcEnvelopeVersion(RPCException):
"not supported by this endpoint.")
+class RpcVersionCapError(RPCException):
+ message = _("Specified RPC version cap, %(version_cap)s, is too low")
+
+
class Connection(object):
"""A connection, returned by rpc.create_connection().
diff --git a/nova/openstack/common/rpc/dispatcher.py b/nova/openstack/common/rpc/dispatcher.py
index 3c84671df..81d16bcee 100644
--- a/nova/openstack/common/rpc/dispatcher.py
+++ b/nova/openstack/common/rpc/dispatcher.py
@@ -84,6 +84,7 @@ minimum version that supports the new parameter should be specified.
"""
from nova.openstack.common.rpc import common as rpc_common
+from nova.openstack.common.rpc import serializer as rpc_serializer
class RpcDispatcher(object):
@@ -93,16 +94,38 @@ class RpcDispatcher(object):
contains a list of underlying managers that have an API_VERSION attribute.
"""
- def __init__(self, callbacks):
+ def __init__(self, callbacks, serializer=None):
"""Initialize the rpc dispatcher.
:param callbacks: List of proxy objects that are an instance
of a class with rpc methods exposed. Each proxy
object should have an RPC_API_VERSION attribute.
+ :param serializer: The Serializer object that will be used to
+ deserialize arguments before the method call and
+ to serialize the result after it returns.
"""
self.callbacks = callbacks
+ if serializer is None:
+ serializer = rpc_serializer.NoOpSerializer()
+ self.serializer = serializer
super(RpcDispatcher, self).__init__()
+ def _deserialize_args(self, context, kwargs):
+ """Helper method called to deserialize args before dispatch.
+
+ This calls our serializer on each argument, returning a new set of
+ args that have been deserialized.
+
+ :param context: The request context
+ :param kwargs: The arguments to be deserialized
+ :returns: A new set of deserialized args
+ """
+ new_kwargs = dict()
+ for argname, arg in kwargs.iteritems():
+ new_kwargs[argname] = self.serializer.deserialize_entity(context,
+ arg)
+ return new_kwargs
+
def dispatch(self, ctxt, version, method, namespace, **kwargs):
"""Dispatch a message based on a requested version.
@@ -145,7 +168,9 @@ class RpcDispatcher(object):
if not hasattr(proxyobj, method):
continue
if is_compatible:
- return getattr(proxyobj, method)(ctxt, **kwargs)
+ kwargs = self._deserialize_args(ctxt, kwargs)
+ result = getattr(proxyobj, method)(ctxt, **kwargs)
+ return self.serializer.serialize_entity(ctxt, result)
if had_compatible:
raise AttributeError("No such RPC function '%s'" % method)
diff --git a/nova/openstack/common/rpc/proxy.py b/nova/openstack/common/rpc/proxy.py
index daebcbfa7..dcdfc0864 100644
--- a/nova/openstack/common/rpc/proxy.py
+++ b/nova/openstack/common/rpc/proxy.py
@@ -1,6 +1,6 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright 2012 Red Hat, Inc.
+# Copyright 2012-2013 Red Hat, Inc.
#
# 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
@@ -23,6 +23,8 @@ For more information about rpc API version numbers, see:
from nova.openstack.common import rpc
+from nova.openstack.common.rpc import common as rpc_common
+from nova.openstack.common.rpc import serializer as rpc_serializer
class RpcProxy(object):
@@ -34,16 +36,28 @@ class RpcProxy(object):
rpc API.
"""
- def __init__(self, topic, default_version):
+ # The default namespace, which can be overriden in a subclass.
+ RPC_API_NAMESPACE = None
+
+ def __init__(self, topic, default_version, version_cap=None,
+ serializer=None):
"""Initialize an RpcProxy.
:param topic: The topic to use for all messages.
:param default_version: The default API version to request in all
outgoing messages. This can be overridden on a per-message
basis.
+ :param version_cap: Optionally cap the maximum version used for sent
+ messages.
+ :param serializer: Optionaly (de-)serialize entities with a
+ provided helper.
"""
self.topic = topic
self.default_version = default_version
+ self.version_cap = version_cap
+ if serializer is None:
+ serializer = rpc_serializer.NoOpSerializer()
+ self.serializer = serializer
super(RpcProxy, self).__init__()
def _set_version(self, msg, vers):
@@ -52,7 +66,11 @@ class RpcProxy(object):
:param msg: The message having a version added to it.
:param vers: The version number to add to the message.
"""
- msg['version'] = vers if vers else self.default_version
+ v = vers if vers else self.default_version
+ if (self.version_cap and not
+ rpc_common.version_is_compatible(self.version_cap, v)):
+ raise rpc_common.RpcVersionCapError(version=self.version_cap)
+ msg['version'] = v
def _get_topic(self, topic):
"""Return the topic to use for a message."""
@@ -62,9 +80,25 @@ class RpcProxy(object):
def make_namespaced_msg(method, namespace, **kwargs):
return {'method': method, 'namespace': namespace, 'args': kwargs}
- @staticmethod
- def make_msg(method, **kwargs):
- return RpcProxy.make_namespaced_msg(method, None, **kwargs)
+ def make_msg(self, method, **kwargs):
+ return self.make_namespaced_msg(method, self.RPC_API_NAMESPACE,
+ **kwargs)
+
+ def _serialize_msg_args(self, context, kwargs):
+ """Helper method called to serialize message arguments.
+
+ This calls our serializer on each argument, returning a new
+ set of args that have been serialized.
+
+ :param context: The request context
+ :param kwargs: The arguments to serialize
+ :returns: A new set of serialized arguments
+ """
+ new_kwargs = dict()
+ for argname, arg in kwargs.iteritems():
+ new_kwargs[argname] = self.serializer.serialize_entity(context,
+ arg)
+ return new_kwargs
def call(self, context, msg, topic=None, version=None, timeout=None):
"""rpc.call() a remote method.
@@ -81,9 +115,11 @@ class RpcProxy(object):
:returns: The return value from the remote method.
"""
self._set_version(msg, version)
+ msg['args'] = self._serialize_msg_args(context, msg['args'])
real_topic = self._get_topic(topic)
try:
- return rpc.call(context, real_topic, msg, timeout)
+ result = rpc.call(context, real_topic, msg, timeout)
+ return self.serializer.deserialize_entity(context, result)
except rpc.common.Timeout as exc:
raise rpc.common.Timeout(
exc.info, real_topic, msg.get('method'))
@@ -104,9 +140,11 @@ class RpcProxy(object):
from the remote method as they arrive.
"""
self._set_version(msg, version)
+ msg['args'] = self._serialize_msg_args(context, msg['args'])
real_topic = self._get_topic(topic)
try:
- return rpc.multicall(context, real_topic, msg, timeout)
+ result = rpc.multicall(context, real_topic, msg, timeout)
+ return self.serializer.deserialize_entity(context, result)
except rpc.common.Timeout as exc:
raise rpc.common.Timeout(
exc.info, real_topic, msg.get('method'))
@@ -124,6 +162,7 @@ class RpcProxy(object):
remote method.
"""
self._set_version(msg, version)
+ msg['args'] = self._serialize_msg_args(context, msg['args'])
rpc.cast(context, self._get_topic(topic), msg)
def fanout_cast(self, context, msg, topic=None, version=None):
@@ -139,6 +178,7 @@ class RpcProxy(object):
from the remote method.
"""
self._set_version(msg, version)
+ msg['args'] = self._serialize_msg_args(context, msg['args'])
rpc.fanout_cast(context, self._get_topic(topic), msg)
def cast_to_server(self, context, server_params, msg, topic=None,
@@ -157,6 +197,7 @@ class RpcProxy(object):
return values.
"""
self._set_version(msg, version)
+ msg['args'] = self._serialize_msg_args(context, msg['args'])
rpc.cast_to_server(context, server_params, self._get_topic(topic), msg)
def fanout_cast_to_server(self, context, server_params, msg, topic=None,
@@ -175,5 +216,6 @@ class RpcProxy(object):
return values.
"""
self._set_version(msg, version)
+ msg['args'] = self._serialize_msg_args(context, msg['args'])
rpc.fanout_cast_to_server(context, server_params,
self._get_topic(topic), msg)
diff --git a/nova/openstack/common/rpc/serializer.py b/nova/openstack/common/rpc/serializer.py
new file mode 100644
index 000000000..0a2c9c4f1
--- /dev/null
+++ b/nova/openstack/common/rpc/serializer.py
@@ -0,0 +1,52 @@
+# Copyright 2013 IBM Corp.
+#
+# 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.
+
+"""Provides the definition of an RPC serialization handler"""
+
+import abc
+
+
+class Serializer(object):
+ """Generic (de-)serialization definition base class"""
+ __metaclass__ = abc.ABCMeta
+
+ @abc.abstractmethod
+ def serialize_entity(self, context, entity):
+ """Serialize something to primitive form.
+
+ :param context: Security context
+ :param entity: Entity to be serialized
+ :returns: Serialized form of entity
+ """
+ pass
+
+ @abc.abstractmethod
+ def deserialize_entity(self, context, entity):
+ """Deserialize something from primitive form.
+
+ :param context: Security context
+ :param entity: Primitive to be deserialized
+ :returns: Deserialized form of entity
+ """
+ pass
+
+
+class NoOpSerializer(Serializer):
+ """A serializer that does nothing"""
+
+ def serialize_entity(self, context, entity):
+ return entity
+
+ def deserialize_entity(self, context, entity):
+ return entity
diff --git a/nova/service.py b/nova/service.py
index 12bab14c3..3731986c4 100644
--- a/nova/service.py
+++ b/nova/service.py
@@ -19,26 +19,20 @@
"""Generic Node base class for all workers that run on hosts."""
-import errno
import inspect
import os
import random
-import signal
import sys
-import time
-import eventlet
-import greenlet
from oslo.config import cfg
from nova import conductor
from nova import context
from nova import exception
-from nova.openstack.common import eventlet_backdoor
from nova.openstack.common import importutils
from nova.openstack.common import log as logging
-from nova.openstack.common import loopingcall
from nova.openstack.common import rpc
+from nova.openstack.common import service
from nova import servicegroup
from nova import utils
from nova import version
@@ -119,275 +113,7 @@ CONF.register_opts(service_opts)
CONF.import_opt('host', 'nova.netconf')
-class SignalExit(SystemExit):
- def __init__(self, signo, exccode=1):
- super(SignalExit, self).__init__(exccode)
- self.signo = signo
-
-
-class Launcher(object):
- """Launch one or more services and wait for them to complete."""
-
- def __init__(self):
- """Initialize the service launcher.
-
- :returns: None
-
- """
- self._services = []
- self.backdoor_port = eventlet_backdoor.initialize_if_enabled()
-
- @staticmethod
- def run_server(server):
- """Start and wait for a server to finish.
-
- :param service: Server to run and wait for.
- :returns: None
-
- """
- server.start()
- server.wait()
-
- def launch_server(self, server):
- """Load and start the given server.
-
- :param server: The server you would like to start.
- :returns: None
-
- """
- if self.backdoor_port is not None:
- server.backdoor_port = self.backdoor_port
- gt = eventlet.spawn(self.run_server, server)
- self._services.append(gt)
-
- def stop(self):
- """Stop all services which are currently running.
-
- :returns: None
-
- """
- for service in self._services:
- service.kill()
-
- def wait(self):
- """Waits until all services have been stopped, and then returns.
-
- :returns: None
-
- """
- for service in self._services:
- try:
- service.wait()
- except greenlet.GreenletExit:
- pass
-
-
-class ServiceLauncher(Launcher):
- def _handle_signal(self, signo, frame):
- # Allow the process to be killed again and die from natural causes
- signal.signal(signal.SIGTERM, signal.SIG_DFL)
- signal.signal(signal.SIGINT, signal.SIG_DFL)
-
- raise SignalExit(signo)
-
- def wait(self):
- signal.signal(signal.SIGTERM, self._handle_signal)
- signal.signal(signal.SIGINT, self._handle_signal)
-
- LOG.debug(_('Full set of CONF:'))
- for flag in CONF:
- flag_get = CONF.get(flag, None)
- # hide flag contents from log if contains a password
- # should use secret flag when switch over to openstack-common
- if ("_password" in flag or "_key" in flag or
- (flag == "sql_connection" and "mysql:" in flag_get)):
- LOG.debug(_('%(flag)s : FLAG SET ') % locals())
- else:
- LOG.debug('%(flag)s : %(flag_get)s' % locals())
-
- status = None
- try:
- super(ServiceLauncher, self).wait()
- except SignalExit as exc:
- signame = {signal.SIGTERM: 'SIGTERM',
- signal.SIGINT: 'SIGINT'}[exc.signo]
- LOG.info(_('Caught %s, exiting'), signame)
- status = exc.code
- except SystemExit as exc:
- status = exc.code
- finally:
- self.stop()
- rpc.cleanup()
-
- if status is not None:
- sys.exit(status)
-
-
-class ServerWrapper(object):
- def __init__(self, server, workers):
- self.server = server
- self.workers = workers
- self.children = set()
- self.forktimes = []
-
-
-class ProcessLauncher(object):
- def __init__(self):
- self.children = {}
- self.sigcaught = None
- self.running = True
- rfd, self.writepipe = os.pipe()
- self.readpipe = eventlet.greenio.GreenPipe(rfd, 'r')
-
- signal.signal(signal.SIGTERM, self._handle_signal)
- signal.signal(signal.SIGINT, self._handle_signal)
-
- def _handle_signal(self, signo, frame):
- self.sigcaught = signo
- self.running = False
-
- # Allow the process to be killed again and die from natural causes
- signal.signal(signal.SIGTERM, signal.SIG_DFL)
- signal.signal(signal.SIGINT, signal.SIG_DFL)
-
- def _pipe_watcher(self):
- # This will block until the write end is closed when the parent
- # dies unexpectedly
- self.readpipe.read()
-
- LOG.info(_('Parent process has died unexpectedly, exiting'))
-
- sys.exit(1)
-
- def _child_process(self, server):
- # Setup child signal handlers differently
- def _sigterm(*args):
- signal.signal(signal.SIGTERM, signal.SIG_DFL)
- raise SignalExit(signal.SIGTERM)
-
- signal.signal(signal.SIGTERM, _sigterm)
- # Block SIGINT and let the parent send us a SIGTERM
- signal.signal(signal.SIGINT, signal.SIG_IGN)
-
- # Reopen the eventlet hub to make sure we don't share an epoll
- # fd with parent and/or siblings, which would be bad
- eventlet.hubs.use_hub()
-
- # Close write to ensure only parent has it open
- os.close(self.writepipe)
- # Create greenthread to watch for parent to close pipe
- eventlet.spawn(self._pipe_watcher)
-
- # Reseed random number generator
- random.seed()
-
- launcher = Launcher()
- launcher.run_server(server)
-
- def _start_child(self, wrap):
- if len(wrap.forktimes) > wrap.workers:
- # Limit ourselves to one process a second (over the period of
- # number of workers * 1 second). This will allow workers to
- # start up quickly but ensure we don't fork off children that
- # die instantly too quickly.
- if time.time() - wrap.forktimes[0] < wrap.workers:
- LOG.info(_('Forking too fast, sleeping'))
- time.sleep(1)
-
- wrap.forktimes.pop(0)
-
- wrap.forktimes.append(time.time())
-
- pid = os.fork()
- if pid == 0:
- # NOTE(johannes): All exceptions are caught to ensure this
- # doesn't fallback into the loop spawning children. It would
- # be bad for a child to spawn more children.
- status = 0
- try:
- self._child_process(wrap.server)
- except SignalExit as exc:
- signame = {signal.SIGTERM: 'SIGTERM',
- signal.SIGINT: 'SIGINT'}[exc.signo]
- LOG.info(_('Caught %s, exiting'), signame)
- status = exc.code
- except SystemExit as exc:
- status = exc.code
- except BaseException:
- LOG.exception(_('Unhandled exception'))
- status = 2
- finally:
- wrap.server.stop()
-
- os._exit(status)
-
- LOG.info(_('Started child %d'), pid)
-
- wrap.children.add(pid)
- self.children[pid] = wrap
-
- return pid
-
- def launch_server(self, server, workers=1):
- wrap = ServerWrapper(server, workers)
-
- LOG.info(_('Starting %d workers'), wrap.workers)
- while self.running and len(wrap.children) < wrap.workers:
- self._start_child(wrap)
-
- def _wait_child(self):
- try:
- pid, status = os.wait()
- except OSError as exc:
- if exc.errno not in (errno.EINTR, errno.ECHILD):
- raise
- return None
-
- if os.WIFSIGNALED(status):
- sig = os.WTERMSIG(status)
- LOG.info(_('Child %(pid)d killed by signal %(sig)d'), locals())
- else:
- code = os.WEXITSTATUS(status)
- LOG.info(_('Child %(pid)d exited with status %(code)d'), locals())
-
- if pid not in self.children:
- LOG.warning(_('pid %d not in child list'), pid)
- return None
-
- wrap = self.children.pop(pid)
- wrap.children.remove(pid)
- return wrap
-
- def wait(self):
- """Loop waiting on children to die and respawning as necessary."""
- while self.running:
- wrap = self._wait_child()
- if not wrap:
- continue
-
- while self.running and len(wrap.children) < wrap.workers:
- self._start_child(wrap)
-
- if self.sigcaught:
- signame = {signal.SIGTERM: 'SIGTERM',
- signal.SIGINT: 'SIGINT'}[self.sigcaught]
- LOG.info(_('Caught %s, stopping children'), signame)
-
- for pid in self.children:
- try:
- os.kill(pid, signal.SIGTERM)
- except OSError as exc:
- if exc.errno != errno.ESRCH:
- raise
-
- # Wait for children to die
- if self.children:
- LOG.info(_('Waiting on %d children to exit'), len(self.children))
- while self.children:
- self._wait_child()
-
-
-class Service(object):
+class Service(service.Service):
"""Service object for binaries running on hosts.
A service takes a manager and enables rpc by listening to queues based
@@ -398,6 +124,7 @@ class Service(object):
periodic_enable=None, periodic_fuzzy_delay=None,
periodic_interval_max=None, db_allowed=True,
*args, **kwargs):
+ super(Service, self).__init__()
self.host = host
self.binary = binary
self.topic = topic
@@ -417,7 +144,6 @@ class Service(object):
self.periodic_fuzzy_delay = periodic_fuzzy_delay
self.periodic_interval_max = periodic_interval_max
self.saved_args, self.saved_kwargs = args, kwargs
- self.timers = []
self.backdoor_port = None
self.conductor_api = conductor.API(use_local=db_allowed)
self.conductor_api.wait_until_ready(context.get_admin_context())
@@ -464,9 +190,7 @@ class Service(object):
LOG.debug(_("Join ServiceGroup membership for this service %s")
% self.topic)
# Add service to the ServiceGroup membership group.
- pulse = self.servicegroup_api.join(self.host, self.topic, self)
- if pulse:
- self.timers.append(pulse)
+ self.servicegroup_api.join(self.host, self.topic, self)
if self.periodic_enable:
if self.periodic_fuzzy_delay:
@@ -474,10 +198,10 @@ class Service(object):
else:
initial_delay = None
- periodic = loopingcall.DynamicLoopingCall(self.periodic_tasks)
- periodic.start(initial_delay=initial_delay,
- periodic_interval_max=self.periodic_interval_max)
- self.timers.append(periodic)
+ self.tg.add_dynamic_timer(self.periodic_tasks,
+ initial_delay=initial_delay,
+ periodic_interval_max=
+ self.periodic_interval_max)
def _create_service_ref(self, context):
svc_values = {
@@ -546,25 +270,12 @@ class Service(object):
LOG.warn(_('Service killed that has no database entry'))
def stop(self):
- # Try to shut the connection down, but if we get any sort of
- # errors, go ahead and ignore them.. as we're shutting down anyway
try:
self.conn.close()
except Exception:
pass
- for x in self.timers:
- try:
- x.stop()
- except Exception:
- pass
- self.timers = []
- def wait(self):
- for x in self.timers:
- try:
- x.wait()
- except Exception:
- pass
+ super(Service, self).stop()
def periodic_tasks(self, raise_on_error=False):
"""Tasks to be run at a periodic interval."""
@@ -667,6 +378,10 @@ class WSGIService(object):
self.server.wait()
+def process_launcher():
+ return service.ProcessLauncher()
+
+
# NOTE(vish): the global launcher is to maintain the existing
# functionality of calling service.serve +
# service.wait
@@ -678,12 +393,7 @@ def serve(server, workers=None):
if _launcher:
raise RuntimeError(_('serve() can only be called once'))
- if workers:
- _launcher = ProcessLauncher()
- _launcher.launch_server(server, workers=workers)
- else:
- _launcher = ServiceLauncher()
- _launcher.launch_server(server)
+ _launcher = service.launch(server, workers=workers)
def wait():
diff --git a/nova/servicegroup/drivers/db.py b/nova/servicegroup/drivers/db.py
index 24fcfd04f..22b25d61c 100644
--- a/nova/servicegroup/drivers/db.py
+++ b/nova/servicegroup/drivers/db.py
@@ -18,7 +18,6 @@ from oslo.config import cfg
from nova import conductor
from nova import context
from nova.openstack.common import log as logging
-from nova.openstack.common import loopingcall
from nova.openstack.common import timeutils
from nova.servicegroup import api
from nova import utils
@@ -47,11 +46,8 @@ class DbDriver(api.ServiceGroupDriver):
' ServiceGroup driver'))
report_interval = service.report_interval
if report_interval:
- pulse = loopingcall.FixedIntervalLoopingCall(self._report_state,
- service)
- pulse.start(interval=report_interval,
- initial_delay=report_interval)
- return pulse
+ service.tg.add_timer(report_interval, self._report_state,
+ report_interval, service)
def is_up(self, service_ref):
"""Moved from nova.utils
diff --git a/nova/servicegroup/drivers/mc.py b/nova/servicegroup/drivers/mc.py
index 86c27a3aa..6e8cda456 100644
--- a/nova/servicegroup/drivers/mc.py
+++ b/nova/servicegroup/drivers/mc.py
@@ -22,7 +22,6 @@ from oslo.config import cfg
from nova import conductor
from nova import context
from nova.openstack.common import log as logging
-from nova.openstack.common import loopingcall
from nova.openstack.common import memorycache
from nova.openstack.common import timeutils
from nova.servicegroup import api
@@ -58,11 +57,8 @@ class MemcachedDriver(api.ServiceGroupDriver):
'Memcached based ServiceGroup driver'))
report_interval = service.report_interval
if report_interval:
- pulse = loopingcall.FixedIntervalLoopingCall(self._report_state,
- service)
- pulse.start(interval=report_interval,
- initial_delay=report_interval)
- return pulse
+ service.tg.add_timer(report_interval, self._report_state,
+ report_interval, service)
def is_up(self, service_ref):
"""Moved from nova.utils
diff --git a/nova/tests/api/openstack/compute/test_servers.py b/nova/tests/api/openstack/compute/test_servers.py
index 22aecf020..993451263 100644
--- a/nova/tests/api/openstack/compute/test_servers.py
+++ b/nova/tests/api/openstack/compute/test_servers.py
@@ -1402,8 +1402,9 @@ class ServersControllerTest(test.TestCase):
name='public image', is_public=True,
status='active', properties={'key1': 'value1'},
min_ram="4096", min_disk="10")
- self.stubs.Set(compute_api.API, '_get_image',
- fake_get_image)
+
+ self.stubs.Set(fake._FakeImageService, 'show', fake_get_image)
+
self.stubs.Set(db, 'instance_get_by_uuid',
fakes.fake_instance_get(vm_state=vm_states.ACTIVE))
image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
@@ -1429,8 +1430,35 @@ class ServersControllerTest(test.TestCase):
name='public image', is_public=True,
status='active', properties={'key1': 'value1'},
min_ram="128", min_disk="100000")
- self.stubs.Set(compute_api.API, '_get_image',
- fake_get_image)
+
+ self.stubs.Set(fake._FakeImageService, 'show', fake_get_image)
+
+ self.stubs.Set(db, 'instance_get_by_uuid',
+ fakes.fake_instance_get(vm_state=vm_states.ACTIVE))
+ image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
+ image_href = 'http://localhost/v2/fake/images/%s' % image_uuid
+ body = {
+ 'rebuild': {
+ 'name': 'new_name',
+ 'imageRef': image_href,
+ },
+ }
+
+ req = fakes.HTTPRequest.blank('/v2/fake/servers/a/action')
+ req.method = 'POST'
+ req.body = jsonutils.dumps(body)
+ req.headers["content-type"] = "application/json"
+ self.assertRaises(webob.exc.HTTPBadRequest,
+ self.controller._action_rebuild, req, FAKE_UUID, body)
+
+ def test_rebuild_instance_with_deleted_image(self):
+ def fake_get_image(self, context, image_href):
+ return dict(id='76fa36fc-c930-4bf3-8c8a-ea2a2420deb6',
+ name='public image', is_public=True,
+ status='DELETED')
+
+ self.stubs.Set(fake._FakeImageService, 'show', fake_get_image)
+
self.stubs.Set(db, 'instance_get_by_uuid',
fakes.fake_instance_get(vm_state=vm_states.ACTIVE))
image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
diff --git a/nova/tests/compute/test_compute.py b/nova/tests/compute/test_compute.py
index 3101e3aa2..933d40d59 100644
--- a/nova/tests/compute/test_compute.py
+++ b/nova/tests/compute/test_compute.py
@@ -3493,6 +3493,7 @@ class ComputeTestCase(BaseTestCase):
self.compute.driver.ensure_filtering_rules_for_instance(
mox.IsA(instance), nw_info)
+ test_notifier.NOTIFICATIONS = []
# start test
self.mox.ReplayAll()
migrate_data = {'is_shared_storage': False}
@@ -3500,6 +3501,13 @@ class ComputeTestCase(BaseTestCase):
block_migration=False,
migrate_data=migrate_data)
self.assertEqual(ret, None)
+ self.assertEqual(len(test_notifier.NOTIFICATIONS), 2)
+ msg = test_notifier.NOTIFICATIONS[0]
+ self.assertEqual(msg['event_type'],
+ 'compute.instance.live_migration.pre.start')
+ msg = test_notifier.NOTIFICATIONS[1]
+ self.assertEqual(msg['event_type'],
+ 'compute.instance.live_migration.pre.end')
# cleanup
db.instance_destroy(c, instance['uuid'])
@@ -3719,11 +3727,20 @@ class ComputeTestCase(BaseTestCase):
self.compute.network_api.setup_networks_on_host(self.admin_ctxt,
mox.IgnoreArg(), self.compute.host)
+ test_notifier.NOTIFICATIONS = []
self.mox.ReplayAll()
self.compute.post_live_migration_at_destination(self.admin_ctxt,
self.instance)
+ self.assertEqual(len(test_notifier.NOTIFICATIONS), 2)
+ msg = test_notifier.NOTIFICATIONS[0]
+ self.assertEqual(msg['event_type'],
+ 'compute.instance.live_migration.post.dest.start')
+ msg = test_notifier.NOTIFICATIONS[1]
+ self.assertEqual(msg['event_type'],
+ 'compute.instance.live_migration.post.dest.end')
+
return self.compute.conductor_api.instance_get_by_uuid(self.admin_ctxt,
self.instance['uuid'])
@@ -3749,6 +3766,31 @@ class ComputeTestCase(BaseTestCase):
updated = self._finish_post_live_migration_at_destination()
self.assertIsNone(updated['node'])
+ def test_rollback_live_migration_at_destination_correctly(self):
+ # creating instance testdata
+ c = context.get_admin_context()
+ instance_ref = self._create_fake_instance({'host': 'dummy'})
+ inst_uuid = instance_ref['uuid']
+ inst_id = instance_ref['id']
+
+ instance = jsonutils.to_primitive(db.instance_get(c, inst_id))
+ test_notifier.NOTIFICATIONS = []
+ # start test
+ self.mox.ReplayAll()
+ ret = self.compute.rollback_live_migration_at_destination(c,
+ instance=instance)
+ self.assertEqual(ret, None)
+ self.assertEqual(len(test_notifier.NOTIFICATIONS), 2)
+ msg = test_notifier.NOTIFICATIONS[0]
+ self.assertEqual(msg['event_type'],
+ 'compute.instance.live_migration.rollback.dest.start')
+ msg = test_notifier.NOTIFICATIONS[1]
+ self.assertEqual(msg['event_type'],
+ 'compute.instance.live_migration.rollback.dest.end')
+
+ # cleanup
+ db.instance_destroy(c, inst_uuid)
+
def test_run_kill_vm(self):
# Detect when a vm is terminated behind the scenes.
self.stubs.Set(compute_manager.ComputeManager,
@@ -5501,6 +5543,105 @@ class ComputeAPITestCase(BaseTestCase):
instance = db.instance_get_by_uuid(self.context, instance_uuid)
self.assertEqual(instance['task_state'], task_states.REBUILDING)
+ def test_rebuild_with_deleted_image(self):
+ # If we're given a deleted image by glance, we should not be able to
+ # rebuild from it
+ instance = jsonutils.to_primitive(
+ self._create_fake_instance(params={'image_ref': '1'}))
+
+ self.fake_image['name'] = 'fake_name'
+ self.fake_image['status'] = 'DELETED'
+ self.stubs.Set(fake_image._FakeImageService, 'show', self.fake_show)
+
+ expected_message = (
+ exception.ImageNotActive.message % {'image_id':
+ self.fake_image['id']})
+ with testtools.ExpectedException(exception.ImageNotActive,
+ expected_message):
+ self.compute_api.rebuild(self.context, instance,
+ self.fake_image['id'], 'new_password')
+
+ def test_rebuild_with_too_little_ram(self):
+ instance = jsonutils.to_primitive(
+ self._create_fake_instance(params={'image_ref': '1'}))
+
+ def fake_extract_instance_type(_inst):
+ return dict(memory_mb=64, root_gb=1)
+
+ self.stubs.Set(flavors, 'extract_instance_type',
+ fake_extract_instance_type)
+
+ self.fake_image['min_ram'] = 128
+ self.stubs.Set(fake_image._FakeImageService, 'show', self.fake_show)
+
+ self.assertRaises(exception.InstanceTypeMemoryTooSmall,
+ self.compute_api.rebuild, self.context,
+ instance, self.fake_image['id'], 'new_password')
+
+ # Reduce image memory requirements and make sure it works
+ self.fake_image['min_ram'] = 64
+
+ self.compute_api.rebuild(self.context,
+ instance, self.fake_image['id'], 'new_password')
+ db.instance_destroy(self.context, instance['uuid'])
+
+ def test_rebuild_with_too_little_disk(self):
+ instance = jsonutils.to_primitive(
+ self._create_fake_instance(params={'image_ref': '1'}))
+
+ def fake_extract_instance_type(_inst):
+ return dict(memory_mb=64, root_gb=1)
+
+ self.stubs.Set(flavors, 'extract_instance_type',
+ fake_extract_instance_type)
+
+ self.fake_image['min_disk'] = 2
+ self.stubs.Set(fake_image._FakeImageService, 'show', self.fake_show)
+
+ self.assertRaises(exception.InstanceTypeDiskTooSmall,
+ self.compute_api.rebuild, self.context,
+ instance, self.fake_image['id'], 'new_password')
+
+ # Reduce image disk requirements and make sure it works
+ self.fake_image['min_disk'] = 1
+
+ self.compute_api.rebuild(self.context,
+ instance, self.fake_image['id'], 'new_password')
+ db.instance_destroy(self.context, instance['uuid'])
+
+ def test_rebuild_with_just_enough_ram_and_disk(self):
+ instance = jsonutils.to_primitive(
+ self._create_fake_instance(params={'image_ref': '1'}))
+
+ def fake_extract_instance_type(_inst):
+ return dict(memory_mb=64, root_gb=1)
+
+ self.stubs.Set(flavors, 'extract_instance_type',
+ fake_extract_instance_type)
+
+ self.fake_image['min_ram'] = 64
+ self.fake_image['min_disk'] = 1
+ self.stubs.Set(fake_image._FakeImageService, 'show', self.fake_show)
+
+ self.compute_api.rebuild(self.context,
+ instance, self.fake_image['id'], 'new_password')
+ db.instance_destroy(self.context, instance['uuid'])
+
+ def test_rebuild_with_no_ram_and_disk_reqs(self):
+ instance = jsonutils.to_primitive(
+ self._create_fake_instance(params={'image_ref': '1'}))
+
+ def fake_extract_instance_type(_inst):
+ return dict(memory_mb=64, root_gb=1)
+
+ self.stubs.Set(flavors, 'extract_instance_type',
+ fake_extract_instance_type)
+ self.stubs.Set(fake_image._FakeImageService, 'show', self.fake_show)
+
+ self.compute_api.rebuild(self.context,
+ instance, self.fake_image['id'], 'new_password')
+ db.instance_destroy(self.context, instance['uuid'])
+
def _stub_out_reboot(self, device_name):
def fake_reboot_instance(rpcapi, context, instance,
block_device_info,
@@ -6155,6 +6296,22 @@ class ComputeAPITestCase(BaseTestCase):
self.context, instance)
self.compute.terminate_instance(self.context, instance=instance)
+ def test_resize_no_image(self):
+ def _fake_prep_resize(_context, **args):
+ image = args['image']
+ self.assertEqual(image, {})
+
+ instance = self._create_fake_instance(params={'image_ref': ''})
+ instance = db.instance_get_by_uuid(self.context, instance['uuid'])
+ instance = jsonutils.to_primitive(instance)
+ self.compute.run_instance(self.context, instance=instance)
+
+ self.stubs.Set(self.compute_api.scheduler_rpcapi,
+ 'prep_resize', _fake_prep_resize)
+
+ self.compute_api.resize(self.context, instance, None)
+ self.compute.terminate_instance(self.context, instance=instance)
+
def test_migrate(self):
instance = self._create_fake_instance()
instance = db.instance_get_by_uuid(self.context, instance['uuid'])
diff --git a/nova/tests/compute/test_compute_cells.py b/nova/tests/compute/test_compute_cells.py
index 40ae4e3de..ad4e6c754 100644
--- a/nova/tests/compute/test_compute_cells.py
+++ b/nova/tests/compute/test_compute_cells.py
@@ -145,9 +145,6 @@ class CellsComputeAPITestCase(test_compute.ComputeAPITestCase):
def test_instance_metadata(self):
self.skipTest("Test is incompatible with cells.")
- def test_live_migrate(self):
- self.skipTest("Test is incompatible with cells.")
-
def test_snapshot_given_image_uuid(self):
self.skipTest("Test doesn't apply to API cell.")
diff --git a/nova/tests/integrated/test_api_samples.py b/nova/tests/integrated/test_api_samples.py
index cb2d14289..9b678ddd3 100644
--- a/nova/tests/integrated/test_api_samples.py
+++ b/nova/tests/integrated/test_api_samples.py
@@ -52,12 +52,12 @@ from nova.tests.api.openstack.compute.contrib import test_fping
from nova.tests.api.openstack.compute.contrib import test_networks
from nova.tests.api.openstack.compute.contrib import test_services
from nova.tests.api.openstack import fakes
-from nova.tests.baremetal.db import base as bm_db_base
from nova.tests import fake_instance_actions
from nova.tests import fake_network
from nova.tests.image import fake
from nova.tests.integrated import integrated_helpers
from nova.tests import utils as test_utils
+from nova.tests.virt.baremetal.db import base as bm_db_base
from nova import utils
from nova.volume import cinder
diff --git a/nova/tests/integrated/test_multiprocess_api.py b/nova/tests/integrated/test_multiprocess_api.py
index c85a43a0c..2610cdcb7 100644
--- a/nova/tests/integrated/test_multiprocess_api.py
+++ b/nova/tests/integrated/test_multiprocess_api.py
@@ -54,8 +54,8 @@ class MultiprocessWSGITest(integrated_helpers._IntegratedTestBase):
# os._exit() which doesn't have this problem.
status = 0
try:
- launcher = service.ProcessLauncher()
- launcher.launch_server(self.osapi, workers=self.osapi.workers)
+ launcher = service.process_launcher()
+ launcher.launch_service(self.osapi, workers=self.osapi.workers)
launcher.wait()
except SystemExit as exc:
status = exc.code
diff --git a/nova/tests/test_migrations.py b/nova/tests/test_migrations.py
index de5eb1b40..688db500d 100644
--- a/nova/tests/test_migrations.py
+++ b/nova/tests/test_migrations.py
@@ -1339,7 +1339,7 @@ class TestBaremetalMigrations(BaseMigrationTestCase, CommonTestsMixIn):
super(TestBaremetalMigrations, self).__init__(*args, **kwargs)
self.DEFAULT_CONFIG_FILE = os.path.join(os.path.dirname(__file__),
- 'test_baremetal_migrations.conf')
+ 'virt/baremetal/test_baremetal_migrations.conf')
# Test machines can set the NOVA_TEST_MIGRATIONS_CONF variable
# to override the location of the config file for migration testing
self.CONFIG_FILE_PATH = os.environ.get(
diff --git a/nova/tests/test_service.py b/nova/tests/test_service.py
index 2cbc82fda..3ca6d7bc1 100644
--- a/nova/tests/test_service.py
+++ b/nova/tests/test_service.py
@@ -201,7 +201,6 @@ class TestLauncher(test.TestCase):
self.service = service.WSGIService("test_service")
def test_launch_app(self):
- launcher = service.Launcher()
- launcher.launch_server(self.service)
+ service.serve(self.service)
self.assertNotEquals(0, self.service.port)
- launcher.stop()
+ service._launcher.stop()
diff --git a/nova/tests/test_virt_drivers.py b/nova/tests/test_virt_drivers.py
index 395663600..c054b9624 100644
--- a/nova/tests/test_virt_drivers.py
+++ b/nova/tests/test_virt_drivers.py
@@ -25,9 +25,9 @@ from nova import exception
from nova.openstack.common import importutils
from nova.openstack.common import log as logging
from nova import test
-from nova.tests import fake_libvirt_utils
from nova.tests.image import fake as fake_image
from nova.tests import utils as test_utils
+from nova.tests.virt.libvirt import fake_libvirt_utils
from nova.virt import event as virtevent
from nova.virt import fake
@@ -67,9 +67,9 @@ class _FakeDriverBackendTestCase(object):
else:
self.saved_libvirt = None
- import nova.tests.fake_imagebackend as fake_imagebackend
- import nova.tests.fake_libvirt_utils as fake_libvirt_utils
- import nova.tests.fakelibvirt as fakelibvirt
+ import nova.tests.virt.libvirt.fake_imagebackend as fake_imagebackend
+ import nova.tests.virt.libvirt.fake_libvirt_utils as fake_libvirt_utils
+ import nova.tests.virt.libvirt.fakelibvirt as fakelibvirt
sys.modules['libvirt'] = fakelibvirt
import nova.virt.libvirt.driver
diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py
index 45ebfaab3..2628f2582 100644
--- a/nova/tests/test_xenapi.py
+++ b/nova/tests/test_xenapi.py
@@ -2117,8 +2117,9 @@ class XenAPIBWCountersTestCase(stubs.XenAPITestBase):
# TODO(salvatore-orlando): this class and
-# nova.tests.test_libvirt.IPTablesFirewallDriverTestCase share a lot of code.
-# Consider abstracting common code in a base class for firewall driver testing.
+# nova.tests.virt.test_libvirt.IPTablesFirewallDriverTestCase share a lot of
+# code. Consider abstracting common code in a base class for firewall driver
+# testing.
class XenAPIDom0IptablesFirewallTestCase(stubs.XenAPITestBase):
_in_rules = [
diff --git a/nova/tests/baremetal/__init__.py b/nova/tests/virt/baremetal/__init__.py
index f15d84efc..34b09daac 100644
--- a/nova/tests/baremetal/__init__.py
+++ b/nova/tests/virt/baremetal/__init__.py
@@ -12,4 +12,4 @@
# 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.tests.baremetal import *
+from nova.tests.virt.baremetal import *
diff --git a/nova/tests/baremetal/db/__init__.py b/nova/tests/virt/baremetal/db/__init__.py
index 543dfc1ae..0f1f4e846 100644
--- a/nova/tests/baremetal/db/__init__.py
+++ b/nova/tests/virt/baremetal/db/__init__.py
@@ -12,4 +12,4 @@
# 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.tests.baremetal.db import *
+from nova.tests.virt.baremetal.db import *
diff --git a/nova/tests/baremetal/db/base.py b/nova/tests/virt/baremetal/db/base.py
index 499eee32a..499eee32a 100644
--- a/nova/tests/baremetal/db/base.py
+++ b/nova/tests/virt/baremetal/db/base.py
diff --git a/nova/tests/baremetal/db/test_bm_interface.py b/nova/tests/virt/baremetal/db/test_bm_interface.py
index e870ec5e0..24b6ae1e1 100644
--- a/nova/tests/baremetal/db/test_bm_interface.py
+++ b/nova/tests/virt/baremetal/db/test_bm_interface.py
@@ -19,7 +19,7 @@ Bare-metal DB testcase for BareMetalInterface
from nova import exception
from nova.openstack.common.db import exception as db_exc
-from nova.tests.baremetal.db import base
+from nova.tests.virt.baremetal.db import base
from nova.virt.baremetal import db
diff --git a/nova/tests/baremetal/db/test_bm_node.py b/nova/tests/virt/baremetal/db/test_bm_node.py
index 204a6bf7b..0acd5a994 100644
--- a/nova/tests/baremetal/db/test_bm_node.py
+++ b/nova/tests/virt/baremetal/db/test_bm_node.py
@@ -18,8 +18,8 @@ Bare-Metal DB testcase for BareMetalNode
"""
from nova import exception
-from nova.tests.baremetal.db import base
-from nova.tests.baremetal.db import utils
+from nova.tests.virt.baremetal.db import base
+from nova.tests.virt.baremetal.db import utils
from nova.virt.baremetal import db
diff --git a/nova/tests/baremetal/db/test_bm_pxe_ip.py b/nova/tests/virt/baremetal/db/test_bm_pxe_ip.py
index fe8ba5b3e..85f3e2f4b 100644
--- a/nova/tests/baremetal/db/test_bm_pxe_ip.py
+++ b/nova/tests/virt/baremetal/db/test_bm_pxe_ip.py
@@ -19,8 +19,8 @@ Bare-metal DB testcase for BareMetalPxeIp
from nova import exception
from nova.openstack.common.db import exception as db_exc
-from nova.tests.baremetal.db import base
-from nova.tests.baremetal.db import utils
+from nova.tests.virt.baremetal.db import base
+from nova.tests.virt.baremetal.db import utils
from nova.virt.baremetal import db
diff --git a/nova/tests/baremetal/db/utils.py b/nova/tests/virt/baremetal/db/utils.py
index c3b3cff5f..c3b3cff5f 100644
--- a/nova/tests/baremetal/db/utils.py
+++ b/nova/tests/virt/baremetal/db/utils.py
diff --git a/nova/tests/test_baremetal_migrations.conf b/nova/tests/virt/baremetal/test_baremetal_migrations.conf
index 774f14994..774f14994 100644
--- a/nova/tests/test_baremetal_migrations.conf
+++ b/nova/tests/virt/baremetal/test_baremetal_migrations.conf
diff --git a/nova/tests/baremetal/test_driver.py b/nova/tests/virt/baremetal/test_driver.py
index 3b0295a92..0564faf1e 100644
--- a/nova/tests/baremetal/test_driver.py
+++ b/nova/tests/virt/baremetal/test_driver.py
@@ -25,10 +25,10 @@ from oslo.config import cfg
from nova.compute import power_state
from nova import exception
from nova import test
-from nova.tests.baremetal.db import base as bm_db_base
-from nova.tests.baremetal.db import utils as bm_db_utils
from nova.tests.image import fake as fake_image
from nova.tests import utils
+from nova.tests.virt.baremetal.db import base as bm_db_base
+from nova.tests.virt.baremetal.db import utils as bm_db_utils
from nova.virt.baremetal import baremetal_states
from nova.virt.baremetal import db
from nova.virt.baremetal import driver as bm_driver
diff --git a/nova/tests/baremetal/test_ipmi.py b/nova/tests/virt/baremetal/test_ipmi.py
index 01bb58d8b..ba7a875cf 100644
--- a/nova/tests/baremetal/test_ipmi.py
+++ b/nova/tests/virt/baremetal/test_ipmi.py
@@ -26,7 +26,7 @@ import tempfile
from oslo.config import cfg
from nova import test
-from nova.tests.baremetal.db import utils as bm_db_utils
+from nova.tests.virt.baremetal.db import utils as bm_db_utils
from nova import utils
from nova.virt.baremetal import baremetal_states
from nova.virt.baremetal import ipmi
diff --git a/nova/tests/baremetal/test_nova_baremetal_deploy_helper.py b/nova/tests/virt/baremetal/test_nova_baremetal_deploy_helper.py
index 42ee6c8e4..28f40bcf9 100644
--- a/nova/tests/baremetal/test_nova_baremetal_deploy_helper.py
+++ b/nova/tests/virt/baremetal/test_nova_baremetal_deploy_helper.py
@@ -25,7 +25,7 @@ import mox
from nova.cmd import baremetal_deploy_helper as bmdh
from nova.openstack.common import log as logging
from nova import test
-from nova.tests.baremetal.db import base as bm_db_base
+from nova.tests.virt.baremetal.db import base as bm_db_base
from nova.virt.baremetal import db as bm_db
bmdh.LOG = logging.getLogger('nova.virt.baremetal.deploy_helper')
diff --git a/nova/tests/baremetal/test_nova_baremetal_manage.py b/nova/tests/virt/baremetal/test_nova_baremetal_manage.py
index 6be63aac2..6651e6ad4 100644
--- a/nova/tests/baremetal/test_nova_baremetal_manage.py
+++ b/nova/tests/virt/baremetal/test_nova_baremetal_manage.py
@@ -17,7 +17,7 @@
# under the License.
from nova.cmd import baremetal_manage as bm_man
-from nova.tests.baremetal.db import base as bm_db_base
+from nova.tests.virt.baremetal.db import base as bm_db_base
class BareMetalDbCommandsTestCase(bm_db_base.BMDBTestCase):
diff --git a/nova/tests/baremetal/test_pxe.py b/nova/tests/virt/baremetal/test_pxe.py
index 994a8ee35..022f9c692 100644
--- a/nova/tests/baremetal/test_pxe.py
+++ b/nova/tests/virt/baremetal/test_pxe.py
@@ -28,10 +28,10 @@ from testtools import matchers
from nova import exception
from nova.openstack.common.db import exception as db_exc
-from nova.tests.baremetal.db import base as bm_db_base
-from nova.tests.baremetal.db import utils as bm_db_utils
from nova.tests.image import fake as fake_image
from nova.tests import utils
+from nova.tests.virt.baremetal.db import base as bm_db_base
+from nova.tests.virt.baremetal.db import utils as bm_db_utils
from nova.virt.baremetal import baremetal_states
from nova.virt.baremetal import db
from nova.virt.baremetal import pxe
diff --git a/nova/tests/baremetal/test_tilera.py b/nova/tests/virt/baremetal/test_tilera.py
index a30732a3d..488cba4df 100755
--- a/nova/tests/baremetal/test_tilera.py
+++ b/nova/tests/virt/baremetal/test_tilera.py
@@ -24,10 +24,10 @@ from oslo.config import cfg
from nova import exception
from nova.openstack.common.db import exception as db_exc
-from nova.tests.baremetal.db import base as bm_db_base
-from nova.tests.baremetal.db import utils as bm_db_utils
from nova.tests.image import fake as fake_image
from nova.tests import utils
+from nova.tests.virt.baremetal.db import base as bm_db_base
+from nova.tests.virt.baremetal.db import utils as bm_db_utils
from nova.virt.baremetal import baremetal_states
from nova.virt.baremetal import db
from nova.virt.baremetal import tilera
diff --git a/nova/tests/baremetal/test_tilera_pdu.py b/nova/tests/virt/baremetal/test_tilera_pdu.py
index fee5bc49e..95d840574 100755
--- a/nova/tests/baremetal/test_tilera_pdu.py
+++ b/nova/tests/virt/baremetal/test_tilera_pdu.py
@@ -21,7 +21,7 @@
from oslo.config import cfg
from nova import test
-from nova.tests.baremetal.db import utils as bm_db_utils
+from nova.tests.virt.baremetal.db import utils as bm_db_utils
from nova import utils
from nova.virt.baremetal import baremetal_states
from nova.virt.baremetal import tilera_pdu
diff --git a/nova/tests/baremetal/test_utils.py b/nova/tests/virt/baremetal/test_utils.py
index df5112deb..df5112deb 100644
--- a/nova/tests/baremetal/test_utils.py
+++ b/nova/tests/virt/baremetal/test_utils.py
diff --git a/nova/tests/baremetal/test_virtual_power_driver.py b/nova/tests/virt/baremetal/test_virtual_power_driver.py
index 5f4b5f0cb..58a1e4f08 100644
--- a/nova/tests/baremetal/test_virtual_power_driver.py
+++ b/nova/tests/virt/baremetal/test_virtual_power_driver.py
@@ -23,10 +23,10 @@ from oslo.config import cfg
from nova import exception
from nova.openstack.common import processutils
-from nova.tests.baremetal.db import base as bm_db_base
-from nova.tests.baremetal.db import utils as bm_db_utils
from nova.tests.image import fake as fake_image
from nova.tests import utils
+from nova.tests.virt.baremetal.db import base as bm_db_base
+from nova.tests.virt.baremetal.db import utils as bm_db_utils
from nova.virt.baremetal import db
from nova.virt.baremetal import virtual_power_driver
import nova.virt.powervm.common as connection
diff --git a/nova/tests/baremetal/test_volume_driver.py b/nova/tests/virt/baremetal/test_volume_driver.py
index 24dadac94..24dadac94 100644
--- a/nova/tests/baremetal/test_volume_driver.py
+++ b/nova/tests/virt/baremetal/test_volume_driver.py
diff --git a/nova/tests/virt/libvirt/__init__.py b/nova/tests/virt/libvirt/__init__.py
new file mode 100644
index 000000000..a02a20177
--- /dev/null
+++ b/nova/tests/virt/libvirt/__init__.py
@@ -0,0 +1,15 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright (c) 2013 OpenStack Foundation
+#
+# 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.
diff --git a/nova/tests/fake_imagebackend.py b/nova/tests/virt/libvirt/fake_imagebackend.py
index 48426505e..48426505e 100644
--- a/nova/tests/fake_imagebackend.py
+++ b/nova/tests/virt/libvirt/fake_imagebackend.py
diff --git a/nova/tests/fake_libvirt_utils.py b/nova/tests/virt/libvirt/fake_libvirt_utils.py
index ba00a7091..ba00a7091 100644
--- a/nova/tests/fake_libvirt_utils.py
+++ b/nova/tests/virt/libvirt/fake_libvirt_utils.py
diff --git a/nova/tests/fakelibvirt.py b/nova/tests/virt/libvirt/fakelibvirt.py
index 30c3e4d9c..30c3e4d9c 100644
--- a/nova/tests/fakelibvirt.py
+++ b/nova/tests/virt/libvirt/fakelibvirt.py
diff --git a/nova/tests/test_fakelibvirt.py b/nova/tests/virt/libvirt/test_fakelibvirt.py
index ee2008544..52183ab5f 100644
--- a/nova/tests/test_fakelibvirt.py
+++ b/nova/tests/virt/libvirt/test_fakelibvirt.py
@@ -18,7 +18,7 @@ from nova import test
from lxml import etree
-import nova.tests.fakelibvirt as libvirt
+import nova.tests.virt.libvirt.fakelibvirt as libvirt
def get_vm_xml(name="testname", uuid=None, source_type='file',
diff --git a/nova/tests/test_imagebackend.py b/nova/tests/virt/libvirt/test_imagebackend.py
index b5d64a218..6548ab76c 100644
--- a/nova/tests/test_imagebackend.py
+++ b/nova/tests/virt/libvirt/test_imagebackend.py
@@ -23,8 +23,8 @@ from oslo.config import cfg
from nova import exception
from nova.openstack.common import uuidutils
from nova import test
-from nova.tests import fake_libvirt_utils
from nova.tests import fake_processutils
+from nova.tests.virt.libvirt import fake_libvirt_utils
from nova.virt.libvirt import imagebackend
CONF = cfg.CONF
diff --git a/nova/tests/test_imagecache.py b/nova/tests/virt/libvirt/test_imagecache.py
index bdc895474..bdc895474 100644
--- a/nova/tests/test_imagecache.py
+++ b/nova/tests/virt/libvirt/test_imagecache.py
diff --git a/nova/tests/test_libvirt.py b/nova/tests/virt/libvirt/test_libvirt.py
index 338a1559f..f72c37cd1 100644
--- a/nova/tests/test_libvirt.py
+++ b/nova/tests/virt/libvirt/test_libvirt.py
@@ -45,10 +45,10 @@ from nova.openstack.common import jsonutils
from nova.openstack.common import loopingcall
from nova.openstack.common import uuidutils
from nova import test
-from nova.tests import fake_libvirt_utils
from nova.tests import fake_network
import nova.tests.image.fake
from nova.tests import matchers
+from nova.tests.virt.libvirt import fake_libvirt_utils
from nova import utils
from nova import version
from nova.virt.disk import api as disk
@@ -68,7 +68,7 @@ from nova.virt import netutils
try:
import libvirt
except ImportError:
- import nova.tests.fakelibvirt as libvirt
+ import nova.tests.virt.libvirt.fakelibvirt as libvirt
libvirt_driver.libvirt = libvirt
@@ -351,7 +351,8 @@ class LibvirtConnTestCase(test.TestCase):
return FakeVirtDomain()
# Creating mocks
- volume_driver = 'iscsi=nova.tests.test_libvirt.FakeVolumeDriver'
+ volume_driver = ('iscsi=nova.tests.virt.libvirt.test_libvirt'
+ '.FakeVolumeDriver')
self.flags(libvirt_volume_drivers=[volume_driver])
fake = FakeLibvirtDriver()
# Customizing above fake if necessary
diff --git a/nova/tests/test_libvirt_blockinfo.py b/nova/tests/virt/libvirt/test_libvirt_blockinfo.py
index aae5bec58..aae5bec58 100644
--- a/nova/tests/test_libvirt_blockinfo.py
+++ b/nova/tests/virt/libvirt/test_libvirt_blockinfo.py
diff --git a/nova/tests/test_libvirt_config.py b/nova/tests/virt/libvirt/test_libvirt_config.py
index 8eed7136e..8eed7136e 100644
--- a/nova/tests/test_libvirt_config.py
+++ b/nova/tests/virt/libvirt/test_libvirt_config.py
diff --git a/nova/tests/test_libvirt_utils.py b/nova/tests/virt/libvirt/test_libvirt_utils.py
index 60f0682a8..60f0682a8 100644
--- a/nova/tests/test_libvirt_utils.py
+++ b/nova/tests/virt/libvirt/test_libvirt_utils.py
diff --git a/nova/tests/test_libvirt_vif.py b/nova/tests/virt/libvirt/test_libvirt_vif.py
index 0b661d147..c9c6aef12 100644
--- a/nova/tests/test_libvirt_vif.py
+++ b/nova/tests/virt/libvirt/test_libvirt_vif.py
@@ -20,7 +20,7 @@ from oslo.config import cfg
from nova import exception
from nova.network import model as network_model
from nova import test
-from nova.tests import fakelibvirt
+from nova.tests.virt.libvirt import fakelibvirt
from nova import utils
from nova.virt.libvirt import config as vconfig
from nova.virt.libvirt import vif
diff --git a/nova/tests/test_libvirt_volume.py b/nova/tests/virt/libvirt/test_libvirt_volume.py
index 6d2dc9dce..86773dd10 100644
--- a/nova/tests/test_libvirt_volume.py
+++ b/nova/tests/virt/libvirt/test_libvirt_volume.py
@@ -23,7 +23,7 @@ from oslo.config import cfg
from nova import exception
from nova.storage import linuxscsi
from nova import test
-from nova.tests import fake_libvirt_utils
+from nova.tests.virt.libvirt import fake_libvirt_utils
from nova import utils
from nova.virt import fake
from nova.virt.libvirt import utils as libvirt_utils
diff --git a/openstack-common.conf b/openstack-common.conf
index 87be18491..086796b12 100644
--- a/openstack-common.conf
+++ b/openstack-common.conf
@@ -17,6 +17,7 @@ module=local
module=lockutils
module=log
module=loopingcall
+module=memorycache
module=network_utils
module=notifier
module=patch_tox_venv