def __init__(self, config):
        #BEGIN_CONSTRUCTOR
        self.config = config
        self.config['mongo-collection'] = self.MONGO_COLLECTION

        logging.basicConfig(format='%(created)s %(levelname)s: %(message)s',
                            level=logging.INFO)

        self.handler = Handler(self.config)
        #END_CONSTRUCTOR
        pass
    def __init__(self, config):
        #BEGIN_CONSTRUCTOR
        self.config = config
        self.config['mongo-collection'] = self.MONGO_COLLECTION
        self.config['mongo-hid-counter-collection'] = self.MONGO_HID_COUNTER_COLLECTION
        self.config.setdefault('mongo-authmechanism', self.MONGO_AUTHMECHANISM)

        logging.basicConfig(format='%(created)s %(levelname)s: %(message)s',
                            level=logging.INFO)

        self.handler = Handler(self.config)
        #END_CONSTRUCTOR
        pass
Esempio n. 3
0
    def setUpClass(cls):
        cls.token = os.environ.get('KB_AUTH_TOKEN', None)
        config_file = os.environ.get('KB_DEPLOYMENT_CONFIG', None)
        cls.cfg = {}
        config = ConfigParser()
        config.read(config_file)
        for nameval in config.items('AbstractHandle'):
            cls.cfg[nameval[0]] = nameval[1]
        cls.cfg['admin-token'] = cls.token
        cls.cfg['mongo-collection'] = 'handle'
        cls.cfg['mongo-hid-counter-collection'] = 'handle_id_counter'
        cls.cfg['mongo-authmechanism'] = 'DEFAULT'

        # Getting username from Auth profile for token
        authServiceUrl = cls.cfg['auth-service-url']
        auth_client = _KBaseAuth(authServiceUrl)
        cls.user_id = auth_client.get_user(cls.token)
        cls.shock_url = cls.cfg['shock-url']

        cls.mongo_helper = MongoHelper()
        cls.my_client = cls.mongo_helper.create_test_db(
            db=cls.cfg['mongo-database'], col=cls.cfg['mongo-collection'])
        cls.handler = Handler(cls.cfg)
        cls.mongo_util = MongoUtil(cls.cfg)

        cls.shock_ids_to_delete = list()
