Example #1
0
async def copy(src_bundle, dest_bundle, request={}, start_time=None, **kwargs):
    start_time = start_time or time.time()

    src_path, src_provider = src_bundle.pop('path'), utils.make_provider(**src_bundle.pop('provider'))
    dest_path, dest_provider = dest_bundle.pop('path'), utils.make_provider(**dest_bundle.pop('provider'))

    logger.info('Starting copying {!r}, {!r} to {!r}, {!r}'
                .format(src_path, src_provider, dest_path, dest_provider))

    metadata, errors = None, []
    try:
        metadata, created = await src_provider.copy(dest_provider, src_path, dest_path, **kwargs)
    except Exception as e:
        logger.error('Copy failed with error {!r}'.format(e))
        errors = [e.__repr__()]
        raise  # Ensure sentry sees this
    else:
        logger.info('Copy succeeded')
        dest_path = WaterButlerPath.from_metadata(metadata)
    finally:
        source = LogPayload(src_bundle['nid'], src_provider, path=src_path)
        destination = LogPayload(
            dest_bundle['nid'], dest_provider, path=dest_path, metadata=metadata
        )

        await remote_logging.wait_for_log_futures(
            'copy', source=source, destination=destination, start_time=start_time,
            errors=errors, request=request, api_version='celery',
        )

    return metadata, created
Example #2
0
async def move(src_bundle, dest_bundle, start_time=None, **kwargs):
    start_time = start_time or time.time()

    src_path, src_provider = src_bundle.pop('path'), utils.make_provider(**src_bundle.pop('provider'))
    dest_path, dest_provider = dest_bundle.pop('path'), utils.make_provider(**dest_bundle.pop('provider'))

    logger.info('Starting moving {!r}, {!r} to {!r}, {!r}'.format(src_path, src_provider, dest_path, dest_provider))

    metadata, errors = None, []
    try:
        metadata, created = await src_provider.move(dest_provider, src_path, dest_path, **kwargs)
    except Exception as e:
        logger.error('Move failed with error {!r}'.format(e))
        errors = [e.__repr__()]
        raise  # Ensure sentry sees this
    else:
        logger.info('Move succeeded')
        dest_path = WaterButlerPath.from_metadata(metadata)
    finally:
        source = LogPayload(src_bundle['nid'], src_provider, path=src_path)
        destination = LogPayload(
            dest_bundle['nid'], dest_provider, path=dest_path, metadata=metadata
        )

        await utils.log_to_callback(
            'move',
            source=source,
            destination=destination,
            start_time=start_time,
            errors=errors
        )

    return metadata, created
Example #3
0
def copy(src_bundle,
         dest_bundle,
         callback_url,
         auth,
         start_time=None,
         **kwargs):
    start_time = start_time or time.time()
    src_path, src_provider = src_bundle.pop('path'), utils.make_provider(
        **src_bundle.pop('provider'))
    dest_path, dest_provider = dest_bundle.pop('path'), utils.make_provider(
        **dest_bundle.pop('provider'))

    data = {
        'errors': [],
        'action':
        'copy',
        'source':
        dict(
            src_bundle, **{
                'path': src_path.path,
                'name': src_path.name,
                'materialized': str(src_path),
                'provider': src_provider.NAME,
            }),
        'destination':
        dict(
            dest_bundle, **{
                'path': dest_path.path,
                'name': dest_path.name,
                'materialized': str(dest_path),
                'provider': dest_provider.NAME,
            }),
        'auth':
        auth['auth'],
    }

    logger.info('Starting copying {!r}, {!r} to {!r}, {!r}'.format(
        src_path, src_provider, dest_path, dest_provider))

    try:
        metadata, created = yield from src_provider.copy(
            dest_provider, src_path, dest_path, **kwargs)
    except Exception as e:
        logger.error('Copy failed with error {!r}'.format(e))
        data.update({'errors': [e.__repr__()]})
        raise  # Ensure sentry sees this
    else:
        logger.info('Copy succeeded')
        data.update({'destination': dict(src_bundle, **metadata.serialized())})
    finally:
        resp = yield from utils.send_signed_request(
            'PUT', callback_url,
            dict(
                data, **{
                    'time': time.time() + 60,
                    'email': time.time() - start_time > settings.WAIT_TIMEOUT
                }))
        logger.info('Callback returned {!r}'.format(resp))

    return metadata, created
Example #4
0
async def move(src_bundle, dest_bundle, callback_url, auth, start_time=None, **kwargs):
    start_time = start_time or time.time()
    src_path, src_provider = src_bundle.pop('path'), utils.make_provider(**src_bundle.pop('provider'))
    dest_path, dest_provider = dest_bundle.pop('path'), utils.make_provider(**dest_bundle.pop('provider'))

    data = {
        'errors': [],
        'action': 'move',
        'source': dict(src_bundle, **{
            'path': src_path.identifier_path if src_provider.NAME in IDENTIFIER_PATHS else '/' + src_path.raw_path,
            'name': src_path.name,
            'materialized': str(src_path),
            'provider': src_provider.NAME,
            'kind': src_path.kind,
        }),
        'destination': dict(dest_bundle, **{
            'path': dest_path.identifier_path if dest_provider.NAME in IDENTIFIER_PATHS else '/' + dest_path.raw_path,
            'name': dest_path.name,
            'materialized': str(dest_path),
            'provider': dest_provider.NAME,
            'kind': dest_path.kind,
        }),
        'auth': auth['auth'],
    }

    logger.info('Starting moving {!r}, {!r} to {!r}, {!r}'.format(src_path, src_provider, dest_path, dest_provider))

    try:
        metadata, created = await src_provider.move(dest_provider, src_path, dest_path, **kwargs)
    except Exception as e:
        logger.error('Move failed with error {!r}'.format(e))
        data.update({'errors': [e.__repr__()]})
        raise  # Ensure sentry sees this
    else:
        logger.info('Move succeeded')
        data.update({'destination': dict(src_bundle, **metadata.serialized())})
    finally:
        resp = await utils.send_signed_request('PUT', callback_url, dict(data, **{
            'time': time.time() + 60,
            'email': time.time() - start_time > settings.WAIT_TIMEOUT
        }))
        logger.info('Callback returned {!r}'.format(resp))

        resp_data = await resp.read()
        if resp.status // 100 != 2:
            raise Exception(
                'Callback failed with {!r}, got {}'.format(resp, resp_data.decode('utf-8'))
            ) from sys.exc_info()[1]

        logger.info('Callback succeeded with {}'.format(resp_data.decode('utf-8')))

    return metadata, created
