예제 #1
0
def replicate_resource_bag_to_user_zone(user, res_id):
    """
    Replicate resource bag to iRODS user zone
    Args:
        user: the requesting user
        res_id: the resource id with its bag to be replicated to iRODS user zone

    Returns:
    None, but exceptions will be raised if there is an issue with iRODS operation
    """
    # do on-demand bag creation

    res = utils.get_resource_by_shortkey(res_id)
    res_coll = res.root_path
    istorage = res.get_irods_storage()
    bag_modified_flag = True
    # needs to check whether res_id collection exists before getting/setting AVU on it to
    # accommodate the case where the very same resource gets deleted by another request when
    # it is getting downloaded
    if istorage.exists(res_coll):
        bag_modified = istorage.getAVU(res_coll, 'bag_modified')

        # make sure bag_modified_flag is set to False only if bag exists and bag_modified AVU
        # is False; otherwise, bag_modified_flag will take the default True value so that the
        # bag will be created or recreated
        if bag_modified:
            if bag_modified.lower() == "false":
                bag_file_name = res_id + '.zip'
                if res.resource_federation_path:
                    bag_full_path = os.path.join(res.resource_federation_path, 'bags',
                                                 bag_file_name)
                else:
                    bag_full_path = os.path.join('bags', bag_file_name)

                if istorage.exists(bag_full_path):
                    bag_modified_flag = False

        if bag_modified_flag:
            # import here to avoid circular import issue
            from hs_core.tasks import create_bag_by_irods
            status = create_bag_by_irods(res_id)
            if not status:
                # bag fails to be created successfully
                raise SessionException(-1, '', 'The resource bag fails to be created '
                                               'before bag replication')

        # do replication of the resource bag to irods user zone
        if not res.resource_federation_path:
            istorage.set_fed_zone_session()
        src_file = res.bag_path
        tgt_file = '/{userzone}/home/{username}/{resid}.zip'.format(
            userzone=settings.HS_USER_IRODS_ZONE, username=user.username, resid=res_id)
        fsize = istorage.size(src_file)
        utils.validate_user_quota(user, fsize)
        istorage.copyFiles(src_file, tgt_file)
        update_quota_usage(user=user)
    else:
        raise ValidationError("Resource {} does not exist in iRODS".format(res.short_id))
예제 #2
0
    def create_irods_user_in_user_zone(self):
        """Create corresponding irods account in user zone."""
        try:
            exec_cmd = "{0} {1} {2}".format(settings.HS_USER_ZONE_PROXY_USER_CREATE_USER_CMD,
                                            self.user.username, self.user.username)
            output = run_ssh_command(host=settings.HS_USER_ZONE_HOST,
                                     uname=settings.HS_USER_ZONE_PROXY_USER,
                                     pwd=settings.HS_USER_ZONE_PROXY_USER_PWD,
                                     exec_cmd=exec_cmd)
            if output:
                if 'ERROR:' in output.upper():
                    # irods account failed to create
                    self.assertRaises(SessionException(-1, output, output))

            user_profile = UserProfile.objects.filter(user=self.user).first()
            user_profile.create_irods_user_account = True
            user_profile.save()
        except Exception as ex:
            self.assertRaises(SessionException(-1, ex.message, ex.message))
예제 #3
0
    def delete_irods_user_in_user_zone(self):
        """Delete irods test user in user zone."""
        try:
            exec_cmd = "{0} {1}".format(settings.HS_USER_ZONE_PROXY_USER_DELETE_USER_CMD,
                                        self.user.username)
            output = run_ssh_command(host=settings.HS_USER_ZONE_HOST,
                                     uname=settings.HS_USER_ZONE_PROXY_USER,
                                     pwd=settings.HS_USER_ZONE_PROXY_USER_PWD,
                                     exec_cmd=exec_cmd)
            if output:
                if 'ERROR:' in output.upper():
                    # there is an error from icommand run, report the error
                    self.assertRaises(SessionException(-1, output, output))

            user_profile = UserProfile.objects.filter(user=self.user).first()
            user_profile.create_irods_user_account = False
            user_profile.save()
        except Exception as ex:
            # there is an error from icommand run, report the error
            self.assertRaises(SessionException(-1, ex.message, ex.message))
예제 #4
0
    def create_irods_user_in_user_zone(self):
        """Create corresponding irods account in user zone."""
        try:
            exec_cmd = "{0} {1} {2}".format(
                settings.LINUX_ADMIN_USER_CREATE_USER_IN_USER_ZONE_CMD,
                self.user.username, self.user.username)
            output = run_ssh_command(
                host=settings.HS_USER_ZONE_HOST,
                uname=settings.LINUX_ADMIN_USER_FOR_HS_USER_ZONE,
                pwd=settings.LINUX_ADMIN_USER_PWD_FOR_HS_USER_ZONE,
                exec_cmd=exec_cmd)
            for out_str in output:
                if 'ERROR:' in out_str.upper():
                    # irods account failed to create
                    self.assertRaises(SessionException(-1, out_str, out_str))

            user_profile = UserProfile.objects.filter(user=self.user).first()
            user_profile.create_irods_user_account = True
            user_profile.save()
        except Exception as ex:
            self.assertRaises(SessionException(-1, str(ex), str(ex)))
