예제 #1
0
 def _purge_quota(self, quota, params):
     """
     This method should only be called for a Quota that has previously been deleted.
     Purging a deleted Quota deletes all of the following from the database:
     - UserQuotaAssociations where quota_id == Quota.id
     - GroupQuotaAssociations where quota_id == Quota.id
     """
     quotas = util.listify(quota)
     names = []
     for q in quotas:
         if not q.deleted:
             names.append(q.name)
     if len(names) == 1:
         raise ActionInputError(
             "Quota '%s' has not been deleted, so it cannot be purged." %
             (names[0]))
     elif len(names) > 1:
         raise ActionInputError(
             "Quotas have not been deleted so they cannot be undeleted: " +
             ', '.join(names))
     message = "Purged %d quotas: " % len(quotas)
     for q in quotas:
         # Delete UserQuotaAssociations
         for uqa in q.users:
             self.sa_session.delete(uqa)
         # Delete GroupQuotaAssociations
         for gqa in q.groups:
             self.sa_session.delete(gqa)
         names.append(q.name)
     self.sa_session.flush()
     message += ', '.join(names)
     return message
예제 #2
0
파일: admin.py 프로젝트: yin-max/galaxy
 def _manage_users_and_groups_for_quota(self,
                                        quota,
                                        params,
                                        decode_id=None):
     if quota.default:
         raise ActionInputError(
             'Default quotas cannot be associated with specific users and groups.'
         )
     else:
         in_users = [
             self.sa_session.query(
                 self.app.model.User).get(decode_id(x) if decode_id else x)
             for x in util.listify(params.in_users)
         ]
         if None in in_users:
             raise ActionInputError(
                 "One or more invalid user id has been provided.")
         in_groups = [
             self.sa_session.query(self.app.model.Group).get(
                 decode_id(x) if decode_id else x)
             for x in util.listify(params.in_groups)
         ]
         if None in in_groups:
             raise ActionInputError(
                 "One or more invalid group id has been provided.")
         self.app.quota_agent.set_entity_quota_associations(
             quotas=[quota], users=in_users, groups=in_groups)
         self.sa_session.refresh(quota)
         message = "Quota '%s' has been updated with %d associated users and %d associated groups." % (
             quota.name, len(in_users), len(in_groups))
         return message
예제 #3
0
 def _rename_quota( self, quota, params ):
     if not params.name:
         raise ActionInputError( 'Enter a valid name' )
     elif params.name != quota.name and self.sa_session.query( self.app.model.Quota ).filter( self.app.model.Quota.table.c.name==params.name ).first():
         raise ActionInputError( 'A quota with that name already exists' )
     else:
         old_name = quota.name
         quota.name = params.name
         quota.description = params.description
         self.sa_session.add( quota )
         self.sa_session.flush()
         message = "Quota '%s' has been renamed to '%s'" % ( old_name, params.name )
         return message
예제 #4
0
 def _create_quota(self, params, decode_id=None):
     if params.amount.lower() in ('unlimited', 'none', 'no limit'):
         create_amount = None
     else:
         try:
             create_amount = util.size_to_bytes(params.amount)
         except AssertionError:
             create_amount = False
     if not params.name or not params.description:
         raise ActionInputError("Enter a valid name and a description.")
     elif self.sa_session.query(self.app.model.Quota).filter(self.app.model.Quota.table.c.name == params.name).first():
         raise ActionInputError("Quota names must be unique and a quota with that name already exists, so choose another name.")
     elif not params.get('amount', None):
         raise ActionInputError("Enter a valid quota amount.")
     elif create_amount is False:
         raise ActionInputError("Unable to parse the provided amount.")
     elif params.operation not in self.app.model.Quota.valid_operations:
         raise ActionInputError("Enter a valid operation.")
     elif params.default != 'no' and params.default not in self.app.model.DefaultQuotaAssociation.types.__members__.values():
         raise ActionInputError("Enter a valid default type.")
     elif params.default != 'no' and params.operation != '=':
         raise ActionInputError("Operation for a default quota must be '='.")
     elif create_amount is None and params.operation != '=':
         raise ActionInputError("Operation for an unlimited quota must be '='.")
     else:
         # Create the quota
         quota = self.app.model.Quota(name=params.name, description=params.description, amount=create_amount, operation=params.operation)
         self.sa_session.add(quota)
         # If this is a default quota, create the DefaultQuotaAssociation
         if params.default != 'no':
             self.app.quota_agent.set_default_quota(params.default, quota)
             message = "Default quota '%s' has been created." % quota.name
         else:
             # Create the UserQuotaAssociations
             in_users = [self.sa_session.query(self.app.model.User).get(decode_id(x) if decode_id else x) for x in util.listify(params.in_users)]
             in_groups = [self.sa_session.query(self.app.model.Group).get(decode_id(x) if decode_id else x) for x in util.listify(params.in_groups)]
             if None in in_users:
                 raise ActionInputError("One or more invalid user id has been provided.")
             for user in in_users:
                 uqa = self.app.model.UserQuotaAssociation(user, quota)
                 self.sa_session.add(uqa)
             # Create the GroupQuotaAssociations
             if None in in_groups:
                 raise ActionInputError("One or more invalid group id has been provided.")
             for group in in_groups:
                 gqa = self.app.model.GroupQuotaAssociation(group, quota)
                 self.sa_session.add(gqa)
             message = "Quota '%s' has been created with %d associated users and %d associated groups." % (quota.name, len(in_users), len(in_groups))
         self.sa_session.flush()
         return quota, message