class AbstractHandle:
    '''
    Module Name:
    AbstractHandle

    Module Description:
    A KBase module: AbstractHandle
provides a programmatic access to a remote file store
    '''

    ######## WARNING FOR GEVENT USERS ####### noqa
    # Since asynchronous IO can lead to methods - even the same method -
    # interrupting each other, you must be *very* careful when using global
    # state. A method could easily clobber the state set by another while
    # the latter method is running.
    ######################################### noqa
    VERSION = "1.0.2"
    GIT_URL = "https://github.com/kbase/handle_service2.git"
    GIT_COMMIT_HASH = "33acad4d0a875581704bc868d1f54c3bd2581324"

    #BEGIN_CLASS_HEADER
    MONGO_COLLECTION = 'handle'
    MONGO_HID_COUNTER_COLLECTION = 'handle_id_counter'
    MONGO_AUTHMECHANISM = 'DEFAULT'
    #END_CLASS_HEADER

    # config contains contents of config file in a hash or None if it couldn't
    # be found
    def __init__(self, config):
        #BEGIN_CONSTRUCTOR
        self.config = config
        self.config['mongo-collection'] = self.MONGO_COLLECTION
        self.config['mongo-hid-counter-collection'] = self.MONGO_HID_COUNTER_COLLECTION
        self.config.setdefault('mongo-authmechanism', self.MONGO_AUTHMECHANISM)

        logging.basicConfig(format='%(created)s %(levelname)s: %(message)s',
                            level=logging.INFO)

        self.handler = Handler(self.config)
        #END_CONSTRUCTOR
        pass


    def persist_handle(self, ctx, handle):
        """
        The persist_handle writes the handle to a persistent store that can be later retrieved using the list_handles function.
        :param handle: instance of type "Handle" -> structure: parameter
           "hid" of type "HandleId" (Handle provides a unique reference that
           enables access to the data files through functions provided as
           part of the HandleService. In the case of using shock, the id is
           the node id. In the case of using shock the value of type is
           shock. In the future these values should enumerated. The value of
           url is the http address of the shock server, including the
           protocol (http or https) and if necessary the port. The values of
           remote_md5 and remote_sha1 are those computed on the file in the
           remote data store. These can be used to verify uploads and
           downloads.), parameter "file_name" of String, parameter "id" of
           type "NodeId", parameter "type" of String, parameter "url" of
           String, parameter "remote_md5" of String, parameter "remote_sha1"
           of String
        :returns: instance of String
        """
        # ctx is the context object
        # return variables are: hid
        #BEGIN persist_handle
        logging.info("Start persist handle")

        hid = self.handler.persist_handle(handle, ctx['user_id'])
        #END persist_handle

        # At some point might do deeper type checking...
        if not isinstance(hid, str):
            raise ValueError('Method persist_handle return value ' +
                             'hid is not type str as required.')
        # return the results
        return [hid]

    def hids_to_handles(self, ctx, hids):
        """
        Given a list of handle ids, this function returns a list of handles.
        This method is replaced by fetch_handles_by.
        :param hids: instance of list of type "HandleId" (Handle provides a
           unique reference that enables access to the data files through
           functions provided as part of the HandleService. In the case of
           using shock, the id is the node id. In the case of using shock the
           value of type is shock. In the future these values should
           enumerated. The value of url is the http address of the shock
           server, including the protocol (http or https) and if necessary
           the port. The values of remote_md5 and remote_sha1 are those
           computed on the file in the remote data store. These can be used
           to verify uploads and downloads.)
        :returns: instance of list of type "Handle" -> structure: parameter
           "hid" of type "HandleId" (Handle provides a unique reference that
           enables access to the data files through functions provided as
           part of the HandleService. In the case of using shock, the id is
           the node id. In the case of using shock the value of type is
           shock. In the future these values should enumerated. The value of
           url is the http address of the shock server, including the
           protocol (http or https) and if necessary the port. The values of
           remote_md5 and remote_sha1 are those computed on the file in the
           remote data store. These can be used to verify uploads and
           downloads.), parameter "file_name" of String, parameter "id" of
           type "NodeId", parameter "type" of String, parameter "url" of
           String, parameter "remote_md5" of String, parameter "remote_sha1"
           of String
        """
        # ctx is the context object
        # return variables are: handles
        #BEGIN hids_to_handles
        handles = self.fetch_handles_by(ctx, {'elements': hids, 'field_name': 'hid'})[0]
        #END hids_to_handles

        # At some point might do deeper type checking...
        if not isinstance(handles, list):
            raise ValueError('Method hids_to_handles return value ' +
                             'handles is not type list as required.')
        # return the results
        return [handles]

    def ids_to_handles(self, ctx, ids):
        """
        Given a list of ids, this function returns a list of handles.
        In case of Shock, the list of ids are shock node ids.
        This method is replaced by fetch_handles_by.
        :param ids: instance of list of type "NodeId"
        :returns: instance of list of type "Handle" -> structure: parameter
           "hid" of type "HandleId" (Handle provides a unique reference that
           enables access to the data files through functions provided as
           part of the HandleService. In the case of using shock, the id is
           the node id. In the case of using shock the value of type is
           shock. In the future these values should enumerated. The value of
           url is the http address of the shock server, including the
           protocol (http or https) and if necessary the port. The values of
           remote_md5 and remote_sha1 are those computed on the file in the
           remote data store. These can be used to verify uploads and
           downloads.), parameter "file_name" of String, parameter "id" of
           type "NodeId", parameter "type" of String, parameter "url" of
           String, parameter "remote_md5" of String, parameter "remote_sha1"
           of String
        """
        # ctx is the context object
        # return variables are: handles
        #BEGIN ids_to_handles
        handles = self.fetch_handles_by(ctx, {'elements': ids, 'field_name': 'id'})[0]
        #END ids_to_handles

        # At some point might do deeper type checking...
        if not isinstance(handles, list):
            raise ValueError('Method ids_to_handles return value ' +
                             'handles is not type list as required.')
        # return the results
        return [handles]

    def fetch_handles_by(self, ctx, params):
        """
        This function select records if field column entry is in elements and returns a list of handles.
        :param params: instance of type "FetchHandlesParams" -> structure:
           parameter "elements" of list of String, parameter "field_name" of
           String
        :returns: instance of list of type "Handle" -> structure: parameter
           "hid" of type "HandleId" (Handle provides a unique reference that
           enables access to the data files through functions provided as
           part of the HandleService. In the case of using shock, the id is
           the node id. In the case of using shock the value of type is
           shock. In the future these values should enumerated. The value of
           url is the http address of the shock server, including the
           protocol (http or https) and if necessary the port. The values of
           remote_md5 and remote_sha1 are those computed on the file in the
           remote data store. These can be used to verify uploads and
           downloads.), parameter "file_name" of String, parameter "id" of
           type "NodeId", parameter "type" of String, parameter "url" of
           String, parameter "remote_md5" of String, parameter "remote_sha1"
           of String
        """
        # ctx is the context object
        # return variables are: handles
        #BEGIN fetch_handles_by
        handles = self.handler.fetch_handles_by(params)
        #END fetch_handles_by

        # At some point might do deeper type checking...
        if not isinstance(handles, list):
            raise ValueError('Method fetch_handles_by return value ' +
                             'handles is not type list as required.')
        # return the results
        return [handles]

    def is_owner(self, ctx, hids):
        """
        Given a list of handle ids, this function determines if the underlying data is owned by the caller.
        If any one of the handle ids reference unreadable data this function returns false.
        :param hids: instance of list of type "HandleId" (Handle provides a
           unique reference that enables access to the data files through
           functions provided as part of the HandleService. In the case of
           using shock, the id is the node id. In the case of using shock the
           value of type is shock. In the future these values should
           enumerated. The value of url is the http address of the shock
           server, including the protocol (http or https) and if necessary
           the port. The values of remote_md5 and remote_sha1 are those
           computed on the file in the remote data store. These can be used
           to verify uploads and downloads.)
        :returns: instance of Long
        """
        # ctx is the context object
        # return variables are: returnVal
        #BEGIN is_owner
        returnVal = self.handler.is_owner(hids, ctx['token'], ctx['user_id'])
        #END is_owner

        # At some point might do deeper type checking...
        if not isinstance(returnVal, int):
            raise ValueError('Method is_owner return value ' +
                             'returnVal is not type int as required.')
        # return the results
        return [returnVal]

    def delete_handles(self, ctx, handles):
        """
        The delete_handles function takes a list of handles and deletes them on the handle service server.
        :param handles: instance of list of type "Handle" -> structure:
           parameter "hid" of type "HandleId" (Handle provides a unique
           reference that enables access to the data files through functions
           provided as part of the HandleService. In the case of using shock,
           the id is the node id. In the case of using shock the value of
           type is shock. In the future these values should enumerated. The
           value of url is the http address of the shock server, including
           the protocol (http or https) and if necessary the port. The values
           of remote_md5 and remote_sha1 are those computed on the file in
           the remote data store. These can be used to verify uploads and
           downloads.), parameter "file_name" of String, parameter "id" of
           type "NodeId", parameter "type" of String, parameter "url" of
           String, parameter "remote_md5" of String, parameter "remote_sha1"
           of String
        :returns: instance of Long
        """
        # ctx is the context object
        # return variables are: deleted_count
        #BEGIN delete_handles
        deleted_count = self.handler.delete_handles(handles, ctx['user_id'])
        #END delete_handles

        # At some point might do deeper type checking...
        if not isinstance(deleted_count, int):
            raise ValueError('Method delete_handles return value ' +
                             'deleted_count is not type int as required.')
        # return the results
        return [deleted_count]

    def are_readable(self, ctx, hids):
        """
        Given a list of handle ids, this function determines if the underlying data is readable by the caller.
        If any one of the handle ids reference unreadable data this function returns false.
        :param hids: instance of list of type "HandleId" (Handle provides a
           unique reference that enables access to the data files through
           functions provided as part of the HandleService. In the case of
           using shock, the id is the node id. In the case of using shock the
           value of type is shock. In the future these values should
           enumerated. The value of url is the http address of the shock
           server, including the protocol (http or https) and if necessary
           the port. The values of remote_md5 and remote_sha1 are those
           computed on the file in the remote data store. These can be used
           to verify uploads and downloads.)
        :returns: instance of Long
        """
        # ctx is the context object
        # return variables are: returnVal
        #BEGIN are_readable
        returnVal = self.handler.are_readable(hids, ctx['token'])
        #END are_readable

        # At some point might do deeper type checking...
        if not isinstance(returnVal, int):
            raise ValueError('Method are_readable return value ' +
                             'returnVal is not type int as required.')
        # return the results
        return [returnVal]

    def is_readable(self, ctx, hid):
        """
        Given a handle id, this function queries the underlying data store to see if the data being referred to is readable to by the caller.
        :param hid: instance of type "HandleId" (Handle provides a unique
           reference that enables access to the data files through functions
           provided as part of the HandleService. In the case of using shock,
           the id is the node id. In the case of using shock the value of
           type is shock. In the future these values should enumerated. The
           value of url is the http address of the shock server, including
           the protocol (http or https) and if necessary the port. The values
           of remote_md5 and remote_sha1 are those computed on the file in
           the remote data store. These can be used to verify uploads and
           downloads.)
        :returns: instance of Long
        """
        # ctx is the context object
        # return variables are: returnVal
        #BEGIN is_readable
        returnVal = self.are_readable(ctx, [hid])[0]
        #END is_readable

        # At some point might do deeper type checking...
        if not isinstance(returnVal, int):
            raise ValueError('Method is_readable return value ' +
                             'returnVal is not type int as required.')
        # return the results
        return [returnVal]

    def add_read_acl(self, ctx, hids, username):
        """
        The add_read_acl function will update the acl of the shock node that the handle references.
        The function is only accessible to a specific list of users specified at startup time.
        The underlying shock node will be made readable to the user requested.
        :param hids: instance of list of type "HandleId" (Handle provides a
           unique reference that enables access to the data files through
           functions provided as part of the HandleService. In the case of
           using shock, the id is the node id. In the case of using shock the
           value of type is shock. In the future these values should
           enumerated. The value of url is the http address of the shock
           server, including the protocol (http or https) and if necessary
           the port. The values of remote_md5 and remote_sha1 are those
           computed on the file in the remote data store. These can be used
           to verify uploads and downloads.)
        :param username: instance of String
        :returns: instance of Long
        """
        # ctx is the context object
        # return variables are: returnVal
        #BEGIN add_read_acl
        returnVal = self.handler.add_read_acl(hids, ctx['token'], username=username)
        #END add_read_acl

        # At some point might do deeper type checking...
        if not isinstance(returnVal, int):
            raise ValueError('Method add_read_acl return value ' +
                             'returnVal is not type int as required.')
        # return the results
        return [returnVal]

    def set_public_read(self, ctx, hids):
        """
        The set_public_read function will update the acl of the shock node that the handle references to make the node globally readable.
        The function is only accessible to a specific list of users specified at startup time.
        :param hids: instance of list of type "HandleId" (Handle provides a
           unique reference that enables access to the data files through
           functions provided as part of the HandleService. In the case of
           using shock, the id is the node id. In the case of using shock the
           value of type is shock. In the future these values should
           enumerated. The value of url is the http address of the shock
           server, including the protocol (http or https) and if necessary
           the port. The values of remote_md5 and remote_sha1 are those
           computed on the file in the remote data store. These can be used
           to verify uploads and downloads.)
        :returns: instance of Long
        """
        # ctx is the context object
        # return variables are: returnVal
        #BEGIN set_public_read
        returnVal = self.handler.add_read_acl(hids, ctx['token'])
        #END set_public_read

        # At some point might do deeper type checking...
        if not isinstance(returnVal, int):
            raise ValueError('Method set_public_read return value ' +
                             'returnVal is not type int as required.')
        # return the results
        return [returnVal]
    def status(self, ctx):
        #BEGIN_STATUS
        returnVal = {'state': "OK",
                     'message': "",
                     'version': self.VERSION,
                     'git_url': self.GIT_URL,
                     'git_commit_hash': self.GIT_COMMIT_HASH}
        #END_STATUS
        return [returnVal]