예제 #5
0
def create_bag_by_irods(resource_id, create_zip=True):
    """Create a resource bag on iRODS side by running the bagit rule and ibun zip.
    This function runs as a celery task, invoked asynchronously so that it does not
    block the main web thread when it creates bags for very large files which will take some time.
    :param
    resource_id: the resource uuid that is used to look for the resource to create the bag for.
    :param create_zip: defaults to True, set to false to create bagit files without zipping
    :return: bag_url if bag creation operation succeeds or
             raise an exception if resource does not exist or any other issues that prevent bags from being created.
    """
    res = utils.get_resource_by_shortkey(resource_id)

    istorage = res.get_irods_storage()

    bag_path = res.bag_path

    metadata_dirty = res.getAVU('metadata_dirty')
    metadata_dirty = metadata_dirty is None or metadata_dirty
    # if metadata has been changed, then regenerate metadata xml files
    if metadata_dirty:
        create_bag_metadata_files(res)

    bag_modified = res.getAVU("bag_modified")
    bag_modified = bag_modified is None or bag_modified
    if metadata_dirty or bag_modified:
        create_bagit_files_by_irods(res, istorage)
        res.setAVU("bag_modified", False)

    if create_zip:
        irods_bagit_input_path = res.get_irods_path(resource_id,
                                                    prepend_short_id=False)

        # only proceed when the resource is not deleted potentially by another request
        # when being downloaded
        is_exist = istorage.exists(irods_bagit_input_path)
        if is_exist:
            try:
                if istorage.exists(bag_path):
                    istorage.delete(bag_path)
                istorage.zipup(irods_bagit_input_path, bag_path)
                if res.raccess.published:
                    # compute checksum to meet DataONE distribution requirement
                    chksum = istorage.checksum(bag_path)
                    res.bag_checksum = chksum
                return res.bag_url
            except SessionException as ex:
                raise SessionException(-1, '', ex.stderr)
        else:
            raise ObjectDoesNotExist(
                'Resource {} does not exist.'.format(resource_id))
예제 #6
0
def add_file_to_resource(resource,
                         f,
                         folder=None,
                         fed_res_file_name_or_path='',
                         fed_copy_or_move=None):
    """
    Add a ResourceFile to a Resource.  Adds the 'format' metadata element to the resource.
    :param resource: Resource to which file should be added
    :param f: File-like object to add to a resource
    :param folder: name of the folder path to which the file needs be uploaded
    :param fed_res_file_name_or_path: the logical file name of the resource content file for
                                      federated iRODS resource or the federated zone name;
                                      By default, it is empty. A non-empty value indicates
                                      the file needs to be added into the federated zone, either
                                      from local disk where f holds the uploaded file from local
                                      disk, or from the federated zone directly where f is empty
                                      but fed_res_file_name_or_path has the whole data object
                                      iRODS path in the federated zone
    :param fed_copy_or_move: indicate whether the file should be copied or moved from private user
                             account to proxy user account in federated zone; A value of 'copy'
                             indicates copy is needed, a value of 'move' indicates no copy, but
                             the file will be moved from private user account to proxy user account.
                             The default value is None, which indicates N/A, or not applicable,
                             since the files do not come from a federated zone, and this copy or
                             move operation is not applicable, but any value other
                             than 'copy' or 'move' is regarded as N/A.

    :return: The identifier of the ResourceFile added.
    """
    if f:
        file_format_type = get_file_mime_type(f.name)
        if fed_res_file_name_or_path:
            ret = ResourceFile.objects.create(
                content_object=resource,
                file_folder=folder,
                resource_file=None,
                fed_resource_file=File(f)
                if not isinstance(f, UploadedFile) else f)
        else:
            ret = ResourceFile.objects.create(
                content_object=resource,
                file_folder=folder,
                resource_file=File(f)
                if not isinstance(f, UploadedFile) else f,
                fed_resource_file=None)

    elif fed_res_file_name_or_path and (fed_copy_or_move == 'copy'
                                        or fed_copy_or_move == 'move'):
        size = get_fed_zone_file_size(fed_res_file_name_or_path)
        file_format_type = get_file_mime_type(fed_res_file_name_or_path)
        ret = ResourceFile.objects.create(
            content_object=resource,
            resource_file=None,
            fed_resource_file=None,
            fed_resource_file_name_or_path=fed_res_file_name_or_path,
            fed_resource_file_size=size)
        try:
            from_fname = fed_res_file_name_or_path
            filename = from_fname.rsplit('/')[-1]
            istorage = resource.get_irods_storage()
            if resource.resource_federation_path:
                if folder:
                    to_fname = os.path.join(resource.resource_federation_path,
                                            resource.short_id, 'data',
                                            'contents', folder, filename)
                else:
                    to_fname = os.path.join(resource.resource_federation_path,
                                            resource.short_id, 'data',
                                            'contents', filename)
            else:
                if folder:
                    to_fname = os.path.join(resource.short_id, 'data',
                                            'contents', folder, filename)
                else:
                    to_fname = os.path.join(resource.short_id, 'data',
                                            'contents', filename)

            if fed_copy_or_move == 'copy':
                istorage.copyFiles(from_fname, to_fname)
            else:
                istorage.moveFile(from_fname, to_fname)
            # update file path now that file has been copied or moved to HydroShare
            # proxy account space
            ret.fed_resource_file_name_or_path = 'data/contents/{file_name}'.format(
                file_name=filename)
            ret.save()
        except SessionException as ex:
            # delete the file added if there is any exception
            ret.delete()
            # raise the exception for the calling function to inform the error on the page interface
            raise SessionException(ex.exitcode, ex.stdout, ex.stderr)
    else:
        raise ValueError(
            'Invalid input parameter is passed into this add_file_to_resource() '
            'function')

    # add format metadata element if necessary
    if file_format_type not in [
            mime.value for mime in resource.metadata.formats.all()
    ]:
        resource.metadata.create_element('format', value=file_format_type)

    return ret