예제 #5
0
파일: quotas.py 프로젝트: mvdbeek/galaxy
 def rename_quota(self, quota, params) -> str:
     if not params.name:
         raise ActionInputError('Enter a valid name.')
     elif params.name != quota.name and self.sa_session.query(model.Quota).filter(model.Quota.name == params.name).first():
         raise ActionInputError('A quota with that name already exists.')
     else:
         old_name = quota.name
         quota.name = params.name
         if params.description:
             quota.description = params.description
         self.sa_session.add(quota)
         self.sa_session.flush()
         message = f"Quota '{old_name}' has been renamed to '{params.name}'."
         return message
예제 #6
0
 def unset_quota_default(self, quota, params=None) -> str:
     if not quota.default:
         raise ActionInputError(f"Quota '{quota.name}' is not a default.")
     else:
         message = f"Quota '{quota.name}' is no longer the default for {quota.default[0].type} users."
         for dqa in quota.default:
             self.sa_session.delete(dqa)
         self.sa_session.flush()
         return message
예제 #7
0
파일: quotas.py 프로젝트: mvdbeek/galaxy
 def undelete_quota(self, quota, params=None) -> str:
     quotas = util.listify(quota)
     names = []
     for q in quotas:
         if not q.deleted:
             names.append(q.name)
     if len(names) == 1:
         raise ActionInputError(f"Quota '{names[0]}' has not been deleted, so it cannot be undeleted.")
     elif len(names) > 1:
         raise ActionInputError(f"Quotas have not been deleted so they cannot be undeleted: {', '.join(names)}")
     message = f"Undeleted {len(quotas)} quotas: "
     for q in quotas:
         q.deleted = False
         self.sa_session.add(q)
         names.append(q.name)
     self.sa_session.flush()
     message += ', '.join(names)
     return message
예제 #8
0
 def _undelete_quota( self, quota, params ):
     quotas = util.listify( quota )
     names = []
     for q in quotas:
         if not q.deleted:
             names.append( q.name )
     if len( names ) == 1:
         raise ActionInputError( "Quota '%s' has not been deleted, so it cannot be undeleted." % ( names[0] ) )
     elif len( names ) > 1:
         raise ActionInputError( "Quotas have not been deleted so they cannot be undeleted: " + ', '.join( names ) )
     message = "Undeleted %d quotas: " % len( quotas )
     for q in quotas:
         q.deleted = False
         self.sa_session.add( q )
         names.append( q.name )
     self.sa_session.flush()
     message += ', '.join( names )
     return message
예제 #9
0
 def _mark_quota_deleted( self, quota, params ):
     quotas = util.listify( quota )
     names = []
     for q in quotas:
         if q.default:
             names.append( q.name )
     if len( names ) == 1:
         raise ActionInputError( "Quota '%s' is a default, please unset it as a default before deleting it" % ( names[0] ) )
     elif len( names ) > 1:
         raise ActionInputError( "Quotas are defaults, please unset them as defaults before deleting them: " + ', '.join( names ) )
     message = "Deleted %d quotas: " % len( quotas )
     for q in quotas:
         q.deleted = True
         self.sa_session.add( q )
         names.append( q.name )
     self.sa_session.flush()
     message += ', '.join( names )
     return message
예제 #10
0
파일: quotas.py 프로젝트: mvdbeek/galaxy
 def delete_quota(self, quota, params=None) -> str:
     quotas = util.listify(quota)
     names = []
     for q in quotas:
         if q.default:
             names.append(q.name)
     if len(names) == 1:
         raise ActionInputError(f"Quota '{names[0]}' is a default, please unset it as a default before deleting it.")
     elif len(names) > 1:
         raise ActionInputError(f"Quotas are defaults, please unset them as defaults before deleting them: {', '.join(names)}")
     message = f"Deleted {len(quotas)} quotas: "
     for q in quotas:
         q.deleted = True
         self.sa_session.add(q)
         names.append(q.name)
     self.sa_session.flush()
     message += ', '.join(names)
     return message
