From b3bb58a093cd51dd2ede336242549b1f9367cf3d Mon Sep 17 00:00:00 2001 From: Aleksey Veresov Date: Tue, 16 Jul 2024 15:59:53 +0200 Subject: [PATCH] [FSTORE-1454] Unify variable_api and project_api (#219) * Merge variable_api of hsfs * Merge project_api of hsfs * Ruff project_api * Fix client/external so that Project API get_client works That is, set _project_id. * Fix Project API docs * Add docs to variable_api * Ruff client/external.py * Refactor variable_api --- python/hopsworks/client/external.py | 11 +++- python/hopsworks/core/project_api.py | 14 ++++- python/hopsworks/core/variable_api.py | 85 ++++++++++++++++++++++++--- 3 files changed, 97 insertions(+), 13 deletions(-) diff --git a/python/hopsworks/client/external.py b/python/hopsworks/client/external.py index 171c2ba7b..d0a277e71 100644 --- a/python/hopsworks/client/external.py +++ b/python/hopsworks/client/external.py @@ -14,11 +14,11 @@ # limitations under the License. # -import os import base64 -import requests +import os -from hopsworks.client import base, auth, exceptions +import requests +from hopsworks.client import auth, base, exceptions class Client(base.Client): @@ -41,6 +41,11 @@ def __init__( self._port = port self._base_url = "https://" + self._host + ":" + str(self._port) self._project_name = project + if project is not None: + project_info = self._get_project_info(project) + self._project_id = str(project_info["projectId"]) + else: + self._project_id = None if api_key_value is not None: api_key = api_key_value diff --git a/python/hopsworks/core/project_api.py b/python/hopsworks/core/project_api.py index 7795dd3e0..46e8a3df9 100644 --- a/python/hopsworks/core/project_api.py +++ b/python/hopsworks/core/project_api.py @@ -14,8 +14,9 @@ # limitations under the License. # -from hopsworks import client, project, constants import json + +from hopsworks import client, constants, project from hopsworks.client.exceptions import RestAPIError @@ -27,8 +28,6 @@ def _exists(self, name: str): name: Name of the project. # Returns `bool`: True if project exists, otherwise False - # Raises - `RestAPIError`: If unable to check the existence of the project """ try: self._get_project(name) @@ -111,3 +110,12 @@ def _create_project( project = self._get_project(name) print("Project created successfully, explore it at " + project.get_url()) return project + + def get_client(self): + _client = client.get_instance() + path_params = [ + "project", + _client._project_id, + "client", + ] + return _client._send_request("GET", path_params, stream=True) diff --git a/python/hopsworks/core/variable_api.py b/python/hopsworks/core/variable_api.py index 6c8e02a80..d4e8d188c 100644 --- a/python/hopsworks/core/variable_api.py +++ b/python/hopsworks/core/variable_api.py @@ -1,5 +1,5 @@ # -# Copyright 2022 Logical Clocks AB +# Copyright 2022 Hopsworks AB # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -13,8 +13,13 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from __future__ import annotations + +import re +from typing import Optional, Tuple from hopsworks import client +from hopsworks.client.exceptions import RestAPIError class VariableApi: @@ -22,7 +27,15 @@ def __init__(self): pass def get_variable(self, variable: str): - """Get the configured value for a variable""" + """Get the configured value of a variable. + + # Arguments + vairable: Name of the variable. + # Returns + The vairable's value + # Raises + `RestAPIError`: If unable to get the variable + """ _client = client.get_instance() @@ -31,15 +44,73 @@ def get_variable(self, variable: str): return domain["successMessage"] - def get_version(self, software: str): + def get_version(self, software: str) -> Optional[str]: + """Get version of a software component. + + # Arguments + software: Name of the software. + # Returns + The software's version, if the software is available, otherwise `None`. + # Raises + `RestAPIError`: If unable to get the version + """ + _client = client.get_instance() - path_params = [ - "variables", - "versions", - ] + path_params = ["variables", "versions"] resp = _client._send_request("GET", path_params) + for entry in resp: if entry["software"] == software: return entry["version"] return None + + def parse_major_and_minor( + self, backend_version: str + ) -> Tuple[Optional[str], Optional[str]]: + """Extract major and minor version from full version. + + # Arguments + backend_version: The full version. + # Returns + (major, minor): The pair of major and minor parts of the version, or (None, None) if the version format is incorrect. + """ + + version_pattern = r"(\d+)\.(\d+)" + matches = re.match(version_pattern, backend_version) + + if matches is None: + return (None, None) + return matches.group(1), matches.group(2) + + def get_flyingduck_enabled(self) -> bool: + """Check if Flying Duck is enabled on the backend. + + # Returns + `True`: If flying duck is availalbe, `False` otherwise. + # Raises + `RestAPIError`: If unable to obtain the flag's value. + """ + return self.get_variable("enable_flyingduck") == "true" + + def get_loadbalancer_external_domain(self) -> str: + """Get domain of external loadbalancer. + + # Returns + `str`: The domain of external loadbalancer, if it is set up, otherwise empty string `""`. + """ + try: + return self.get_variable("loadbalancer_external_domain") + except RestAPIError: + return "" + + def get_service_discovery_domain(self) -> str: + """Get domain of service discovery server. + + # Returns + `str`: The domain of service discovery server, if it is set up, otherwise empty string `""`. + """ + try: + return self.get_variable("service_discovery_domain") + except RestAPIError: + return ""