Example #5
0
async def copy(src_bundle, dest_bundle, callback_url, auth, start_time=None, **kwargs):
    start_time = start_time or time.time()
    src_path, src_provider = src_bundle.pop('path'), utils.make_provider(**src_bundle.pop('provider'))
    dest_path, dest_provider = dest_bundle.pop('path'), utils.make_provider(**dest_bundle.pop('provider'))

    data = {
        'errors': [],
        'action': 'copy',
        'source': dict(src_bundle, **{
            'path': src_path.identifier_path if src_provider.NAME in IDENTIFIER_PATHS else '/' + src_path.raw_path,
            'name': src_path.name,
            'materialized': str(src_path),
            'provider': src_provider.NAME,
            'kind': src_path.kind,
        }),
        'destination': dict(dest_bundle, **{
            'path': dest_path.identifier_path if dest_provider.NAME in IDENTIFIER_PATHS else '/' + dest_path.raw_path,
            'name': dest_path.name,
            'materialized': str(dest_path),
            'provider': dest_provider.NAME,
            'kind': dest_path.kind,
        }),
        'auth': auth['auth'],
    }

    logger.info('Starting copying {!r}, {!r} to {!r}, {!r}'.format(src_path, src_provider, dest_path, dest_provider))

    try:
        metadata, created = await src_provider.copy(dest_provider, src_path, dest_path, **kwargs)
    except Exception as e:
        logger.error('Copy failed with error {!r}'.format(e))
        data.update({'errors': [e.__repr__()]})
        raise  # Ensure sentry sees this
    else:
        logger.info('Copy succeeded')
        data.update({'destination': dict(src_bundle, **metadata.serialized())})
    finally:
        resp = await utils.send_signed_request('PUT', callback_url, dict(data, **{
            'time': time.time() + 60,
            'email': time.time() - start_time > settings.WAIT_TIMEOUT
        }))
        logger.info('Callback returned {!r}'.format(resp))

        resp_data = await resp.read()
        if resp.status // 100 != 2:
            raise Exception(
                'Callback failed with {!r}, got {}'.format(resp, resp_data.decode('utf-8'))
            ) from sys.exc_info()[1]

        logger.info('Callback succeeded with {}'.format(resp_data.decode('utf-8')))

    return metadata, created
Example #6
0
async def copy(src_bundle,
               dest_bundle,
               request=None,
               start_time=None,
               **kwargs):

    request = request or {}
    start_time = start_time or time.time()

    src_path = src_bundle.pop('path')
    src_provider = utils.make_provider(**src_bundle.pop('provider'),
                                       is_celery_task=True)

    dest_path = dest_bundle.pop('path')
    dest_provider = utils.make_provider(**dest_bundle.pop('provider'),
                                        is_celery_task=True)

    logger.info('Starting copying {!r}, {!r} to {!r}, {!r}'.format(
        src_path, src_provider, dest_path, dest_provider))

    metadata, errors = None, []
    try:
        metadata, created = await src_provider.copy(dest_provider, src_path,
                                                    dest_path, **kwargs)
    except Exception as e:
        logger.error('Copy failed with error {!r}'.format(e))
        errors = [e.__repr__()]
        raise  # Ensure sentry sees this
    else:
        logger.info('Copy succeeded')
        dest_path = WaterButlerPath.from_metadata(metadata)
    finally:
        source = LogPayload(src_bundle['nid'], src_provider, path=src_path)
        destination = LogPayload(dest_bundle['nid'],
                                 dest_provider,
                                 path=dest_path,
                                 metadata=metadata)

        await remote_logging.wait_for_log_futures(
            'copy',
            source=source,
            destination=destination,
            start_time=start_time,
            errors=errors,
            request=request,
            api_version='celery',
        )

    return metadata, created
Example #7
0
def _upload_parity(path, credentials, settings):
    _, name = os.path.split(path)
    provider_name = settings.get('provider')
    provider = make_provider(provider_name, {}, credentials, settings)
    with open(path, 'rb') as file_pointer:
        stream = streams.FileStreamReader(file_pointer)
        yield from provider.upload(stream, path='/' + name)
Example #8
0
 def make_provider(self, provider, prefix='', **kwargs):
     payload = yield from auth_handler.fetch(
         self.request,
         dict(kwargs, provider=provider, action=self.action + prefix))
     self.auth = payload
     self.callback_url = payload.pop('callback_url')
     return utils.make_provider(provider, **payload)
Example #9
0
    async def prepare(self):
        """Builds an MFR provider instance, to which it passes the the ``url`` query parameter.
        From that, the file metadata is extracted.  Also builds cached waterbutler providers.
        """
        if self.request.method == 'OPTIONS':
            return

        try:
            self.url = self.request.query_arguments['url'][0].decode('utf-8')
        except KeyError:
            raise exceptions.ProviderError(
                '"url" is a required argument.',
                provider=settings.PROVIDER_NAME,
                code=400,
            )

        self.provider = utils.make_provider(settings.PROVIDER_NAME,
                                            self.request, self.url)

        self.metadata = await self.provider.metadata()
        self.extension_metrics.add('ext', self.metadata.ext)

        self.cache_provider = waterbutler.core.utils.make_provider(
            settings.CACHE_PROVIDER_NAME,
            {},  # User information which can be left blank
            settings.CACHE_PROVIDER_CREDENTIALS,
            settings.CACHE_PROVIDER_SETTINGS)

        self.local_cache_provider = waterbutler.core.utils.make_provider(
            'filesystem', {}, {}, settings.LOCAL_CACHE_PROVIDER_SETTINGS)

        self.source_file_id = uuid.uuid4()
        self.add_header('X-MFR-REQUEST-ID', str(uuid.uuid4()))
Example #10
0
    def prepare(self, *args, **kwargs):
        # TODO Find a nicer way to handle this
        if self.request.method.lower() == 'options':
            return

        self.path = self.path_kwargs['path'] or '/'
        provider = self.path_kwargs['provider']
        self.resource = self.path_kwargs['resource']

        if self.request.method.lower() in self.VALIDATORS:
            # create must validate before accepting files
            getattr(self, self.VALIDATORS[self.request.method.lower()])()

        self.auth = yield from auth_handler.get(self.resource, provider,
                                                self.request)
        self.provider = utils.make_provider(provider, self.auth['auth'],
                                            self.auth['credentials'],
                                            self.auth['settings'])
        self.path = yield from self.provider.validate_path(self.path)

        # The one special case
        if self.request.method == 'PUT' and self.path.is_file:
            yield from self.prepare_stream()
        else:
            self.stream = None
        self.body = b''