예제 #11
0
 def _unset_quota_default( self, quota, params ):
     if not quota.default:
         raise ActionInputError( "Quota '%s' is not a default." % quota.name )
     else:
         message = "Quota '%s' is no longer the default for %s users." % ( quota.name, quota.default[0].type )
         for dqa in quota.default:
             self.sa_session.delete( dqa )
         self.sa_session.flush()
         return message
예제 #12
0
    def update( self, trans, id, **kwd ):
        """
        PATCH /api/repositories/{encoded_repository_id}
        Updates information about a repository in the Tool Shed.

        :param id: the encoded id of the Repository object

        :param payload: dictionary structure containing::
            'name':                  repo's name (optional)
            'synopsis':              repo's synopsis (optional)
            'description':           repo's description (optional)
            'remote_repository_url': repo's remote repo (optional)
            'homepage_url':          repo's homepage url (optional)
            'category_ids':          list of existing encoded TS category ids
                                     the updated repo should be associated with (optional)
        :type payload: dict

        :returns:   detailed repository information
        :rtype:     dict

        :raises: RequestParameterInvalidException, InsufficientPermissionsException
        """
        payload = kwd.get( 'payload', None )
        if not payload:
            raise RequestParameterMissingException( "You did not specify any payload." )

        name = payload.get( 'name', None )
        synopsis = payload.get( 'synopsis', None )
        description = payload.get( 'description', None )
        remote_repository_url = payload.get( 'remote_repository_url', None )
        homepage_url = payload.get( 'homepage_url', None )
        category_ids = payload.get( 'category_ids', None )
        if category_ids is not None:
            # We need to know if it was actually passed, and listify turns None into []
            category_ids = util.listify( category_ids )

        update_kwds = dict(
            name=name,
            description=synopsis,
            long_description=description,
            remote_repository_url=remote_repository_url,
            homepage_url=homepage_url,
            category_ids=category_ids,
        )

        repo, message = repository_util.update_repository( app=trans.app, trans=trans, id=id, **update_kwds )
        if repo is None:
            if "You are not the owner" in message:
                raise InsufficientPermissionsException( message )
            else:
                raise ActionInputError( message )

        repository_dict = repo.to_dict( view='element', value_mapper=self.__get_value_mapper( trans ) )
        repository_dict[ 'category_ids' ] = \
            [ trans.security.encode_id( x.category.id ) for x in repo.categories ]
        return repository_dict
예제 #13
0
 def _manage_users_and_groups_for_quota( self, quota, params ):
     if quota.default:
         raise ActionInputError( 'Default quotas cannot be associated with specific users and groups' )
     else:
         in_users = [ self.sa_session.query( self.app.model.User ).get( x ) for x in util.listify( params.in_users ) ]
         in_groups = [ self.sa_session.query( self.app.model.Group ).get( x ) for x in util.listify( params.in_groups ) ]
         self.app.quota_agent.set_entity_quota_associations( quotas=[ quota ], users=in_users, groups=in_groups )
         self.sa_session.refresh( quota )
         message = "Quota '%s' has been updated with %d associated users and %d associated groups" % ( quota.name, len( in_users ), len( in_groups ) )
         return message
예제 #14
0
 def create_quota(self,
                  payload: dict,
                  decode_id=None) -> Tuple[model.Quota, str]:
     params = CreateQuotaParams.parse_obj(payload)
     create_amount = self._parse_amount(params.amount)
     if self.sa_session.query(
             model.Quota).filter(model.Quota.name == params.name).first():
         raise ActionInputError(
             "Quota names must be unique and a quota with that name already exists, please choose another name."
         )
     elif create_amount is False:
         raise ActionInputError("Unable to parse the provided amount.")
     elif params.operation not in model.Quota.valid_operations:
         raise ActionInputError("Enter a valid operation.")
     elif params.default != DefaultQuotaValues.NO and params.operation != QuotaOperation.EXACT:
         raise ActionInputError(
             "Operation for a default quota must be '='.")
     elif create_amount is None and params.operation != QuotaOperation.EXACT:
         raise ActionInputError(
             "Operation for an unlimited quota must be '='.")
     # Create the quota
     quota = model.Quota(name=params.name,
                         description=params.description,
                         amount=create_amount,
                         operation=params.operation)
     self.sa_session.add(quota)
     # If this is a default quota, create the DefaultQuotaAssociation
     if params.default != DefaultQuotaValues.NO:
         self.quota_agent.set_default_quota(params.default, quota)
         message = f"Default quota '{quota.name}' has been created."
     else:
         # Create the UserQuotaAssociations
         in_users = [
             self.sa_session.query(
                 model.User).get(decode_id(x) if decode_id else x)
             for x in util.listify(params.in_users)
         ]
         in_groups = [
             self.sa_session.query(
                 model.Group).get(decode_id(x) if decode_id else x)
             for x in util.listify(params.in_groups)
         ]
         if None in in_users:
             raise ActionInputError(
                 "One or more invalid user id has been provided.")
         for user in in_users:
             uqa = model.UserQuotaAssociation(user, quota)
             self.sa_session.add(uqa)
         # Create the GroupQuotaAssociations
         if None in in_groups:
             raise ActionInputError(
                 "One or more invalid group id has been provided.")
         for group in in_groups:
             gqa = model.GroupQuotaAssociation(group, quota)
             self.sa_session.add(gqa)
         message = f"Quota '{quota.name}' has been created with {len(in_users)} associated users and {len(in_groups)} associated groups."
     self.sa_session.flush()
     return quota, message
