def resources_from_flavor(instance, flavor): """Convert a flavor into a set of resources for placement, taking into account boot-from-volume instances. This takes an instance and a flavor and returns a dict of resource_class:amount based on the attributes of the flavor, accounting for any overrides that are made in extra_specs. """ is_bfv = compute_utils.is_volume_backed_instance(instance._context, instance) swap_in_gb = compute_utils.convert_mb_to_ceil_gb(flavor.swap) disk = ((0 if is_bfv else flavor.root_gb) + swap_in_gb + flavor.ephemeral_gb) resources = { orc.VCPU: flavor.vcpus, orc.MEMORY_MB: flavor.memory_mb, orc.DISK_GB: disk, } if "extra_specs" in flavor: # TODO(efried): This method is currently only used from places that # assume the compute node is the only resource provider. So for now, # we just merge together all the resources specified in the flavor and # pass them along. This will need to be adjusted when nested and/or # shared RPs are in play. rreq = ResourceRequest.from_extra_specs(flavor.extra_specs) resources = rreq.merged_resources(flavor_resources=resources) return resources
def test_is_volume_backed_instance_bdm_local_no_image(self): # if the root device is local the instance is not volume backed, even # if no image_ref is set. ctxt = self.context instance = create_instance(ctxt, params={ 'root_device_name': 'vda', 'image_ref': '' }) bdms = block_device_obj.block_device_make_list(ctxt, [ fake_block_device.FakeDbBlockDeviceDict({ 'source_type': 'volume', 'device_name': '/dev/vda', 'volume_id': uuids.volume_id, 'destination_type': 'local', 'instance_uuid': 'f8000000-0000-0000-0000-000000000000', 'boot_index': 0, 'snapshot_id': None }), fake_block_device.FakeDbBlockDeviceDict({ 'source_type': 'volume', 'device_name': '/dev/vdb', 'instance_uuid': 'f8000000-0000-0000-0000-000000000000', 'boot_index': 1, 'destination_type': 'volume', 'volume_id': 'c2ec2156-d75e-11e2-985b-5254009297d6', 'snapshot_id': None }) ]) self.assertFalse( compute_utils.is_volume_backed_instance(ctxt, instance, bdms))
def _action_create_image(self, req, id, body): """Snapshot a server instance.""" context = req.environ['nova.context'] entity = body.get("createImage", {}) image_name = entity.get("name") if not image_name: msg = _("createImage entity requires name attribute") raise exc.HTTPBadRequest(explanation=msg) props = {} metadata = entity.get('metadata', {}) common.check_img_metadata_properties_quota(context, metadata) try: props.update(metadata) except ValueError: msg = _("Invalid metadata") raise exc.HTTPBadRequest(explanation=msg) instance = self._get_server(context, req, id) bdms = objects.BlockDeviceMappingList.get_by_instance_uuid( context, instance.uuid) try: if compute_utils.is_volume_backed_instance(context, instance, bdms): policy.enforce(context, 'compute:snapshot_volume_backed', {'project_id': context.project_id, 'user_id': context.user_id}) image = self.compute_api.snapshot_volume_backed( context, instance, image_name, extra_properties=props) else: image = self.compute_api.snapshot(context, instance, image_name, extra_properties=props) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state(state_error, 'createImage', id) except exception.Invalid as err: raise exc.HTTPBadRequest(explanation=err.format_message()) # build location of newly-created image entity image_id = str(image['id']) url_prefix = self._view_builder._update_glance_link_prefix( req.application_url) image_ref = common.url_join(url_prefix, context.project_id, 'images', image_id) resp = webob.Response(status_int=202) resp.headers['Location'] = image_ref return resp
def test_is_volume_backed_instance_bdm_local_no_image(self): # if the root device is local the instance is not volume backed, even # if no image_ref is set. ctxt = self.context instance = create_instance(ctxt, params={ 'root_device_name': 'vda', 'image_ref': '' }) bdms = block_device_obj.block_device_make_list(ctxt, [fake_block_device.FakeDbBlockDeviceDict( {'source_type': 'volume', 'device_name': '/dev/vda', 'volume_id': uuids.volume_id, 'destination_type': 'local', 'instance_uuid': 'f8000000-0000-0000-0000-000000000000', 'boot_index': 0, 'snapshot_id': None}), fake_block_device.FakeDbBlockDeviceDict( {'source_type': 'volume', 'device_name': '/dev/vdb', 'instance_uuid': 'f8000000-0000-0000-0000-000000000000', 'boot_index': 1, 'destination_type': 'volume', 'volume_id': 'c2ec2156-d75e-11e2-985b-5254009297d6', 'snapshot_id': None})]) self.assertFalse( compute_utils.is_volume_backed_instance(ctxt, instance, bdms))
def resources_from_flavor(instance, flavor): """Convert a flavor into a set of resources for placement, taking into account boot-from-volume instances. This takes an instance and a flavor and returns a dict of resource_class:amount based on the attributes of the flavor, accounting for any overrides that are made in extra_specs. """ is_bfv = compute_utils.is_volume_backed_instance(instance._context, instance) swap_in_gb = compute_utils.convert_mb_to_ceil_gb(flavor.swap) disk = ((0 if is_bfv else flavor.root_gb) + swap_in_gb + flavor.ephemeral_gb) resources = { fields.ResourceClass.VCPU: flavor.vcpus, fields.ResourceClass.MEMORY_MB: flavor.memory_mb, fields.ResourceClass.DISK_GB: disk, } if "extra_specs" in flavor: # TODO(efried): This method is currently only used from places that # assume the compute node is the only resource provider. So for now, # we just merge together all the resources specified in the flavor and # pass them along. This will need to be adjusted when nested and/or # shared RPs are in play. rreq = ResourceRequest.from_extra_specs(flavor.extra_specs) resources = rreq.merged_resources(flavor_resources=resources) return resources
def test_is_volume_backed_instance_bdm_local_no_image(self): # if the root device is local the instance is not volume backed, even # if no image_ref is set. ctxt = self.context instance = create_instance(ctxt, params={"root_device_name": "vda", "image_ref": ""}) bdms = block_device_obj.block_device_make_list( ctxt, [ fake_block_device.FakeDbBlockDeviceDict( { "source_type": "volume", "device_name": "/dev/vda", "volume_id": uuids.volume_id, "destination_type": "local", "instance_uuid": "f8000000-0000-0000-0000-000000000000", "boot_index": 0, "snapshot_id": None, } ), fake_block_device.FakeDbBlockDeviceDict( { "source_type": "volume", "device_name": "/dev/vdb", "instance_uuid": "f8000000-0000-0000-0000-000000000000", "boot_index": 1, "destination_type": "volume", "volume_id": "c2ec2156-d75e-11e2-985b-5254009297d6", "snapshot_id": None, } ), ], ) self.assertFalse(compute_utils.is_volume_backed_instance(ctxt, instance, bdms))
def test_is_volume_backed_instance_empty_bdm_by_uuid(self, mock_bdms): ctxt = self.context instance = create_instance(ctxt) mock_bdms.return_value = block_device_obj.block_device_make_list( ctxt, []) self.assertFalse( compute_utils.is_volume_backed_instance(ctxt, instance, None)) mock_bdms.assert_called_with(ctxt, instance.uuid)
def test_is_volume_backed_instance_empty_bdm_by_uuid(self, mock_bdms): ctxt = self.context instance = create_instance(ctxt) mock_bdms.return_value = block_device_obj.block_device_make_list( ctxt, []) self.assertFalse( compute_utils.is_volume_backed_instance(ctxt, instance, None)) mock_bdms.assert_called_with(ctxt, instance.uuid)
def test_is_volume_backed_instance_empty_bdm_with_image(self): ctxt = self.context instance = create_instance(ctxt, params={ 'root_device_name': 'vda', 'image_ref': FAKE_IMAGE_REF }) self.assertFalse( compute_utils.is_volume_backed_instance( ctxt, instance, block_device_obj.block_device_make_list(ctxt, [])))
def _instance_to_allocations_dict(instance): """Given an `objects.Instance` object, return a dict, keyed by resource class of the amount used by the instance. :param instance: `objects.Instance` object to translate """ # NOTE(danms): Boot-from-volume instances consume no local disk is_bfv = compute_utils.is_volume_backed_instance(instance._context, instance) disk = (0 if is_bfv else instance.flavor.root_gb) + instance.flavor.swap + instance.flavor.ephemeral_gb return {MEMORY_MB: instance.flavor.memory_mb, VCPU: instance.flavor.vcpus, DISK_GB: disk}
def test_is_volume_backed_instance_empty_bdm_with_image(self): ctxt = self.context instance = create_instance(ctxt, params={ 'root_device_name': 'vda', 'image_ref': FAKE_IMAGE_REF }) self.assertFalse( compute_utils.is_volume_backed_instance( ctxt, instance, block_device_obj.block_device_make_list(ctxt, [])))
def _allocations(self, instance): # NOTE(danms): Boot-from-volume instances consume no local disk is_bfv = compute_utils.is_volume_backed_instance( instance._context, instance) disk = ((0 if is_bfv else instance.flavor.root_gb) + instance.flavor.swap + instance.flavor.ephemeral_gb) return { MEMORY_MB: instance.flavor.memory_mb, VCPU: instance.flavor.vcpus, DISK_GB: disk, }
def _allocations(self, instance): # NOTE(danms): Boot-from-volume instances consume no local disk is_bfv = compute_utils.is_volume_backed_instance(instance._context, instance) disk = ((0 if is_bfv else instance.flavor.root_gb) + instance.flavor.swap + instance.flavor.ephemeral_gb) return { 'MEMORY_MB': instance.flavor.memory_mb, 'VCPU': instance.flavor.vcpus, 'DISK_GB': disk, }
def test_is_volume_backed_instance_bdm_volume_with_image(self): ctxt = self.context instance = create_instance(ctxt, params={ 'root_device_name': 'vda', 'image_ref': FAKE_IMAGE_REF }) bdms = block_device_obj.block_device_make_list(ctxt, [fake_block_device.FakeDbBlockDeviceDict( {'source_type': 'volume', 'device_name': '/dev/vda', 'volume_id': uuids.volume_id, 'boot_index': 0, 'destination_type': 'volume'})]) self.assertTrue( compute_utils.is_volume_backed_instance(ctxt, instance, bdms))
def test_is_volume_backed_instance_bdm_volume_with_image(self): ctxt = self.context instance = create_instance(ctxt, params={ 'root_device_name': 'vda', 'image_ref': FAKE_IMAGE_REF }) bdms = block_device_obj.block_device_make_list(ctxt, [fake_block_device.FakeDbBlockDeviceDict( {'source_type': 'volume', 'device_name': '/dev/vda', 'volume_id': uuids.volume_id, 'boot_index': 0, 'destination_type': 'volume'})]) self.assertTrue( compute_utils.is_volume_backed_instance(ctxt, instance, bdms))
def _instance_to_allocations_dict(instance): """Given an `objects.Instance` object, return a dict, keyed by resource class of the amount used by the instance. :param instance: `objects.Instance` object to translate """ # NOTE(danms): Boot-from-volume instances consume no local disk is_bfv = compute_utils.is_volume_backed_instance(instance._context, instance) disk = ((0 if is_bfv else instance.flavor.root_gb) + instance.flavor.swap + instance.flavor.ephemeral_gb) return { MEMORY_MB: instance.flavor.memory_mb, VCPU: instance.flavor.vcpus, DISK_GB: disk, }
def test_is_volume_backed_instance_bdm_snapshot(self): ctxt = self.context instance = create_instance(ctxt, params={'root_device_name': 'vda'}) bdms = block_device_obj.block_device_make_list(ctxt, [ fake_block_device.FakeDbBlockDeviceDict({ 'source_type': 'volume', 'device_name': '/dev/vda', 'snapshot_id': 'de8836ac-d75e-11e2-8271-5254009297d6', 'instance_uuid': 'f8000000-0000-0000-0000-000000000000', 'destination_type': 'volume', 'boot_index': 0, 'volume_id': None }) ]) self.assertTrue( compute_utils.is_volume_backed_instance(ctxt, instance, bdms))
def test_is_volume_backed_instance_bdm_snapshot(self): ctxt = self.context instance = create_instance(ctxt, params={ 'root_device_name': 'vda' }) bdms = block_device_obj.block_device_make_list(ctxt, [fake_block_device.FakeDbBlockDeviceDict( {'source_type': 'volume', 'device_name': '/dev/vda', 'snapshot_id': 'de8836ac-d75e-11e2-8271-5254009297d6', 'instance_uuid': 'f8000000-0000-0000-0000-000000000000', 'destination_type': 'volume', 'boot_index': 0, 'volume_id': None})]) self.assertTrue( compute_utils.is_volume_backed_instance(ctxt, instance, bdms))
def _action_create_image(self, req, id, body): """Snapshot a server instance.""" context = req.environ['nova.context'] context.can(server_policies.SERVERS % 'create_image') entity = body["createImage"] image_name = common.normalize_name(entity["name"]) metadata = entity.get('metadata', {}) common.check_img_metadata_properties_quota(context, metadata) instance = self._get_server(context, req, id) bdms = objects.BlockDeviceMappingList.get_by_instance_uuid( context, instance.uuid) try: if compute_utils.is_volume_backed_instance(context, instance, bdms): context.can(server_policies.SERVERS % 'create_image:allow_volume_backed') image = self.compute_api.snapshot_volume_backed( context, instance, image_name, extra_properties= metadata) else: image = self.compute_api.snapshot(context, instance, image_name, extra_properties=metadata) except exception.InstanceUnknownCell as e: raise exc.HTTPNotFound(explanation=e.format_message()) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state(state_error, 'createImage', id) except exception.Invalid as err: raise exc.HTTPBadRequest(explanation=err.format_message()) # build location of newly-created image entity image_id = str(image['id']) image_ref = glance.generate_image_url(image_id) resp = webob.Response(status_int=202) resp.headers['Location'] = image_ref return resp
def _instance_to_allocations_dict(instance): """Given an `objects.Instance` object, return a dict, keyed by resource class of the amount used by the instance. :param instance: `objects.Instance` object to translate """ # NOTE(danms): Boot-from-volume instances consume no local disk is_bfv = compute_utils.is_volume_backed_instance(instance._context, instance) # TODO(johngarbutt) we have to round up swap MB to the next GB. # It would be better to claim disk in MB, but that is hard now. swap_in_gb = convert_mb_to_ceil_gb(instance.flavor.swap) disk = ((0 if is_bfv else instance.flavor.root_gb) + swap_in_gb + instance.flavor.ephemeral_gb) alloc_dict = { MEMORY_MB: instance.flavor.memory_mb, VCPU: instance.flavor.vcpus, DISK_GB: disk, } # Pull out any resource overrides, which are in the format # "resources:FOO" and generate a dict of FOO=value candidates # for overriding the resources in the allocation. overrides = { k.split(':', 1)[1]: v for k, v in instance.flavor.extra_specs.items() if k.startswith('resources:') } # Any resource overrides which are properly namespaced as custom, # or are standard resource class values override the alloc_dict # already constructed from the base flavor values above. Since # extra_specs are string values and resource counts are always # integers, we convert them here too for any that we find. overrides = { k: int(v) for k, v in overrides.items() if (k.startswith(objects.ResourceClass.CUSTOM_NAMESPACE) or k in fields.ResourceClass.STANDARD) } alloc_dict.update(overrides) # Remove any zero allocations. return {key: val for key, val in alloc_dict.items() if val}
def test_is_volume_backed_instance_bdm_volume_with_image(self): ctxt = self.context instance = create_instance(ctxt, params={"root_device_name": "vda", "image_ref": FAKE_IMAGE_REF}) bdms = block_device_obj.block_device_make_list( ctxt, [ fake_block_device.FakeDbBlockDeviceDict( { "source_type": "volume", "device_name": "/dev/vda", "volume_id": uuids.volume_id, "boot_index": 0, "destination_type": "volume", } ) ], ) self.assertTrue(compute_utils.is_volume_backed_instance(ctxt, instance, bdms))
def test_is_volume_backed_instance_bdm_snapshot(self): ctxt = self.context instance = create_instance(ctxt, params={"root_device_name": "vda"}) bdms = block_device_obj.block_device_make_list( ctxt, [ fake_block_device.FakeDbBlockDeviceDict( { "source_type": "volume", "device_name": "/dev/vda", "snapshot_id": "de8836ac-d75e-11e2-8271-5254009297d6", "instance_uuid": "f8000000-0000-0000-0000-000000000000", "destination_type": "volume", "boot_index": 0, "volume_id": None, } ) ], ) self.assertTrue(compute_utils.is_volume_backed_instance(ctxt, instance, bdms))
def _instance_to_allocations_dict(instance): """Given an `objects.Instance` object, return a dict, keyed by resource class of the amount used by the instance. :param instance: `objects.Instance` object to translate """ # NOTE(danms): Boot-from-volume instances consume no local disk is_bfv = compute_utils.is_volume_backed_instance(instance._context, instance) # TODO(johngarbutt) we have to round up swap MB to the next GB. # It would be better to claim disk in MB, but that is hard now. swap_in_gb = _convert_mb_to_ceil_gb(instance.flavor.swap) disk = ((0 if is_bfv else instance.flavor.root_gb) + swap_in_gb + instance.flavor.ephemeral_gb) alloc_dict = { MEMORY_MB: instance.flavor.memory_mb, VCPU: instance.flavor.vcpus, DISK_GB: disk, } # Remove any zero allocations. return {key: val for key, val in alloc_dict.items() if val}
def resources_from_flavor(instance, flavor): """Convert a flavor into a set of resources for placement, taking into account boot-from-volume instances. This takes an instance and a flavor and returns a dict of resource_class:amount based on the attributes of the flavor, accounting for any overrides that are made in extra_specs. """ is_bfv = compute_utils.is_volume_backed_instance(instance._context, instance) # create a fake RequestSpec as a wrapper to the caller req_spec = objects.RequestSpec(flavor=flavor, is_bfv=is_bfv) # TODO(efried): This method is currently only used from places that # assume the compute node is the only resource provider. So for now, we # just merge together all the resources specified in the flavor and pass # them along. This will need to be adjusted when nested and/or shared RPs # are in play. res_req = ResourceRequest(req_spec) return res_req.merged_resources()
def _instance_to_allocations_dict(instance): """Given an `objects.Instance` object, return a dict, keyed by resource class of the amount used by the instance. :param instance: `objects.Instance` object to translate """ # NOTE(danms): Boot-from-volume instances consume no local disk is_bfv = compute_utils.is_volume_backed_instance(instance._context, instance) # TODO(johngarbutt) we have to round up swap MB to the next GB. # It would be better to claim disk in MB, but that is hard now. swap_in_gb = _convert_mb_to_ceil_gb(instance.flavor.swap) disk = ((0 if is_bfv else instance.flavor.root_gb) + swap_in_gb + instance.flavor.ephemeral_gb) alloc_dict = { MEMORY_MB: instance.flavor.memory_mb, VCPU: instance.flavor.vcpus, DISK_GB: disk, } # Remove any zero allocations. return {key: val for key, val in alloc_dict.items() if val}
def _instance_to_allocations_dict(instance): """Given an `objects.Instance` object, return a dict, keyed by resource class of the amount used by the instance. :param instance: `objects.Instance` object to translate """ # NOTE(danms): Boot-from-volume instances consume no local disk is_bfv = compute_utils.is_volume_backed_instance(instance._context, instance) # TODO(johngarbutt) we have to round up swap MB to the next GB. # It would be better to claim disk in MB, but that is hard now. swap_in_gb = convert_mb_to_ceil_gb(instance.flavor.swap) disk = ((0 if is_bfv else instance.flavor.root_gb) + swap_in_gb + instance.flavor.ephemeral_gb) alloc_dict = { MEMORY_MB: instance.flavor.memory_mb, VCPU: instance.flavor.vcpus, DISK_GB: disk, } # Pull out any resource overrides, which are in the format # "resources:FOO" and generate a dict of FOO=value candidates # for overriding the resources in the allocation. overrides = {k.split(':', 1)[1]: v for k, v in instance.flavor.extra_specs.items() if k.startswith('resources:')} # Any resource overrides which are properly namespaced as custom, # or are standard resource class values override the alloc_dict # already constructed from the base flavor values above. Since # extra_specs are string values and resource counts are always # integers, we convert them here too for any that we find. overrides = {k: int(v) for k, v in overrides.items() if (k.startswith(objects.ResourceClass.CUSTOM_NAMESPACE) or k in fields.ResourceClass.STANDARD)} alloc_dict.update(overrides) # Remove any zero allocations. return {key: val for key, val in alloc_dict.items() if val}
def resources_from_flavor(instance, flavor): """Convert a flavor into a set of resources for placement, taking into account boot-from-volume instances. This takes an instance and a flavor and returns a dict of resource_class:amount based on the attributes of the flavor, accounting for any overrides that are made in extra_specs. """ is_bfv = compute_utils.is_volume_backed_instance(instance._context, instance) swap_in_gb = compute_utils.convert_mb_to_ceil_gb(flavor.swap) disk = ((0 if is_bfv else flavor.root_gb) + swap_in_gb + flavor.ephemeral_gb) resources = { fields.ResourceClass.VCPU: flavor.vcpus, fields.ResourceClass.MEMORY_MB: flavor.memory_mb, fields.ResourceClass.DISK_GB: disk, } if "extra_specs" in flavor: _process_extra_specs(flavor.extra_specs, resources) return resources
def resources_from_flavor(instance, flavor): """Convert a flavor into a set of resources for placement, taking into account boot-from-volume instances. This takes an instance and a flavor and returns a dict of resource_class:amount based on the attributes of the flavor, accounting for any overrides that are made in extra_specs. """ is_bfv = compute_utils.is_volume_backed_instance(instance._context, instance) swap_in_gb = compute_utils.convert_mb_to_ceil_gb(flavor.swap) disk = ((0 if is_bfv else flavor.root_gb) + swap_in_gb + flavor.ephemeral_gb) resources = { fields.ResourceClass.VCPU: flavor.vcpus, fields.ResourceClass.MEMORY_MB: flavor.memory_mb, fields.ResourceClass.DISK_GB: disk, } if "extra_specs" in flavor: _process_extra_specs(flavor.extra_specs, resources) return resources
def test_is_volume_backed_instance_no_bdm_no_image(self): ctxt = self.context instance = create_instance(ctxt, params={'image_ref': ''}) self.assertTrue( compute_utils.is_volume_backed_instance(ctxt, instance, None))
def test_is_volume_backed_instance_no_bdm_no_image(self): ctxt = self.context instance = create_instance(ctxt, params={'image_ref': ''}) self.assertTrue( compute_utils.is_volume_backed_instance(ctxt, instance, None))