Example #11
0
    async def prepare(self):
        """Builds an MFR provider instance, to which it passes the the ``url`` query parameter.
        From that, the file metadata is extracted.  Also builds cached waterbutler providers.
        """
        if self.request.method == 'OPTIONS':
            return

        try:
            self.url = self.request.query_arguments['url'][0].decode('utf-8')
        except KeyError:
            raise exceptions.ProviderError('"url" is a required argument.', code=400)

        self.provider = utils.make_provider(
            settings.PROVIDER_NAME,
            self.request,
            self.url
        )

        self.metadata = await self.provider.metadata()
        self.extension_metrics.add('ext', self.metadata.ext)

        self.cache_provider = waterbutler.core.utils.make_provider(
            settings.CACHE_PROVIDER_NAME,
            {},  # User information which can be left blank
            settings.CACHE_PROVIDER_CREDENTIALS,
            settings.CACHE_PROVIDER_SETTINGS
        )

        self.local_cache_provider = waterbutler.core.utils.make_provider(
            'filesystem', {}, {}, settings.LOCAL_CACHE_PROVIDER_SETTINGS
        )

        self.source_file_id = uuid.uuid4()
Example #12
0
 async def make_provider(self, provider, prefix='', **kwargs):
     payload = await auth_handler.fetch(
         self.request,
         dict(kwargs, provider=provider, action=self.action + prefix)
     )
     self.auth = payload
     return utils.make_provider(provider, **payload)
Example #13
0
    def prepare(self, *args, **kwargs):
        # TODO Find a nicer way to handle this
        if self.request.method.lower() == "options":
            return

        self.path = self.path_kwargs["path"] or "/"
        provider = self.path_kwargs["provider"]
        self.resource = self.path_kwargs["resource"]

        if self.request.method.lower() in self.VALIDATORS:
            # create must validate before accepting files
            getattr(self, self.VALIDATORS[self.request.method.lower()])()

        self.auth = yield from auth_handler.get(self.resource, provider, self.request)
        self.provider = utils.make_provider(
            provider, self.auth["auth"], self.auth["credentials"], self.auth["settings"]
        )
        self.path = yield from self.provider.validate_path(self.path)

        # The one special case
        if self.request.method == "PUT" and self.path.is_file:
            yield from self.prepare_stream()
        else:
            self.stream = None
        self.body = b""
Example #14
0
async def _upload_parity(path, credentials, settings):
    _, name = os.path.split(path)
    provider_name = settings.get('provider')
    provider = make_provider(provider_name, {}, credentials, settings)
    with open(path, 'rb') as file_pointer:
        stream = streams.FileStreamReader(file_pointer)
        await provider.upload(stream,
                              (await provider.validate_path('/' + name)))
Example #15
0
 def make_provider(self, provider, prefix='', **kwargs):
     payload = yield from auth_handler.fetch(
         self.request,
         dict(kwargs, provider=provider, action=self.action + prefix)
     )
     self.auth = payload
     self.callback_url = payload.pop('callback_url')
     return utils.make_provider(provider, **payload)
Example #16
0
    def make_provider(self, settings):
        """Requests on different files may need to use different providers,
        instances, e.g. when different files lives in different containers
        within a provider. This helper creates a single-use provider instance
        that optionally overrides the settings.

        :param dict settings: Overridden settings
        """
        return utils.make_provider(self.provider_name, self.auth, self.credentials["storage"], self.settings["storage"])
Example #17
0
async def _upload_parity(path, credentials, settings):
    _, name = os.path.split(path)
    provider_name = settings.get('provider')
    provider = make_provider(provider_name, {}, credentials, settings)
    with open(path, 'rb') as file_pointer:
        stream = streams.FileStreamReader(file_pointer)
        stream.add_writer('sha256', streams.HashStreamWriter(hashlib.sha256))
        await provider.upload(stream,
                              (await provider.validate_path('/' + name)))
    return (name, stream.writers['sha256'].hexdigest)
Example #18
0
async def _upload_parity(path, credentials, settings):
    _, name = os.path.split(path)
    provider_name = settings.get('provider')
    provider = make_provider(provider_name, {}, credentials, settings)
    with open(path, 'rb') as file_pointer:
        stream = streams.FileStreamReader(file_pointer)
        await provider.upload(
            stream,
            (await provider.validate_path('/' + name))
        )
Example #19
0
def move(src_bundle, dest_bundle, callback_url, auth, start_time=None, **kwargs):
    start_time = start_time or time.time()
    src_path, src_provider = src_bundle.pop('path'), utils.make_provider(**src_bundle.pop('provider'))
    dest_path, dest_provider = dest_bundle.pop('path'), utils.make_provider(**dest_bundle.pop('provider'))

    data = {
        'errors': [],
        'action': 'move',
        'source': dict(src_bundle, **{
            'path': src_path.path,
            'name': src_path.name,
            'materialized': str(src_path),
            'provider': src_provider.NAME,
        }),
        'destination': dict(dest_bundle, **{
            'path': dest_path.path,
            'name': dest_path.name,
            'materialized': str(dest_path),
            'provider': dest_provider.NAME,
        }),
        'auth': auth['auth'],
    }

    logger.info('Starting moving {!r}, {!r} to {!r}, {!r}'.format(src_path, src_provider, dest_path, dest_provider))

    try:
        metadata, created = yield from src_provider.move(dest_provider, src_path, dest_path, **kwargs)
    except Exception as e:
        logger.error('Move failed with error {!r}'.format(e))
        data.update({'errors': [e.__repr__()]})
        raise  # Ensure sentry sees this
    else:
        logger.info('Move succeeded')
        data.update({'destination': dict(src_bundle, **metadata.serialized())})
    finally:
        resp = yield from utils.send_signed_request('PUT', callback_url, dict(data, **{
            'time': time.time() + 60,
            'email': time.time() - start_time > settings.WAIT_TIMEOUT
        }))
        logger.info('Callback returned {!r}'.format(resp))

    return metadata, created
