Exemple #1
0
def _archive(remote_path,
             project_name=None,
             block=False,
             timeout=120,
             action='zip'):
    """
    Create an archive (zip file) of a file or directory in a Hopsworks dataset.

    Args:
        :remote_path: the path to the remote file or directory in the dataset.
        :action: Allowed values are zip/unzip. Whether to compress/extract respectively.
        :block: whether this method should wait for the zipping process to complete before returning.
        :project_name: whether this method should wait for the zipping process to complete beefore returning.
        :timeout: number of seconds to wait for the action to complete before returning.
    Returns:
        None
    """
    project_id = project.project_id_as_shared(project_name)
    resource_url = constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_REST_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_PROJECT_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   project_id + constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_DATASETS_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   remote_path + "?action=" + action

    util.send_request('POST', resource_url)

    if block is True:
        # Wait for zip file to appear. When it does, check that parent dir zipState is not set to CHOWNING
        count = 0
        while count < timeout:
            # Get the status of the zipped file
            zip_exists = path_exists(remote_path + ".zip", project_name)
            # Get the zipState of the directory being zipped
            dir_status = get_path_info(remote_path, project_name)
            zip_state = dir_status[
                'zipState'] if 'zipState' in dir_status else None

            if zip_exists and zip_state == 'NONE':
                print("Zipping completed.")
                return
            else:
                print("Zipping...")
                time.sleep(1)
            count += 1
        raise CompressTimeout(
            "Timeout of {} seconds exceeded while compressing {}.".format(
                timeout, remote_path))
def get_authorization_token():
    """
    Get the authorization token to interact with elasticsearch.

    Args:

    Returns:
        The authorization token to be used in http header.
    """
    headers = {
        constants.HTTP_CONFIG.HTTP_CONTENT_TYPE:
        constants.HTTP_CONFIG.HTTP_APPLICATION_JSON
    }
    method = constants.HTTP_CONFIG.HTTP_GET
    resource_url = constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_REST_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_ELASTIC_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_ELASTIC_JWT_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   hdfs.project_id()
    response = util.send_request(method, resource_url, headers=headers)
    response_object = response.json()
    if response.status_code >= 400:
        error_code, error_msg, user_msg = util._parse_rest_error(
            response_object)
        raise RestAPIError("Could not get authorization token for elastic (url: {}), server response: \n " \
                           "HTTP code: {}, HTTP reason: {}, error code: {}, error msg: {}, user msg: {}".format(
            resource_url, response.status_code, response.reason, error_code, error_msg, user_msg))

    return "Bearer " + response_object["token"]
def _attach_model_xattr(ml_id, json_data):
    """
    Utility method for putting JSON data into elastic search

    Args:
        :ml_id: the id of the model
        :json_data: the data to put

    Returns:
        None

    """
    headers = {'Content-type': 'application/json'}
    resource_url = constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_REST_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_PROJECT_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   hdfs.project_id() + constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_MODELS_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   ml_id

    response = util.send_request('PUT',
                                 resource_url,
                                 data=json_data,
                                 headers=headers)
    response_object = response.json()
    if response.status_code >= 400:
        error_code, error_msg, user_msg = util._parse_rest_error(
            response_object)
        raise RestAPIError(
            "Could not attach model summary to model (url: {}), server response: \n "
            "HTTP code: {}, HTTP reason: {}, error code: {}, error msg: {}, user msg: {}"
            .format(resource_url, response.status_code, response.reason,
                    error_code, error_msg, user_msg))
    else:
        return response_object
