Isilon / isilon_sdk_python

Official generated source of the Isilon SDK Python language bindings.
35 stars 34 forks source link

list_quota_quotas() with v9.4 fails for quotas with no description #61

Open nikolisg7 opened 1 year ago

nikolisg7 commented 1 year ago

Hello everyone!

OneFS 9.4 introduced a "description" field for quotas, which is as I understand it optional. Despite of that, running list_quota_quotas() against a 9.4.x.x cluster yields an error if there are quotas with no description. Here is the traceback:

In [9]: api_instance.list_quota_quotas()
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Input In [9], in <cell line: 1>()
----> 1 api_instance.list_quota_quotas()

File ~/bin/anaconda3/envs/ansiblepython310/lib/python3.10/site-packages/isilon_sdk/v9_4_0/api/quota_api.py:1865, in QuotaApi.list_quota_quotas(self, **kwargs)
   1863     return self.list_quota_quotas_with_http_info(**kwargs)  # noqa: E501
   1864 else:
-> 1865     (data) = self.list_quota_quotas_with_http_info(**kwargs)  # noqa: E501
   1866     return data

File ~/bin/anaconda3/envs/ansiblepython310/lib/python3.10/site-packages/isilon_sdk/v9_4_0/api/quota_api.py:1971, in QuotaApi.list_quota_quotas_with_http_info(self, **kwargs)
   1968 # Authentication setting
   1969 auth_settings = ['basicAuth']  # noqa: E501
-> 1971 return self.api_client.call_api(
   1972     '/platform/15/quota/quotas', 'GET',
   1973     path_params,
   1974     query_params,
   1975     header_params,
   1976     body=body_params,
   1977     post_params=form_params,
   1978     files=local_var_files,
   1979     response_type='QuotaQuotasExtended',  # noqa: E501
   1980     auth_settings=auth_settings,
   1981     async_req=params.get('async_req'),
   1982     _return_http_data_only=params.get('_return_http_data_only'),
   1983     _preload_content=params.get('_preload_content', True),
   1984     _request_timeout=params.get('_request_timeout'),
   1985     collection_formats=collection_formats)

File ~/bin/anaconda3/envs/ansiblepython310/lib/python3.10/site-packages/isilon_sdk/v9_4_0/api_client.py:341, in ApiClient.call_api(self, resource_path, method, path_params, query_params, header_params, body, post_params, files, response_type, auth_settings, async_req, _return_http_data_only, collection_formats, _preload_content, _request_timeout)
    304 """Makes the HTTP request (synchronous) and returns deserialized data.
    305 
    306 To make an async request, set the async_req parameter.
   (...)
    338     then the method will return the response directly.
    339 """
    340 if not async_req:
--> 341     return self.__call_api(resource_path, method,
    342                            path_params, query_params, header_params,
    343                            body, post_params, files,
    344                            response_type, auth_settings,
    345                            _return_http_data_only, collection_formats,
    346                            _preload_content, _request_timeout)
    347 else:
    348     thread = self.pool.apply_async(self.__call_api, (resource_path,
    349                                    method, path_params, query_params,
    350                                    header_params, body,
   (...)
    354                                    collection_formats,
    355                                    _preload_content, _request_timeout))

File ~/bin/anaconda3/envs/ansiblepython310/lib/python3.10/site-packages/isilon_sdk/v9_4_0/api_client.py:185, in ApiClient.__call_api(self, resource_path, method, path_params, query_params, header_params, body, post_params, files, response_type, auth_settings, _return_http_data_only, collection_formats, _preload_content, _request_timeout)
    182 if _preload_content:
    183     # deserialize response data
    184     if response_type:
--> 185         return_data = self.deserialize(response_data, response_type)
    186     else:
    187         return_data = None

File ~/bin/anaconda3/envs/ansiblepython310/lib/python3.10/site-packages/isilon_sdk/v9_4_0/api_client.py:257, in ApiClient.deserialize(self, response, response_type)
    254 except ValueError:
    255     data = response.data
--> 257 return self.__deserialize(data, response_type)

File ~/bin/anaconda3/envs/ansiblepython310/lib/python3.10/site-packages/isilon_sdk/v9_4_0/api_client.py:296, in ApiClient.__deserialize(self, data, klass)
    294     return self.__deserialize_datatime(data)
    295 else:
--> 296     return self.__deserialize_model(data, klass)

File ~/bin/anaconda3/envs/ansiblepython310/lib/python3.10/site-packages/isilon_sdk/v9_4_0/api_client.py:671, in ApiClient.__deserialize_model(self, data, klass)
    667         if (data is not None and
    668                 klass.attribute_map[attr] in data and
    669                 isinstance(data, (list, dict))):
    670             value = data[klass.attribute_map[attr]]