Example #20
0
    async def prepare(self, *args, **kwargs):
        method = self.request.method.lower()

        # TODO Find a nicer way to handle this
        if method == 'options':
            return

        self.arguments = {
            key: list_or_value(value)
            for key, value in self.request.query_arguments.items()
        }

        # Going with version as its the most correct term
        # TODO Change all references of revision to version @chrisseto
        # revisions will still be accepted until necessary changes are made to OSF
        self.requested_version = (self.get_query_argument('version', default=None) or
                                  self.get_query_argument('revision', default=None))

        self.path = self.path_kwargs['path'] or '/'
        provider = self.path_kwargs['provider']
        self.resource = self.path_kwargs['resource']

        # pre-validator methods perform validations that can be performed before ensuring that the
        # path given by the url is valid.  An example would be making sure that a particular query
        # parameter matches and allowed value.  We do this because validating the path requires
        # issuing one or more API calls to the provider, and some providers are quite stingy with
        # their rate limits.
        if method in self.PRE_VALIDATORS:
            getattr(self, self.PRE_VALIDATORS[method])()

        # Delay setup of the provider when method is post, as we need to evaluate the json body
        # action.
        if method != 'post':
            self.auth = await auth_handler.get(self.resource, provider, self.request,
                                               path=self.path, version=self.requested_version)
            self.provider = utils.make_provider(provider, self.auth['auth'],
                                                self.auth['credentials'], self.auth['settings'])
            self.path = await self.provider.validate_v1_path(self.path, **self.arguments)

        self.target_path = None

        # post-validator methods perform validations that expect that the path given in the url has
        # been verified for existence and type.
        if method in self.POST_VALIDATORS:
            await getattr(self, self.POST_VALIDATORS[method])()

        # The one special case
        if method == 'put' and self.target_path.is_file:
            await self.prepare_stream()
        else:
            self.stream = None
        self.body = b''

        self.add_header('X-WATERBUTLER-REQUEST-ID', str(uuid.uuid4()))
Example #21
0
    def make_provider(self, settings):
        """Requests on different files may need to use different providers,
        instances, e.g. when different files lives in different containers
        within a provider. This helper creates a single-use provider instance
        that optionally overrides the settings.

        :param dict settings: Overridden settings
        """
        return utils.make_provider(
            self.provider_name,
            self.auth,
            self.credentials['storage'],
            self.settings['storage'],
        )
Example #22
0
    async def prepare(self):
        self.arguments = {key: list_or_value(value) for key, value in self.request.query_arguments.items()}
        try:
            self.arguments["action"] = self.ACTION_MAP[self.request.method]
        except KeyError:
            return

        self.payload = await auth_handler.fetch(self.request, self.arguments)

        self.provider = utils.make_provider(
            self.arguments["provider"], self.payload["auth"], self.payload["credentials"], self.payload["settings"]
        )

        self.path = await self.provider.validate_path(**self.arguments)
        self.arguments["path"] = self.path  # TODO Not this
Example #23
0
    async def prepare(self, *args, **kwargs):
        method = self.request.method.lower()

        # TODO Find a nicer way to handle this
        if method == 'options':
            return

        self.arguments = {
            key: list_or_value(value)
            for key, value in self.request.query_arguments.items()
        }

        self.path = self.path_kwargs['path'] or '/'
        provider = self.path_kwargs['provider']
        self.resource = self.path_kwargs['resource']

        # pre-validator methods perform validations that can be performed before ensuring that the
        # path given by the url is valid.  An example would be making sure that a particular query
        # parameter matches and allowed value.  We do this because validating the path requires
        # issuing one or more API calls to the provider, and some providers are quite stingy with
        # their rate limits.
        if method in self.PRE_VALIDATORS:
            getattr(self, self.PRE_VALIDATORS[method])()

        # Delay setup of the provider when method is post, as we need to evaluate the json body action.
        if method != 'post':
            self.auth = await auth_handler.get(self.resource, provider,
                                               self.request)
            self.provider = utils.make_provider(provider, self.auth['auth'],
                                                self.auth['credentials'],
                                                self.auth['settings'])
            self.path = await self.provider.validate_v1_path(
                self.path, **self.arguments)

        self.target_path = None

        # post-validator methods perform validations that expect that the path given in the url has
        # been verified for existence and type.
        if method in self.POST_VALIDATORS:
            await getattr(self, self.POST_VALIDATORS[method])()

        # The one special case
        if method == 'put' and self.target_path.is_file:
            await self.prepare_stream()
        else:
            self.stream = None
        self.body = b''
Example #24
0
    def make_provider(self, settings):
        """Requests on different files may need to use different providers,
        instances, e.g. when different files lives in different containers
        within a provider. This helper creates a single-use provider instance
        that optionally overrides the settings.

        :param dict settings: Overridden settings
        """
        if not getattr(self, '_inner_provider', None):
            self._inner_provider = utils.make_provider(
                self.provider_name,
                self.auth,
                self.credentials['storage'],
                self.settings['storage'],
                is_celery_task=self.is_celery_task,
            )
        return self._inner_provider
Example #25
0
    def prepare(self):
        if self.request.method == 'OPTIONS':
            return

        self.url = self.request.query_arguments['url'][0].decode('utf-8')

        self.provider = utils.make_provider(settings.PROVIDER_NAME,
                                            self.request, self.url)

        self.metadata = yield from self.provider.metadata()

        self.cache_provider = waterbutler.core.utils.make_provider(
            settings.CACHE_PROVIDER_NAME,
            {},  # User information which can be left blank
            settings.CACHE_PROVIDER_CREDENTIALS,
            settings.CACHE_PROVIDER_SETTINGS)

        self.local_cache_provider = waterbutler.core.utils.make_provider(
            'filesystem', {}, {}, settings.LOCAL_CACHE_PROVIDER_SETTINGS)
