github.com/treeverse/lakefs@v1.24.1-0.20240520134607-95648127bfb0/clients/python-legacy/lakefs_client/configuration.py (about)

     1  """
     2      lakeFS API
     3  
     4      lakeFS HTTP API  # noqa: E501
     5  
     6      The version of the OpenAPI document: 1.0.0
     7      Contact: services@treeverse.io
     8      Generated by: https://openapi-generator.tech
     9  """
    10  
    11  
    12  import copy
    13  import logging
    14  import multiprocessing
    15  import sys
    16  import urllib3
    17  
    18  from http import client as http_client
    19  from lakefs_client.exceptions import ApiValueError
    20  
    21  
    22  JSON_SCHEMA_VALIDATION_KEYWORDS = {
    23      'multipleOf', 'maximum', 'exclusiveMaximum',
    24      'minimum', 'exclusiveMinimum', 'maxLength',
    25      'minLength', 'pattern', 'maxItems', 'minItems'
    26  }
    27  
    28  class Configuration(object):
    29      """NOTE: This class is auto generated by OpenAPI Generator
    30  
    31      Ref: https://openapi-generator.tech
    32      Do not edit the class manually.
    33  
    34      :param host: Base url
    35      :param api_key: Dict to store API key(s).
    36        Each entry in the dict specifies an API key.
    37        The dict key is the name of the security scheme in the OAS specification.
    38        The dict value is the API key secret.
    39      :param api_key_prefix: Dict to store API prefix (e.g. Bearer)
    40        The dict key is the name of the security scheme in the OAS specification.
    41        The dict value is an API key prefix when generating the auth data.
    42      :param username: Username for HTTP basic authentication
    43      :param password: Password for HTTP basic authentication
    44      :param discard_unknown_keys: Boolean value indicating whether to discard
    45        unknown properties. A server may send a response that includes additional
    46        properties that are not known by the client in the following scenarios:
    47        1. The OpenAPI document is incomplete, i.e. it does not match the server
    48           implementation.
    49        2. The client was generated using an older version of the OpenAPI document
    50           and the server has been upgraded since then.
    51        If a schema in the OpenAPI document defines the additionalProperties attribute,
    52        then all undeclared properties received by the server are injected into the
    53        additional properties map. In that case, there are undeclared properties, and
    54        nothing to discard.
    55      :param disabled_client_side_validations (string): Comma-separated list of
    56        JSON schema validation keywords to disable JSON schema structural validation
    57        rules. The following keywords may be specified: multipleOf, maximum,
    58        exclusiveMaximum, minimum, exclusiveMinimum, maxLength, minLength, pattern,
    59        maxItems, minItems.
    60        By default, the validation is performed for data generated locally by the client
    61        and data received from the server, independent of any validation performed by
    62        the server side. If the input data does not satisfy the JSON schema validation
    63        rules specified in the OpenAPI document, an exception is raised.
    64        If disabled_client_side_validations is set, structural validation is
    65        disabled. This can be useful to troubleshoot data validation problem, such as
    66        when the OpenAPI document validation rules do not match the actual API data
    67        received by the server.
    68      :param server_index: Index to servers configuration.
    69      :param server_variables: Mapping with string values to replace variables in
    70        templated server configuration. The validation of enums is performed for
    71        variables with defined enum values before.
    72      :param server_operation_index: Mapping from operation ID to an index to server
    73        configuration.
    74      :param server_operation_variables: Mapping from operation ID to a mapping with
    75        string values to replace variables in templated server configuration.
    76        The validation of enums is performed for variables with defined enum values before.
    77      :param ssl_ca_cert: str - the path to a file of concatenated CA certificates
    78        in PEM format
    79  
    80      :Example:
    81  
    82      API Key Authentication Example.
    83      Given the following security scheme in the OpenAPI specification:
    84        components:
    85          securitySchemes:
    86            cookieAuth:         # name for the security scheme
    87              type: apiKey
    88              in: cookie
    89              name: JSESSIONID  # cookie name
    90  
    91      You can programmatically set the cookie:
    92  
    93  conf = lakefs_client.Configuration(
    94      api_key={'cookieAuth': 'abc123'}
    95      api_key_prefix={'cookieAuth': 'JSESSIONID'}
    96  )
    97  
    98      The following cookie will be added to the HTTP request:
    99         Cookie: JSESSIONID abc123
   100  
   101      HTTP Basic Authentication Example.
   102      Given the following security scheme in the OpenAPI specification:
   103        components:
   104          securitySchemes:
   105            http_basic_auth:
   106              type: http
   107              scheme: basic
   108  
   109      Configure API client with HTTP basic authentication:
   110  
   111  conf = lakefs_client.Configuration(
   112      username='the-user',
   113      password='the-password',
   114  )
   115  
   116      """
   117  
   118      _default = None
   119  
   120      def __init__(self, host=None,
   121                   api_key=None, api_key_prefix=None,
   122                   access_token=None,
   123                   username=None, password=None,
   124                   discard_unknown_keys=False,
   125                   disabled_client_side_validations="",
   126                   server_index=None, server_variables=None,
   127                   server_operation_index=None, server_operation_variables=None,
   128                   ssl_ca_cert=None,
   129                   ):
   130          """Constructor
   131          """
   132          self._base_path = "http://localhost/api/v1" if host is None else host
   133          """Default Base url
   134          """
   135          self.server_index = 0 if server_index is None and host is None else server_index
   136          self.server_operation_index = server_operation_index or {}
   137          """Default server index
   138          """
   139          self.server_variables = server_variables or {}
   140          self.server_operation_variables = server_operation_variables or {}
   141          """Default server variables
   142          """
   143          self.temp_folder_path = None
   144          """Temp file folder for downloading files
   145          """
   146          # Authentication Settings
   147          self.access_token = access_token
   148          self.api_key = {}
   149          if api_key:
   150              self.api_key = api_key
   151          """dict to store API key(s)
   152          """
   153          self.api_key_prefix = {}
   154          if api_key_prefix:
   155              self.api_key_prefix = api_key_prefix
   156          """dict to store API prefix (e.g. Bearer)
   157          """
   158          self.refresh_api_key_hook = None
   159          """function hook to refresh API key if expired
   160          """
   161          self.username = username
   162          """Username for HTTP basic authentication
   163          """
   164          self.password = password
   165          """Password for HTTP basic authentication
   166          """
   167          self.discard_unknown_keys = discard_unknown_keys
   168          self.disabled_client_side_validations = disabled_client_side_validations
   169          self.logger = {}
   170          """Logging Settings
   171          """
   172          self.logger["package_logger"] = logging.getLogger("lakefs_client")
   173          self.logger["urllib3_logger"] = logging.getLogger("urllib3")
   174          self.logger_format = '%(asctime)s %(levelname)s %(message)s'
   175          """Log format
   176          """
   177          self.logger_stream_handler = None
   178          """Log stream handler
   179          """
   180          self.logger_file_handler = None
   181          """Log file handler
   182          """
   183          self.logger_file = None
   184          """Debug file location
   185          """
   186          self.debug = False
   187          """Debug switch
   188          """
   189  
   190          self.verify_ssl = True
   191          """SSL/TLS verification
   192             Set this to false to skip verifying SSL certificate when calling API
   193             from https server.
   194          """
   195          self.ssl_ca_cert = ssl_ca_cert
   196          """Set this to customize the certificate file to verify the peer.
   197          """
   198          self.cert_file = None
   199          """client certificate file
   200          """
   201          self.key_file = None
   202          """client key file
   203          """
   204          self.assert_hostname = None
   205          """Set this to True/False to enable/disable SSL hostname verification.
   206          """
   207  
   208          self.connection_pool_maxsize = multiprocessing.cpu_count() * 5
   209          """urllib3 connection pool's maximum number of connections saved
   210             per pool. urllib3 uses 1 connection as default value, but this is
   211             not the best value when you are making a lot of possibly parallel
   212             requests to the same host, which is often the case here.
   213             cpu_count * 5 is used as default value to increase performance.
   214          """
   215  
   216          self.proxy = None
   217          """Proxy URL
   218          """
   219          self.proxy_headers = None
   220          """Proxy headers
   221          """
   222          self.safe_chars_for_path_param = ''
   223          """Safe chars for path_param
   224          """
   225          self.retries = None
   226          """Adding retries to override urllib3 default value 3
   227          """
   228          # Enable client side validation
   229          self.client_side_validation = True
   230  
   231          # Options to pass down to the underlying urllib3 socket
   232          self.socket_options = None
   233  
   234      def __deepcopy__(self, memo):
   235          cls = self.__class__
   236          result = cls.__new__(cls)
   237          memo[id(self)] = result
   238          for k, v in self.__dict__.items():
   239              if k not in ('logger', 'logger_file_handler'):
   240                  setattr(result, k, copy.deepcopy(v, memo))
   241          # shallow copy of loggers
   242          result.logger = copy.copy(self.logger)
   243          # use setters to configure loggers
   244          result.logger_file = self.logger_file
   245          result.debug = self.debug
   246          return result
   247  
   248      def __setattr__(self, name, value):
   249          object.__setattr__(self, name, value)
   250          if name == 'disabled_client_side_validations':
   251              s = set(filter(None, value.split(',')))
   252              for v in s:
   253                  if v not in JSON_SCHEMA_VALIDATION_KEYWORDS:
   254                      raise ApiValueError(
   255                          "Invalid keyword: '{0}''".format(v))
   256              self._disabled_client_side_validations = s
   257  
   258      @classmethod
   259      def set_default(cls, default):
   260          """Set default instance of configuration.
   261  
   262          It stores default configuration, which can be
   263          returned by get_default_copy method.
   264  
   265          :param default: object of Configuration
   266          """
   267          cls._default = copy.deepcopy(default)
   268  
   269      @classmethod
   270      def get_default_copy(cls):
   271          """Return new instance of configuration.
   272  
   273          This method returns newly created, based on default constructor,
   274          object of Configuration class or returns a copy of default
   275          configuration passed by the set_default method.
   276  
   277          :return: The configuration object.
   278          """
   279          if cls._default is not None:
   280              return copy.deepcopy(cls._default)
   281          return Configuration()
   282  
   283      @property
   284      def logger_file(self):
   285          """The logger file.
   286  
   287          If the logger_file is None, then add stream handler and remove file
   288          handler. Otherwise, add file handler and remove stream handler.
   289  
   290          :param value: The logger_file path.
   291          :type: str
   292          """
   293          return self.__logger_file
   294  
   295      @logger_file.setter
   296      def logger_file(self, value):
   297          """The logger file.
   298  
   299          If the logger_file is None, then add stream handler and remove file
   300          handler. Otherwise, add file handler and remove stream handler.
   301  
   302          :param value: The logger_file path.
   303          :type: str
   304          """
   305          self.__logger_file = value
   306          if self.__logger_file:
   307              # If set logging file,
   308              # then add file handler and remove stream handler.
   309              self.logger_file_handler = logging.FileHandler(self.__logger_file)
   310              self.logger_file_handler.setFormatter(self.logger_formatter)
   311              for _, logger in self.logger.items():
   312                  logger.addHandler(self.logger_file_handler)
   313  
   314      @property
   315      def debug(self):
   316          """Debug status
   317  
   318          :param value: The debug status, True or False.
   319          :type: bool
   320          """
   321          return self.__debug
   322  
   323      @debug.setter
   324      def debug(self, value):
   325          """Debug status
   326  
   327          :param value: The debug status, True or False.
   328          :type: bool
   329          """
   330          self.__debug = value
   331          if self.__debug:
   332              # if debug status is True, turn on debug logging
   333              for _, logger in self.logger.items():
   334                  logger.setLevel(logging.DEBUG)
   335              # turn on http_client debug
   336              http_client.HTTPConnection.debuglevel = 1
   337          else:
   338              # if debug status is False, turn off debug logging,
   339              # setting log level to default `logging.WARNING`
   340              for _, logger in self.logger.items():
   341                  logger.setLevel(logging.WARNING)
   342              # turn off http_client debug
   343              http_client.HTTPConnection.debuglevel = 0
   344  
   345      @property
   346      def logger_format(self):
   347          """The logger format.
   348  
   349          The logger_formatter will be updated when sets logger_format.
   350  
   351          :param value: The format string.
   352          :type: str
   353          """
   354          return self.__logger_format
   355  
   356      @logger_format.setter
   357      def logger_format(self, value):
   358          """The logger format.
   359  
   360          The logger_formatter will be updated when sets logger_format.
   361  
   362          :param value: The format string.
   363          :type: str
   364          """
   365          self.__logger_format = value
   366          self.logger_formatter = logging.Formatter(self.__logger_format)
   367  
   368      def get_api_key_with_prefix(self, identifier, alias=None):
   369          """Gets API key (with prefix if set).
   370  
   371          :param identifier: The identifier of apiKey.
   372          :param alias: The alternative identifier of apiKey.
   373          :return: The token for api key authentication.
   374          """
   375          if self.refresh_api_key_hook is not None:
   376              self.refresh_api_key_hook(self)
   377          key = self.api_key.get(identifier, self.api_key.get(alias) if alias is not None else None)
   378          if key:
   379              prefix = self.api_key_prefix.get(identifier)
   380              if prefix:
   381                  return "%s %s" % (prefix, key)
   382              else:
   383                  return key
   384  
   385      def get_basic_auth_token(self):
   386          """Gets HTTP basic authentication header (string).
   387  
   388          :return: The token for basic HTTP authentication.
   389          """
   390          username = ""
   391          if self.username is not None:
   392              username = self.username
   393          password = ""
   394          if self.password is not None:
   395              password = self.password
   396          return urllib3.util.make_headers(
   397              basic_auth=username + ':' + password
   398          ).get('authorization')
   399  
   400      def auth_settings(self):
   401          """Gets Auth Settings dict for api client.
   402  
   403          :return: The Auth Settings information dict.
   404          """
   405          auth = {}
   406          if self.username is not None and self.password is not None:
   407              auth['basic_auth'] = {
   408                  'type': 'basic',
   409                  'in': 'header',
   410                  'key': 'Authorization',
   411                  'value': self.get_basic_auth_token()
   412              }
   413          if 'cookie_auth' in self.api_key:
   414              auth['cookie_auth'] = {
   415                  'type': 'api_key',
   416                  'in': 'cookie',
   417                  'key': 'internal_auth_session',
   418                  'value': self.get_api_key_with_prefix(
   419                      'cookie_auth',
   420                  ),
   421              }
   422          if self.access_token is not None:
   423              auth['jwt_token'] = {
   424                  'type': 'bearer',
   425                  'in': 'header',
   426                  'format': 'JWT',
   427                  'key': 'Authorization',
   428                  'value': 'Bearer ' + self.access_token
   429              }
   430          if 'oidc_auth' in self.api_key:
   431              auth['oidc_auth'] = {
   432                  'type': 'api_key',
   433                  'in': 'cookie',
   434                  'key': 'oidc_auth_session',
   435                  'value': self.get_api_key_with_prefix(
   436                      'oidc_auth',
   437                  ),
   438              }
   439          if 'saml_auth' in self.api_key:
   440              auth['saml_auth'] = {
   441                  'type': 'api_key',
   442                  'in': 'cookie',
   443                  'key': 'saml_auth_session',
   444                  'value': self.get_api_key_with_prefix(
   445                      'saml_auth',
   446                  ),
   447              }
   448          return auth
   449  
   450      def to_debug_report(self):
   451          """Gets the essential information for debugging.
   452  
   453          :return: The report for debugging.
   454          """
   455          return "Python SDK Debug Report:\n"\
   456                 "OS: {env}\n"\
   457                 "Python Version: {pyversion}\n"\
   458                 "Version of the API: 1.0.0\n"\
   459                 "SDK Package Version: 0.1.0-SNAPSHOT".\
   460                 format(env=sys.platform, pyversion=sys.version)
   461  
   462      def get_host_settings(self):
   463          """Gets an array of host settings
   464  
   465          :return: An array of host settings
   466          """
   467          return [
   468              {
   469                  'url': "/api/v1",
   470                  'description': "lakeFS server endpoint",
   471              }
   472          ]
   473  
   474      def get_host_from_settings(self, index, variables=None, servers=None):
   475          """Gets host URL based on the index and variables
   476          :param index: array index of the host settings
   477          :param variables: hash of variable and the corresponding value
   478          :param servers: an array of host settings or None
   479          :return: URL based on host settings
   480          """
   481          if index is None:
   482              return self._base_path
   483  
   484          variables = {} if variables is None else variables
   485          servers = self.get_host_settings() if servers is None else servers
   486  
   487          try:
   488              server = servers[index]
   489          except IndexError:
   490              raise ValueError(
   491                  "Invalid index {0} when selecting the host settings. "
   492                  "Must be less than {1}".format(index, len(servers)))
   493  
   494          url = server['url']
   495  
   496          # go through variables and replace placeholders
   497          for variable_name, variable in server.get('variables', {}).items():
   498              used_value = variables.get(
   499                  variable_name, variable['default_value'])
   500  
   501              if 'enum_values' in variable \
   502                      and used_value not in variable['enum_values']:
   503                  raise ValueError(
   504                      "The variable `{0}` in the host URL has invalid value "
   505                      "{1}. Must be {2}.".format(
   506                          variable_name, variables[variable_name],
   507                          variable['enum_values']))
   508  
   509              url = url.replace("{" + variable_name + "}", used_value)
   510  
   511          return url
   512  
   513      @property
   514      def host(self):
   515          """Return generated host."""
   516          return self.get_host_from_settings(self.server_index, variables=self.server_variables)
   517  
   518      @host.setter
   519      def host(self, value):
   520          """Fix base path."""
   521          self._base_path = value
   522          self.server_index = None