예제 #15
0
 def edit_quota(self, quota, params) -> str:
     if params.amount.lower() in ('unlimited', 'none', 'no limit'):
         new_amount = None
     else:
         try:
             new_amount = util.size_to_bytes(params.amount)
         except (AssertionError, ValueError):
             new_amount = False
     if not params.amount:
         raise ActionInputError('Enter a valid amount.')
     elif new_amount is False:
         raise ActionInputError('Unable to parse the provided amount.')
     elif params.operation not in model.Quota.valid_operations:
         raise ActionInputError('Enter a valid operation.')
     else:
         quota.amount = new_amount
         quota.operation = params.operation
         self.sa_session.add(quota)
         self.sa_session.flush()
         message = f"Quota '{quota.name}' is now '{quota.operation}{quota.display_amount}'."
         return message
예제 #16
0
 def _edit_quota( self, quota, params ):
     if params.amount.lower() in ( 'unlimited', 'none', 'no limit' ):
         new_amount = None
     else:
         try:
             new_amount = util.size_to_bytes( params.amount )
         except AssertionError:
             new_amount = False
     if not params.amount:
         raise ActionInputError( 'Enter a valid amount' )
     elif new_amount is False:
         raise ActionInputError( 'Unable to parse the provided amount' )
     elif params.operation not in self.app.model.Quota.valid_operations:
         raise ActionInputError( 'Enter a valid operation' )
     else:
         quota.amount = new_amount
         quota.operation = params.operation
         self.sa_session.add( quota )
         self.sa_session.flush()
         message = "Quota '%s' is now '%s'" % ( quota.name, quota.operation + quota.display_amount )
         return message
예제 #17
0
 def _set_quota_default( self, quota, params ):
     if params.default != 'no' and params.default not in self.app.model.DefaultQuotaAssociation.types.__dict__.values():
         raise ActionInputError( 'Enter a valid default type.' )
     else:
         if params.default != 'no':
             self.app.quota_agent.set_default_quota( params.default, quota )
             message = "Quota '%s' is now the default for %s users" % ( quota.name, params.default )
         else:
             if quota.default:
                 message = "Quota '%s' is no longer the default for %s users." % ( quota.name, quota.default[0].type )
                 for dqa in quota.default:
                     self.sa_session.delete( dqa )
                 self.sa_session.flush()
             else:
                 message = "Quota '%s' is not a default." % quota.name
         return message
예제 #18
0
파일: quotas.py 프로젝트: mvdbeek/galaxy
 def set_quota_default(self, quota, params) -> str:
     if params.default != 'no' and params.default not in model.DefaultQuotaAssociation.types.__members__.values():
         raise ActionInputError('Enter a valid default type.')
     else:
         if params.default != 'no':
             self.quota_agent.set_default_quota(params.default, quota)
             message = f"Quota '{quota.name}' is now the default for {params.default} users."
         else:
             if quota.default:
                 message = f"Quota '{quota.name}' is no longer the default for {quota.default[0].type} users."
                 for dqa in quota.default:
                     self.sa_session.delete(dqa)
                 self.sa_session.flush()
             else:
                 message = f"Quota '{quota.name}' is not a default."
         return message