Example #26
0
    async def prepare(self, *args, **kwargs):
        method = self.request.method.lower()

        # TODO Find a nicer way to handle this
        if method == 'options':
            return

        self.arguments = {
            key: list_or_value(value)
            for key, value in self.request.query_arguments.items()
        }

        self.path = self.path_kwargs['path'] or '/'
        provider = self.path_kwargs['provider']
        self.resource = self.path_kwargs['resource']

        # pre-validator methods perform validations that can be performed before ensuring that the
        # path given by the url is valid.  An example would be making sure that a particular query
        # parameter matches and allowed value.  We do this because validating the path requires
        # issuing one or more API calls to the provider, and some providers are quite stingy with
        # their rate limits.
        if method in self.PRE_VALIDATORS:
            getattr(self, self.PRE_VALIDATORS[method])()

        self.auth = await auth_handler.get(self.resource, provider, self.request)
        self.provider = utils.make_provider(provider, self.auth['auth'], self.auth['credentials'], self.auth['settings'])
        self.path = await self.provider.validate_v1_path(self.path, **self.arguments)

        self.target_path = None

        # post-validator methods perform validations that expect that the path given in the url has
        # been verified for existence and type.
        if method in self.POST_VALIDATORS:
            await getattr(self, self.POST_VALIDATORS[method])()

        # The one special case
        if method == 'put' and self.target_path.is_file:
            await self.prepare_stream()
        else:
            self.stream = None
        self.body = b''
Example #27
0
    async def prepare(self):
        self.arguments = {
            key: list_or_value(value)
            for key, value in self.request.query_arguments.items()
        }
        try:
            self.arguments['action'] = self.ACTION_MAP[self.request.method]
        except KeyError:
            return

        self.payload = await auth_handler.fetch(self.request, self.arguments)

        self.provider = utils.make_provider(
            self.arguments['provider'],
            self.payload['auth'],
            self.payload['credentials'],
            self.payload['settings'],
        )

        self.path = await self.provider.validate_path(**self.arguments)
        self.arguments['path'] = self.path  # TODO Not this
Example #28
0
    def prepare(self):
        self.arguments = {
            key: list_or_value(value)
            for key, value in self.request.query_arguments.items()
        }
        try:
            self.arguments['action'] = self.ACTION_MAP[self.request.method]
        except KeyError:
            return

        self.payload = yield from auth_handler.fetch(self.request, self.arguments)

        self.provider = utils.make_provider(
            self.arguments['provider'],
            self.payload['auth'],
            self.payload['credentials'],
            self.payload['settings'],
        )

        self.path = yield from self.provider.validate_path(**self.arguments)
        self.arguments['path'] = self.path  # TODO Not this
Example #29
0
    def prepare(self, *args, **kwargs):
        # TODO Find a nicer way to handle this
        if self.request.method.lower() == 'options':
            return

        self.path = self.path_kwargs['path'] or '/'
        provider = self.path_kwargs['provider']
        self.resource = self.path_kwargs['resource']

        if self.request.method.lower() in self.VALIDATORS:
            # create must validate before accepting files
            getattr(self, self.VALIDATORS[self.request.method.lower()])()

        self.auth = yield from auth_handler.get(self.resource, provider, self.request)
        self.provider = utils.make_provider(provider, self.auth['auth'], self.auth['credentials'], self.auth['settings'])
        self.path = yield from self.provider.validate_path(self.path)

        # The one special case
        if self.request.method == 'PUT' and self.path.is_file:
            yield from self.prepare_stream()
        else:
            self.stream = None
        self.body = b''
Example #30
0
    def prepare(self):
        if self.request.method == 'OPTIONS':
            return

        self.url = self.request.query_arguments['url'][0].decode('utf-8')

        self.provider = utils.make_provider(
            settings.PROVIDER_NAME,
            self.request,
            self.url
        )

        self.metadata = yield from self.provider.metadata()

        self.cache_provider = waterbutler.core.utils.make_provider(
            settings.CACHE_PROVIDER_NAME,
            {},  # User information which can be left blank
            settings.CACHE_PROVIDER_CREDENTIALS,
            settings.CACHE_PROVIDER_SETTINGS
        )

        self.local_cache_provider = waterbutler.core.utils.make_provider(
            'filesystem', {}, {}, settings.LOCAL_CACHE_PROVIDER_SETTINGS
        )
Example #31
0
    def move_or_copy(self):
        # Force the json body to load into memory
        yield self.request.body

        if self.json.get('action') not in ('copy', 'move', 'rename'):
            # Note: null is used as the default to avoid python specific error messages
            raise exceptions.InvalidParameters('Action must be copy, move or rename, not {}'.format(self.json.get('action', 'null')))

        if self.json['action'] == 'rename':
            action = 'move'
            self.dest_auth = self.auth
            self.dest_provider = self.provider
            self.dest_path = self.path.parent
        else:
            if 'path' not in self.json:
                raise exceptions.InvalidParameters('Path is required for moves or copies')

            action = self.json['action']

            # Note: attached to self so that _send_hook has access to these
            self.dest_resource = self.json.get('resource', self.resource)

            # TODO optimize for same provider and resource
            self.dest_auth = yield from auth_handler.get(
                self.dest_resource,
                self.json.get('provider', self.provider.NAME),
                self.request
            )

            self.dest_provider = make_provider(
                self.json.get('provider', self.provider.NAME),
                self.dest_auth['auth'],
                self.dest_auth['credentials'],
                self.dest_auth['settings']
            )

            self.dest_path = yield from self.dest_provider.validate_path(self.json['path'])

        if not getattr(self.provider, 'can_intra_' + action)(self.dest_provider, self.path):
            result = yield from getattr(tasks, action).adelay(*self.build_args(self.dest_provider, self.dest_path))
            metadata, created = yield from tasks.wait_on_celery(result)
        else:
            metadata, created = (
                yield from tasks.backgrounded(
                    getattr(self.provider, action),
                    self.dest_provider,
                    self.path,
                    self.dest_path,
                    rename=self.json.get('rename'),
                    conflict=self.json.get('conflict', 'replace'),
                )
            )

        metadata = metadata.serialized()

        if created:
            self.set_status(201)
        else:
            self.set_status(200)

        self.write(metadata)
