summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--nova/api/openstack/compute/contrib/attach_interfaces.py2
-rw-r--r--nova/api/openstack/compute/contrib/consoles.py2
-rw-r--r--nova/api/openstack/compute/contrib/server_external_events.py2
-rw-r--r--nova/api/openstack/compute/plugins/v3/servers.py2
-rw-r--r--nova/api/openstack/compute/servers.py2
-rw-r--r--nova/compute/manager.py15
-rw-r--r--nova/exception.py2
-rw-r--r--nova/objects/agent.py2
-rw-r--r--nova/objects/aggregate.py2
-rw-r--r--nova/objects/bandwidth_usage.py2
-rw-r--r--nova/objects/base.py11
-rw-r--r--nova/objects/block_device.py2
-rw-r--r--nova/objects/cell_mapping.py1
-rw-r--r--nova/objects/compute_node.py2
-rw-r--r--nova/objects/dns_domain.py2
-rw-r--r--nova/objects/ec2.py5
-rw-r--r--nova/objects/external_event.py1
-rw-r--r--nova/objects/fields.py2
-rw-r--r--nova/objects/fixed_ip.py2
-rw-r--r--nova/objects/flavor.py2
-rw-r--r--nova/objects/floating_ip.py2
-rw-r--r--nova/objects/hv_spec.py1
-rw-r--r--nova/objects/image_meta.py2
-rw-r--r--nova/objects/instance.py2
-rw-r--r--nova/objects/instance_action.py4
-rw-r--r--nova/objects/instance_fault.py2
-rw-r--r--nova/objects/instance_group.py2
-rw-r--r--nova/objects/instance_info_cache.py1
-rw-r--r--nova/objects/instance_mapping.py2
-rw-r--r--nova/objects/instance_numa_topology.py2
-rw-r--r--nova/objects/instance_pci_requests.py2
-rw-r--r--nova/objects/keypair.py2
-rw-r--r--nova/objects/migration.py2
-rw-r--r--nova/objects/network.py2
-rw-r--r--nova/objects/network_request.py2
-rw-r--r--nova/objects/numa.py4
-rw-r--r--nova/objects/pci_device.py2
-rw-r--r--nova/objects/pci_device_pool.py2
-rw-r--r--nova/objects/quotas.py2
-rw-r--r--nova/objects/security_group.py2
-rw-r--r--nova/objects/security_group_rule.py2
-rw-r--r--nova/objects/service.py2
-rw-r--r--nova/objects/tag.py2
-rw-r--r--nova/objects/vcpu_model.py2
-rw-r--r--nova/objects/virt_cpu_topology.py1
-rw-r--r--nova/objects/virtual_interface.py2
-rw-r--r--nova/tests/unit/api/openstack/compute/contrib/test_security_groups.py2
-rw-r--r--nova/tests/unit/api/openstack/compute/contrib/test_server_external_events.py4
-rw-r--r--nova/tests/unit/compute/test_compute.py11
-rw-r--r--nova/tests/unit/objects/test_objects.py9
-rw-r--r--nova/tests/unit/virt/ironic/test_driver.py26
-rw-r--r--nova/tests/unit/virt/test_block_device.py134
-rw-r--r--nova/tests/unit/virt/vmwareapi/test_driver_api.py19
-rw-r--r--nova/virt/block_device.py21
-rw-r--r--nova/virt/ironic/driver.py13
-rw-r--r--nova/virt/libvirt/host.py35
-rw-r--r--nova/virt/libvirt/utils.py4
-rw-r--r--nova/virt/vmwareapi/constants.py2
-rw-r--r--nova/virt/vmwareapi/driver.py15
59 files changed, 354 insertions, 57 deletions
diff --git a/nova/api/openstack/compute/contrib/attach_interfaces.py b/nova/api/openstack/compute/contrib/attach_interfaces.py
index 7c79dbcf7f..481e1a3e0a 100644
--- a/nova/api/openstack/compute/contrib/attach_interfaces.py
+++ b/nova/api/openstack/compute/contrib/attach_interfaces.py
@@ -135,7 +135,7 @@ class InterfaceAttachmentController(object):
except NotImplementedError:
msg = _("Network driver does not support this function.")
raise webob.exc.HTTPNotImplemented(explanation=msg)
- except exception.InterfaceAttachFailed as e:
+ except exception.InterfaceAttachFailed:
msg = _("Failed to attach interface")
raise webob.exc.HTTPInternalServerError(explanation=msg)
except exception.InstanceInvalidState as state_error:
diff --git a/nova/api/openstack/compute/contrib/consoles.py b/nova/api/openstack/compute/contrib/consoles.py
index 39ed03f70d..0a8a00aac3 100644
--- a/nova/api/openstack/compute/contrib/consoles.py
+++ b/nova/api/openstack/compute/contrib/consoles.py
@@ -44,7 +44,7 @@ class ConsolesController(wsgi.Controller):
output = self.compute_api.get_vnc_console(context,
instance,
console_type)
- except exception.InstanceNotReady as e:
+ except exception.InstanceNotReady:
raise webob.exc.HTTPConflict(
explanation=_('Instance not yet ready'))
except exception.InstanceNotFound as e:
diff --git a/nova/api/openstack/compute/contrib/server_external_events.py b/nova/api/openstack/compute/contrib/server_external_events.py
index 2e33178305..fcc42b9c82 100644
--- a/nova/api/openstack/compute/contrib/server_external_events.py
+++ b/nova/api/openstack/compute/contrib/server_external_events.py
@@ -55,7 +55,7 @@ class ServerExternalEventsController(wsgi.Controller):
client_event = dict(_event)
event = objects.InstanceExternalEvent(context)
- status = client_event.get('status')
+ status = client_event.get('status', 'completed')
if status not in external_event_obj.EVENT_STATUSES:
raise webob.exc.HTTPBadRequest(
_('Invalid event status `%s\'') % status)
diff --git a/nova/api/openstack/compute/plugins/v3/servers.py b/nova/api/openstack/compute/plugins/v3/servers.py
index da14b29657..f263a8094f 100644
--- a/nova/api/openstack/compute/plugins/v3/servers.py
+++ b/nova/api/openstack/compute/plugins/v3/servers.py
@@ -563,7 +563,7 @@ class ServersController(wsgi.Controller):
try:
flavor_id = self._flavor_id_from_req_data(body)
- except ValueError as error:
+ except ValueError:
msg = _("Invalid flavorRef provided.")
raise exc.HTTPBadRequest(explanation=msg)
diff --git a/nova/api/openstack/compute/servers.py b/nova/api/openstack/compute/servers.py
index 8f8f90f396..e0e1de6d1e 100644
--- a/nova/api/openstack/compute/servers.py
+++ b/nova/api/openstack/compute/servers.py
@@ -636,7 +636,7 @@ class Controller(wsgi.Controller):
except UnicodeDecodeError as error:
msg = "UnicodeError: %s" % error
raise exc.HTTPBadRequest(explanation=msg)
- except Exception as error:
+ except Exception:
# The remaining cases can be handled in a standard fashion.
self._handle_create_exception(*sys.exc_info())
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index ec76bf2b58..d08e87026d 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -1386,15 +1386,18 @@ class ComputeManager(manager.Manager):
volume = self.volume_api.get(context, vol_id)
volume_status = volume['status']
if volume_status not in ['creating', 'downloading']:
- if volume_status != 'available':
- LOG.warning(_LW("Volume id: %s finished being created but "
- "was not set as 'available'"), vol_id)
- return attempt
+ if volume_status == 'available':
+ return attempt
+ LOG.warning(_LW("Volume id: %(vol_id)s finished being "
+ "created but its status is %(vol_status)s."),
+ {'vol_id': vol_id,
+ 'vol_status': volume_status})
+ break
greenthread.sleep(CONF.block_device_allocate_retries_interval)
- # NOTE(harlowja): Should only happen if we ran out of attempts
raise exception.VolumeNotCreated(volume_id=vol_id,
seconds=int(time.time() - start),
- attempts=attempts)
+ attempts=attempt,
+ volume_status=volume_status)
def _decode_files(self, injected_files):
"""Base64 decode the list of files to inject."""
diff --git a/nova/exception.py b/nova/exception.py
index bba76200c0..1f36eb4495 100644
--- a/nova/exception.py
+++ b/nova/exception.py
@@ -275,7 +275,7 @@ class VolumeUnattached(Invalid):
class VolumeNotCreated(NovaException):
msg_fmt = _("Volume %(volume_id)s did not finish being created"
" even after we waited %(seconds)s seconds or %(attempts)s"
- " attempts.")
+ " attempts. And its status is %(volume_status)s.")
class InvalidKeypair(Invalid):
diff --git a/nova/objects/agent.py b/nova/objects/agent.py
index 260737288e..d6d5b04041 100644
--- a/nova/objects/agent.py
+++ b/nova/objects/agent.py
@@ -20,6 +20,7 @@ from nova.objects import fields
# TODO(berrange): Remove NovaObjectDictCompat
+@base.NovaObjectRegistry.register
class Agent(base.NovaPersistentObject, base.NovaObject,
base.NovaObjectDictCompat):
VERSION = '1.0'
@@ -70,6 +71,7 @@ class Agent(base.NovaPersistentObject, base.NovaObject,
self.obj_reset_changes()
+@base.NovaObjectRegistry.register
class AgentList(base.ObjectListBase, base.NovaObject):
VERSION = '1.0'
diff --git a/nova/objects/aggregate.py b/nova/objects/aggregate.py
index 937196fb44..3c2a03ddaf 100644
--- a/nova/objects/aggregate.py
+++ b/nova/objects/aggregate.py
@@ -21,6 +21,7 @@ from nova.objects import fields
# TODO(berrange): Remove NovaObjectDictCompat
+@base.NovaObjectRegistry.register
class Aggregate(base.NovaPersistentObject, base.NovaObject,
base.NovaObjectDictCompat):
# Version 1.0: Initial version
@@ -150,6 +151,7 @@ class Aggregate(base.NovaPersistentObject, base.NovaObject,
return self.metadata.get('availability_zone', None)
+@base.NovaObjectRegistry.register
class AggregateList(base.ObjectListBase, base.NovaObject):
# Version 1.0: Initial version
# Version 1.1: Added key argument to get_by_host()
diff --git a/nova/objects/bandwidth_usage.py b/nova/objects/bandwidth_usage.py
index dc463e1837..918df017ee 100644
--- a/nova/objects/bandwidth_usage.py
+++ b/nova/objects/bandwidth_usage.py
@@ -16,6 +16,7 @@ from nova.objects import fields
# TODO(berrange): Remove NovaObjectDictCompat
+@base.NovaObjectRegistry.register
class BandwidthUsage(base.NovaPersistentObject, base.NovaObject,
base.NovaObjectDictCompat):
# Version 1.0: Initial version
@@ -65,6 +66,7 @@ class BandwidthUsage(base.NovaPersistentObject, base.NovaObject,
self._from_db_object(self._context, self, db_bw_usage)
+@base.NovaObjectRegistry.register
class BandwidthUsageList(base.ObjectListBase, base.NovaObject):
# Version 1.0: Initial version
# Version 1.1: Add use_slave to get_by_uuids
diff --git a/nova/objects/base.py b/nova/objects/base.py
index 58a4beddc7..0cf23cf0b4 100644
--- a/nova/objects/base.py
+++ b/nova/objects/base.py
@@ -97,6 +97,17 @@ def make_class_properties(cls):
setattr(cls, name, property(getter, setter, deleter))
+# NOTE(danms): This is transitional to get the registration decorator
+# on everything before we make a cut over
+class NovaObjectRegistry(object):
+ classes = []
+
+ @classmethod
+ def register(cls, obj_cls):
+ cls.classes.append(obj_cls.obj_name())
+ return obj_cls
+
+
class NovaObjectMetaclass(type):
"""Metaclass that allows tracking of object classes."""
diff --git a/nova/objects/block_device.py b/nova/objects/block_device.py
index 9210df6e1c..5fa2e147f4 100644
--- a/nova/objects/block_device.py
+++ b/nova/objects/block_device.py
@@ -38,6 +38,7 @@ def _expected_cols(expected_attrs):
# TODO(berrange): Remove NovaObjectDictCompat
+@base.NovaObjectRegistry.register
class BlockDeviceMapping(base.NovaPersistentObject, base.NovaObject,
base.NovaObjectDictCompat):
# Version 1.0: Initial version
@@ -232,6 +233,7 @@ class BlockDeviceMapping(base.NovaPersistentObject, base.NovaObject,
self.obj_reset_changes(fields=['instance'])
+@base.NovaObjectRegistry.register
class BlockDeviceMappingList(base.ObjectListBase, base.NovaObject):
# Version 1.0: Initial version
# Version 1.1: BlockDeviceMapping <= version 1.1
diff --git a/nova/objects/cell_mapping.py b/nova/objects/cell_mapping.py
index b8c76e2843..f337e4d330 100644
--- a/nova/objects/cell_mapping.py
+++ b/nova/objects/cell_mapping.py
@@ -17,6 +17,7 @@ from nova.objects import base
from nova.objects import fields
+@base.NovaObjectRegistry.register
class CellMapping(base.NovaTimestampObject, base.NovaObject):
# Version 1.0: Initial version
VERSION = '1.0'
diff --git a/nova/objects/compute_node.py b/nova/objects/compute_node.py
index e11ca577b7..27625f9db8 100644
--- a/nova/objects/compute_node.py
+++ b/nova/objects/compute_node.py
@@ -24,6 +24,7 @@ from nova import utils
# TODO(berrange): Remove NovaObjectDictCompat
+@base.NovaObjectRegistry.register
class ComputeNode(base.NovaPersistentObject, base.NovaObject,
base.NovaObjectDictCompat):
# Version 1.0: Initial version
@@ -271,6 +272,7 @@ class ComputeNode(base.NovaPersistentObject, base.NovaObject,
return self._cached_service
+@base.NovaObjectRegistry.register
class ComputeNodeList(base.ObjectListBase, base.NovaObject):
# Version 1.0: Initial version
# ComputeNode <= version 1.2
diff --git a/nova/objects/dns_domain.py b/nova/objects/dns_domain.py
index 08f333b245..7dd5bd6675 100644
--- a/nova/objects/dns_domain.py
+++ b/nova/objects/dns_domain.py
@@ -19,6 +19,7 @@ from nova.objects import fields
# TODO(berrange): Remove NovaObjectDictCompat
+@base.NovaObjectRegistry.register
class DNSDomain(base.NovaPersistentObject, base.NovaObject,
base.NovaObjectDictCompat):
# Version 1.0: Initial version
@@ -58,6 +59,7 @@ class DNSDomain(base.NovaPersistentObject, base.NovaObject,
db.dnsdomain_unregister(context, domain)
+@base.NovaObjectRegistry.register
class DNSDomainList(base.ObjectListBase, base.NovaObject):
# Version 1.0: Initial version
VERSION = '1.0'
diff --git a/nova/objects/ec2.py b/nova/objects/ec2.py
index a02cbf6bba..18e7d06bee 100644
--- a/nova/objects/ec2.py
+++ b/nova/objects/ec2.py
@@ -20,6 +20,7 @@ from nova.objects import fields
# TODO(berrange): Remove NovaObjectDictCompat
+@base.NovaObjectRegistry.register
class EC2InstanceMapping(base.NovaPersistentObject, base.NovaObject,
base.NovaObjectDictCompat):
# Version 1.0: Initial version
@@ -60,6 +61,7 @@ class EC2InstanceMapping(base.NovaPersistentObject, base.NovaObject,
# TODO(berrange): Remove NovaObjectDictCompat
+@base.NovaObjectRegistry.register
class EC2VolumeMapping(base.NovaPersistentObject, base.NovaObject,
base.NovaObjectDictCompat):
# Version 1.0: Initial version
@@ -100,6 +102,7 @@ class EC2VolumeMapping(base.NovaPersistentObject, base.NovaObject,
# TODO(berrange): Remove NovaObjectDictCompat
+@base.NovaObjectRegistry.register
class EC2SnapshotMapping(base.NovaPersistentObject, base.NovaObject,
base.NovaObjectDictCompat):
# Version 1.0: Initial version
@@ -140,6 +143,7 @@ class EC2SnapshotMapping(base.NovaPersistentObject, base.NovaObject,
# TODO(berrange): Remove NovaObjectDictCompat
+@base.NovaObjectRegistry.register
class S3ImageMapping(base.NovaPersistentObject, base.NovaObject,
base.NovaObjectDictCompat):
# Version 1.0: Initial version
@@ -179,6 +183,7 @@ class S3ImageMapping(base.NovaPersistentObject, base.NovaObject,
return cls._from_db_object(context, cls(context), db_s3imap)
+@base.NovaObjectRegistry.register
class EC2Ids(base.NovaObject):
# Version 1.0: Initial version
VERSION = '1.0'
diff --git a/nova/objects/external_event.py b/nova/objects/external_event.py
index 1effae001f..1d884e6e02 100644
--- a/nova/objects/external_event.py
+++ b/nova/objects/external_event.py
@@ -29,6 +29,7 @@ EVENT_STATUSES = ['failed', 'completed', 'in-progress']
# TODO(berrange): Remove NovaObjectDictCompat
+@obj_base.NovaObjectRegistry.register
class InstanceExternalEvent(obj_base.NovaObject,
obj_base.NovaObjectDictCompat):
# Version 1.0: Initial version
diff --git a/nova/objects/fields.py b/nova/objects/fields.py
index fff3f4a443..106818b30b 100644
--- a/nova/objects/fields.py
+++ b/nova/objects/fields.py
@@ -371,7 +371,7 @@ class HVType(Enum):
try:
value = hv_type.canonicalize(value)
except exception.InvalidHypervisorVirtType:
- msg = _("Hypervisr virt type '%s' is not valid") % value
+ msg = _("Hypervisor virt type '%s' is not valid") % value
raise ValueError(msg)
return super(HVType, self).coerce(obj, attr, value)
diff --git a/nova/objects/fixed_ip.py b/nova/objects/fixed_ip.py
index 38742d2d07..3895260365 100644
--- a/nova/objects/fixed_ip.py
+++ b/nova/objects/fixed_ip.py
@@ -27,6 +27,7 @@ FIXED_IP_OPTIONAL_ATTRS = ['instance', 'network', 'virtual_interface',
# TODO(berrange): Remove NovaObjectDictCompat
+@obj_base.NovaObjectRegistry.register
class FixedIP(obj_base.NovaPersistentObject, obj_base.NovaObject,
obj_base.NovaObjectDictCompat):
# Version 1.0: Initial version
@@ -203,6 +204,7 @@ class FixedIP(obj_base.NovaPersistentObject, obj_base.NovaObject,
self.obj_reset_changes(['instance_uuid', 'instance'])
+@obj_base.NovaObjectRegistry.register
class FixedIPList(obj_base.ObjectListBase, obj_base.NovaObject):
# Version 1.0: Initial version
# Version 1.1: Added get_by_network()
diff --git a/nova/objects/flavor.py b/nova/objects/flavor.py
index b14efdf4ea..c52d9bf16d 100644
--- a/nova/objects/flavor.py
+++ b/nova/objects/flavor.py
@@ -23,6 +23,7 @@ OPTIONAL_FIELDS = ['extra_specs', 'projects']
# TODO(berrange): Remove NovaObjectDictCompat
+@base.NovaObjectRegistry.register
class Flavor(base.NovaPersistentObject, base.NovaObject,
base.NovaObjectDictCompat):
# Version 1.0: Initial version
@@ -250,6 +251,7 @@ class Flavor(base.NovaPersistentObject, base.NovaObject,
db.flavor_destroy(self._context, self.name)
+@base.NovaObjectRegistry.register
class FlavorList(base.ObjectListBase, base.NovaObject):
VERSION = '1.1'
diff --git a/nova/objects/floating_ip.py b/nova/objects/floating_ip.py
index e3149b168e..f1fb152e80 100644
--- a/nova/objects/floating_ip.py
+++ b/nova/objects/floating_ip.py
@@ -22,6 +22,7 @@ FLOATING_IP_OPTIONAL_ATTRS = ['fixed_ip']
# TODO(berrange): Remove NovaObjectDictCompat
+@obj_base.NovaObjectRegistry.register
class FloatingIP(obj_base.NovaPersistentObject, obj_base.NovaObject,
obj_base.NovaObjectDictCompat):
# Version 1.0: Initial version
@@ -162,6 +163,7 @@ class FloatingIP(obj_base.NovaPersistentObject, obj_base.NovaObject,
self._from_db_object(self._context, self, db_floatingip)
+@obj_base.NovaObjectRegistry.register
class FloatingIPList(obj_base.ObjectListBase, obj_base.NovaObject):
# Version 1.3: FloatingIP 1.2
# Version 1.4: FloatingIP 1.3
diff --git a/nova/objects/hv_spec.py b/nova/objects/hv_spec.py
index 30880f07a7..8ae320676d 100644
--- a/nova/objects/hv_spec.py
+++ b/nova/objects/hv_spec.py
@@ -18,6 +18,7 @@ from nova.objects import fields
# TODO(berrange): Remove NovaObjectDictCompat
+@base.NovaObjectRegistry.register
class HVSpec(base.NovaObject,
base.NovaObjectDictCompat):
# Version 1.0: Initial version
diff --git a/nova/objects/image_meta.py b/nova/objects/image_meta.py
index c1daf9822c..bb54c60563 100644
--- a/nova/objects/image_meta.py
+++ b/nova/objects/image_meta.py
@@ -21,6 +21,7 @@ from nova import utils
from nova.virt import hardware
+@base.NovaObjectRegistry.register
class ImageMeta(base.NovaObject):
VERSION = '1.0'
@@ -98,6 +99,7 @@ class ImageMeta(base.NovaObject):
return cls.from_dict(image_meta)
+@base.NovaObjectRegistry.register
class ImageMetaProps(base.NovaObject):
VERSION = ImageMeta.VERSION
diff --git a/nova/objects/instance.py b/nova/objects/instance.py
index cc5e5b4f27..e4c159303f 100644
--- a/nova/objects/instance.py
+++ b/nova/objects/instance.py
@@ -133,6 +133,7 @@ def compat_instance(instance):
# TODO(berrange): Remove NovaObjectDictCompat
+@base.NovaObjectRegistry.register
class Instance(base.NovaPersistentObject, base.NovaObject,
base.NovaObjectDictCompat):
# Version 1.0: Initial version
@@ -1169,6 +1170,7 @@ def _make_instance_list(context, inst_list, db_inst_list, expected_attrs):
return inst_list
+@base.NovaObjectRegistry.register
class InstanceList(base.ObjectListBase, base.NovaObject):
# Version 1.0: Initial version
# Version 1.1: Added use_slave to get_by_host
diff --git a/nova/objects/instance_action.py b/nova/objects/instance_action.py
index 1a0b05cfd5..651e456821 100644
--- a/nova/objects/instance_action.py
+++ b/nova/objects/instance_action.py
@@ -21,6 +21,7 @@ from nova.objects import fields
# TODO(berrange): Remove NovaObjectDictCompat
+@base.NovaObjectRegistry.register
class InstanceAction(base.NovaPersistentObject, base.NovaObject,
base.NovaObjectDictCompat):
# Version 1.0: Initial version
@@ -93,6 +94,7 @@ class InstanceAction(base.NovaPersistentObject, base.NovaObject,
self._from_db_object(self._context, self, db_action)
+@base.NovaObjectRegistry.register
class InstanceActionList(base.ObjectListBase, base.NovaObject):
# Version 1.0: Initial version
# InstanceAction <= version 1.1
@@ -112,6 +114,7 @@ class InstanceActionList(base.ObjectListBase, base.NovaObject):
# TODO(berrange): Remove NovaObjectDictCompat
+@base.NovaObjectRegistry.register
class InstanceActionEvent(base.NovaPersistentObject, base.NovaObject,
base.NovaObjectDictCompat):
# Version 1.0: Initial version
@@ -204,6 +207,7 @@ class InstanceActionEvent(base.NovaPersistentObject, base.NovaObject,
self.finish_with_failure(self._context, exc_val=None, exc_tb=None)
+@base.NovaObjectRegistry.register
class InstanceActionEventList(base.ObjectListBase, base.NovaObject):
fields = {
'objects': fields.ListOfObjectsField('InstanceActionEvent'),
diff --git a/nova/objects/instance_fault.py b/nova/objects/instance_fault.py
index e900a600c0..d61332aef1 100644
--- a/nova/objects/instance_fault.py
+++ b/nova/objects/instance_fault.py
@@ -30,6 +30,7 @@ LOG = logging.getLogger(__name__)
# TODO(berrange): Remove NovaObjectDictCompat
+@base.NovaObjectRegistry.register
class InstanceFault(base.NovaPersistentObject, base.NovaObject,
base.NovaObjectDictCompat):
# Version 1.0: Initial version
@@ -90,6 +91,7 @@ class InstanceFault(base.NovaPersistentObject, base.NovaObject,
LOG.exception(_LE("Failed to notify cells of instance fault"))
+@base.NovaObjectRegistry.register
class InstanceFaultList(base.ObjectListBase, base.NovaObject):
# Version 1.0: Initial version
# InstanceFault <= version 1.1
diff --git a/nova/objects/instance_group.py b/nova/objects/instance_group.py
index ff57dfc303..abf2fd5269 100644
--- a/nova/objects/instance_group.py
+++ b/nova/objects/instance_group.py
@@ -24,6 +24,7 @@ from nova import utils
# TODO(berrange): Remove NovaObjectDictCompat
+@base.NovaObjectRegistry.register
class InstanceGroup(base.NovaPersistentObject, base.NovaObject,
base.NovaObjectDictCompat):
# Version 1.0: Initial version
@@ -197,6 +198,7 @@ class InstanceGroup(base.NovaPersistentObject, base.NovaObject,
return len(instances)
+@base.NovaObjectRegistry.register
class InstanceGroupList(base.ObjectListBase, base.NovaObject):
# Version 1.0: Initial version
# InstanceGroup <= version 1.3
diff --git a/nova/objects/instance_info_cache.py b/nova/objects/instance_info_cache.py
index 5ec3b1bc1e..a565fc57b5 100644
--- a/nova/objects/instance_info_cache.py
+++ b/nova/objects/instance_info_cache.py
@@ -26,6 +26,7 @@ LOG = logging.getLogger(__name__)
# TODO(berrange): Remove NovaObjectDictCompat
+@base.NovaObjectRegistry.register
class InstanceInfoCache(base.NovaPersistentObject, base.NovaObject,
base.NovaObjectDictCompat):
# Version 1.0: Initial version
diff --git a/nova/objects/instance_mapping.py b/nova/objects/instance_mapping.py
index be6af6d5d2..d9d8a4d41b 100644
--- a/nova/objects/instance_mapping.py
+++ b/nova/objects/instance_mapping.py
@@ -18,6 +18,7 @@ from nova.objects import base
from nova.objects import fields
+@base.NovaObjectRegistry.register
class InstanceMapping(base.NovaTimestampObject, base.NovaObject):
# Version 1.0: Initial version
VERSION = '1.0'
@@ -107,6 +108,7 @@ class InstanceMapping(base.NovaTimestampObject, base.NovaObject):
self._destroy_in_db(self._context, self.instance_uuid)
+@base.NovaObjectRegistry.register
class InstanceMappingList(base.ObjectListBase, base.NovaObject):
# Version 1.0: Initial version
VERSION = '1.0'
diff --git a/nova/objects/instance_numa_topology.py b/nova/objects/instance_numa_topology.py
index dad4c0eec9..f180050a44 100644
--- a/nova/objects/instance_numa_topology.py
+++ b/nova/objects/instance_numa_topology.py
@@ -22,6 +22,7 @@ from nova.virt import hardware
# TODO(berrange): Remove NovaObjectDictCompat
+@base.NovaObjectRegistry.register
class InstanceNUMACell(base.NovaObject,
base.NovaObjectDictCompat):
# Version 1.0: Initial version
@@ -109,6 +110,7 @@ class InstanceNUMACell(base.NovaObject,
# TODO(berrange): Remove NovaObjectDictCompat
+@base.NovaObjectRegistry.register
class InstanceNUMATopology(base.NovaObject,
base.NovaObjectDictCompat):
# Version 1.0: Initial version
diff --git a/nova/objects/instance_pci_requests.py b/nova/objects/instance_pci_requests.py
index 2a07b148ba..e09d1f613f 100644
--- a/nova/objects/instance_pci_requests.py
+++ b/nova/objects/instance_pci_requests.py
@@ -19,6 +19,7 @@ from nova import utils
# TODO(berrange): Remove NovaObjectDictCompat
+@base.NovaObjectRegistry.register
class InstancePCIRequest(base.NovaObject,
base.NovaObjectDictCompat):
# Version 1.0: Initial version
@@ -52,6 +53,7 @@ class InstancePCIRequest(base.NovaObject,
# TODO(berrange): Remove NovaObjectDictCompat
+@base.NovaObjectRegistry.register
class InstancePCIRequests(base.NovaObject,
base.NovaObjectDictCompat):
# Version 1.0: Initial version
diff --git a/nova/objects/keypair.py b/nova/objects/keypair.py
index 1a1565de44..139fa4d267 100644
--- a/nova/objects/keypair.py
+++ b/nova/objects/keypair.py
@@ -24,6 +24,7 @@ KEYPAIR_TYPE_X509 = 'x509'
# TODO(berrange): Remove NovaObjectDictCompat
+@base.NovaObjectRegistry.register
class KeyPair(base.NovaPersistentObject, base.NovaObject,
base.NovaObjectDictCompat):
# Version 1.0: Initial version
@@ -78,6 +79,7 @@ class KeyPair(base.NovaPersistentObject, base.NovaObject,
db.key_pair_destroy(self._context, self.user_id, self.name)
+@base.NovaObjectRegistry.register
class KeyPairList(base.ObjectListBase, base.NovaObject):
# Version 1.0: Initial version
# KeyPair <= version 1.1
diff --git a/nova/objects/migration.py b/nova/objects/migration.py
index 7bf48d6b50..c8469f6758 100644
--- a/nova/objects/migration.py
+++ b/nova/objects/migration.py
@@ -28,6 +28,7 @@ def _determine_migration_type(migration):
# TODO(berrange): Remove NovaObjectDictCompat
+@base.NovaObjectRegistry.register
class Migration(base.NovaPersistentObject, base.NovaObject,
base.NovaObjectDictCompat):
# Version 1.0: Initial version
@@ -115,6 +116,7 @@ class Migration(base.NovaPersistentObject, base.NovaObject,
return objects.Instance.get_by_uuid(self._context, self.instance_uuid)
+@base.NovaObjectRegistry.register
class MigrationList(base.ObjectListBase, base.NovaObject):
# Version 1.0: Initial version
# Migration <= 1.1
diff --git a/nova/objects/network.py b/nova/objects/network.py
index c8e997fe5b..26a5af235b 100644
--- a/nova/objects/network.py
+++ b/nova/objects/network.py
@@ -41,6 +41,7 @@ CONF.register_opts(network_opts)
# TODO(berrange): Remove NovaObjectDictCompat
+@obj_base.NovaObjectRegistry.register
class Network(obj_base.NovaPersistentObject, obj_base.NovaObject,
obj_base.NovaObjectDictCompat):
# Version 1.0: Initial version
@@ -206,6 +207,7 @@ class Network(obj_base.NovaPersistentObject, obj_base.NovaObject,
self._from_db_object(context, self, db_network)
+@obj_base.NovaObjectRegistry.register
class NetworkList(obj_base.ObjectListBase, obj_base.NovaObject):
# Version 1.0: Initial version
# Version 1.1: Added get_by_project()
diff --git a/nova/objects/network_request.py b/nova/objects/network_request.py
index 405c3c0d18..3e15480bb6 100644
--- a/nova/objects/network_request.py
+++ b/nova/objects/network_request.py
@@ -18,6 +18,7 @@ from nova import utils
# TODO(berrange): Remove NovaObjectDictCompat
+@obj_base.NovaObjectRegistry.register
class NetworkRequest(obj_base.NovaObject,
obj_base.NovaObjectDictCompat):
# Version 1.0: Initial version
@@ -57,6 +58,7 @@ class NetworkRequest(obj_base.NovaObject,
return cls(network_id=network_id, address=address)
+@obj_base.NovaObjectRegistry.register
class NetworkRequestList(obj_base.ObjectListBase, obj_base.NovaObject):
fields = {
'objects': fields.ListOfObjectsField('NetworkRequest'),
diff --git a/nova/objects/numa.py b/nova/objects/numa.py
index 112074091c..20df535deb 100644
--- a/nova/objects/numa.py
+++ b/nova/objects/numa.py
@@ -35,6 +35,7 @@ def all_things_equal(obj_a, obj_b):
# TODO(berrange): Remove NovaObjectDictCompat
+@base.NovaObjectRegistry.register
class NUMACell(base.NovaObject,
base.NovaObjectDictCompat):
# Version 1.0: Initial version
@@ -131,6 +132,7 @@ class NUMACell(base.NovaObject,
# TODO(berrange): Remove NovaObjectDictCompat
+@base.NovaObjectRegistry.register
class NUMAPagesTopology(base.NovaObject,
base.NovaObjectDictCompat):
# Version 1.0: Initial version
@@ -160,6 +162,7 @@ class NUMAPagesTopology(base.NovaObject,
# TODO(berrange): Remove NovaObjectDictCompat
+@base.NovaObjectRegistry.register
class NUMATopology(base.NovaObject,
base.NovaObjectDictCompat):
# Version 1.0: Initial version
@@ -210,6 +213,7 @@ class NUMATopology(base.NovaObject,
for cell_dict in data_dict.get('cells', [])])
+@base.NovaObjectRegistry.register
class NUMATopologyLimits(base.NovaObject):
# Version 1.0: Initial version
VERSION = '1.0'
diff --git a/nova/objects/pci_device.py b/nova/objects/pci_device.py
index 01050fbe36..5098b7569a 100644
--- a/nova/objects/pci_device.py
+++ b/nova/objects/pci_device.py
@@ -42,6 +42,7 @@ def compare_pci_device_attributes(obj_a, obj_b):
# TODO(berrange): Remove NovaObjectDictCompat
+@base.NovaObjectRegistry.register
class PciDevice(base.NovaPersistentObject, base.NovaObject,
base.NovaObjectDictCompat):
@@ -200,6 +201,7 @@ class PciDevice(base.NovaPersistentObject, base.NovaObject,
self._from_db_object(self._context, self, db_pci)
+@base.NovaObjectRegistry.register
class PciDeviceList(base.ObjectListBase, base.NovaObject):
# Version 1.0: Initial version
# PciDevice <= 1.1
diff --git a/nova/objects/pci_device_pool.py b/nova/objects/pci_device_pool.py
index 13e57c4560..38799c16ed 100644
--- a/nova/objects/pci_device_pool.py
+++ b/nova/objects/pci_device_pool.py
@@ -24,6 +24,7 @@ from nova.objects import fields
from nova import utils
+@base.NovaObjectRegistry.register
class PciDevicePool(base.NovaObject):
# Version 1.0: Initial version
# Version 1.1: Added numa_node field
@@ -67,6 +68,7 @@ class PciDevicePool(base.NovaObject):
return pci_pool
+@base.NovaObjectRegistry.register
class PciDevicePoolList(base.ObjectListBase, base.NovaObject):
# Version 1.0: Initial version
# PciDevicePool <= 1.0
diff --git a/nova/objects/quotas.py b/nova/objects/quotas.py
index a1aef29766..2cc8534e9d 100644
--- a/nova/objects/quotas.py
+++ b/nova/objects/quotas.py
@@ -47,6 +47,7 @@ def ids_from_server_group(context, server_group):
# TODO(berrange): Remove NovaObjectDictCompat
+@base.NovaObjectRegistry.register
class Quotas(base.NovaObject,
base.NovaObjectDictCompat):
# Version 1.0: initial version
@@ -144,6 +145,7 @@ class Quotas(base.NovaObject,
db.quota_update(context, project_id, resource, limit, user_id=user_id)
+@base.NovaObjectRegistry.register
class QuotasNoOp(Quotas):
def reserve(context, expire=None, project_id=None, user_id=None,
**deltas):
diff --git a/nova/objects/security_group.py b/nova/objects/security_group.py
index 0b56527556..8f5dbca843 100644
--- a/nova/objects/security_group.py
+++ b/nova/objects/security_group.py
@@ -19,6 +19,7 @@ from nova.objects import fields
# TODO(berrange): Remove NovaObjectDictCompat
+@base.NovaObjectRegistry.register
class SecurityGroup(base.NovaPersistentObject, base.NovaObject,
base.NovaObjectDictCompat):
# Version 1.0: Initial version
@@ -73,6 +74,7 @@ class SecurityGroup(base.NovaPersistentObject, base.NovaObject,
db.security_group_get(self._context, self.id))
+@base.NovaObjectRegistry.register
class SecurityGroupList(base.ObjectListBase, base.NovaObject):
# Version 1.0: Initial version
# SecurityGroup <= version 1.1
diff --git a/nova/objects/security_group_rule.py b/nova/objects/security_group_rule.py
index da75e03738..8e724a2be9 100644
--- a/nova/objects/security_group_rule.py
+++ b/nova/objects/security_group_rule.py
@@ -22,6 +22,7 @@ OPTIONAL_ATTRS = ['parent_group', 'grantee_group']
# TODO(berrange): Remove NovaObjectDictCompat
+@base.NovaObjectRegistry.register
class SecurityGroupRule(base.NovaPersistentObject, base.NovaObject,
base.NovaObjectDictCompat):
# Version 1.0: Initial version
@@ -84,6 +85,7 @@ class SecurityGroupRule(base.NovaPersistentObject, base.NovaObject,
return cls._from_db_object(context, cls(), db_rule)
+@base.NovaObjectRegistry.register
class SecurityGroupRuleList(base.ObjectListBase, base.NovaObject):
fields = {
'objects': fields.ListOfObjectsField('SecurityGroupRule'),
diff --git a/nova/objects/service.py b/nova/objects/service.py
index ca11066320..ce5dd9b6ce 100644
--- a/nova/objects/service.py
+++ b/nova/objects/service.py
@@ -27,6 +27,7 @@ LOG = logging.getLogger(__name__)
# TODO(berrange): Remove NovaObjectDictCompat
+@base.NovaObjectRegistry.register
class Service(base.NovaPersistentObject, base.NovaObject,
base.NovaObjectDictCompat):
# Version 1.0: Initial version
@@ -179,6 +180,7 @@ class Service(base.NovaPersistentObject, base.NovaObject,
db.service_destroy(self._context, self.id)
+@base.NovaObjectRegistry.register
class ServiceList(base.ObjectListBase, base.NovaObject):
# Version 1.0: Initial version
# Service <= version 1.2
diff --git a/nova/objects/tag.py b/nova/objects/tag.py
index 87a81cb852..c463ddf2b6 100644
--- a/nova/objects/tag.py
+++ b/nova/objects/tag.py
@@ -16,6 +16,7 @@ from nova.objects import base
from nova.objects import fields
+@base.NovaObjectRegistry.register
class Tag(base.NovaObject):
# Version 1.0: Initial version
VERSION = '1.0'
@@ -43,6 +44,7 @@ class Tag(base.NovaObject):
db.instance_tag_delete(context, resource_id, name)
+@base.NovaObjectRegistry.register
class TagList(base.ObjectListBase, base.NovaObject):
# Version 1.0: Initial version
VERSION = '1.0'
diff --git a/nova/objects/vcpu_model.py b/nova/objects/vcpu_model.py
index 87742dc1fa..32940ce26d 100644
--- a/nova/objects/vcpu_model.py
+++ b/nova/objects/vcpu_model.py
@@ -17,6 +17,7 @@ from nova.objects import base
from nova.objects import fields
+@base.NovaObjectRegistry.register
class VirtCPUModel(base.NovaObject):
# Version 1.0: Initial version
VERSION = '1.0'
@@ -57,6 +58,7 @@ class VirtCPUModel(base.NovaObject):
return cls.obj_from_primitive(jsonutils.loads(db_extra['vcpu_model']))
+@base.NovaObjectRegistry.register
class VirtCPUFeature(base.NovaObject):
VERSION = VirtCPUModel.VERSION
diff --git a/nova/objects/virt_cpu_topology.py b/nova/objects/virt_cpu_topology.py
index 66a09cd2c1..d0dbd15a98 100644
--- a/nova/objects/virt_cpu_topology.py
+++ b/nova/objects/virt_cpu_topology.py
@@ -15,6 +15,7 @@ from nova.objects import fields
# TODO(berrange): Remove NovaObjectDictCompat
+@base.NovaObjectRegistry.register
class VirtCPUTopology(base.NovaObject,
base.NovaObjectDictCompat):
# Version 1.0: Initial version
diff --git a/nova/objects/virtual_interface.py b/nova/objects/virtual_interface.py
index be44cfcd83..0414def6a8 100644
--- a/nova/objects/virtual_interface.py
+++ b/nova/objects/virtual_interface.py
@@ -20,6 +20,7 @@ from nova.objects import fields
# TODO(berrange): Remove NovaObjectDictCompat
+@base.NovaObjectRegistry.register
class VirtualInterface(base.NovaPersistentObject, base.NovaObject,
base.NovaObjectDictCompat):
# Version 1.0: Initial version
@@ -80,6 +81,7 @@ class VirtualInterface(base.NovaPersistentObject, base.NovaObject,
db.virtual_interface_delete_by_instance(context, instance_uuid)
+@base.NovaObjectRegistry.register
class VirtualInterfaceList(base.ObjectListBase, base.NovaObject):
# Version 1.0: Initial version
VERSION = '1.0'
diff --git a/nova/tests/unit/api/openstack/compute/contrib/test_security_groups.py b/nova/tests/unit/api/openstack/compute/contrib/test_security_groups.py
index 33cba6b585..fa6c67bea4 100644
--- a/nova/tests/unit/api/openstack/compute/contrib/test_security_groups.py
+++ b/nova/tests/unit/api/openstack/compute/contrib/test_security_groups.py
@@ -189,7 +189,7 @@ class TestSecurityGroupsV21(test.TestCase):
except webob.exc.HTTPBadRequest as exc:
self.assertEqual('description has a minimum character requirement'
' of 1.', exc.explanation)
- except exception.InvalidInput as exc:
+ except exception.InvalidInput:
self.fail('Should have raised BadRequest exception instead of')
self._assert_no_security_groups_reserved(req.environ['nova.context'])
diff --git a/nova/tests/unit/api/openstack/compute/contrib/test_server_external_events.py b/nova/tests/unit/api/openstack/compute/contrib/test_server_external_events.py
index 8b5a4e05da..eebc5e9303 100644
--- a/nova/tests/unit/api/openstack/compute/contrib/test_server_external_events.py
+++ b/nova/tests/unit/api/openstack/compute/contrib/test_server_external_events.py
@@ -60,13 +60,13 @@ class ServerExternalEventsTestV21(test.NoDBTestCase):
'server_uuid': fake_instance_uuids[0],
'status': 'completed'}
self.event_2 = {'name': 'network-changed',
- 'server_uuid': fake_instance_uuids[1],
- 'status': 'completed'}
+ 'server_uuid': fake_instance_uuids[1]}
self.default_body = {'events': [self.event_1, self.event_2]}
self.resp_event_1 = dict(self.event_1)
self.resp_event_1['code'] = 200
self.resp_event_2 = dict(self.event_2)
self.resp_event_2['code'] = 200
+ self.resp_event_2['status'] = 'completed'
self.default_resp_body = {'events': [self.resp_event_1,
self.resp_event_2]}
self.req = fakes.HTTPRequest.blank('', use_admin_context=True)
diff --git a/nova/tests/unit/compute/test_compute.py b/nova/tests/unit/compute/test_compute.py
index 9da07e1d77..f9b15cf895 100644
--- a/nova/tests/unit/compute/test_compute.py
+++ b/nova/tests/unit/compute/test_compute.py
@@ -452,6 +452,17 @@ class ComputeVolumeTestCase(BaseTestCase):
self.compute._await_block_device_map_created,
self.context, '1')
+ def test_await_block_device_created_failed(self):
+ c = self.compute
+
+ fake_result = {'status': 'error', 'id': 'blah'}
+ with mock.patch.object(c.volume_api, 'get',
+ return_value=fake_result) as fake_get:
+ self.assertRaises(exception.VolumeNotCreated,
+ c._await_block_device_map_created,
+ self.context, '1')
+ fake_get.assert_called_once_with(self.context, '1')
+
def test_await_block_device_created_slow(self):
c = self.compute
self.flags(block_device_allocate_retries=4)
diff --git a/nova/tests/unit/objects/test_objects.py b/nova/tests/unit/objects/test_objects.py
index 300289a256..849b787ab8 100644
--- a/nova/tests/unit/objects/test_objects.py
+++ b/nova/tests/unit/objects/test_objects.py
@@ -1283,6 +1283,15 @@ class TestObjectVersions(test.NoDBTestCase):
'versions have been bumped, and then update their '
'hashes here.')
+ def test_registry_matches_metaclass(self):
+ reference = set(object_data.keys())
+ actual = set(base.NovaObjectRegistry.classes)
+ test_objects = set(['MyObj', 'MyOwnedObject', 'TestSubclassedObject'])
+ # NOTE(danms): In the new registry, we don't implicitly track test
+ # objects, so make sure that the difference between the metaclass and
+ # the opt-in registry is the set of test objects.
+ self.assertEqual(test_objects, reference.symmetric_difference(actual))
+
def _get_object_field_name(self, field):
if isinstance(field._type, fields.Object):
return field._type._obj_name
diff --git a/nova/tests/unit/virt/ironic/test_driver.py b/nova/tests/unit/virt/ironic/test_driver.py
index dfa6b5285c..47d08e0fca 100644
--- a/nova/tests/unit/virt/ironic/test_driver.py
+++ b/nova/tests/unit/virt/ironic/test_driver.py
@@ -509,9 +509,21 @@ class IronicDriverTestCase(test.NoDBTestCase):
'power_state': ironic_states.NOSTATE,
'provision_state': ironic_states.AVAILABLE},
# a node not in maintenance or bad power state, bad provision state
- {'uuid': uuidutils.generate_uuid,
+ {'uuid': uuidutils.generate_uuid(),
+ 'power_state': ironic_states.POWER_ON,
+ 'provision_state': ironic_states.MANAGEABLE},
+ # a node in cleaning
+ {'uuid': uuidutils.generate_uuid(),
+ 'power_state': ironic_states.POWER_ON,
+ 'provision_state': ironic_states.CLEANING},
+ # a node in deleting
+ {'uuid': uuidutils.generate_uuid(),
'power_state': ironic_states.POWER_ON,
- 'provision_state': ironic_states.MANAGEABLE}
+ 'provision_state': ironic_states.DELETING},
+ # a node in deleted
+ {'uuid': uuidutils.generate_uuid(),
+ 'power_state': ironic_states.POWER_ON,
+ 'provision_state': ironic_states.DELETED}
]
for n in node_dicts:
node = ironic_utils.get_test_node(**n)
@@ -531,20 +543,14 @@ class IronicDriverTestCase(test.NoDBTestCase):
{'uuid': uuidutils.generate_uuid(),
'instance_uuid': uuidutils.generate_uuid(),
'provision_state': ironic_states.ACTIVE},
- # a node in deploying but no instance yet
- {'uuid': uuidutils.generate_uuid(),
- 'provision_state': ironic_states.DEPLOYWAIT},
- # a node that made it to cleaning before losing its instance uuid
- {'uuid': uuidutils.generate_uuid,
- 'instance_uuid': uuidutils.generate_uuid(),
- 'provision_state': ironic_states.CLEANING},
]
for n in node_dicts:
node = ironic_utils.get_test_node(**n)
self.assertTrue(self.driver._node_resources_used(node))
unused_node = ironic_utils.get_test_node(
- power_state=ironic_states.AVAILABLE)
+ instance_uuid=None,
+ provision_state=ironic_states.AVAILABLE)
self.assertFalse(self.driver._node_resources_used(unused_node))
@mock.patch.object(FAKE_CLIENT.node, 'list')
diff --git a/nova/tests/unit/virt/test_block_device.py b/nova/tests/unit/virt/test_block_device.py
index d32a20309a..64040a4d79 100644
--- a/nova/tests/unit/virt/test_block_device.py
+++ b/nova/tests/unit/virt/test_block_device.py
@@ -20,6 +20,7 @@ import six
from nova import block_device
from nova import context
+from nova import exception
from nova import test
from nova.tests.unit import fake_instance
from nova.tests.unit import matchers
@@ -328,6 +329,37 @@ class TestDriverBlockDevice(test.NoDBTestCase):
self.assertEqual('fake-volume-id-2', test_bdm.volume_id)
self.assertEqual(3, test_bdm.volume_size)
+ def _test_call_wait_func(self, delete_on_termination, delete_fail=False):
+ test_bdm = self.driver_classes['volume'](self.volume_bdm)
+ test_bdm['delete_on_termination'] = delete_on_termination
+ with mock.patch.object(self.volume_api, 'delete') as vol_delete:
+ wait_func = mock.MagicMock()
+ mock_exception = exception.VolumeNotCreated(volume_id='fake-id',
+ seconds=1,
+ attempts=1,
+ volume_status='error')
+ wait_func.side_effect = mock_exception
+
+ if delete_on_termination and delete_fail:
+ vol_delete.side_effect = Exception()
+
+ self.assertRaises(exception.VolumeNotCreated,
+ test_bdm._call_wait_func,
+ context=self.context,
+ wait_func=wait_func,
+ volume_api=self.volume_api,
+ volume_id='fake-id')
+ self.assertEqual(delete_on_termination, vol_delete.called)
+
+ def test_call_wait_delete_volume(self):
+ self._test_call_wait_func(True)
+
+ def test_call_wait_delete_volume_fail(self):
+ self._test_call_wait_func(True, True)
+
+ def test_call_wait_no_delete_volume(self):
+ self._test_call_wait_func(False)
+
def _test_volume_attach(self, driver_bdm, bdm_dict,
fake_volume, check_attach=True,
fail_check_attach=False, driver_attach=False,
@@ -560,6 +592,43 @@ class TestDriverBlockDevice(test.NoDBTestCase):
self.virt_driver, wait_func)
self.assertEqual(test_bdm.volume_id, 'fake-volume-id-2')
+ def test_snapshot_attach_fail_volume(self):
+ fail_volume_snapshot = self.snapshot_bdm.copy()
+ fail_volume_snapshot['volume_id'] = None
+ test_bdm = self.driver_classes['snapshot'](fail_volume_snapshot)
+
+ snapshot = {'id': 'fake-volume-id-1',
+ 'attach_status': 'detached'}
+ volume = {'id': 'fake-volume-id-2',
+ 'attach_status': 'detached'}
+
+ instance = fake_instance.fake_instance_obj(mock.sentinel.ctx,
+ **{'uuid': 'fake-uuid'})
+ with contextlib.nested(
+ mock.patch.object(self.volume_api, 'get_snapshot',
+ return_value=snapshot),
+ mock.patch.object(self.volume_api, 'create', return_value=volume),
+ mock.patch.object(self.volume_api, 'delete'),
+ ) as (vol_get_snap, vol_create, vol_delete):
+ wait_func = mock.MagicMock()
+ mock_exception = exception.VolumeNotCreated(volume_id=volume['id'],
+ seconds=1,
+ attempts=1,
+ volume_status='error')
+ wait_func.side_effect = mock_exception
+ self.assertRaises(exception.VolumeNotCreated,
+ test_bdm.attach, context=self.context,
+ instance=instance,
+ volume_api=self.volume_api,
+ virt_driver=self.virt_driver,
+ wait_func=wait_func)
+
+ vol_get_snap.assert_called_once_with(
+ self.context, 'fake-snapshot-id-1')
+ vol_create.assert_called_once_with(
+ self.context, 3, '', '', snapshot, availability_zone=None)
+ vol_delete.assert_called_once_with(self.context, volume['id'])
+
def test_snapshot_attach_volume(self):
test_bdm = self.driver_classes['snapshot'](
self.snapshot_bdm)
@@ -604,6 +673,39 @@ class TestDriverBlockDevice(test.NoDBTestCase):
self.virt_driver, wait_func)
self.assertEqual(test_bdm.volume_id, 'fake-volume-id-2')
+ def test_image_attach_fail_volume(self):
+ fail_volume_image = self.image_bdm.copy()
+ fail_volume_image['volume_id'] = None
+ test_bdm = self.driver_classes['image'](fail_volume_image)
+
+ image = {'id': 'fake-image-id-1'}
+ volume = {'id': 'fake-volume-id-2',
+ 'attach_status': 'detached'}
+
+ instance = fake_instance.fake_instance_obj(mock.sentinel.ctx,
+ **{'uuid': 'fake-uuid'})
+ with contextlib.nested(
+ mock.patch.object(self.volume_api, 'create', return_value=volume),
+ mock.patch.object(self.volume_api, 'delete'),
+ ) as (vol_create, vol_delete):
+ wait_func = mock.MagicMock()
+ mock_exception = exception.VolumeNotCreated(volume_id=volume['id'],
+ seconds=1,
+ attempts=1,
+ volume_status='error')
+ wait_func.side_effect = mock_exception
+ self.assertRaises(exception.VolumeNotCreated,
+ test_bdm.attach, context=self.context,
+ instance=instance,
+ volume_api=self.volume_api,
+ virt_driver=self.virt_driver,
+ wait_func=wait_func)
+
+ vol_create.assert_called_once_with(
+ self.context, 1, '', '', image_id=image['id'],
+ availability_zone=None)
+ vol_delete.assert_called_once_with(self.context, volume['id'])
+
def test_image_attach_volume(self):
test_bdm = self.driver_classes['image'](
self.image_bdm)
@@ -626,6 +728,38 @@ class TestDriverBlockDevice(test.NoDBTestCase):
self.virt_driver)
self.assertEqual(test_bdm.volume_id, 'fake-volume-id-2')
+ def test_blank_attach_fail_volume(self):
+ no_blank_volume = self.blank_bdm.copy()
+ no_blank_volume['volume_id'] = None
+ test_bdm = self.driver_classes['blank'](no_blank_volume)
+ instance = fake_instance.fake_instance_obj(mock.sentinel.ctx,
+ **{'uuid': 'fake-uuid'})
+ volume = {'id': 'fake-volume-id-2',
+ 'display_name': 'fake-uuid-blank-vol'}
+
+ with contextlib.nested(
+ mock.patch.object(self.volume_api, 'create', return_value=volume),
+ mock.patch.object(self.volume_api, 'delete'),
+ ) as (vol_create, vol_delete):
+ wait_func = mock.MagicMock()
+ mock_exception = exception.VolumeNotCreated(volume_id=volume['id'],
+ seconds=1,
+ attempts=1,
+ volume_status='error')
+ wait_func.side_effect = mock_exception
+ self.assertRaises(exception.VolumeNotCreated,
+ test_bdm.attach, context=self.context,
+ instance=instance,
+ volume_api=self.volume_api,
+ virt_driver=self.virt_driver,
+ wait_func=wait_func)
+
+ vol_create.assert_called_once_with(
+ self.context, test_bdm.volume_size, 'fake-uuid-blank-vol',
+ '', availability_zone=instance.availability_zone)
+ vol_delete.assert_called_once_with(
+ self.context, volume['id'])
+
def test_blank_attach_volume(self):
no_blank_volume = self.blank_bdm.copy()
no_blank_volume['volume_id'] = None
diff --git a/nova/tests/unit/virt/vmwareapi/test_driver_api.py b/nova/tests/unit/virt/vmwareapi/test_driver_api.py
index 5a7cd1135f..9dfbaa30bd 100644
--- a/nova/tests/unit/virt/vmwareapi/test_driver_api.py
+++ b/nova/tests/unit/virt/vmwareapi/test_driver_api.py
@@ -2309,3 +2309,22 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
test_mor = "domain-26"
nodename = "%s.%s" % (test_mor, vmwareapi_fake._FAKE_VCENTER_UUID)
self.assertEqual(nodename, self.conn._normalize_nodename(nodename))
+
+ @mock.patch.object(driver.LOG, 'warning')
+ def test_min_version(self, mock_warning):
+ self.conn._check_min_version()
+ self.assertFalse(mock_warning.called)
+
+ @mock.patch.object(driver.LOG, 'warning')
+ @mock.patch.object(oslo_vim_util, 'get_vc_version',
+ return_value='5.0.0')
+ def test_invalid_min_version(self, mock_version, mock_warning):
+ self.conn._check_min_version()
+ # assert that the min version is in a warning message
+ expected_arg = {'version': constants.MIN_VC_VERSION}
+ version_arg_found = False
+ for call in mock_warning.call_args_list:
+ if call[0][1] == expected_arg:
+ version_arg_found = True
+ break
+ self.assertTrue(version_arg_found)
diff --git a/nova/virt/block_device.py b/nova/virt/block_device.py
index 7a0c488463..dcac11e92b 100644
--- a/nova/virt/block_device.py
+++ b/nova/virt/block_device.py
@@ -22,8 +22,10 @@ from oslo_utils import excutils
import six
from nova import block_device
+from nova import exception
from nova.i18n import _LE
from nova.i18n import _LI
+from nova.i18n import _LW
from nova import objects
from nova.objects import base as obj_base
from nova.volume import encryptors
@@ -303,6 +305,19 @@ class DriverVolumeBlockDevice(DriverBlockDevice):
pass
super(DriverVolumeBlockDevice, self).save()
+ def _call_wait_func(self, context, wait_func, volume_api, volume_id):
+ try:
+ wait_func(context, volume_id)
+ except exception.VolumeNotCreated:
+ with excutils.save_and_reraise_exception():
+ if self['delete_on_termination']:
+ try:
+ volume_api.delete(context, volume_id)
+ except Exception as exc:
+ LOG.warn(_LW('Failed to delete volume: %(volume_id)s '
+ 'due to %(exc)s'),
+ {'volume_id': volume_id, 'exc': exc})
+
class DriverSnapshotBlockDevice(DriverVolumeBlockDevice):
@@ -319,7 +334,7 @@ class DriverSnapshotBlockDevice(DriverVolumeBlockDevice):
vol = volume_api.create(context, self.volume_size, '', '',
snapshot, availability_zone=av_zone)
if wait_func:
- wait_func(context, vol['id'])
+ self._call_wait_func(context, wait_func, volume_api, vol['id'])
self.volume_id = vol['id']
@@ -342,7 +357,7 @@ class DriverImageBlockDevice(DriverVolumeBlockDevice):
'', '', image_id=self.image_id,
availability_zone=av_zone)
if wait_func:
- wait_func(context, vol['id'])
+ self._call_wait_func(context, wait_func, volume_api, vol['id'])
self.volume_id = vol['id']
@@ -364,7 +379,7 @@ class DriverBlankBlockDevice(DriverVolumeBlockDevice):
vol = volume_api.create(context, self.volume_size, vol_name, '',
availability_zone=av_zone)
if wait_func:
- wait_func(context, vol['id'])
+ self._call_wait_func(context, wait_func, volume_api, vol['id'])
self.volume_id = vol['id']
diff --git a/nova/virt/ironic/driver.py b/nova/virt/ironic/driver.py
index a342e4ea98..1a284691bf 100644
--- a/nova/virt/ironic/driver.py
+++ b/nova/virt/ironic/driver.py
@@ -222,14 +222,13 @@ class IronicDriver(virt_driver.ComputeDriver):
a new instance on the node, has an instance on the node, or is in
the process of cleaning up from a deleted instance. Returns True if
used.
+
+ If we report resources as consumed for a node that does not have an
+ instance on it, the resource tracker will notice there's no instances
+ consuming resources and try to correct us. So only nodes with an
+ instance attached should report as consumed here.
"""
- used_provision_states = [
- ironic_states.CLEANING, ironic_states.DEPLOYING,
- ironic_states.DEPLOYWAIT, ironic_states.DEPLOYDONE,
- ironic_states.ACTIVE, ironic_states.DELETING,
- ironic_states.DELETED]
- return (node_obj.instance_uuid is not None or
- node_obj.provision_state in used_provision_states)
+ return node_obj.instance_uuid is not None
def _node_resource(self, node):
"""Helper method to create resource dict from node stats."""
diff --git a/nova/virt/libvirt/host.py b/nova/virt/libvirt/host.py
index 4bae94caa7..2a4b0e8e24 100644
--- a/nova/virt/libvirt/host.py
+++ b/nova/virt/libvirt/host.py
@@ -392,25 +392,22 @@ class Host(object):
event = args[0]
self._events_delayed.pop(event.uuid, None)
- if self._lifecycle_delay > 0:
- # Cleanup possible delayed stop events.
- if event.uuid in self._events_delayed.keys():
- self._events_delayed[event.uuid].cancel()
- self._events_delayed.pop(event.uuid, None)
- LOG.debug("Removed pending event for %s due to "
- "lifecycle event", event.uuid)
-
- if event.transition == virtevent.EVENT_LIFECYCLE_STOPPED:
- # Delay STOPPED event, as they may be followed by a STARTED
- # event in case the instance is rebooting
- id_ = greenthread.spawn_after(self._lifecycle_delay,
- self._event_emit, event)
- self._events_delayed[event.uuid] = id_
- # add callback to cleanup self._events_delayed dict after
- # event was called
- id_.link(event_cleanup, event)
- else:
- self._event_emit(event)
+ # Cleanup possible delayed stop events.
+ if event.uuid in self._events_delayed.keys():
+ self._events_delayed[event.uuid].cancel()
+ self._events_delayed.pop(event.uuid, None)
+ LOG.debug("Removed pending event for %s due to "
+ "lifecycle event", event.uuid)
+
+ if event.transition == virtevent.EVENT_LIFECYCLE_STOPPED:
+ # Delay STOPPED event, as they may be followed by a STARTED
+ # event in case the instance is rebooting
+ id_ = greenthread.spawn_after(self._lifecycle_delay,
+ self._event_emit, event)
+ self._events_delayed[event.uuid] = id_
+ # add callback to cleanup self._events_delayed dict after
+ # event was called
+ id_.link(event_cleanup, event)
else:
self._event_emit(event)
diff --git a/nova/virt/libvirt/utils.py b/nova/virt/libvirt/utils.py
index 84eba5ab2d..52b315eee1 100644
--- a/nova/virt/libvirt/utils.py
+++ b/nova/virt/libvirt/utils.py
@@ -238,7 +238,7 @@ def pick_disk_driver_name(hypervisor_version, is_block_dev=False):
return 'qemu'
else:
raise
- except processutils.ProcessExecutionError as exc:
+ except processutils.ProcessExecutionError:
LOG.debug("xend is not started")
# libvirt will try to use libxl toolstack
return 'qemu'
@@ -577,7 +577,7 @@ def is_mounted(mount_path, source=None):
utils.execute(*check_cmd)
return True
- except processutils.ProcessExecutionError as exc:
+ except processutils.ProcessExecutionError:
return False
except OSError as exc:
# info since it's not required to have this tool.
diff --git a/nova/virt/vmwareapi/constants.py b/nova/virt/vmwareapi/constants.py
index f3ee48be58..dd1523aeee 100644
--- a/nova/virt/vmwareapi/constants.py
+++ b/nova/virt/vmwareapi/constants.py
@@ -18,6 +18,8 @@ Shared constants across the VMware driver
from nova.network import model as network_model
+MIN_VC_VERSION = '5.1.0'
+
DISK_FORMAT_ISO = 'iso'
DISK_FORMAT_VMDK = 'vmdk'
DISK_FORMATS_ALL = [DISK_FORMAT_ISO, DISK_FORMAT_VMDK]
diff --git a/nova/virt/vmwareapi/driver.py b/nova/virt/vmwareapi/driver.py
index 0e1b21997f..b2aa55777f 100644
--- a/nova/virt/vmwareapi/driver.py
+++ b/nova/virt/vmwareapi/driver.py
@@ -32,6 +32,7 @@ from oslo_vmware import vim_util
import six
from nova import exception
+from nova import utils
from nova.i18n import _, _LI, _LW
from nova.openstack.common import versionutils
from nova.virt import driver
@@ -149,6 +150,8 @@ class VMwareVCDriver(driver.ComputeDriver):
self._session = VMwareAPISession(scheme=scheme)
+ self._check_min_version()
+
# Update the PBM location if necessary
if CONF.vmware.pbm_enabled:
self._update_pbm_location()
@@ -199,6 +202,18 @@ class VMwareVCDriver(driver.ComputeDriver):
# Register the OpenStack extension
self._register_openstack_extension()
+ def _check_min_version(self):
+ min_version = utils.convert_version_to_int(constants.MIN_VC_VERSION)
+ vc_version = vim_util.get_vc_version(self._session)
+ LOG.info(_LI("VMware VC version: %s"), vc_version)
+ if min_version > utils.convert_version_to_int(vc_version):
+ # TODO(garyk): enforce this from M
+ LOG.warning(_LW('Running Nova with a VMware VC version less than '
+ '%(version)s is deprecated. The required minimum '
+ 'version of VC will be raised to %(version)s '
+ 'in the 2016.1 release.'),
+ {'version': constants.MIN_VC_VERSION})
+
@property
def need_legacy_block_device_info(self):
return False