Exemple #4
0
def _http(resource_url,
          headers=None,
          method=constants.HTTP_CONFIG.HTTP_GET,
          data=None):
    response = util.send_request(method,
                                 resource_url,
                                 headers=headers,
                                 data=data)
    try:
        response_object = response.json()
    except JSONDecodeError:
        response_object = None

    if (response.status_code // 100) != 2:
        if response_object:
            error_code, error_msg, user_msg = util._parse_rest_error(
                response_object)
        else:
            error_code, error_msg, user_msg = "", "", ""

        raise RestAPIError(
            "Could not execute HTTP request (url: {}), server response: \n "
            "HTTP code: {}, HTTP reason: {}, error code: {}, error msg: {}, user msg: {}"
            .format(resource_url, response.status_code, response.reason,
                    error_code, error_msg, user_msg))

    return response_object
Exemple #5
0
def start_job(name, args=None):
    """
    Start an execution of the job. Only one execution can be active for a job.

    Returns:
        The job status.
    """
    method = constants.HTTP_CONFIG.HTTP_POST
    resource_url = constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_REST_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_PROJECT_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   hdfs.project_id() + constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_JOBS_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   name + constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_EXECUTIONS_RESOURCE

    response = util.send_request(method, resource_url, args)
    response_object = response.json()
    if response.status_code >= 400:
        error_code, error_msg, user_msg = util._parse_rest_error(
            response_object)
        raise RestAPIError(
            "Could not perform action on job's execution (url: {}), server response: \n "
            "HTTP code: {}, HTTP reason: {}, error code: {}, error msg: {}, user msg: {}"
            .format(resource_url, response.status_code, response.reason,
                    error_code, error_msg, user_msg))

    return response_object
def assume_role(role_arn=None, role_session_name=None, duration_seconds=3600):
    """
    Assume a role and sets the temporary credential to the spark context hadoop configuration and environment variables.

    Args:
        :role_arn: (string) the role arn to be assumed
        :role_session_name: (string) use to uniquely identify a session when the same role is assumed by different principals or for different reasons.
        :duration_seconds: (int) the duration of the session. Maximum session duration is 3600 seconds.

    >>> from hops.credentials_provider import assume_role
    >>> assume_role(role_arn="arn:aws:iam::<AccountNumber>:role/analyst")

    or

    >>> assume_role() # to assume the default role

    Returns:
        temporary credentials
    """
    query = _query_string(role_arn, role_session_name, duration_seconds)
    method = constants.HTTP_CONFIG.HTTP_GET
    resource_url = _get_cloud_resource(
    ) + constants.REST_CONFIG.HOPSWORKS_AWS_CLOUD_SESSION_TOKEN_RESOURCE + query

    response = util.send_request(method, resource_url)
    json_content = _parse_response(response, resource_url)
    _set_spark_hadoop_conf(json_content)
    _set_envs(json_content)
    return json_content
Exemple #7
0
def delete_secret(name):
    """

    Delete a secret for this user

    >>> from hops import secret
    >>> secret.delete_secret('my_secret')

    Args:
        name: Name of the secret to delete
    """
    resource_url = constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_REST_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_USER_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_SECRETS_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   name

    method = constants.HTTP_CONFIG.HTTP_DELETE

    response = util.send_request(method, resource_url)
    if response.status_code >= 400:
        error_code, error_msg, user_msg = util._parse_rest_error(
            response_object)
        raise RestAPIError(
            "Could not delete secret (url: {}), server response: \n "
            "HTTP code: {}, HTTP reason: {}, error code: {}, error msg: {}, user msg: {}"
            .format(resource_url, response.status_code, response.reason,
                    error_code, error_msg, user_msg))
Exemple #8
0
def _delete_serving_rest(serving_id):
    """
    Makes a REST request to Hopsworks REST API for deleting a serving instance

    Args:
        :serving_id: id of the serving to delete

    Returns:
        None

    Raises:
        :RestAPIError: if there was an error with the REST call to Hopsworks
    """
    method = constants.HTTP_CONFIG.HTTP_DELETE
    resource_url = (constants.DELIMITERS.SLASH_DELIMITER +
                    constants.REST_CONFIG.HOPSWORKS_REST_RESOURCE +
                    constants.DELIMITERS.SLASH_DELIMITER +
                    constants.REST_CONFIG.HOPSWORKS_PROJECT_RESOURCE +
                    constants.DELIMITERS.SLASH_DELIMITER + hdfs.project_id() +
                    constants.DELIMITERS.SLASH_DELIMITER +
                    constants.REST_CONFIG.HOPSWORKS_SERVING_RESOURCE +
                    constants.DELIMITERS.SLASH_DELIMITER + str(serving_id))
    response = util.send_request(method, resource_url)

    if response.status_code != 200:
        response_object = response.json()
        error_code, error_msg, user_msg = util._parse_rest_error(
            response_object)
        raise exceptions.RestAPIError(
            "Could not delete serving with id {} (url: {}), "
            "server response: \n "
            "HTTP code: {}, HTTP reason: {}, error code: {}, error msg: {}, "
            "user msg: {}".format(serving_id, resource_url,
                                  response.status_code, response.reason,
                                  error_code, error_msg, user_msg))
Exemple #9
0
def _get_fs_tags():
    """
    Makes a REST call to Hopsworks to get tags that can be attached to featuregroups or training datasets

    Returns:
        List of tags

    """
    method = constants.HTTP_CONFIG.HTTP_GET
    headers = {
        constants.HTTP_CONFIG.HTTP_CONTENT_TYPE:
        constants.HTTP_CONFIG.HTTP_APPLICATION_JSON
    }
    resource_url = (constants.DELIMITERS.SLASH_DELIMITER +
                    constants.REST_CONFIG.HOPSWORKS_REST_RESOURCE +
                    constants.DELIMITERS.SLASH_DELIMITER +
                    constants.REST_CONFIG.HOPSWORKS_FEATURESTORE_TAGS_RESOURCE)
    response = util.send_request(method, resource_url, headers=headers)
    response_object = response.json()
    if response.status_code >= 400:
        error_code, error_msg, user_msg = util._parse_rest_error(
            response_object)
        raise RestAPIError("Could not get tags (url: {}), server response: \n " \
                           "HTTP code: {}, HTTP reason: {}, error code: {}, error msg: {}, user msg: {}".format(
            resource_url, response.status_code, response.reason, error_code, error_msg, user_msg))

    results = []
    if 'items' in response_object:
        for tag in response_object['items']:
            results.append(tag['name'])
    return results
Exemple #10
0
def remove_xattr(hdfs_path, xattr_name):
    """
    Remove an extended attribute attached to an hdfs_path

    Args:
        :hdfs_path: path of a file or directory
        :xattr_name: name of the extended attribute

    Returns:
        None
    """
    hdfs_path = urllib.parse.quote(hdfs._expand_path(hdfs_path))
    headers = {
        constants.HTTP_CONFIG.HTTP_CONTENT_TYPE:
        constants.HTTP_CONFIG.HTTP_APPLICATION_JSON
    }
    method = constants.HTTP_CONFIG.HTTP_DELETE
    resource_url = constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_REST_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_PROJECT_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   hdfs.project_id() + constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_XATTR_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   hdfs_path + constants.DELIMITERS.QUESTION_MARK_DELIMITER + constants.XATTRS.XATTRS_PARAM_NAME + \
                   constants.DELIMITERS.JDBC_CONNECTION_STRING_VALUE_DELIMITER + xattr_name
    response = util.send_request(method, resource_url, headers=headers)
    if response.status_code >= 400:
        response_object = response.json()
        error_code, error_msg, user_msg = util._parse_rest_error(
            response_object)
        raise RestAPIError("Could not remove extened attributes from a path (url: {}), server response: \n " \
                           "HTTP code: {}, HTTP reason: {}, error code: {}, error msg: {}, user msg: {}".format(
            resource_url, response.status_code, response.reason, error_code, error_msg, user_msg))
Exemple #11
0
def _start_or_stop_serving_rest(serving_id, action):
    """
    Makes a REST request to Hopsworks REST API for starting/stopping a serving instance

    Args:
        :serving_id: id of the serving to start/stop
        :action: the action to perform (start or stop)

    Returns:
        None

    Raises:
        :RestAPIError: if there was an error with the REST call to Hopsworks
    """
    method = constants.HTTP_CONFIG.HTTP_POST
    resource_url = (constants.DELIMITERS.SLASH_DELIMITER +
                    constants.REST_CONFIG.HOPSWORKS_REST_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER +
                    constants.REST_CONFIG.HOPSWORKS_PROJECT_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER +
                    hdfs.project_id() + constants.DELIMITERS.SLASH_DELIMITER +
                    constants.REST_CONFIG.HOPSWORKS_SERVING_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER
                    + str(serving_id) + constants.MODEL_SERVING.SERVING_START_OR_STOP_PATH_PARAM + action)
    response = util.send_request(method, resource_url)

    if response.status_code != 200:
        response_object = response.json()
        error_code, error_msg, user_msg = util._parse_rest_error(response_object)
        raise exceptions.RestAPIError("Could not perform action {} on serving with id {} (url: {}), "
                                      "server response: \n "
                                      "HTTP code: {}, HTTP reason: {}, error code: {}, error msg: {}, "
                                      "user msg: {}".format(action, serving_id, resource_url, response.status_code,
                                                            response.reason, error_code, error_msg, user_msg))
Exemple #12
0
def _get_online_featurestore_jdbc_connector_rest(featurestore_id):
    """
    Makes a REST call to Hopsworks to get the JDBC connection to the online feature store

    Args:
        :featurestore_id: the id of the featurestore

    Returns:
        the http response

    """
    method = constants.HTTP_CONFIG.HTTP_GET
    resource_url = (
        constants.DELIMITERS.SLASH_DELIMITER +
        constants.REST_CONFIG.HOPSWORKS_REST_RESOURCE +
        constants.DELIMITERS.SLASH_DELIMITER +
        constants.REST_CONFIG.HOPSWORKS_PROJECT_RESOURCE +
        constants.DELIMITERS.SLASH_DELIMITER + hdfs.project_id() +
        constants.DELIMITERS.SLASH_DELIMITER +
        constants.REST_CONFIG.HOPSWORKS_FEATURESTORES_RESOURCE +
        constants.DELIMITERS.SLASH_DELIMITER + str(featurestore_id) +
        constants.DELIMITERS.SLASH_DELIMITER + constants.REST_CONFIG.
        HOPSWORKS_FEATURESTORES_STORAGE_CONNECTORS_RESOURCE +
        constants.DELIMITERS.SLASH_DELIMITER + constants.REST_CONFIG.
        HOPSWORKS_ONLINE_FEATURESTORE_STORAGE_CONNECTOR_RESOURCE)
    response = util.send_request(method, resource_url)
    response_object = response.json()
    if response.status_code != 200:
        error_code, error_msg, user_msg = util._parse_rest_error(
            response_object)
        raise RestAPIError("Could not fetch online featurestore connector (url: {}), server response: \n " \
                           "HTTP code: {}, HTTP reason: {}, error code: {}, error msg: {}, user msg: {}".format(
            resource_url, response.status_code, response.reason, error_code, error_msg, user_msg))
    return response_object
Exemple #13
0
def _get_fs_schema(tagName):
    """
    Makes a REST call to Hopsworks to get tag schema that can be attached to featuregroups or training datasets

    """
    method = constants.HTTP_CONFIG.HTTP_GET
    headers = {
        constants.HTTP_CONFIG.HTTP_CONTENT_TYPE:
        constants.HTTP_CONFIG.HTTP_APPLICATION_JSON
    }
    resource_url = (
        constants.DELIMITERS.SLASH_DELIMITER +
        constants.REST_CONFIG.HOPSWORKS_REST_RESOURCE +
        constants.DELIMITERS.SLASH_DELIMITER +
        constants.REST_CONFIG.HOPSWORKS_FEATURESTORE_TAGS_RESOURCE +
        constants.DELIMITERS.SLASH_DELIMITER + tagName)
    response = util.send_request(method, resource_url, headers=headers)
    response_object = response.json()
    if response.status_code >= 400:
        error_code, error_msg, user_msg = util._parse_rest_error(
            response_object)
        raise RestAPIError("Could not get tags (url: {}), server response: \n " \
                           "HTTP code: {}, HTTP reason: {}, error code: {}, error msg: {}, user msg: {}".format(
            resource_url, response.status_code, response.reason, error_code, error_msg, user_msg))

    tag = {}
    if ('name' in response_object) and ('value' in response_object):
        tag[response_object['name']] = json.loads(response_object['value'])
    return tag
Exemple #14
0
def _post_fs_schema(schemaName, schemaValue):
    """
    Makes a REST call to Hopsworks to create schemas for tags that can be attached to datasets

    """
    method = constants.HTTP_CONFIG.HTTP_POST
    headers = {
        constants.HTTP_CONFIG.HTTP_CONTENT_TYPE:
        constants.HTTP_CONFIG.HTTP_APPLICATION_JSON
    }
    resource_url = (
        constants.DELIMITERS.SLASH_DELIMITER +
        constants.REST_CONFIG.HOPSWORKS_REST_RESOURCE +
        constants.DELIMITERS.SLASH_DELIMITER +
        constants.REST_CONFIG.HOPSWORKS_FEATURESTORE_TAGS_RESOURCE +
        constants.DELIMITERS.SLASH_DELIMITER + "?name=" + schemaName)
    response = util.send_request(method,
                                 resource_url,
                                 headers=headers,
                                 data=schemaValue)
    response_object = response.json()
    if response.status_code >= 400:
        error_code, error_msg, user_msg = util._parse_rest_error(
            response_object)
        raise RestAPIError("Could not create tag schema (url: {}), server response: \n " \
                           "HTTP code: {}, HTTP reason: {}, error code: {}, error msg: {}, user msg: {}".format(
            resource_url, response.status_code, response.reason, error_code, error_msg, user_msg))
Exemple #15
0
def _get_servings_rest():
    """
    Makes a REST request to Hopsworks to get a list of all servings in the current project

    Returns:
         JSON response parsed as a python dict

    Raises:
        :RestAPIError: if there was an error with the REST call to Hopsworks
    """
    method = constants.HTTP_CONFIG.HTTP_GET
    resource_url = (constants.DELIMITERS.SLASH_DELIMITER +
                    constants.REST_CONFIG.HOPSWORKS_REST_RESOURCE +
                    constants.DELIMITERS.SLASH_DELIMITER +
                    constants.REST_CONFIG.HOPSWORKS_PROJECT_RESOURCE +
                    constants.DELIMITERS.SLASH_DELIMITER + hdfs.project_id() +
                    constants.DELIMITERS.SLASH_DELIMITER +
                    constants.REST_CONFIG.HOPSWORKS_SERVING_RESOURCE +
                    constants.DELIMITERS.SLASH_DELIMITER)
    response = util.send_request(method, resource_url)
    response_object = response.json()
    if response.status_code != 200:
        error_code, error_msg, user_msg = util._parse_rest_error(
            response_object)
        raise exceptions.RestAPIError(
            "Could not fetch list of servings from Hopsworks REST API (url: {}), "
            "server response: \n "
            "HTTP code: {}, HTTP reason: {}, error code: {}, "
            "error msg: {}, user msg: {}".format(resource_url,
                                                 response.status_code,
                                                 response.reason, error_code,
                                                 error_msg, user_msg))
    return response_object
Exemple #16
0
def get_executions(name, query=""):
    """
    Get a list of the currently running executions for this job.
    Returns:
        The job status.
    """
    method = constants.HTTP_CONFIG.HTTP_GET
    resource_url = constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_REST_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_PROJECT_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   hdfs.project_id() + constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_JOBS_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   name + constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_EXECUTIONS_RESOURCE + query
    response = util.send_request(method, resource_url)
    response_object = response.json()
    if response.status_code >= 500:
        error_code, error_msg, user_msg = util._parse_rest_error(
            response_object)
        raise RestAPIError(
            "Could not get current job's execution (url: {}), server response: \n "
            "HTTP code: {}, HTTP reason: {}, error code: {}, error msg: {}, user msg: {}"
            .format(resource_url, response.status_code, response.reason,
                    error_code, error_msg, user_msg))
    if response.status_code >= 400:
        return None
    return response_object
Exemple #17
0
def get_schema(topic):
    """
    Gets the Avro schema for a particular Kafka topic.

    Args:
        :topic: Kafka topic name

    Returns:
        Avro schema as a string object in JSON format
    """
    method = constants.HTTP_CONFIG.HTTP_GET
    resource_url = constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_REST_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_PROJECT_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   hdfs.project_id() + constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_KAFKA_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_TOPICS_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   topic + constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_SUBJECTS_RESOURCE
    response = util.send_request(method, resource_url)
    response_object = response.json()

    if response.status_code != 200:
        error_code, error_msg, user_msg = util._parse_rest_error(
            response_object)
        raise RestAPIError(
            "Could not get Avro schema (url: {}), server response: \n "
            "HTTP code: {}, HTTP reason: {}, error code: {}, error msg: {}, user msg: {}"
            .format(resource_url, response.status_code, response.reason,
                    error_code, error_msg, user_msg))

    return response_object['schema']
Exemple #18
0
    def download(self):
        with util.send_request(constants.HTTP_CONFIG.HTTP_GET,
                               resource="/" + self.resource,
                               stream=True) as response:

            if response.status_code // 100 != 2:
                error_code, error_msg, user_msg = util._parse_rest_error(
                    response.json())
                raise RestAPIError(
                    "Could not perform action on job's execution (url: {}), server response: \n "
                    "HTTP code: {}, HTTP reason: {}, error code: {}, error msg: {}, user msg: {}"
                    .format(self.resource, response.status_code,
                            response.reason, error_code, error_msg, user_msg))

            with open(self.file, "wb") as f:
                downloaded = 0
                file_size = response.headers.get('Content-Length')
                if not file_size:
                    print("Downloading file ...", end=" ")
                for chunk in response.iter_content(chunk_size=self.chunk_size):
                    f.write(chunk)
                    downloaded += len(chunk)
                    if file_size:
                        progress = round(downloaded / int(file_size) * 100, 3)
                        print("Progress: " + str(progress) + "%")
                if not file_size:
                    print("DONE")
Exemple #19
0
def _job_execution_action(name, action):
    """
    Manages execution for the given job, start or stop. Submits an http request to the HOPSWORKS REST API.

    Returns:
        The job status.
    """
    method = constants.HTTP_CONFIG.HTTP_POST
    resource_url = constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_REST_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_PROJECT_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   hdfs.project_id() + constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_JOBS_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   name + constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_EXECUTIONS_RESOURCE + "?action=" + action
    response = util.send_request(method, resource_url)
    response_object = response.json()
    if response.status_code >= 400:
        error_code, error_msg, user_msg = util._parse_rest_error(
            response_object)
        raise RestAPIError(
            "Could not perform action on job's execution (url: {}), server response: \n "
            "HTTP code: {}, HTTP reason: {}, error code: {}, error msg: {}, user msg: {}"
            .format(resource_url, response.status_code, response.reason,
                    error_code, error_msg, user_msg))

    return response_object
Exemple #20
0
def _make_inference_request_rest(serving_name, data, verb):
    """
    Makes a REST request to Hopsworks for submitting an inference request to the serving instance

    Args:
        :serving_name: name of the model being served
        :data: data/json to send to the serving
        :verb: type of request (:predict, :classify, or :regress)

    Returns:
        the JSON response

    Raises:
        :RestAPIError: if there was an error with the REST call to Hopsworks
    """
    json_embeddable = json.dumps(data)
    headers = {constants.HTTP_CONFIG.HTTP_CONTENT_TYPE: constants.HTTP_CONFIG.HTTP_APPLICATION_JSON}
    method = constants.HTTP_CONFIG.HTTP_POST
    resource_url = (constants.DELIMITERS.SLASH_DELIMITER +
                    constants.REST_CONFIG.HOPSWORKS_REST_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER +
                    constants.REST_CONFIG.HOPSWORKS_PROJECT_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER +
                    hdfs.project_id() + constants.DELIMITERS.SLASH_DELIMITER +
                    constants.REST_CONFIG.HOPSWORKS_INFERENCE_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER +
                    constants.REST_CONFIG.HOPSWORKS_MODELS_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER
                    + serving_name + verb)
    response = util.send_request(method, resource_url, data=json_embeddable, headers=headers)
    response_object = response.json()
    error_code, error_msg, user_msg = util._parse_rest_error(response_object)

    if response.status_code != 201 and response.status_code != 200:
        raise exceptions.RestAPIError("Could not create or update serving (url: {}), server response: \n " \
                                      "HTTP code: {}, HTTP reason: {}, error code: {}, error msg: {}, "
                                      "user msg: {}".format(resource_url, response.status_code, response.reason,
                                                            error_code, error_msg, user_msg))
    return response_object
Exemple #21
0
def _attach_model_xattr(ml_id, json_data):
    """
    Utility method for putting JSON data into elastic search

    Args:
        :project: the project of the user/app
        :appid: the YARN appid
        :elastic_id: the id in elastic
        :json_data: the data to put

    Returns:
        None

    """
    headers = {'Content-type': 'application/json'}
    resource_url = constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_REST_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_PROJECT_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   hdfs.project_id() + constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_MODELS_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   ml_id

    resp = util.send_request('PUT',
                             resource_url,
                             data=json_data,
                             headers=headers)
Exemple #22
0
def _get_featurestores():
    """
    Sends a REST request to get all featurestores for the project

    Returns:
        a list of Featurestore JSON DTOs

    Raises:
        :RestAPIError: if there was an error in the REST call to Hopsworks
    """
    method = constants.HTTP_CONFIG.HTTP_GET
    resource_url = (constants.DELIMITERS.SLASH_DELIMITER +
                    constants.REST_CONFIG.HOPSWORKS_REST_RESOURCE +
                    constants.DELIMITERS.SLASH_DELIMITER +
                    constants.REST_CONFIG.HOPSWORKS_PROJECT_RESOURCE +
                    constants.DELIMITERS.SLASH_DELIMITER + hdfs.project_id() +
                    constants.DELIMITERS.SLASH_DELIMITER +
                    constants.REST_CONFIG.HOPSWORKS_FEATURESTORES_RESOURCE)
    response = util.send_request(method, resource_url)
    response_object = response.json()

    if response.status_code != 200:
        error_code, error_msg, user_msg = util._parse_rest_error(
            response_object)
        raise RestAPIError("Could not fetch feature stores (url: {}), server response: \n " \
                           "HTTP code: {}, HTTP reason: {}, error code: {}, error msg: {}, user msg: {}".format(
            resource_url, response.status_code, response.reason, error_code, error_msg, user_msg))

    return response_object
Exemple #23
0
def _create_or_update_serving_rest(model_path, model_name, serving_type, model_version,
                                   batching_enabled = None, topic_name=None,  num_partitions = None,
                                   num_replicas = None, serving_id = None, instances=1):
    """
    Makes a REST request to Hopsworks for creating or updating a model serving instance

    Args:
        :model_path: path to the model or artifact being served
        :model_name: the name of the serving to create
        :serving_type: the type of serving
        :model_version: version of the serving
        :batching_enabled: boolean flag whether to enable batching for inference requests to the serving
        :topic_name: name of the kafka topic ("CREATE" to create a new one, or "NONE" to not use kafka topic)
        :num_partitions: kafka partitions
        :num_replicas: kafka replicas
        :serving_id: the id of the serving in case of UPDATE, if serving_id is None, it is a CREATE operation.
        :instances: the number of serving instances (the more instances the more inference requests can
        be served in parallel)

    Returns:
        None

    Raises:
        :RestAPIError: if there was an error with the REST call to Hopsworks
    """
    json_contents = {
        constants.REST_CONFIG.JSON_SERVING_MODEL_VERSION: model_version,
        constants.REST_CONFIG.JSON_SERVING_ARTIFACT_PATH: model_path,
        constants.REST_CONFIG.JSON_SERVING_TYPE: serving_type,
        constants.REST_CONFIG.JSON_SERVING_NAME: model_name,
        constants.REST_CONFIG.JSON_SERVING_KAFKA_TOPIC_DTO: {
            constants.REST_CONFIG.JSON_KAFKA_TOPIC_NAME: topic_name,
            constants.REST_CONFIG.JSON_KAFKA_NUM_PARTITIONS: num_partitions,
            constants.REST_CONFIG.JSON_KAFKA_NUM_REPLICAS: num_replicas
        },
        constants.REST_CONFIG.JSON_SERVING_REQUESTED_INSTANCES: instances,
    }
    if serving_id is not None:
        json_contents[constants.REST_CONFIG.JSON_SERVING_ID] = serving_id
    if serving_type == constants.MODEL_SERVING.SERVING_TYPE_TENSORFLOW:
        json_contents[constants.REST_CONFIG.JSON_SERVING_BATCHING_ENABLED] = batching_enabled
    json_embeddable = json.dumps(json_contents)
    headers = {constants.HTTP_CONFIG.HTTP_CONTENT_TYPE: constants.HTTP_CONFIG.HTTP_APPLICATION_JSON}
    method = constants.HTTP_CONFIG.HTTP_PUT
    resource_url = (constants.DELIMITERS.SLASH_DELIMITER +
                    constants.REST_CONFIG.HOPSWORKS_REST_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER +
                    constants.REST_CONFIG.HOPSWORKS_PROJECT_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER +
                    hdfs.project_id() + constants.DELIMITERS.SLASH_DELIMITER +
                    constants.REST_CONFIG.HOPSWORKS_SERVING_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER)
    response = util.send_request(method, resource_url, data=json_embeddable, headers=headers)

    if response.status_code != 201 and response.status_code != 200:
        response_object = response.json()
        error_code, error_msg, user_msg = util._parse_rest_error(response_object)
        raise exceptions.RestAPIError("Could not create or update serving (url: {}), server response: \n " \
                                      "HTTP code: {}, HTTP reason: {}, error code: {}, error msg: {}, "
                                      "user msg: {}".format(resource_url, response.status_code, response.reason,
                                                            error_code, error_msg, user_msg))
def _get_roles(role_id=None):
    by_id = ""
    if role_id:
        by_id = constants.DELIMITERS.SLASH_DELIMITER + str(role_id)
    method = constants.HTTP_CONFIG.HTTP_GET
    resource_url = _get_cloud_resource(
    ) + constants.REST_CONFIG.HOPSWORKS_CLOUD_ROLE_MAPPINGS_RESOURCE + by_id
    response = util.send_request(method, resource_url)
    return _parse_response(response, resource_url)
Exemple #25
0
def _get_training_dataset_rest(training_dataset_id, featurestore_id):
    """
    Makes a REST call to hopsworks for getting the metadata of a particular training dataset (including the statistics)

    Args:
        :training_dataset_id: id of the training_dataset
        :featurestore_id: id of the featurestore where the training dataset resides

    Returns:
        The REST response

    Raises:
        :RestAPIError: if there was an error in the REST call to Hopsworks
    """
    headers = {
        constants.HTTP_CONFIG.HTTP_CONTENT_TYPE:
        constants.HTTP_CONFIG.HTTP_APPLICATION_JSON
    }
    method = constants.HTTP_CONFIG.HTTP_GET
    connection = util._get_http_connection(https=True)
    resource_url = (constants.DELIMITERS.SLASH_DELIMITER +
                    constants.REST_CONFIG.HOPSWORKS_REST_RESOURCE +
                    constants.DELIMITERS.SLASH_DELIMITER +
                    constants.REST_CONFIG.HOPSWORKS_PROJECT_RESOURCE +
                    constants.DELIMITERS.SLASH_DELIMITER + util.project_id() +
                    constants.DELIMITERS.SLASH_DELIMITER +
                    constants.REST_CONFIG.HOPSWORKS_FEATURESTORES_RESOURCE +
                    constants.DELIMITERS.SLASH_DELIMITER +
                    str(featurestore_id) +
                    constants.DELIMITERS.SLASH_DELIMITER +
                    constants.REST_CONFIG.HOPSWORKS_TRAININGDATASETS_RESOURCE +
                    constants.DELIMITERS.SLASH_DELIMITER +
                    str(training_dataset_id))
    response = util.send_request(connection,
                                 method,
                                 resource_url,
                                 headers=headers)
    resp_body = response.read().decode('utf-8')
    response_object = json.loads(resp_body)
    try:  # for python 3
        if (response.code != 200):
            error_code, error_msg, user_msg = util._parse_rest_error(
                response_object)
            raise RestAPIError("Could not get the metadata of featuregroup (url: {}), server response: \n " \
                               "HTTP code: {}, HTTP reason: {}, error code: {}, error msg: {}, user msg: {}".format(
                resource_url, response.code, response.reason, error_code, error_msg, user_msg))
    except:  # for python 2
        if (response.status != 200):
            error_code, error_msg, user_msg = util._parse_rest_error(
                response_object)
            raise RestAPIError("Could not get the metadata of featuregroup (url: {}), server response: \n " \
                               "HTTP code: {}, HTTP reason: {}, error code: {}, error msg: {}, user msg: {}".format(
                resource_url, response.status, response.reason, error_code, error_msg, user_msg))
    return response_object
Exemple #26
0
def get_best_model(name, metric, direction):
    """
    Get the best model version by sorting on attached metadata such as model accuracy.

    For example if you run this:

    >>> from hops import model
    >>> from hops.model import Metric
    >>> model.get_best_model('mnist', 'accuracy', Metric.MAX)

    It will return the mnist version where the 'accuracy' is the highest.

    Args:
        :name: name of the model
        :metric: name of the metric to compare
        :direction: whether metric should be maximized or minimized to find the best model

    Returns:
        The best model

    Raises:
        :ModelNotFound: if the model was not found
    """

    if direction.upper() == Metric.MAX:
        direction = "desc"
    elif direction.upper() == Metric.MIN:
        direction = "asc"
    else:
        raise Exception(
            "Invalid direction, should be Metric.MAX or Metric.MIN")

    headers = {
        constants.HTTP_CONFIG.HTTP_CONTENT_TYPE:
        constants.HTTP_CONFIG.HTTP_APPLICATION_JSON
    }

    resource_url = constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_REST_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_PROJECT_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   hdfs.project_id() + constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_MODELS_RESOURCE + \
                   "?filter_by=name_eq:" + name + "&sort_by=" + metric + ":" + direction + "&limit=1"

    response_object = util.send_request('GET', resource_url, headers=headers)

    if not response_object.ok or 'items' not in json.loads(
            response_object.content.decode("UTF-8")):
        raise ModelNotFound(
            "No model with name {} and metric {} could be found.".format(
                name, metric))

    return json.loads(response_object.content.decode("UTF-8"))['items'][0]
Exemple #27
0
def create_secret(name, secret, project_name=None):
    """
    Create a secret

    Creating a secret for this user

    >>> from hops import secret
    >>> secret_token = 'DIOK4jmgFdwadjnDDW98'
    >>> secret.create_secret('my_secret', secret_token)

    Creating a secret and share it with all members of a project

    >>> from hops import secret
    >>> secret_token = 'DIOK4jmgFdwadjnDDW98'
    >>> secret.create_secret('my_secret', secret_token, project_name='someproject')

    Args:
        name: Name of the secret to create
        secret: Value of the secret
        project_name: Name of the project to share the secret with
    """

    secret_config = {'name': name, 'secret': secret}

    if project_name is None:
        secret_config['visibility'] = "PRIVATE"
    else:
        scope_project = project.get_project_info(project_name)
        secret_config['scope'] = scope_project['projectId']
        secret_config['visibility'] = "PROJECT"

    headers = {
        constants.HTTP_CONFIG.HTTP_CONTENT_TYPE:
        constants.HTTP_CONFIG.HTTP_APPLICATION_JSON
    }
    method = constants.HTTP_CONFIG.HTTP_POST
    resource_url = constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_REST_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_USER_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_SECRETS_RESOURCE
    response = util.send_request(method,
                                 resource_url,
                                 data=json.dumps(secret_config),
                                 headers=headers)
    response_object = response.json()
    if response.status_code >= 400:
        error_code, error_msg, user_msg = util._parse_rest_error(
            response_object)
        raise RestAPIError(
            "Could not create secret (url: {}), server response: \n "
            "HTTP code: {}, HTTP reason: {}, error code: {}, error msg: {}, user msg: {}"
            .format(resource_url, response.status_code, response.reason,
                    error_code, error_msg, user_msg))
Exemple #28
0
def delete(remote_path, project_name=None, block=True, timeout=30):
    """
    Delete the dir or file in Hopsworks, specified by the remote_path.

    Example usage:

    >>> from hops import dataset
    >>> dataset.delete("Projects/project_name/Resources/myremotefile.txt")

    Args:
        :remote_path: the path to the remote file or directory in the dataset
        :project_name: whether this method should wait for the zipping process to complete before returning.
        :block: whether to wait for the deletion to complete or not.
        :timeout: number of seconds to wait for the deletion to complete before returning.

    Returns:
        None
    """
    project_id = project.project_id_as_shared(project_name)
    resource_url = constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_REST_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_PROJECT_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   project_id + constants.DELIMITERS.SLASH_DELIMITER + \
                   constants.REST_CONFIG.HOPSWORKS_DATASETS_RESOURCE + constants.DELIMITERS.SLASH_DELIMITER + \
                   remote_path

    util.send_request('DELETE', resource_url)

    # Check if path is indeed deleted as REST API is asynchronous
    if block:
        count = 0
        while count < timeout and path_exists(remote_path, project_name):
            print("Waiting for deletion...")
            count += 1
            time.sleep(1)

        if count >= timeout:
            raise DeletionTimeout(
                "Timeout of {} seconds exceeded while deleting path {}.".
                format(timeout, remote_path))
Exemple #29
0
def _get_featurestore_metadata(featurestore):
    """
    Makes a REST call to hopsworks to get all metadata of a featurestore (featuregroups and
    training datasets) for the provided featurestore.

    Args:
        :featurestore: the name of the database, defaults to the project's featurestore

    Returns:
        JSON response

    Raises:
        :RestAPIError: if there was an error in the REST call to Hopsworks
    """
    method = constants.HTTP_CONFIG.HTTP_GET
    connection = util._get_http_connection(https=True)
    resource_url = (
        constants.DELIMITERS.SLASH_DELIMITER +
        constants.REST_CONFIG.HOPSWORKS_REST_RESOURCE +
        constants.DELIMITERS.SLASH_DELIMITER +
        constants.REST_CONFIG.HOPSWORKS_PROJECT_RESOURCE +
        constants.DELIMITERS.SLASH_DELIMITER + util.project_id() +
        constants.DELIMITERS.SLASH_DELIMITER +
        constants.REST_CONFIG.HOPSWORKS_FEATURESTORES_RESOURCE +
        constants.DELIMITERS.SLASH_DELIMITER + featurestore +
        constants.DELIMITERS.SLASH_DELIMITER +
        constants.REST_CONFIG.HOPSWORKS_FEATURESTORE_METADATA_RESOURCE)
    response = util.send_request(connection, method, resource_url)
    resp_body = response.read().decode('utf-8')
    response_object = json.loads(resp_body)
    # for python 3
    if sys.version_info > (3, 0):
        if response.code != 200:
            error_code, error_msg, user_msg = util._parse_rest_error(
                response_object)
            raise RestAPIError(
                "Could not fetch featurestore metadata for featurestore: {} (url: {}), "
                "server response: \n "
                "HTTP code: {}, HTTP reason: {}, error code: {}, "
                "error msg: {}, user msg: {}".format(
                    resource_url, featurestore, response.code, response.reason,
                    error_code, error_msg, user_msg))
    else:  # for python 2
        if response.status != 200:
            error_code, error_msg, user_msg = util._parse_rest_error(
                response_object)
            raise RestAPIError("Could not fetch featurestore metadata for featurestore: {} (url: {}), "
                                 "server response: \n " \
                                 "HTTP code: {}, HTTP reason: {}, error code: {}, "
                                 "error msg: {}, user msg: {}".format(
                resource_url, featurestore, response.status, response.reason, error_code, error_msg, user_msg))
    return response_object
Exemple #30
0
 def send_request(self,
                  method,
                  resource,
                  data=None,
                  headers=None,
                  stream=False,
                  files=None):
     return hopsutil.send_request(method,
                                  resource,
                                  data=data,
                                  headers=headers,
                                  stream=stream,
                                  files=files)