Example #32
0
    def move_or_copy(self):
        # Force the json body to load into memory
        yield self.request.body

        if self.json.get('action') not in ('copy', 'move', 'rename'):
            # Note: null is used as the default to avoid python specific error messages
            raise exceptions.InvalidParameters(
                'Action must be copy, move or rename, not {}'.format(
                    self.json.get('action', 'null')))

        if self.json['action'] == 'rename':
            action = 'move'
            self.dest_auth = self.auth
            self.dest_provider = self.provider
            self.dest_path = self.path.parent
        else:
            if 'path' not in self.json:
                raise exceptions.InvalidParameters(
                    'Path is required for moves or copies')

            action = self.json['action']

            # Note: attached to self so that _send_hook has access to these
            self.dest_resource = self.json.get('resource', self.resource)

            # TODO optimize for same provider and resource
            self.dest_auth = yield from auth_handler.get(
                self.dest_resource,
                self.json.get('provider', self.provider.NAME), self.request)

            self.dest_provider = make_provider(
                self.json.get('provider',
                              self.provider.NAME), self.dest_auth['auth'],
                self.dest_auth['credentials'], self.dest_auth['settings'])

            self.dest_path = yield from self.dest_provider.validate_path(
                self.json['path'])

        if not getattr(self.provider, 'can_intra_' + action)(
                self.dest_provider, self.path):
            result = yield from getattr(tasks, action).adelay(
                *self.build_args(self.dest_provider, self.dest_path))
            metadata, created = yield from tasks.wait_on_celery(result)
        else:
            metadata, created = (yield from tasks.backgrounded(
                getattr(self.provider, action),
                self.dest_provider,
                self.path,
                self.dest_path,
                rename=self.json.get('rename'),
                conflict=self.json.get('conflict', 'replace'),
            ))

        metadata = metadata.serialized()

        if created:
            self.set_status(201)
        else:
            self.set_status(200)

        self.write(metadata)
    async def move_or_copy(self):
        """Copy, move, and rename files and folders.

        **Auth actions**: ``copy``, ``move``, or ``rename``

        **Provider actions**: ``copy`` or ``move``

        *Auth actions* come from the ``action`` body parameter in the request and are used by the
        auth handler.

        *Provider actions* are determined from the *auth action*.  A "rename" is a special case of
        the "move" provider action that implies that the destination resource, provider, and parent
        path will all be the same as the source.
        """

        # Force the json body to load into memory
        await self.request.body

        auth_action = self.json.get('action', 'null')
        if auth_action not in ('copy', 'move', 'rename'):
            raise exceptions.InvalidParameters('Auth action must be "copy", "move", or "rename", '
                                               'not "{}"'.format(auth_action))

        # Provider setup is delayed so the provider action can be updated from the auth action.
        provider = self.path_kwargs.get('provider', '')
        provider_action = auth_action
        if auth_action == 'rename':
            if not self.json.get('rename', ''):
                raise exceptions.InvalidParameters('"rename" field is required for renaming')
            provider_action = 'move'

        self.auth = await auth_handler.get(
            self.resource,
            provider,
            self.request,
            action=auth_action,
            auth_type=AuthType.SOURCE,
            path=self.path,
            version=self.requested_version,
        )
        self.provider = make_provider(
            provider,
            self.auth['auth'],
            self.auth['credentials'],
            self.auth['settings']
        )
        self.path = await self.provider.validate_v1_path(self.path, **self.arguments)

        if auth_action == 'rename':  # 'rename' implies the file/folder does not change location
            self.dest_auth = self.auth
            self.dest_provider = self.provider
            self.dest_path = self.path.parent
            self.dest_resource = self.resource
        else:
            path = self.json.get('path', None)
            if path is None:
                raise exceptions.InvalidParameters('"path" field is required for moves or copies')
            if not path.endswith('/'):
                raise exceptions.InvalidParameters(
                    '"path" field requires a trailing slash to indicate it is a folder'
                )

            # TODO optimize for same provider and resource

            # for copy action, `auth_action` is the same as `provider_action`
            if auth_action == 'copy' and self.path.is_root and not self.json.get('rename'):
                raise exceptions.InvalidParameters('"rename" field is required for copying root')

            # Note: attached to self so that _send_hook has access to these
            self.dest_resource = self.json.get('resource', self.resource)
            self.dest_auth = await auth_handler.get(
                self.dest_resource,
                self.json.get('provider', self.provider.NAME),
                self.request,
                action=auth_action,
                auth_type=AuthType.DESTINATION,
            )
            self.dest_provider = make_provider(
                self.json.get('provider', self.provider.NAME),
                self.dest_auth['auth'],
                self.dest_auth['credentials'],
                self.dest_auth['settings']
            )
            self.dest_path = await self.dest_provider.validate_path(**self.json)

        if not getattr(self.provider, 'can_intra_' + provider_action)(self.dest_provider, self.path):
            # this weird signature syntax courtesy of py3.4 not liking trailing commas on kwargs
            conflict = self.json.get('conflict', DEFAULT_CONFLICT)
            result = await getattr(tasks, provider_action).adelay(
                rename=self.json.get('rename'),
                conflict=conflict,
                request=remote_logging._serialize_request(self.request),
                *self.build_args()
            )
            metadata, created = await tasks.wait_on_celery(result)
        else:
            metadata, created = (
                await tasks.backgrounded(
                    getattr(self.provider, provider_action),
                    self.dest_provider,
                    self.path,
                    self.dest_path,
                    rename=self.json.get('rename'),
                    conflict=self.json.get('conflict', DEFAULT_CONFLICT),
                )
            )

        self.dest_meta = metadata

        if created:
            self.set_status(int(HTTPStatus.CREATED))
        else:
            self.set_status(int(HTTPStatus.OK))

        self.write({'data': metadata.json_api_serialized(self.dest_resource)})