예제 #19
0
파일: cloud.py 프로젝트: msauria/galaxy
    def get(self, trans, payload, **kwargs):
        """
        POST /api/cloud/storage/get

        gets given objects from a given cloud-based bucket to a Galaxy history.

        :type  trans: galaxy.webapps.base.webapp.GalaxyWebTransaction
        :param trans: Galaxy web transaction

        :type  payload: dict
        :param payload: A dictionary structure containing the following keys:

            *   history_id:    the (encoded) id of history to which the object should be received to.
            *   bucket:        the name of a bucket from which data should be fetched from (e.g., a bucket name on AWS S3).
            *   objects:       a list of the names of objects to be fetched.
            *   authz_id:      the encoded ID of CloudAuthz to be used for authorizing access to the resource
                               provider. You may get a list of the defined authorizations via
                               `/api/cloud/authz`. Also, you can use `/api/cloud/authz/create` to define a
                               new authorization.
            *   input_args     [Optional; default value is an empty dict] a dictionary containing the following keys:

                                **   `dbkey`:           [Optional; default value: is `?`]
                                                        Sets the genome (e.g., `hg19`) of the objects being
                                                        fetched to Galaxy.

                                **   `file_type`:       [Optional; default value is `auto`]
                                                        Sets the Galaxy datatype (e.g., `bam`) for the
                                                        objects being fetched to Galaxy. See the following
                                                        link for a complete list of Galaxy data types:
                                                        https://galaxyproject.org/learn/datatypes/

                                **   `space_to_tab`:    [Optional; default value is `False`]
                                                        A boolean value ("true" or "false") that sets if spaces
                                                        should be converted to tab in the objects being
                                                        fetched to Galaxy. Applicable only if `to_posix_lines`
                                                        is True

                                **   `to_posix_lines`:  [Optional; default value is `Yes`]
                                                        A boolean value ("true" or "false"); if "Yes", converts
                                                        universal line endings to POSIX line endings. Set to
                                                        "False" if you upload a gzip, bz2 or zip archive
                                                        containing a binary file.

        :param kwargs:

        :rtype:  dictionary
        :return: a dictionary containing a `summary` view of the datasets copied from the given cloud-based storage.

        """
        if not isinstance(payload, dict):
            raise ActionInputError(
                'Invalid payload data type. The payload is expected to be a dictionary, '
                'but received data of type `{}`.'.format(str(type(payload))))

        missing_arguments = []
        encoded_history_id = payload.get("history_id", None)
        if encoded_history_id is None:
            missing_arguments.append("history_id")

        bucket = payload.get("bucket", None)
        if bucket is None:
            missing_arguments.append("bucket")

        objects = payload.get("objects", None)
        if objects is None:
            missing_arguments.append("objects")

        encoded_authz_id = payload.get("authz_id", None)
        if encoded_authz_id is None:
            missing_arguments.append("authz_id")

        if len(missing_arguments) > 0:
            raise ActionInputError(
                f"The following required arguments are missing in the payload: {missing_arguments}"
            )

        try:
            history_id = self.decode_id(encoded_history_id)
        except exceptions.MalformedId as e:
            raise ActionInputError(f'Invalid history ID. {e}')

        try:
            authz_id = self.decode_id(encoded_authz_id)
        except exceptions.MalformedId as e:
            raise ActionInputError(f'Invalid authz ID. {e}')

        if not isinstance(objects, list):
            raise ActionInputError(
                'The `objects` should be a list, but received an object of type {} instead.'
                .format(type(objects)))

        datasets = self.cloud_manager.get(trans=trans,
                                          history_id=history_id,
                                          bucket_name=bucket,
                                          objects=objects,
                                          authz_id=authz_id,
                                          input_args=payload.get(
                                              "input_args", None))
        rtv = []
        for dataset in datasets:
            rtv.append(
                self.datasets_serializer.serialize_to_view(dataset,
                                                           view='summary'))
        return rtv