예제 #7
0
def add_file_to_resource(resource,
                         f,
                         folder=None,
                         source_name='',
                         source_size=0,
                         move=False,
                         is_file_reference=False):
    """
    Add a ResourceFile to a Resource.  Adds the 'format' metadata element to the resource.
    :param resource: Resource to which file should be added
    :param f: File-like object to add to a resource
    :param source_name: the logical file name of the resource content file for
                        federated iRODS resource or the federated zone name;
                        By default, it is empty. A non-empty value indicates
                        the file needs to be added into the federated zone, either
                        from local disk where f holds the uploaded file from local
                        disk, or from the federated zone directly where f is empty
                        but source_name has the whole data object
                        iRODS path in the federated zone
    :param source_size: the size of the reference file in source_name if is_file_reference is True; otherwise, it is
                        set to 0 and useless.
    :param move: indicate whether the file should be copied or moved from private user
                 account to proxy user account in federated zone; A value of False
                 indicates copy is needed, a value of True indicates no copy, but
                 the file will be moved from private user account to proxy user account.
                 The default value is False.
    :param is_file_reference: indicate whether the file being added is a reference to an external
                              file stored in an external zone or URL. source_name will hold
                              the reference file path or url
    :return: The identifier of the ResourceFile added.
    """

    # importing here to avoid circular import
    from hs_file_types.models import GenericLogicalFile

    if f:

        openfile = File(f) if not isinstance(f, UploadedFile) else f
        ret = ResourceFile.create(resource,
                                  openfile,
                                  folder=folder,
                                  source=None,
                                  move=False)

        # add format metadata element if necessary
        file_format_type = get_file_mime_type(f.name)

    elif source_name:
        try:
            # create from existing iRODS file
            ret = ResourceFile.create(resource,
                                      None,
                                      folder=folder,
                                      source=source_name,
                                      source_size=source_size,
                                      is_file_reference=is_file_reference,
                                      move=move)
        except SessionException as ex:
            try:
                ret.delete()
            except Exception:
                pass
            # raise the exception for the calling function to inform the error on the page interface
            raise SessionException(ex.exitcode, ex.stdout, ex.stderr)

        # add format metadata element if necessary
        file_format_type = get_file_mime_type(source_name)

    else:
        raise ValueError(
            'Invalid input parameter is passed into this add_file_to_resource() '
            'function')

    # TODO: generate this from data in ResourceFile rather than extension
    if file_format_type not in [
            mime.value for mime in resource.metadata.formats.all()
    ]:
        resource.metadata.create_element('format', value=file_format_type)

    # if a file gets added successfully to composite resource, then better to set the generic
    # logical file here
    if resource.resource_type == "CompositeResource":
        logical_file = GenericLogicalFile.create()
        ret.logical_file_content_object = logical_file
        ret.save()

    return ret