Example #34
0
    async def move_or_copy(self):
        """Copy, move, and rename files and folders.

        **Auth actions**: ``copy``, ``move``, or ``rename``

        **Provider actions**: ``copy`` or ``move``

        *Auth actions* come from the ``action`` body parameter in the request and are used by the
        auth handler.

        *Provider actions* are determined from the *auth action*.  A "rename" is a special case of
        the "move" provider action that implies that the destination resource, provider, and parent
        path will all be the same as the source.
        """

        # Force the json body to load into memory
        await self.request.body

        auth_action = self.json.get('action', 'null')
        if auth_action not in ('copy', 'move', 'rename'):
            raise exceptions.InvalidParameters('Auth action must be "copy", "move", or "rename", '
                                               'not "{}"'.format(auth_action))

        # Provider setup is delayed so the provider action can be updated from the auth action.
        provider = self.path_kwargs.get('provider', '')
        provider_action = auth_action
        if auth_action == 'rename':
            if not self.json.get('rename', ''):
                raise exceptions.InvalidParameters('"rename" field is required for renaming')
            provider_action = 'move'

        self.auth = await auth_handler.get(
            self.resource,
            provider,
            self.request,
            action=auth_action,
            auth_type=AuthType.SOURCE
        )
        self.provider = make_provider(
            provider,
            self.auth['auth'],
            self.auth['credentials'],
            self.auth['settings']
        )
        self.path = await self.provider.validate_v1_path(self.path, **self.arguments)

        if auth_action == 'rename':  # 'rename' implies the file/folder does not change location
            self.dest_auth = self.auth
            self.dest_provider = self.provider
            self.dest_path = self.path.parent
            self.dest_resource = self.resource
        else:
            path = self.json.get('path', None)
            if path is None:
                raise exceptions.InvalidParameters('"path" field is required for moves or copies')
            if not path.endswith('/'):
                raise exceptions.InvalidParameters(
                    '"path" field requires a trailing slash to indicate it is a folder'
                )

            # TODO optimize for same provider and resource

            # for copy action, `auth_action` is the same as `provider_action`
            if auth_action == 'copy' and self.path.is_root and not self.json.get('rename'):
                raise exceptions.InvalidParameters('"rename" field is required for copying root')

            # Note: attached to self so that _send_hook has access to these
            self.dest_resource = self.json.get('resource', self.resource)
            self.dest_auth = await auth_handler.get(
                self.dest_resource,
                self.json.get('provider', self.provider.NAME),
                self.request,
                action=auth_action,
                auth_type=AuthType.DESTINATION,
            )
            self.dest_provider = make_provider(
                self.json.get('provider', self.provider.NAME),
                self.dest_auth['auth'],
                self.dest_auth['credentials'],
                self.dest_auth['settings']
            )
            self.dest_path = await self.dest_provider.validate_path(**self.json)

        if not getattr(self.provider, 'can_intra_' + provider_action)(self.dest_provider, self.path):
            # this weird signature syntax courtesy of py3.4 not liking trailing commas on kwargs
            conflict = self.json.get('conflict', DEFAULT_CONFLICT)
            result = await getattr(tasks, provider_action).adelay(
                rename=self.json.get('rename'),
                conflict=conflict,
                request=remote_logging._serialize_request(self.request),
                *self.build_args()
            )
            metadata, created = await tasks.wait_on_celery(result)
        else:
            metadata, created = (
                await tasks.backgrounded(
                    getattr(self.provider, provider_action),
                    self.dest_provider,
                    self.path,
                    self.dest_path,
                    rename=self.json.get('rename'),
                    conflict=self.json.get('conflict', DEFAULT_CONFLICT),
                )
            )

        self.dest_meta = metadata

        if created:
            self.set_status(int(HTTPStatus.CREATED))
        else:
            self.set_status(int(HTTPStatus.OK))

        self.write({'data': metadata.json_api_serialized(self.dest_resource)})
Example #35
0
    def move_or_copy(self):
        # Force the json body to load into memory
        yield self.request.body

        if self.json.get("action") not in ("copy", "move", "rename"):
            # Note: null is used as the default to avoid python specific error messages
            raise exceptions.InvalidParameters(
                "Action must be copy, move or rename, not {}".format(self.json.get("action", "null"))
            )

        if self.json["action"] == "rename":
            if not self.json.get("rename"):
                raise exceptions.InvalidParameters("Rename is required for renaming")
            action = "move"
            self.dest_auth = self.auth
            self.dest_provider = self.provider
            self.dest_path = self.path.parent
            self.dest_resource = self.resource
        else:
            if "path" not in self.json:
                raise exceptions.InvalidParameters("Path is required for moves or copies")

            action = self.json["action"]

            # Note: attached to self so that _send_hook has access to these
            self.dest_resource = self.json.get("resource", self.resource)

            # TODO optimize for same provider and resource
            self.dest_auth = yield from auth_handler.get(
                self.dest_resource, self.json.get("provider", self.provider.NAME), self.request
            )

            self.dest_provider = make_provider(
                self.json.get("provider", self.provider.NAME),
                self.dest_auth["auth"],
                self.dest_auth["credentials"],
                self.dest_auth["settings"],
            )

            self.dest_path = yield from self.dest_provider.validate_path(self.json["path"])

        if not getattr(self.provider, "can_intra_" + action)(self.dest_provider, self.path):
            # this weird signature syntax courtesy of py3.4 not liking trailing commas on kwargs
            result = yield from getattr(tasks, action).adelay(
                rename=self.json.get("rename"), conflict=self.json.get("conflict", DEFAULT_CONFLICT), *self.build_args()
            )
            metadata, created = yield from tasks.wait_on_celery(result)
        else:
            metadata, created = (
                yield from tasks.backgrounded(
                    getattr(self.provider, action),
                    self.dest_provider,
                    self.path,
                    self.dest_path,
                    rename=self.json.get("rename"),
                    conflict=self.json.get("conflict", DEFAULT_CONFLICT),
                )
            )

        if created:
            self.set_status(201)
        else:
            self.set_status(200)

        self.write({"data": metadata.json_api_serialized(self.dest_resource)})
Example #36
0
    async def move_or_copy(self):
        # Force the json body to load into memory
        await self.request.body

        if self.json.get('action') not in ('copy', 'move', 'rename'):
            # Note: null is used as the default to avoid python specific error messages
            raise exceptions.InvalidParameters(
                'Action must be copy, move or rename, not {}'.format(
                    self.json.get('action', 'null')))

        if self.json['action'] == 'rename':
            if not self.json.get('rename'):
                raise exceptions.InvalidParameters(
                    'Rename is required for renaming')
            action = 'move'
            self.dest_auth = self.auth
            self.dest_provider = self.provider
            self.dest_path = self.path.parent
            self.dest_resource = self.resource
        else:
            if 'path' not in self.json:
                raise exceptions.InvalidParameters(
                    'Path is required for moves or copies')

            action = self.json['action']

            # Note: attached to self so that _send_hook has access to these
            self.dest_resource = self.json.get('resource', self.resource)

            # TODO optimize for same provider and resource
            self.dest_auth = await auth_handler.get(
                self.dest_resource,
                self.json.get('provider', self.provider.NAME), self.request)

            self.dest_provider = make_provider(
                self.json.get('provider',
                              self.provider.NAME), self.dest_auth['auth'],
                self.dest_auth['credentials'], self.dest_auth['settings'])

            self.dest_path = await self.dest_provider.validate_path(
                self.json['path'])

        if not getattr(self.provider, 'can_intra_' + action)(
                self.dest_provider, self.path):
            # this weird signature syntax courtesy of py3.4 not liking trailing commas on kwargs
            result = await getattr(tasks, action).adelay(
                rename=self.json.get('rename'),
                conflict=self.json.get('conflict', DEFAULT_CONFLICT),
                *self.build_args())
            metadata, created = await tasks.wait_on_celery(result)
        else:
            metadata, created = (await tasks.backgrounded(
                getattr(self.provider, action),
                self.dest_provider,
                self.path,
                self.dest_path,
                rename=self.json.get('rename'),
                conflict=self.json.get('conflict', DEFAULT_CONFLICT),
            ))

        self.dest_meta = metadata

        if created:
            self.set_status(201)
        else:
            self.set_status(200)

        self.write({'data': metadata.json_api_serialized(self.dest_resource)})