예제 #20
0
파일: cloud.py 프로젝트: msauria/galaxy
    def send(self, trans, payload, **kwargs):
        """
        POST /api/cloud/storage/send

        Sends given dataset(s) in a given history to a given cloud-based bucket. Each dataset is named
        using the label assigned to the dataset in the given history (see `HistoryDatasetAssociation.name`).
        If no dataset ID is given, this API sends all the datasets belonging to a given history to a given
        cloud-based bucket.

        :type  trans: galaxy.webapps.base.webapp.GalaxyWebTransaction
        :param trans: Galaxy web transaction

        :type  payload: dictionary
        :param payload: A dictionary structure containing the following keys:

            *   history_id              the (encoded) id of history from which the object should be downloaed.
            *   bucket:                 the name of a bucket to which data should be sent (e.g., a bucket name on AWS S3).
            *   authz_id:               the encoded ID of CloudAuthz to be used for authorizing access to the resource
                                        provider. You may get a list of the defined authorizations via
                                        `/api/cloud/authz`. Also, you can use `/api/cloud/authz/create` to define a
                                        new authorization.
            *   dataset_ids:            [Optional; default: None]
                                        A list of encoded dataset IDs belonging to the specified history
                                        that should be sent to the given bucket. If not provided, Galaxy sends
                                        all the datasets belonging the specified history.
            *   overwrite_existing:     [Optional; default: False]
                                        A boolean value. If set to "True", and an object with same name of the dataset
                                        to be sent already exist in the bucket, Galaxy replaces the existing object
                                        with the dataset to be sent. If set to "False", Galaxy appends datetime
                                        to the dataset name to prevent overwriting an existing object.

        :rtype:     dictionary
        :return:    Information about the (un)successfully submitted dataset send jobs,
                    containing the following keys:

                        *   `bucket_name`:                  The name of bucket to which the listed datasets are queued
                                                            to be sent.
                        *   `sent_dataset_labels`:          A list of JSON objects with the following key-value pair:
                            **  `object`:                   The name of object is queued to be created.
                            **  `job_id`:                   The id of the queued send job.

                        *   `failed_dataset_labels`:        A list of JSON objects with the following key-value pair
                                                            representing the datasets Galaxy failed to create
                                                            (and queue) send job for:

                            **  `object`:                   The name of object is queued to be created.
                            **  `error`:                    A descriptive error message.

        """
        missing_arguments = []
        encoded_history_id = payload.get("history_id", None)
        if encoded_history_id is None:
            missing_arguments.append("history_id")

        bucket = payload.get("bucket", None)
        if bucket is None:
            missing_arguments.append("bucket")

        encoded_authz_id = payload.get("authz_id", None)
        if encoded_authz_id is None:
            missing_arguments.append("authz_id")

        if len(missing_arguments) > 0:
            raise ActionInputError(
                f"The following required arguments are missing in the payload: {missing_arguments}"
            )

        try:
            history_id = self.decode_id(encoded_history_id)
        except exceptions.MalformedId as e:
            raise ActionInputError(f'Invalid history ID. {e}')

        try:
            authz_id = self.decode_id(encoded_authz_id)
        except exceptions.MalformedId as e:
            raise ActionInputError(f'Invalid authz ID. {e}')

        encoded_dataset_ids = payload.get("dataset_ids", None)
        if encoded_dataset_ids is None:
            dataset_ids = None
        else:
            dataset_ids = set()
            invalid_dataset_ids = []
            for encoded_id in encoded_dataset_ids:
                try:
                    dataset_ids.add(self.decode_id(encoded_id))
                except exceptions.MalformedId:
                    invalid_dataset_ids.append(encoded_id)
            if len(invalid_dataset_ids) > 0:
                raise ActionInputError(
                    "The following provided dataset IDs are invalid, please correct them and retry. "
                    "{}".format(invalid_dataset_ids))

        log.info(
            msg=
            "Received api/send request for `{}` datasets using authnz with id `{}`, and history `{}`."
            "".format(
                "all the dataset in the given history" if not dataset_ids else
                len(dataset_ids), authz_id, history_id))

        sent, failed = self.cloud_manager.send(trans=trans,
                                               history_id=history_id,
                                               bucket_name=bucket,
                                               authz_id=authz_id,
                                               dataset_ids=dataset_ids,
                                               overwrite_existing=payload.get(
                                                   "overwrite_existing",
                                                   False))
        return {
            'sent_dataset_labels': sent,
            'failed_dataset_labels': failed,
            'bucket_name': bucket
        }
예제 #21
0
    def download(self, trans, payload, **kwargs):
        """
        * POST /api/cloud/storage/download
            Downloads a given dataset in a given history to a given cloud-based bucket. Each dataset is named
            using the label assigned to the dataset in the given history (see `HistoryDatasetAssociation.name`).
            If no dataset ID is given, this API copies all the datasets belonging to a given history to a given
            cloud-based bucket.
        :type  trans: galaxy.web.framework.webapp.GalaxyWebTransaction
        :param trans: Galaxy web transaction

        :type  payload: dictionary
        :param payload: A dictionary structure containing the following keys:
            *   history_id              the (encoded) id of history from which the object should be downloaed.
            *   provider:               the name of a cloud-based resource provider (e.g., `aws`, `azure`, or `openstack`).
            *   bucket:                 the name of a bucket to which data should be downloaded (e.g., a bucket name on AWS S3).
            *   credentials:            a dictionary containing all the credentials required to authenticated to the
                                        specified provider (e.g., {"secret_key": YOUR_AWS_SECRET_TOKEN,
                                        "access_key": YOUR_AWS_ACCESS_TOKEN}).
            *   dataset_ids:            [Optional; default: None]
                                        A list of encoded dataset IDs belonging to the specified history
                                        that should be downloaded to the given bucket. If not provided, Galaxy downloads
                                        all the datasets belonging the specified history.
            *   overwrite_existing:     [Optional; default: False]
                                        A boolean value. If set to "True", and an object with same name of the dataset
                                        to be downloaded already exist in the bucket, Galaxy replaces the existing object
                                        with the dataset to be downloaded. If set to "False", Galaxy appends datetime
                                        to the dataset name to prevent overwriting an existing object.

        :param kwargs:

        :rtype:  dictionary
        :return: Information about the downloaded datasets, including downloaded_dataset_labels
                 and destination bucket name.
        """
        missing_arguments = []
        encoded_history_id = payload.get("history_id", None)
        if encoded_history_id is None:
            missing_arguments.append("history_id")

        provider = payload.get("provider", None)
        if provider is None:
            missing_arguments.append("provider")

        bucket = payload.get("bucket", None)
        if bucket is None:
            missing_arguments.append("bucket")

        credentials = payload.get("credentials", None)
        if credentials is None:
            missing_arguments.append("credentials")

        if len(missing_arguments) > 0:
            raise ActionInputError(
                "The following required arguments are missing in the payload: {}"
                .format(missing_arguments))

        try:
            history_id = self.decode_id(encoded_history_id)
        except exceptions.MalformedId as e:
            raise ActionInputError('Invalid history ID. {}'.format(e))

        encoded_dataset_ids = payload.get("dataset_ids", None)
        if encoded_dataset_ids is None:
            dataset_ids = None
        else:
            dataset_ids = set()
            invalid_dataset_ids = []
            for encoded_id in encoded_dataset_ids:
                try:
                    dataset_ids.add(self.decode_id(encoded_id))
                except exceptions.MalformedId:
                    invalid_dataset_ids.append(encoded_id)
            if len(invalid_dataset_ids) > 0:
                raise ActionInputError(
                    "The following provided dataset IDs are invalid, please correct them and retry. "
                    "{}".format(invalid_dataset_ids))

        uploaded = self.cloud_manager.download(trans=trans,
                                               history_id=history_id,
                                               provider=provider,
                                               bucket_name=bucket,
                                               credentials=credentials,
                                               dataset_ids=dataset_ids,
                                               overwrite_existing=payload.get(
                                                   "overwrite_existing",
                                                   False))
        return {'downloaded_dataset_labels': uploaded, 'bucket_name': bucket}
