def test_as_int(self): test_obj_int = '2' test_obj_float = '2.2' for obj in [test_obj_int, test_obj_float]: self.assertEqual(2, utils.as_int(obj)) obj = 'not_a_number' self.assertEqual(obj, utils.as_int(obj)) self.assertRaises(TypeError, utils.as_int, obj, quiet=False)
def _check_image_metadata(self, context, image_id, size): """Checks image existence and validates that the image metadata.""" # Check image existence if image_id is None: return # NOTE(harlowja): this should raise an error if the image does not # exist, this is expected as it signals that the image_id is missing. image_meta = self.image_service.show(context, image_id) # check whether image is active if image_meta['status'] != 'active': msg = _('Image %(image_id)s is not active.')\ % {'image_id': image_id} raise exception.InvalidInput(reason=msg) # Check image size is not larger than volume size. image_size = utils.as_int(image_meta['size'], quiet=False) image_size_in_gb = (image_size + GB - 1) // GB if image_size_in_gb > size: msg = _('Size of specified image %(image_size)sGB' ' is larger than volume size %(volume_size)sGB.') msg = msg % {'image_size': image_size_in_gb, 'volume_size': size} raise exception.InvalidInput(reason=msg) # Check image min_disk requirement is met for the particular volume min_disk = image_meta.get('min_disk', 0) if size < min_disk: msg = _('Volume size %(volume_size)sGB cannot be smaller' ' than the image minDisk size %(min_disk)sGB.') msg = msg % {'volume_size': size, 'min_disk': min_disk} raise exception.InvalidInput(reason=msg)
def _populate_request_spec(self, context, volume_id, snapshot_id, image_id): # Create the full request spec using the volume_id. # # NOTE(harlowja): this will fetch the volume from the database, if # the volume has been deleted before we got here then this should fail. # # In the future we might want to have a lock on the volume_id so that # the volume can not be deleted while its still being created? if not volume_id: msg = _("No volume_id provided to populate a request_spec from") raise exception.InvalidInput(reason=msg) volume_ref = self.db_api.volume_get(context, volume_id) volume_type_id = volume_ref.get('volume_type_id') vol_type = self.db_api.volume_type_get(context, volume_type_id) return { 'volume_id': volume_id, 'snapshot_id': snapshot_id, 'image_id': image_id, 'volume_properties': { 'size': utils.as_int(volume_ref.get('size'), quiet=False), 'availability_zone': volume_ref.get('availability_zone'), 'volume_type_id': volume_type_id, }, 'volume_type': list(dict(vol_type).iteritems()), }
def _check_image_metadata(self, context, image_id, size): """Checks image existence and validates that the image metadata.""" # Check image existence if image_id is None: return # NOTE(harlowja): this should raise an error if the image does not # exist, this is expected as it signals that the image_id is missing. image_meta = self.image_service.show(context, image_id) # Check image size is not larger than volume size. image_size = utils.as_int(image_meta["size"], quiet=False) image_size_in_gb = (image_size + GB - 1) / GB if image_size_in_gb > size: msg = _("Size of specified image %(image_size)sGB" " is larger than volume size %(volume_size)sGB.") msg = msg % {"image_size": image_size_in_gb, "volume_size": size} raise exception.InvalidInput(reason=msg) # Check image min_disk requirement is met for the particular volume min_disk = image_meta.get("min_disk", 0) if size < min_disk: msg = _("Volume size %(volume_size)sGB cannot be smaller" " than the image minDisk size %(min_disk)sGB.") msg = msg % {"volume_size": size, "min_disk": min_disk} raise exception.InvalidInput(reason=msg)
def _extract_size(size, source_volume, snapshot): """Extracts and validates the volume size. This function will validate or when not provided fill in the provided size variable from the source_volume or snapshot and then does validation on the size that is found and returns said validated size. """ def validate_snap_size(size): if snapshot and size < snapshot.volume_size: msg = _( "Volume size '%(size)s'GB cannot be smaller than" " the snapshot size %(snap_size)sGB. " "They must be >= original snapshot size." ) msg = msg % {"size": size, "snap_size": snapshot.volume_size} raise exception.InvalidInput(reason=msg) def validate_source_size(size): if source_volume and size < source_volume["size"]: msg = _( "Volume size '%(size)s'GB cannot be smaller than " "original volume size %(source_size)sGB. " "They must be >= original volume size." ) msg = msg % {"size": size, "source_size": source_volume["size"]} raise exception.InvalidInput(reason=msg) def validate_int(size): if not isinstance(size, int) or size <= 0: msg = _("Volume size '%(size)s' must be an integer and" " greater than 0") % {"size": size} raise exception.InvalidInput(reason=msg) # Figure out which validation functions we should be applying # on the size value that we extract. validator_functors = [validate_int] if source_volume: validator_functors.append(validate_source_size) elif snapshot: validator_functors.append(validate_snap_size) # If the size is not provided then try to provide it. if not size and source_volume: size = source_volume["size"] elif not size and snapshot: size = snapshot.volume_size size = utils.as_int(size) LOG.debug( "Validating volume '%(size)s' using %(functors)s" % {"size": size, "functors": ", ".join([common.make_pretty_name(func) for func in validator_functors])} ) for func in validator_functors: func(size) return size
def _populate_request_spec(self, volume, snapshot_id, image_id): # Create the full request spec using the volume object. # # NOTE(dulek): At this point, a volume can be deleted before it gets # scheduled. If a delete API call is made, the volume gets instantly # delete and scheduling will fail when it tries to update the DB entry # (with the host) in ScheduleCreateVolumeTask below. volume_type_id = volume.volume_type_id vol_type = volume.volume_type return { 'volume_id': volume.id, 'snapshot_id': snapshot_id, 'image_id': image_id, 'volume_properties': { 'size': utils.as_int(volume.size, quiet=False), 'availability_zone': volume.availability_zone, 'volume_type_id': volume_type_id, }, 'volume_type': list(dict(vol_type).items()), }
def _populate_request_spec(self, context, volume_id, snapshot_id, image_id): # Create the full request spec using the volume_id. # # NOTE(harlowja): this will fetch the volume from the database, if # the volume has been deleted before we got here then this should fail. # # In the future we might want to have a lock on the volume_id so that # the volume can not be deleted while its still being created? if not volume_id: raise exception.InvalidInput(reason=_("No volume_id provided to populate a " "request_spec from")) volume_ref = objects.Volume.get_by_id(context, volume_id) volume_type_id = volume_ref.volume_type_id vol_type = volume_ref.volume_type return { "volume_id": volume_id, "snapshot_id": snapshot_id, "image_id": image_id, "volume_properties": { "size": utils.as_int(volume_ref.size, quiet=False), "availability_zone": volume_ref.availability_zone, "volume_type_id": volume_type_id, }, "volume_type": list(dict(vol_type).items()), }
def check_image_metadata(image_meta, vol_size): """Validates the image metadata.""" # Check whether image is active if image_meta['status'] != 'active': msg = _('Image %(image_id)s is not active.' ) % {'image_id': image_meta['id']} raise exception.InvalidInput(reason=msg) # Check image size is not larger than volume size. image_size = utils.as_int(image_meta['size'], quiet=False) image_size_in_gb = (image_size + GB - 1) // GB if image_size_in_gb > vol_size: msg = _('Size of specified image %(image_size)sGB' ' is larger than volume size %(volume_size)sGB.') msg = msg % {'image_size': image_size_in_gb, 'volume_size': vol_size} raise exception.InvalidInput(reason=msg) # Check image min_disk requirement is met for the particular volume min_disk = image_meta.get('min_disk', 0) if vol_size < min_disk: msg = _('Volume size %(volume_size)sGB cannot be smaller' ' than the image minDisk size %(min_disk)sGB.') msg = msg % {'volume_size': vol_size, 'min_disk': min_disk} raise exception.InvalidInput(reason=msg)
def execute(self, context, volume_ref, request_spec): get_remote_image_service = glance.get_remote_image_service volume_name = volume_ref["name"] volume_size = utils.as_int(volume_ref["size"], quiet=False) # Create a dictionary that will represent the volume to be so that # later tasks can easily switch between the different types and create # the volume according to the volume types specifications (which are # represented in this dictionary). specs = { "status": volume_ref["status"], "type": "raw", # This will have the type of the volume to be # created, which should be one of [raw, snap, # source_vol, image] "volume_id": volume_ref["id"], "volume_name": volume_name, "volume_size": volume_size, } if volume_ref.get("snapshot_id"): # We are making a snapshot based volume instead of a raw volume. specs.update({"type": "snap", "snapshot_id": volume_ref["snapshot_id"]}) elif volume_ref.get("source_volid"): # We are making a source based volume instead of a raw volume. # # NOTE(harlowja): This will likely fail if the source volume # disappeared by the time this call occurred. source_volid = volume_ref.get("source_volid") source_volume_ref = objects.Volume.get_by_id(context, source_volid) specs.update( { "source_volid": source_volid, # This is captured incase we have to revert and we want to set # back the source volume status to its original status. This # may or may not be sketchy to do?? "source_volstatus": source_volume_ref["status"], "type": "source_vol", } ) elif request_spec.get("source_replicaid"): # We are making a clone based on the replica. # # NOTE(harlowja): This will likely fail if the replica # disappeared by the time this call occurred. source_volid = request_spec["source_replicaid"] source_volume_ref = objects.Volume.get_by_id(context, source_volid) specs.update( { "source_replicaid": source_volid, "source_replicastatus": source_volume_ref["status"], "type": "source_replica", } ) elif request_spec.get("image_id"): # We are making an image based volume instead of a raw volume. image_href = request_spec["image_id"] image_service, image_id = get_remote_image_service(context, image_href) specs.update( { "type": "image", "image_id": image_id, "image_location": image_service.get_location(context, image_id), "image_meta": image_service.show(context, image_id), # Instead of refetching the image service later just save it. # # NOTE(harlowja): if we have to later recover this tasks output # on another 'node' that this object won't be able to be # serialized, so we will have to recreate this object on # demand in the future. "image_service": image_service, } ) return specs
def execute(self, context, volume_ref, **kwargs): get_remote_image_service = glance.get_remote_image_service volume_name = volume_ref['name'] volume_size = utils.as_int(volume_ref['size'], quiet=False) # Create a dictionary that will represent the volume to be so that # later tasks can easily switch between the different types and create # the volume according to the volume types specifications (which are # represented in this dictionary). specs = { 'status': volume_ref['status'], 'type': 'raw', # This will have the type of the volume to be # created, which should be one of [raw, snap, # source_vol, image] 'volume_id': volume_ref['id'], 'volume_name': volume_name, 'volume_size': volume_size, } if kwargs.get('snapshot_id'): # We are making a snapshot based volume instead of a raw volume. specs.update({ 'type': 'snap', 'snapshot_id': kwargs['snapshot_id'], }) elif kwargs.get('source_volid'): # We are making a source based volume instead of a raw volume. # # NOTE(harlowja): This will likely fail if the source volume # disappeared by the time this call occurred. source_volid = kwargs['source_volid'] source_volume_ref = self.db.volume_get(context, source_volid) specs.update({ 'source_volid': source_volid, # This is captured incase we have to revert and we want to set # back the source volume status to its original status. This # may or may not be sketchy to do?? 'source_volstatus': source_volume_ref['status'], 'type': 'source_vol', }) elif kwargs.get('source_replicaid'): # We are making a clone based on the replica. # # NOTE(harlowja): This will likely fail if the replica # disappeared by the time this call occurred. source_volid = kwargs['source_replicaid'] source_volume_ref = self.db.volume_get(context, source_volid) specs.update({ 'source_replicaid': source_volid, 'source_replicastatus': source_volume_ref['status'], 'type': 'source_replica', }) elif kwargs.get('image_id'): # We are making an image based volume instead of a raw volume. image_href = kwargs['image_id'] image_service, image_id = get_remote_image_service(context, image_href) specs.update({ 'type': 'image', 'image_id': image_id, 'image_location': image_service.get_location(context, image_id), 'image_meta': image_service.show(context, image_id), # Instead of refetching the image service later just save it. # # NOTE(harlowja): if we have to later recover this tasks output # on another 'node' that this object won't be able to be # serialized, so we will have to recreate this object on # demand in the future. 'image_service': image_service, }) return specs
def execute(self, context, volume, request_spec): get_remote_image_service = glance.get_remote_image_service volume_name = volume.name volume_size = utils.as_int(volume.size, quiet=False) # Create a dictionary that will represent the volume to be so that # later tasks can easily switch between the different types and create # the volume according to the volume types specifications (which are # represented in this dictionary). specs = { 'status': volume.status, 'type': 'raw', # This will have the type of the volume to be # created, which should be one of [raw, snap, # source_vol, image, backup] 'volume_id': volume.id, 'volume_name': volume_name, 'volume_size': volume_size, } if volume.snapshot_id: # We are making a snapshot based volume instead of a raw volume. specs.update({ 'type': 'snap', 'snapshot_id': volume.snapshot_id, }) elif volume.source_volid: # We are making a source based volume instead of a raw volume. # # NOTE(harlowja): This will likely fail if the source volume # disappeared by the time this call occurred. source_volid = volume.source_volid source_volume_ref = objects.Volume.get_by_id(context, source_volid) specs.update({ 'source_volid': source_volid, # This is captured incase we have to revert and we want to set # back the source volume status to its original status. This # may or may not be sketchy to do?? 'source_volstatus': source_volume_ref.status, 'type': 'source_vol', }) elif request_spec.get('image_id'): # We are making an image based volume instead of a raw volume. image_href = request_spec['image_id'] image_service, image_id = get_remote_image_service(context, image_href) specs.update({ 'type': 'image', 'image_id': image_id, 'image_location': image_service.get_location(context, image_id), 'image_meta': image_service.show(context, image_id), # Instead of refetching the image service later just save it. # # NOTE(harlowja): if we have to later recover this tasks output # on another 'node' that this object won't be able to be # serialized, so we will have to recreate this object on # demand in the future. 'image_service': image_service, }) elif request_spec.get('backup_id'): # We are making a backup based volume instead of a raw volume. specs.update({ 'type': 'backup', 'backup_id': request_spec['backup_id'], # NOTE(luqitao): if the driver does not implement the method # `create_volume_from_backup`, cinder-backup will update the # volume's status, otherwise we need update it in the method # `CreateVolumeOnFinishTask`. 'need_update_volume': True, }) return specs
def _extract_size(size, source_volume, snapshot): """Extracts and validates the volume size. This function will validate or when not provided fill in the provided size variable from the source_volume or snapshot and then does validation on the size that is found and returns said validated size. """ def validate_snap_size(size): if snapshot and size < snapshot.volume_size: msg = _("Volume size '%(size)s'GB cannot be smaller than" " the snapshot size %(snap_size)sGB. " "They must be >= original snapshot size.") msg = msg % {'size': size, 'snap_size': snapshot.volume_size} raise exception.InvalidInput(reason=msg) def validate_source_size(size): if source_volume and size < source_volume['size']: msg = _("Volume size '%(size)s'GB cannot be smaller than " "original volume size %(source_size)sGB. " "They must be >= original volume size.") msg = msg % { 'size': size, 'source_size': source_volume['size'] } raise exception.InvalidInput(reason=msg) def validate_int(size): if not isinstance(size, int) or size <= 0: msg = _("Volume size '%(size)s' must be an integer and" " greater than 0") % { 'size': size } raise exception.InvalidInput(reason=msg) # Figure out which validation functions we should be applying # on the size value that we extract. validator_functors = [validate_int] if source_volume: validator_functors.append(validate_source_size) elif snapshot: validator_functors.append(validate_snap_size) # If the size is not provided then try to provide it. if not size and source_volume: size = source_volume['size'] elif not size and snapshot: size = snapshot.volume_size size = utils.as_int(size) LOG.debug( "Validating volume '%(size)s' using %(functors)s" % { 'size': size, 'functors': ", ".join([ common.make_pretty_name(func) for func in validator_functors ]) }) for func in validator_functors: func(size) return size