Esempio n. 1
0
    def CreateVolume(self, request, context):
        request_uuid = str(uuid.uuid4())[:8]
        Utils.validate_param_exists(request, 'name')
        request_name = request.name
        nvmesh_vol_name = Utils.volume_id_to_nvmesh_name(request_name)
        log = self.logger.getChild("CreateVolume:%s(request:%s)" %
                                   (request_name, request_uuid))

        volume_cache = self.volume_to_zone_mapping.get_or_create_new(
            nvmesh_vol_name)

        if volume_cache.lock.locked():
            log.debug(
                "volume already has a request in a progress, waiting for lock to be released"
            )

        with volume_cache.lock:
            log.debug("processing request")
            if volume_cache.csi_volume:
                if volume_cache.csi_volume.capacity_bytes != self._parse_required_capacity(
                        request.capacity_range):
                    raise DriverError(
                        StatusCode.FAILED_PRECONDITION,
                        'Volume already exists with different capacity')

                log.info('Returning volume from cache')
                return CreateVolumeResponse(volume=volume_cache.csi_volume)

            csiVolume = self.do_create_volume(log, nvmesh_vol_name, request)
            volume_cache.csi_volume = csiVolume
            return CreateVolumeResponse(volume=csiVolume)
Esempio n. 2
0
    def DeleteVolume(self, request, context):
        Utils.validate_param_exists(request, 'volume_id')

        volume_id = request.volume_id
        log = self.logger.getChild("DeleteVolume-%s" % volume_id)
        log.debug('delete called')
        zone, nvmesh_vol_name = Utils.zone_and_vol_name_from_co_id(volume_id)
        #secrets = request.secrets

        volume_api = VolumeAPIPool.get_volume_api_for_zone(zone, log)

        err, out = volume_api.delete([NVMeshVolume(_id=nvmesh_vol_name)])
        if err:
            log.error(err)
            raise DriverError(StatusCode.INTERNAL, err)

        log.debug(out)

        if not out[0]['success']:
            err = out[0]['error']

            if err == "Couldn't find the specified volume" or err.startswith(
                    "Failed to find marked volume"):
                # Idempotency - Trying to remove a Volume that doesn't exists, perhaps already deleted
                # should return success
                log.debug("Volume already deleted")
                pass
            else:
                raise DriverError(StatusCode.FAILED_PRECONDITION, err)
        else:
            log.debug("Volume deleted successfully from zone %s" % zone)

        self.volume_to_zone_mapping.remove(nvmesh_vol_name)
        return DeleteVolumeResponse()
Esempio n. 3
0
    def DeleteVolume(self, request, context):
        Utils.validate_param_exists(request, 'volume_id')

        volume_id = request.volume_id
        nvmesh_vol_name = volume_id
        #secrets = request.secrets

        err, out = VolumeAPI().delete([NVMeshVolume(_id=nvmesh_vol_name)])
        if err:
            self.logger.error(err)
            raise DriverError(StatusCode.INTERNAL, err)

        self.logger.debug(out)

        if not out[0]['success']:
            err = out[0]['error']

            if err == "Couldn't find the specified volume":
                # Idempotency - Trying to remove a Volume that doesn't exists, perhaps already deleted
                # should return success
                pass
            else:
                raise DriverError(StatusCode.FAILED_PRECONDITION, err)

        return DeleteVolumeResponse()
Esempio n. 4
0
    def CreateVolume(self, request, context):
        Utils.validate_param_exists(request, 'name')
        name = request.name
        capacity = self._parse_required_capacity(request.capacity_range)
        parameters = request.parameters

        #UNUSED - secrets = request.secrets
        #UNUSED - volume_content_source = request.volume_content_source
        #UNUSED - accessibility_requirements = request.accessibility_requirements

        reqJson = MessageToJson(request)
        self.logger.debug('create volume request: {}'.format(reqJson))
        reqDict = MessageToDict(request)
        capabilities = reqDict['volumeCapabilities']

        is_file_system = False
        is_block_device = False

        csi_metadata = {'csi_name': name, 'capabilities': capabilities}

        for capability in capabilities:
            if 'mount' in capability:
                is_file_system = True
                csi_metadata['fsType'] = capability['mount']['fsType']
            else:
                csi_metadata['block'] = True

            access_mode = capability['accessMode']['mode']
            if Consts.AccessMode.fromCsiString(
                    access_mode) not in Consts.AccessMode.allowed_access_modes(
                    ):
                self.logger.warning(
                    'Requested mode {} is not enforced by NVMesh Storage backend'
                    .format(access_mode))

        if is_file_system and is_block_device:
            raise DriverError(
                StatusCode.INVALID_ARGUMENT,
                'Error: Contradicting capabilities both Block Volume and FileSystem Volume were requested for volume {}. request: {}'
                .format(name, reqJson))

        nvmesh_vol_name = Utils.volume_id_to_nvmesh_name(name)
        nvmesh_params = {}

        self.logger.debug('create volume parameters: {}'.format(parameters))

        if 'vpg' in parameters:
            self.logger.debug('Creating Volume from VPG {}'.format(
                parameters['vpg']))
            nvmesh_params['VPG'] = parameters['vpg']

            # This is a workaround since the nvmesh create volume api expects a 'RAIDLevel'
            # but if 'VPG' is present 'RAIDLevel' field will be ignored
            # and the RAIDLevel will be fetched from the VPG.
            nvmesh_params['RAIDLevel'] = RAIDLevels.CONCATENATED
        else:
            self.logger.debug('Creating without VPG')
            for param in parameters:
                nvmesh_params[param] = parameters[param]

            self._handle_non_vpg_params(nvmesh_params)

        self.logger.debug('nvmesh_params = {}'.format(nvmesh_params))

        volume = NVMeshVolume(name=nvmesh_vol_name,
                              capacity=capacity,
                              csi_metadata=csi_metadata,
                              **nvmesh_params)

        self.logger.debug('Creating volume: {}'.format(str(volume)))
        err, data = VolumeAPI().save([volume])

        if err:
            raise DriverError(
                StatusCode.RESOURCE_EXHAUSTED,
                'Error: {} Details: {} Volume Requested: {}'.format(
                    err, data, str(volume)))
        elif not type(data) == list or not data[0]['success']:
            if 'Name already Exists' in data[0]['error']:
                existing_capacity = self._get_nvmesh_volume_capacity(
                    nvmesh_vol_name)
                if capacity == existing_capacity:
                    # Idempotency - same Name same Capacity - return success
                    pass
                else:
                    raise DriverError(
                        StatusCode.ALREADY_EXISTS,
                        'Error: {} Details: {}'.format(err, data))
            else:
                raise DriverError(StatusCode.RESOURCE_EXHAUSTED,
                                  'Error: {} Details: {}'.format(err, data))

        err, details = self._wait_for_volume_status(
            volume._id, NVMeshConsts.VolumeStatuses.ONLINE)

        if err:
            if err == 'Timed out Waiting for Volume to be Online':
                raise DriverError(StatusCode.FAILED_PRECONDITION,
                                  'Error: {} Details: {}'.format(err, details))
            else:
                raise DriverError(StatusCode.INVALID_ARGUMENT, err)
        else:
            self.logger.debug(details)

        # we return the nvmesh_vol_name that we created to the CO
        # all subsequent requests for this volume will have volume_id of the nvmesh volume name
        csiVolume = Volume(volume_id=nvmesh_vol_name, capacity_bytes=capacity)
        return CreateVolumeResponse(volume=csiVolume)