예제 #22
0
    def create(self, trans, payload, **kwargs):
        """
        * POST /api/cloud/authz
            Request to store the payload as a cloudauthz (cloud authorization) configuration for a user.

        :type  trans: galaxy.webapps.base.webapp.GalaxyWebTransaction
        :param trans: Galaxy web transaction

        :type payload: dict
        :param payload: A dictionary structure containing the following keys:
            *   provider:       the cloud-based resource provider to which this configuration belongs to.

            *   config:         a dictionary containing all the configuration required to request temporary credentials
                                from the provider. See the following page for details:
                                https://galaxyproject.org/cloud/authnz/

            *   authn_id:       the (encoded) ID of a third-party authentication of a user. To have this ID, user must
                                have logged-in to this Galaxy server using third-party identity (e.g., Google), or has
                                associated his/her Galaxy account with a third-party OIDC-based identity. See this page:
                                https://galaxyproject.org/admin/authentication/

            *   description:    [Optional] a brief description for this configuration.

        :param kwargs: empty dict

        :rtype: dict
        :return: a dictionary with the following kvp:
            *   status:     HTTP response code
            *   message:    A message complementary to the response code.
        """
        msg_template = "Rejected user `" + str(
            trans.user.id
        ) + "`'s request to create cloudauthz config because of {}."
        if not isinstance(payload, dict):
            raise ActionInputError(
                'Invalid payload data type. The payload is expected to be a dictionary, but '
                'received data of type `{}`.'.format(str(type(payload))))

        missing_arguments = []
        provider = payload.get('provider', None)
        if provider is None:
            missing_arguments.append('provider')

        config = payload.get('config', None)
        if config is None:
            missing_arguments.append('config')

        authn_id = payload.get('authn_id', None)
        if authn_id is None and provider.lower() not in ["azure", "gcp"]:
            missing_arguments.append('authn_id')

        if len(missing_arguments) > 0:
            log.debug(
                msg_template.format(
                    "missing required config {}".format(missing_arguments)))
            raise RequestParameterMissingException(
                'The following required arguments are missing in the payload: '
                '{}'.format(missing_arguments))

        description = payload.get("description", "")

        if not isinstance(config, dict):
            log.debug(
                msg_template.format(
                    "invalid config type `{}`, expect `dict`".format(
                        type(config))))
            raise RequestParameterInvalidException(
                'Invalid type for the required `config` variable; expect `dict` '
                'but received `{}`.'.format(type(config)))
        if authn_id:
            try:
                authn_id = self.decode_id(authn_id)
            except Exception:
                log.debug(
                    msg_template.format("cannot decode authn_id `" +
                                        str(authn_id) + "`"))
                raise MalformedId('Invalid `authn_id`!')

            try:
                trans.app.authnz_manager.can_user_assume_authn(trans, authn_id)
            except Exception as e:
                raise e

        # No two authorization configuration with
        # exact same key/value should exist.
        for ca in trans.user.cloudauthzs:
            if ca.equals(trans.user.id, provider, authn_id, config):
                log.debug(
                    "Rejected user `{}`'s request to create cloud authorization because a similar config "
                    "already exists.".format(trans.user.id))
                raise ActionInputError(
                    "A similar cloud authorization configuration is already defined."
                )

        try:
            new_cloudauthz = self.cloudauthz_manager.create(
                user_id=trans.user.id,
                provider=provider,
                config=config,
                authn_id=authn_id,
                description=description)
            view = self.cloudauthz_serializer.serialize_to_view(
                new_cloudauthz,
                trans=trans,
                **self._parse_serialization_params(kwargs, 'summary'))
            log.debug(
                'Created a new cloudauthz record for the user id `{}` '.format(
                    str(trans.user.id)))
            return view
        except Exception as e:
            log.exception(
                msg_template.format(
                    "exception while creating the new cloudauthz record"))
            raise InternalServerError(
                'An unexpected error has occurred while responding to the create request of the '
                'cloudauthz API.' + unicodify(e))