Example #37
0
 async def make_provider(self, provider, prefix='', **kwargs):
     payload = await auth_handler.fetch(
         self.request,
         dict(kwargs, provider=provider, action=self.action + prefix))
     self.auth = payload
     return utils.make_provider(provider, **payload)
Example #38
0
    async def move_or_copy(self):
        # Force the json body to load into memory
        await self.request.body

        if self.json.get('action') not in ('copy', 'move', 'rename'):
            # Note: null is used as the default to avoid python specific error messages
            raise exceptions.InvalidParameters(
                'Action must be copy, move or rename, '
                'not {}'.format(self.json.get('action', 'null')))

        # Setup of the provider was delayed so the json action could be retrieved from the request body.
        provider = self.path_kwargs['provider']
        action = self.json['action']

        self.auth = await auth_handler.get(self.resource,
                                           provider,
                                           self.request,
                                           action=action,
                                           auth_type=AuthType.SOURCE)
        self.provider = make_provider(provider, self.auth['auth'],
                                      self.auth['credentials'],
                                      self.auth['settings'])
        self.path = await self.provider.validate_v1_path(
            self.path, **self.arguments)

        if action == 'rename':
            if not self.json.get('rename'):
                raise exceptions.InvalidParameters(
                    'Rename is required for renaming')

            action = 'move'
            self.dest_auth = self.auth
            self.dest_provider = self.provider
            self.dest_path = self.path.parent
            self.dest_resource = self.resource
        else:
            if 'path' not in self.json:
                raise exceptions.InvalidParameters(
                    'Path is required for moves or copies')

            if not self.json['path'].endswith('/'):
                raise exceptions.InvalidParameters(
                    'Path requires a trailing slash to indicate '
                    'it is a folder')

            # TODO optimize for same provider and resource

            # Note: attached to self so that _send_hook has access to these
            self.dest_resource = self.json.get('resource', self.resource)
            self.dest_auth = await auth_handler.get(
                self.dest_resource,
                self.json.get('provider', self.provider.NAME),
                self.request,
                action=action,
                auth_type=AuthType.DESTINATION,
            )
            self.dest_provider = make_provider(
                self.json.get('provider',
                              self.provider.NAME), self.dest_auth['auth'],
                self.dest_auth['credentials'], self.dest_auth['settings'])
            self.dest_path = await self.dest_provider.validate_path(**self.json
                                                                    )

        if not getattr(self.provider, 'can_intra_' + action)(
                self.dest_provider, self.path):
            # this weird signature syntax courtesy of py3.4 not liking trailing commas on kwargs
            conflict = self.json.get('conflict', DEFAULT_CONFLICT)
            result = await getattr(tasks, action).adelay(
                rename=self.json.get('rename'),
                conflict=conflict,
                request=remote_logging._serialize_request(self.request),
                *self.build_args())
            metadata, created = await tasks.wait_on_celery(result)
        else:
            metadata, created = (await tasks.backgrounded(
                getattr(self.provider, action),
                self.dest_provider,
                self.path,
                self.dest_path,
                rename=self.json.get('rename'),
                conflict=self.json.get('conflict', DEFAULT_CONFLICT),
            ))

        self.dest_meta = metadata

        if created:
            self.set_status(201)
        else:
            self.set_status(200)

        self.write({'data': metadata.json_api_serialized(self.dest_resource)})
Example #39
0
    async def move_or_copy(self):
        # Force the json body to load into memory
        await self.request.body

        if self.json.get('action') not in ('copy', 'move', 'rename'):
            # Note: null is used as the default to avoid python specific error messages
            raise exceptions.InvalidParameters('Action must be copy, move or rename, not {}'.format(self.json.get('action', 'null')))

        if self.json['action'] == 'rename':
            if not self.json.get('rename'):
                raise exceptions.InvalidParameters('Rename is required for renaming')
            action = 'move'
            self.dest_auth = self.auth
            self.dest_provider = self.provider
            self.dest_path = self.path.parent
            self.dest_resource = self.resource
        else:
            if 'path' not in self.json:
                raise exceptions.InvalidParameters('Path is required for moves or copies')

            action = self.json['action']

            # Note: attached to self so that _send_hook has access to these
            self.dest_resource = self.json.get('resource', self.resource)

            # TODO optimize for same provider and resource
            self.dest_auth = await auth_handler.get(
                self.dest_resource,
                self.json.get('provider', self.provider.NAME),
                self.request
            )

            self.dest_provider = make_provider(
                self.json.get('provider', self.provider.NAME),
                self.dest_auth['auth'],
                self.dest_auth['credentials'],
                self.dest_auth['settings']
            )

            self.dest_path = await self.dest_provider.validate_path(self.json['path'])

        if not getattr(self.provider, 'can_intra_' + action)(self.dest_provider, self.path):
            # this weird signature syntax courtesy of py3.4 not liking trailing commas on kwargs
            result = await getattr(tasks, action).adelay(
                rename=self.json.get('rename'),
                conflict=self.json.get('conflict', DEFAULT_CONFLICT),
                *self.build_args()
            )
            metadata, created = await tasks.wait_on_celery(result)
        else:
            metadata, created = (
                await tasks.backgrounded(
                    getattr(self.provider, action),
                    self.dest_provider,
                    self.path,
                    self.dest_path,
                    rename=self.json.get('rename'),
                    conflict=self.json.get('conflict', DEFAULT_CONFLICT),
                )
            )

        self.dest_meta = metadata

        if created:
            self.set_status(201)
        else:
            self.set_status(200)

        self.write({'data': metadata.json_api_serialized(self.dest_resource)})