def attach(server_id, volume_id, credentials, atomic_context=None): """Attach a volume to a server.""" vm = util.get_vm(server_id, credentials, for_update=True, non_deleted=True) volume = util.get_volume(credentials, volume_id, for_update=True, non_deleted=True, exception=faults.BadRequest) server_attachments.attach_volume(vm, volume, atomic_context) return volume
def attach_volume(server_id, volume_id, credentials, atomic_context=None): user_id = credentials.userid vm = util.get_vm(server_id, credentials, for_update=True, non_deleted=True) volume = get_volume(credentials, volume_id, for_update=True, non_deleted=True, exception=faults.BadRequest) server_attachments.attach_volume(vm, volume, atomic_context) log.info("User %s attached volume %s to VM %s", user_id, volume.id, vm.id) return volume
def create(user_id, size, server=None, name=None, description=None, source_volume_id=None, source_snapshot_id=None, source_image_id=None, volume_type_id=None, metadata=None, project_id=None, shared_to_project=False): """Create a new volume and optionally attach it to a server. This function serves as the main entry-point for volume creation. It gets the necessary data either from the API or from an snf-manage command and then feeds that data to the lower-level functions that handle the actual creation of the volume and the server attachments. """ volume_type = None # If given a server id, assert that it exists and that it belongs to the # user. if server: volume_type = server.flavor.volume_type # If the server's volume type conflicts with the provided volume type, # raise an exception. if volume_type_id and \ volume_type.id != util.normalize_volume_type_id(volume_type_id): raise faults.BadRequest("Cannot create a volume with type '%s' to" " a server with volume type '%s'." % (volume_type_id, volume_type.id)) # If the user has not provided a valid volume type, raise an exception. if volume_type is None: volume_type = util.get_volume_type(volume_type_id, include_deleted=False, exception=faults.BadRequest) # We cannot create a non-detachable volume without a server. if server is None: util.assert_detachable_volume_type(volume_type) volume = create_common(user_id, size, name=name, description=description, source_image_id=source_image_id, source_snapshot_id=source_snapshot_id, source_volume_id=source_volume_id, volume_type=volume_type, metadata={}, project_id=project_id, shared_to_project=shared_to_project) if server is not None: server_attachments.attach_volume(server, volume) else: quotas.issue_and_accept_commission(volume, action="BUILD") # If the volume has been created in the DB, consider it available. volume.status = "AVAILABLE" volume.save() return volume
def delete_detached_volume(volume, atomic_context): """Delete a detached volume. There is actually no way (that involves Ganeti) to delete a detached volume. Instead, we need to attach it to a helper VM and then delete it. The purpose of this function is to do the first step; find an available helper VM and attach the volume to it. In order to differentiate this action from a common attach action, we set the volume status as DELETING. Then, the dispatcher will handle the deletion of the volume. """ # Fetch a random helper VM from an online and undrained Ganeti backend server = get_random_helper_vm(for_update=True) if server is None: raise faults.ItemNotFound("Cannot find an available helper server") log.debug("Using helper server %s for the removal of volume %s", server, volume) # Attach the volume to the helper server, in order to delete it # internally later. server_attachments.attach_volume(server, volume, atomic_context) volume.status = "DELETING" volume.save() return volume
def attach_volume(request, server_id): req = utils.get_json_body(request) log.debug("attach_volume server_id %s request", server_id, req) user_id = request.user_uniq vm = util.get_vm(server_id, user_id, for_update=True, non_deleted=True) attachment_dict = api.utils.get_attribute(req, "volumeAttachment", required=True) # Get volume volume_id = api.utils.get_attribute(attachment_dict, "volumeId") volume = get_volume(user_id, volume_id, for_update=True, non_deleted=True, exception=faults.BadRequest) vm = server_attachments.attach_volume(vm, volume) attachment = volume_to_attachment(volume) data = json.dumps({'volumeAttachment': attachment}) return HttpResponse(data, status=202)
def attach_volume(request, server_id): req = utils.get_json_body(request) user_id = request.user_uniq log.debug("User %s, VM: %s, Action: attach_volume, Request: %s", request.user_uniq, server_id, req) vm = util.get_vm(server_id, user_id, request.user_projects, for_update=True, non_deleted=True) attachment_dict = api.utils.get_attribute(req, "volumeAttachment", required=True) # Get volume volume_id = api.utils.get_attribute(attachment_dict, "volumeId") volume = get_volume(user_id, request.user_projects, volume_id, for_update=True, non_deleted=True, exception=faults.BadRequest) vm = server_attachments.attach_volume(vm, volume) attachment = volume_to_attachment(volume) data = json.dumps({'volumeAttachment': attachment}) log.info("User %s attached volume %s to VM %s", user_id, volume.id, vm.id) return HttpResponse(data, status=202)
def create(user_id, size, server_id, name=None, description=None, source_volume_id=None, source_snapshot_id=None, source_image_id=None, volume_type_id=None, metadata=None, project=None): # Currently we cannot create volumes without being attached to a server if server_id is None: raise faults.BadRequest("Volume must be attached to server") server = util.get_server(user_id, server_id, for_update=True, non_deleted=True, exception=faults.BadRequest) server_vtype = server.flavor.volume_type if volume_type_id is not None: volume_type = util.get_volume_type(volume_type_id, include_deleted=False, exception=faults.BadRequest) if volume_type != server_vtype: raise faults.BadRequest("Cannot create a volume with type '%s' to" " a server with volume type '%s'." % (volume_type.id, server_vtype.id)) else: volume_type = server_vtype # Assert that not more than one source are used sources = filter(lambda x: x is not None, [source_volume_id, source_snapshot_id, source_image_id]) if len(sources) > 1: raise faults.BadRequest("Volume can not have more than one source!") if source_volume_id is not None: source_type = "volume" source_uuid = source_volume_id elif source_snapshot_id is not None: source_type = "snapshot" source_uuid = source_snapshot_id elif source_image_id is not None: source_type = "image" source_uuid = source_image_id else: source_type = "blank" source_uuid = None if project is None: project = user_id if metadata is not None and \ len(metadata) > settings.CYCLADES_VOLUME_MAX_METADATA: raise faults.BadRequest("Volumes cannot have more than %s metadata " "items" % settings.CYCLADES_VOLUME_MAX_METADATA) volume = _create_volume(server, user_id, project, size, source_type, source_uuid, volume_type=volume_type, name=name, description=description, index=None) if metadata is not None: for meta_key, meta_val in metadata.items(): utils.check_name_length(meta_key, VolumeMetadata.KEY_LENGTH, "Metadata key is too long") utils.check_name_length(meta_val, VolumeMetadata.VALUE_LENGTH, "Metadata key is too long") volume.metadata.create(key=meta_key, value=meta_val) server_attachments.attach_volume(server, volume) return volume
def attach(server, volume_id): """Attach a volume to a server.""" volume = get_volume(volume_id) server_attachments.attach_volume(server, volume) return volume