예제 #23
0
    def upload(self, trans, payload, **kwargs):
        """
        * POST /api/cloud/storage/upload
            Uploads given objects from a given cloud-based bucket to a Galaxy history.
        :type  trans: galaxy.web.framework.webapp.GalaxyWebTransaction
        :param trans: Galaxy web transaction

        :type  payload: dict
        :param payload: A dictionary structure containing the following keys:
            *   history_id:    the (encoded) id of history to which the object should be uploaded to.
            *   provider:      the name of a cloud-based resource provided (e.g., `aws`, `azure`, or `openstack`).
            *   bucket:        the name of a bucket from which data should be uploaded from (e.g., a bucket name on AWS S3).
            *   objects:       a list of the names of objects to be uploaded.
            *   credentials:   a dictionary containing all the credentials required to authenticated to the
            specified provider (e.g., {"secret_key": YOUR_AWS_SECRET_TOKEN, "access_key": YOUR_AWS_ACCESS_TOKEN}).
            *   input_args     [Optional; default value is an empty dict] a dictionary containing the following keys:

                                **   `dbkey`:           [Optional; default value: is `?`]
                                                        Sets the genome (e.g., `hg19`) of the objects being
                                                        uploaded to Galaxy.

                                **   `file_type`:       [Optional; default value is `auto`]
                                                        Sets the Galaxy datatype (e.g., `bam`) for the
                                                        objects being uploaded to Galaxy. See the following
                                                        link for a complete list of Galaxy data types:
                                                        https://galaxyproject.org/learn/datatypes/

                                **   `space_to_tab`:    [Optional; default value is `False`]
                                                        A boolean value ("true" or "false") that sets if spaces
                                                        should be converted to tab in the objects being
                                                        uploaded to Galaxy. Applicable only if `to_posix_lines`
                                                        is True

                                **   `to_posix_lines`:  [Optional; default value is `Yes`]
                                                        A boolean value ("true" or "false"); if "Yes", converts
                                                        universal line endings to POSIX line endings. Set to
                                                        "False" if you upload a gzip, bz2 or zip archive
                                                        containing a binary file.

        :param kwargs:

        :rtype:  dictionary
        :return: a dictionary containing a `summary` view of the datasets copied from the given cloud-based storage.
        """
        if not isinstance(payload, dict):
            raise ActionInputError(
                'Invalid payload data type. The payload is expected to be a dictionary, '
                'but received data of type `{}`.'.format(str(type(payload))))

        missing_arguments = []
        encoded_history_id = payload.get("history_id", None)
        if encoded_history_id is None:
            missing_arguments.append("history_id")

        provider = payload.get("provider", None)
        if provider is None:
            missing_arguments.append("provider")

        bucket = payload.get("bucket", None)
        if bucket is None:
            missing_arguments.append("bucket")

        objects = payload.get("objects", None)
        if objects is None:
            missing_arguments.append("objects")

        credentials = payload.get("credentials", None)
        if credentials is None:
            missing_arguments.append("credentials")

        if len(missing_arguments) > 0:
            raise ActionInputError(
                "The following required arguments are missing in the payload: {}"
                .format(missing_arguments))

        try:
            history_id = self.decode_id(encoded_history_id)
        except exceptions.MalformedId as e:
            raise ActionInputError('Invalid history ID. {}'.format(e))

        if not isinstance(objects, list):
            raise ActionInputError(
                'The `objects` should be a list, but received an object of type {} instead.'
                .format(type(objects)))

        datasets = self.cloud_manager.upload(trans=trans,
                                             history_id=history_id,
                                             provider=provider,
                                             bucket_name=bucket,
                                             objects=objects,
                                             credentials=credentials,
                                             input_args=payload.get(
                                                 "input_args", None))
        rtv = []
        for dataset in datasets:
            rtv.append(
                self.datasets_serializer.serialize_to_view(dataset,
                                                           view='summary'))
        return rtv