--> 671             kwargs[attr] = self.__deserialize(value, attr_type)
    673 instance = klass(**kwargs)
    675 if hasattr(instance, 'get_real_child_model'):

File ~/bin/anaconda3/envs/ansiblepython310/lib/python3.10/site-packages/isilon_sdk/v9_4_0/api_client.py:273, in ApiClient.__deserialize(self, data, klass)
    271 if klass.startswith('list['):
    272     sub_kls = re.match('list\[(.*)\]', klass).group(1)
--> 273     return [self.__deserialize(sub_data, sub_kls)
    274             for sub_data in data]
    276 if klass.startswith('dict('):
    277     sub_kls = re.match('dict\(([^,]*), (.*)\)', klass).group(2)

File ~/bin/anaconda3/envs/ansiblepython310/lib/python3.10/site-packages/isilon_sdk/v9_4_0/api_client.py:273, in <listcomp>(.0)
    271 if klass.startswith('list['):
    272     sub_kls = re.match('list\[(.*)\]', klass).group(1)
--> 273     return [self.__deserialize(sub_data, sub_kls)
    274             for sub_data in data]
    276 if klass.startswith('dict('):
    277     sub_kls = re.match('dict\(([^,]*), (.*)\)', klass).group(2)

File ~/bin/anaconda3/envs/ansiblepython310/lib/python3.10/site-packages/isilon_sdk/v9_4_0/api_client.py:296, in ApiClient.__deserialize(self, data, klass)
    294     return self.__deserialize_datatime(data)
    295 else:
--> 296     return self.__deserialize_model(data, klass)

File ~/bin/anaconda3/envs/ansiblepython310/lib/python3.10/site-packages/isilon_sdk/v9_4_0/api_client.py:673, in ApiClient.__deserialize_model(self, data, klass)
    670             value = data[klass.attribute_map[attr]]
    671             kwargs[attr] = self.__deserialize(value, attr_type)
--> 673 instance = klass(**kwargs)
    675 if hasattr(instance, 'get_real_child_model'):
    676     klass_name = instance.get_real_child_model(data)

File ~/bin/anaconda3/envs/ansiblepython310/lib/python3.10/site-packages/isilon_sdk/v9_4_0/models/quota_quota_extended.py:100, in QuotaQuotaExtended.__init__(self, container, description, efficiency_ratio, enforced, id, include_snapshots, labels, linked, notifications, path, persona, ready, reduction_ratio, thresholds, thresholds_on, type, usage)
     97 self.discriminator = None
     99 self.container = container
--> 100 self.description = description
    101 if efficiency_ratio is not None:
    102     self.efficiency_ratio = efficiency_ratio

File ~/bin/anaconda3/envs/ansiblepython310/lib/python3.10/site-packages/isilon_sdk/v9_4_0/models/quota_quota_extended.py:169, in QuotaQuotaExtended.description(self, description)
    161 """Sets the description of this QuotaQuotaExtended.
    162 
    163 User settable free form text description of the quota.  # noqa: E501
   (...)
    166 :type: str
    167 """
    168 if description is None:
--> 169     raise ValueError("Invalid value for `description`, must not be `None`")  # noqa: E501
    170 if description is not None and len(description) > 1024:
    171     raise ValueError("Invalid value for `description`, length must be less than or equal to `1024`")  # noqa: E501

ValueError: Invalid value for `description`, must not be `None`

We noticed that the API spec specifies the description entry in the response body for GET /platform/15/quota/quotas as required. Here is an excerpt from https://onefs_host:8080/platform/15/quota/quotas?describe, where the GET response body is documented:

"container": {
                "required": true, 
                "type": "boolean", 
                "description": "If true, SMB shares using the quota directory see the quota thresholds as share size."
              }, 
"description": {
                "minLength": 0, 
                "required": true,
                "type": "string", 
                "description": "User settable free form text description of the quota.", 
                "maxLength": 1024
              }, 

There is no description field though in the response body, if none is defined for a particular quota. We observed similar behavior with method get_quota_quota(), when called with an quota id that has no description. My first assumption would be that this spec in the OneFS API results in the QuotaQuotaExtended.description to be mandatory too, then a response that doesn't include a "description" field at all causes the initialization of the QuotaQuotaExtended object to fail

Is this something that can be fixed within the Python SDK or would it require changes on side of the OneFS API?

Thanks! Georgios

claire-peters commented 9 months ago

Using v9.5 and experiencing the same issue, would like very much for this to be addressed.

mmanwani07 commented 8 months ago

Please use latest isilon-sdk package v0.3.01