예제 #8
0
파일: utils.py 프로젝트: e7dal/hydroshare
def add_file_to_resource(resource,
                         f,
                         folder=None,
                         source_name='',
                         check_target_folder=False,
                         add_to_aggregation=True):
    """
    Add a ResourceFile to a Resource.  Adds the 'format' metadata element to the resource.
    :param  resource: Resource to which file should be added
    :param  f: File-like object to add to a resource
    :param  folder: folder at which the file will live
    :param  source_name: the logical file name of the resource content file for
                        federated iRODS resource or the federated zone name;
                        By default, it is empty. A non-empty value indicates
                        the file needs to be added into the federated zone, either
                        from local disk where f holds the uploaded file from local
                        disk, or from the federated zone directly where f is empty
                        but source_name has the whole data object
                        iRODS path in the federated zone
    :param  check_target_folder: if true and the resource is a composite resource then uploading
    a file to the specified folder will be validated before adding the file to the resource
    :param  add_to_aggregation: if true and the resource is a composite resource then the file
    being added to the resource also will be added to a fileset aggregation if such an aggregation
    exists in the file path
    :return: The identifier of the ResourceFile added.
    """

    # validate parameters
    if check_target_folder and resource.resource_type != 'CompositeResource':
        raise ValidationError(
            "Resource must be a CompositeResource for validating target folder"
        )

    if f:
        if check_target_folder and folder is not None:
            tgt_full_upload_path = os.path.join(resource.file_path, folder)
            if not resource.can_add_files(
                    target_full_path=tgt_full_upload_path):
                err_msg = "File can't be added to this folder which represents an aggregation"
                raise ValidationError(err_msg)
        openfile = File(f) if not isinstance(f, UploadedFile) else f
        ret = ResourceFile.create(resource,
                                  openfile,
                                  folder=folder,
                                  source=None)
        if add_to_aggregation:
            if folder is not None and resource.resource_type == 'CompositeResource':
                aggregation = resource.get_fileset_aggregation_in_path(folder)
                if aggregation is not None:
                    # make the added file part of the fileset aggregation
                    aggregation.add_resource_file(ret)

        # add format metadata element if necessary
        file_format_type = get_file_mime_type(f.name)

    elif source_name:
        try:
            # create from existing iRODS file
            ret = ResourceFile.create(resource,
                                      None,
                                      folder=folder,
                                      source=source_name)
        except SessionException as ex:
            try:
                ret.delete()
            except Exception:
                pass
            # raise the exception for the calling function to inform the error on the page interface
            raise SessionException(ex.exitcode, ex.stdout, ex.stderr)

        # add format metadata element if necessary
        file_format_type = get_file_mime_type(source_name)

    else:
        raise ValueError(
            'Invalid input parameter is passed into this add_file_to_resource() '
            'function')

    # TODO: generate this from data in ResourceFile rather than extension
    if file_format_type not in [
            mime.value for mime in resource.metadata.formats.all()
    ]:
        resource.metadata.create_element('format', value=file_format_type)
    ret.calculate_size()

    return ret
예제 #9
0
def add_file_to_resource(resource, f, folder=None, source_name='', move=False):
    """
    Add a ResourceFile to a Resource.  Adds the 'format' metadata element to the resource.
    :param resource: Resource to which file should be added
    :param f: File-like object to add to a resource
    :param source_name: the logical file name of the resource content file for
                        federated iRODS resource or the federated zone name;
                        By default, it is empty. A non-empty value indicates
                        the file needs to be added into the federated zone, either
                        from local disk where f holds the uploaded file from local
                        disk, or from the federated zone directly where f is empty
                        but source_name has the whole data object
                        iRODS path in the federated zone
    :param move: indicate whether the file should be copied or moved from private user
                 account to proxy user account in federated zone; A value of False
                 indicates copy is needed, a value of True indicates no copy, but
                 the file will be moved from private user account to proxy user account.
                 The default value is False.

    :return: The identifier of the ResourceFile added.
    """
    if f:

        openfile = File(f) if not isinstance(f, UploadedFile) else f
        ret = ResourceFile.create(resource,
                                  openfile,
                                  folder=folder,
                                  source=None,
                                  move=False)

        # add format metadata element if necessary
        file_format_type = get_file_mime_type(f.name)

    elif source_name:
        try:
            # create from existing iRODS file
            ret = ResourceFile.create(resource,
                                      None,
                                      folder=folder,
                                      source=source_name,
                                      move=move)
        except SessionException as ex:
            try:
                ret.delete()
            except Exception:
                pass
            # raise the exception for the calling function to inform the error on the page interface
            raise SessionException(ex.exitcode, ex.stdout, ex.stderr)

        # add format metadata element if necessary
        file_format_type = get_file_mime_type(source_name)

    else:
        raise ValueError(
            'Invalid input parameter is passed into this add_file_to_resource() '
            'function')

    # TODO: generate this from data in ResourceFile rather than extension
    if file_format_type not in [
            mime.value for mime in resource.metadata.formats.all()
    ]:
        resource.metadata.create_element('format', value=file_format_type)

    return ret