PyPowerStore 3.4.0.0__tar.gz → 3.4.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. pypowerstore-3.4.1.1/PKG-INFO +20 -0
  2. pypowerstore-3.4.1.1/PyPowerStore/__init__.py +9 -0
  3. {PyPowerStore-3.4.0.0 → pypowerstore-3.4.1.1}/PyPowerStore/client.py +196 -130
  4. {PyPowerStore-3.4.0.0 → pypowerstore-3.4.1.1}/PyPowerStore/configuration.py +935 -711
  5. pypowerstore-3.4.1.1/PyPowerStore/metrics.py +62 -0
  6. {PyPowerStore-3.4.0.0 → pypowerstore-3.4.1.1}/PyPowerStore/objects/__init__.py +7 -10
  7. {PyPowerStore-3.4.0.0 → pypowerstore-3.4.1.1}/PyPowerStore/objects/file_dns.py +42 -33
  8. {PyPowerStore-3.4.0.0 → pypowerstore-3.4.1.1}/PyPowerStore/objects/file_interface.py +53 -40
  9. {PyPowerStore-3.4.0.0 → pypowerstore-3.4.1.1}/PyPowerStore/objects/file_nis.py +43 -35
  10. {PyPowerStore-3.4.0.0 → pypowerstore-3.4.1.1}/PyPowerStore/objects/nfs_server.py +45 -37
  11. {PyPowerStore-3.4.0.0 → pypowerstore-3.4.1.1}/PyPowerStore/objects/smb_server.py +43 -36
  12. {PyPowerStore-3.4.0.0 → pypowerstore-3.4.1.1}/PyPowerStore/objects/snmp_server.py +38 -29
  13. pypowerstore-3.4.1.1/PyPowerStore/powerstore_conn.py +71 -0
  14. {PyPowerStore-3.4.0.0 → pypowerstore-3.4.1.1}/PyPowerStore/protection.py +470 -393
  15. {PyPowerStore-3.4.0.0 → pypowerstore-3.4.1.1}/PyPowerStore/provisioning.py +2711 -2423
  16. pypowerstore-3.4.1.1/PyPowerStore/utils/__init__.py +5 -0
  17. pypowerstore-3.4.1.1/PyPowerStore/utils/constants.py +847 -0
  18. {PyPowerStore-3.4.0.0 → pypowerstore-3.4.1.1}/PyPowerStore/utils/exception.py +1 -1
  19. {PyPowerStore-3.4.0.0 → pypowerstore-3.4.1.1}/PyPowerStore/utils/helpers.py +94 -71
  20. pypowerstore-3.4.1.1/PyPowerStore.egg-info/PKG-INFO +20 -0
  21. {PyPowerStore-3.4.0.0 → pypowerstore-3.4.1.1}/PyPowerStore.egg-info/SOURCES.txt +1 -0
  22. pypowerstore-3.4.1.1/PyPowerStore.egg-info/requires.txt +4 -0
  23. pypowerstore-3.4.1.1/setup.py +24 -0
  24. PyPowerStore-3.4.0.0/PKG-INFO +0 -14
  25. PyPowerStore-3.4.0.0/PyPowerStore/__init__.py +0 -8
  26. PyPowerStore-3.4.0.0/PyPowerStore/powerstore_conn.py +0 -60
  27. PyPowerStore-3.4.0.0/PyPowerStore/utils/__init__.py +0 -0
  28. PyPowerStore-3.4.0.0/PyPowerStore/utils/constants.py +0 -832
  29. PyPowerStore-3.4.0.0/PyPowerStore.egg-info/PKG-INFO +0 -14
  30. PyPowerStore-3.4.0.0/PyPowerStore.egg-info/requires.txt +0 -2
  31. PyPowerStore-3.4.0.0/setup.py +0 -25
  32. {PyPowerStore-3.4.0.0 → pypowerstore-3.4.1.1}/LICENSE +0 -0
  33. {PyPowerStore-3.4.0.0 → pypowerstore-3.4.1.1}/PyPowerStore.egg-info/dependency_links.txt +0 -0
  34. {PyPowerStore-3.4.0.0 → pypowerstore-3.4.1.1}/PyPowerStore.egg-info/top_level.txt +0 -0
  35. {PyPowerStore-3.4.0.0 → pypowerstore-3.4.1.1}/README.md +0 -0
  36. {PyPowerStore-3.4.0.0 → pypowerstore-3.4.1.1}/setup.cfg +0 -0
@@ -0,0 +1,20 @@
1
+ Metadata-Version: 2.4
2
+ Name: PyPowerStore
3
+ Version: 3.4.1.1
4
+ Summary: Python Library for Dell PowerStore
5
+ Home-page: https://github.com/dell/python-powerstore
6
+ Author: Ansible Team at Dell
7
+ Author-email: ansible.team@dell.com
8
+ Classifier: License :: OSI Approved :: Apache Software License
9
+ License-File: LICENSE
10
+ Requires-Dist: urllib3>=1.26.7
11
+ Requires-Dist: requests>=2.23.0
12
+ Requires-Dist: packaging>=26.0
13
+ Requires-Dist: setuptools>=80.10.2
14
+ Dynamic: author
15
+ Dynamic: author-email
16
+ Dynamic: classifier
17
+ Dynamic: home-page
18
+ Dynamic: license-file
19
+ Dynamic: requires-dist
20
+ Dynamic: summary
@@ -0,0 +1,9 @@
1
+ # Copyright: (c) 2024, Dell Technologies
2
+ """__init__.py."""
3
+
4
+ # pylint: disable=invalid-name
5
+
6
+ __title__ = "PyPowerStore"
7
+ __version__ = "3.4.1.0"
8
+ __author__ = "Dell Technologies or its subsidiaries"
9
+ __copyright__ = "Copyright 2024 Dell Technologies"
@@ -1,23 +1,21 @@
1
- # -*- coding: utf-8 -*-
2
1
  # Copyright: (c) 2024, Dell Technologies
3
2
 
4
3
  """Client module for PowerStore"""
5
4
 
6
- import json
5
+ # pylint: disable=too-many-instance-attributes,too-many-arguments,too-many-positional-arguments,no-member,too-many-nested-blocks,too-many-branches,global-statement
6
+
7
7
  import base64
8
- import socket
9
- import requests
8
+ import json
10
9
  import time
11
- from requests.exceptions import SSLError
12
- from requests.exceptions import ConnectionError
13
- from requests.exceptions import TooManyRedirects
14
- from requests.exceptions import Timeout
15
- from PyPowerStore.utils.exception import PowerStoreException
10
+
11
+ import requests
12
+ from requests.exceptions import SSLError, Timeout, TooManyRedirects
13
+
16
14
  from PyPowerStore.utils import constants, helpers
15
+ from PyPowerStore.utils.exception import PowerStoreException
17
16
 
18
17
  requests.packages.urllib3.disable_warnings()
19
18
 
20
- # TODO: kept LOG as global for now will improve it to avoid overriding
21
19
  LOG = helpers.get_logger(__name__)
22
20
 
23
21
  # Codes
@@ -28,10 +26,10 @@ ENGVIS_LIST = ["remote_support", "node", "volume_group", "remote_system"]
28
26
  class AuthenticationManager:
29
27
  """Manage the powerstore authentication"""
30
28
 
31
- def __init__(self, username, password, verify, application_type,
32
- timeout, host=None):
33
- """
34
- Initializes AuthenticationManager
29
+ def __init__(
30
+ self, username, password, verify, application_type, timeout, host=None,
31
+ ):
32
+ """Initializes AuthenticationManager
35
33
 
36
34
  :param username: array username
37
35
  :type username: str
@@ -58,10 +56,10 @@ class AuthenticationManager:
58
56
  self.idle_timeout = 0
59
57
  self.creation_time = None
60
58
  self.headers = {
61
- 'Accept': constants.APP_JSON,
62
- 'Accept-Language': constants.EN_US,
63
- 'content-type': constants.APP_JSON,
64
- 'Application-Type': self.application_type
59
+ "Accept": constants.APP_JSON,
60
+ "Accept-Language": constants.EN_US,
61
+ "content-type": constants.APP_JSON,
62
+ "Application-Type": self.application_type,
65
63
  }
66
64
 
67
65
  def set_host(self, host):
@@ -71,23 +69,32 @@ class AuthenticationManager:
71
69
  def get_authorization(self):
72
70
  """Get the authorization header"""
73
71
  credentials = base64.b64encode(
74
- "{username}:{password}".format(
75
- username=self.username, password=self.password).encode())
76
- return {'authorization': "Basic " + credentials.decode()}
72
+ f"{self.username}:{self.password}".encode(),
73
+ )
74
+ return {"authorization": "Basic " + credentials.decode()}
77
75
 
78
76
  def set_session_timeout_and_creation_time(self, login_response):
79
77
  """Set the session timeout from login response object"""
80
78
  if login_response.status_code == 200:
81
79
  self.creation_time = time.time()
82
80
  json_response = login_response.json()
83
- login_data = login_response.json()[0] if isinstance(json_response, list) else {}
84
- self.idle_timeout = login_data['idle_timeout'] if 'idle_timeout' in login_data else self.idle_timeout
81
+ login_data = (
82
+ login_response.json()[0] if isinstance(json_response, list) else {}
83
+ )
84
+ self.idle_timeout = (
85
+ login_data["idle_timeout"]
86
+ if "idle_timeout" in login_data
87
+ else self.idle_timeout
88
+ )
85
89
 
86
90
  def is_session_alive(self):
87
91
  """Check if the session is alive or not"""
88
- if self.creation_time and self.idle_timeout and \
89
- ((time.time() - self.creation_time) < self.idle_timeout):
90
- return True
92
+ if (
93
+ self.creation_time
94
+ and self.idle_timeout
95
+ and ((time.time() - self.creation_time) < self.idle_timeout)
96
+ ):
97
+ return True
91
98
  return False
92
99
 
93
100
  def login(self):
@@ -96,11 +103,16 @@ class AuthenticationManager:
96
103
  login_headers = dict(self.headers)
97
104
  login_headers.update(self.get_authorization())
98
105
  response = requests.request(
99
- constants.GET, login_url, headers=login_headers, verify=self.verify,
100
- timeout=self.timeout, params=constants.LOGIN_SESSION_DETAILS_QUERY)
106
+ constants.GET,
107
+ login_url,
108
+ headers=login_headers,
109
+ verify=self.verify,
110
+ timeout=self.timeout,
111
+ params=constants.LOGIN_SESSION_DETAILS_QUERY,
112
+ )
101
113
  self.set_session_timeout_and_creation_time(response)
102
- self.dell_emc_token = response.headers.get('DELL-EMC-TOKEN')
103
- self.cookie = response.cookies.get('auth_cookie')
114
+ self.dell_emc_token = response.headers.get("DELL-EMC-TOKEN")
115
+ self.cookie = response.cookies.get("auth_cookie")
104
116
 
105
117
  def get_token_and_cookie(self):
106
118
  """Get the DELL-EMC-TOKEN and set-cookie"""
@@ -108,28 +120,42 @@ class AuthenticationManager:
108
120
  if not self.dell_emc_token or not self.cookie or not self.is_session_alive():
109
121
  self.login()
110
122
 
111
- auth_tokens.update({'DELL-EMC-TOKEN': self.dell_emc_token})
112
- auth_tokens.update({'Cookie': f'auth_cookie={self.cookie}'})
123
+ auth_tokens.update({"DELL-EMC-TOKEN": self.dell_emc_token})
124
+ auth_tokens.update({"Cookie": f"auth_cookie={self.cookie}"})
113
125
  return auth_tokens
114
126
 
115
127
  def logout_session(self):
116
- """ Logout the current session """
128
+ """Logout the current session"""
117
129
  login_url = constants.LOGOUT_URL.format(self.host)
118
130
  logout_headers = {}
119
131
  logout_headers.update(self.headers)
120
- logout_headers.update({'DELL-EMC-TOKEN': self.dell_emc_token})
121
- logout_headers.update({'Cookie': f'auth_cookie={self.cookie}'})
132
+ logout_headers.update({"DELL-EMC-TOKEN": self.dell_emc_token})
133
+ logout_headers.update({"Cookie": f"auth_cookie={self.cookie}"})
122
134
  requests.request(
123
- constants.POST, login_url, headers=logout_headers, verify=self.verify,
124
- data=None, timeout=self.timeout)
135
+ constants.POST,
136
+ login_url,
137
+ headers=logout_headers,
138
+ verify=self.verify,
139
+ data=None,
140
+ timeout=self.timeout,
141
+ )
125
142
  self.dell_emc_token = None
126
143
  self.cookie = None
127
144
 
128
- class Client():
145
+
146
+ class Client:
129
147
  """Client class for PowerStore"""
130
- def __init__(self, username, password, verify, application_type,
131
- timeout=None, enable_log=False):
132
- """ Initializes Client Class
148
+
149
+ def __init__(
150
+ self,
151
+ username,
152
+ password,
153
+ verify,
154
+ application_type,
155
+ timeout=None,
156
+ enable_log=False,
157
+ ):
158
+ """Initializes Client Class
133
159
 
134
160
  :param username: array username
135
161
  :type username: str
@@ -145,23 +171,26 @@ class Client():
145
171
  :type enable_log: bool
146
172
  :type timeout: float
147
173
  """
148
- global LOG
149
174
  self.username = username
150
175
  self.password = password
151
176
  self.verify = verify
152
177
  self.application_type = application_type
153
178
  """Setting default timeout"""
154
179
  self.timeout = timeout if timeout else constants.TIMEOUT
155
- self.auth_manager = AuthenticationManager(self.username,
156
- self.password,
157
- self.verify,
158
- self.application_type,
159
- self.timeout)
180
+ self.auth_manager = AuthenticationManager(
181
+ self.username,
182
+ self.password,
183
+ self.verify,
184
+ self.application_type,
185
+ self.timeout,
186
+ )
187
+ global LOG # Reset LOG based on param
160
188
  LOG = helpers.get_logger(__name__, enable_log=enable_log)
161
189
 
162
- def fetch_response(self, http_method, url, payload=None, querystring=None,
163
- myrange=None):
164
- """ Fetch & return the response based on request parameters.
190
+ def fetch_response(
191
+ self, http_method, url, payload=None, querystring=None, myrange=None,
192
+ ):
193
+ """Fetch & return the response based on request parameters.
165
194
 
166
195
  :param http_method: HTTP Method
167
196
  :type http_method: str
@@ -176,45 +205,59 @@ class Client():
176
205
  :return: Request's response.
177
206
  :rtype: requests.models.Response object
178
207
  """
179
-
180
208
  headers = {
181
- 'Accept': "application/json",
182
- 'Accept-Language': "en-US",
183
- 'content-type': "application/json",
184
- 'Application-Type': self.application_type
209
+ "Accept": "application/json",
210
+ "Accept-Language": "en-US",
211
+ "content-type": "application/json",
212
+ "Application-Type": self.application_type,
185
213
  }
186
- split_host = url.split('/')
214
+ split_host = url.split("/")
187
215
  self.auth_manager.set_host(split_host[2])
188
216
  auth_headers = self.auth_manager.get_token_and_cookie()
189
217
 
190
218
  if split_host[5] in ENGVIS_LIST:
191
- headers['DELL-VISIBILITY'] = 'internal'
219
+ headers["DELL-VISIBILITY"] = "internal"
192
220
 
193
221
  if auth_headers:
194
222
  headers.update(auth_headers)
195
223
 
196
- LOG.debug("Request's http_method: '%s' url: '%s' payload: '%s' "
197
- "querystring: '%s' myrange: '%s'"
198
- % (http_method, url, payload, querystring, myrange))
224
+ LOG.debug(
225
+ "Request's http_method: '%s' url: '%s' payload: '%s' querystring: '%s' myrange: '%s'"
226
+ , http_method, url, payload, querystring, myrange
227
+ )
199
228
  if myrange:
200
229
  headers["Range"] = myrange
201
230
 
202
231
  if payload:
203
232
  response = requests.request(
204
- http_method, url, data=json.dumps(payload), headers=headers,
205
- verify=self.verify, timeout=self.timeout)
233
+ http_method,
234
+ url,
235
+ data=json.dumps(payload),
236
+ headers=headers,
237
+ verify=self.verify,
238
+ timeout=self.timeout,
239
+ )
206
240
  elif querystring:
207
241
  response = requests.request(
208
- http_method, url, headers=headers, params=querystring,
209
- verify=self.verify, timeout=self.timeout)
242
+ http_method,
243
+ url,
244
+ headers=headers,
245
+ params=querystring,
246
+ verify=self.verify,
247
+ timeout=self.timeout,
248
+ )
210
249
  else:
211
250
  response = requests.request(
212
- http_method, url, headers=headers, verify=self.verify,
213
- timeout=self.timeout)
251
+ http_method,
252
+ url,
253
+ headers=headers,
254
+ verify=self.verify,
255
+ timeout=self.timeout,
256
+ )
214
257
  return response
215
258
 
216
259
  def is_valid_response(self, response):
217
- """ Check whether response is valid or not
260
+ """Check whether response is valid or not
218
261
 
219
262
  :param response: Request's response.
220
263
  :type response: requests.models.Response
@@ -225,57 +268,75 @@ class Client():
225
268
  return False
226
269
 
227
270
  def raise_http_exception(self, response):
228
- """ Raises PowerStoreException
271
+ """Raises PowerStoreException
229
272
 
230
273
  :param response: Request's response.
231
274
  :type response: requests.models.Response
232
275
  """
233
276
  if response.status_code == 500:
234
- error_msg = "PowerStore internal server error. Error " \
235
- "details: " + str(response.json())
277
+ error_msg = "PowerStore internal server error. Error details: " + str(
278
+ response.json(),
279
+ )
236
280
  elif response.status_code == 401:
237
281
  error_msg = "Access forbidden: Authentication required."
238
282
  elif response.status_code == 403:
239
- error_msg = "Not allowed - authorization failure. " \
240
- "Error details: " + str(response.json())
283
+ error_msg = "Not allowed - authorization failure. Error details: " + str(
284
+ response.json(),
285
+ )
241
286
  elif response.status_code == 404:
242
- error_msg = "Requested resource not found. " \
243
- "Error details: " + str(response.json())
287
+ error_msg = "Requested resource not found. Error details: " + str(
288
+ response.json(),
289
+ )
244
290
  elif response.status_code == 405:
245
- error_msg = "The HTTP method is not supported on that URL. " \
246
- "Error details: " + str(response.json())
291
+ error_msg = (
292
+ "The HTTP method is not supported on that URL. "
293
+ "Error details: " + str(response.json())
294
+ )
247
295
  elif response.status_code == 406:
248
- error_msg = "Not acceptable - the server cannot satisfy the " \
249
- "Accept: header in the request. Either the format " \
250
- "or version requested is not supported. " \
251
- "Error details: " + str(response.json())
296
+ error_msg = (
297
+ "Not acceptable - the server cannot satisfy the "
298
+ "Accept: header in the request. Either the format "
299
+ "or version requested is not supported. "
300
+ "Error details: " + str(response.json())
301
+ )
252
302
  elif response.status_code == 415:
253
- error_msg = "Invalid request Content-Type. " \
254
- "Error details: " + str(response.json())
303
+ error_msg = "Invalid request Content-Type. Error details: " + str(
304
+ response.json(),
305
+ )
255
306
  elif response.status_code == 416:
256
- error_msg = "Range Not Satisfiable. The client requested a " \
257
- "starting offset (using the ?offset URL parameter, " \
258
- "or the first value in Range header) that was " \
259
- "larger than the number of instances in the queried "\
260
- "result set. Error details: " + str(response.json())
307
+ error_msg = (
308
+ "Range Not Satisfiable. The client requested a "
309
+ "starting offset (using the ?offset URL parameter, "
310
+ "or the first value in Range header) that was "
311
+ "larger than the number of instances in the queried "
312
+ "result set. Error details: " + str(response.json())
313
+ )
261
314
  elif response.status_code == 422:
262
- error_msg = "Request could not be completed. " \
263
- "Error details: " + str(response.json())
315
+ error_msg = "Request could not be completed. Error details: " + str(
316
+ response.json(),
317
+ )
264
318
  elif response.status_code == 503:
265
- error_msg = "The service is temporarily unavailable. "\
266
- "Error details: " + str(response.json())
319
+ error_msg = (
320
+ "The service is temporarily unavailable. "
321
+ "Error details: " + str(response.json())
322
+ )
267
323
  else:
268
324
  error_msg = str(response.json())
269
325
  LOG.error(error_msg)
270
- raise PowerStoreException(PowerStoreException.HTTP_ERR,
271
- "HTTP code: " +
272
- str(response.status_code) +
273
- ", " + response.reason +
274
- " [" + error_msg + "]",
275
- str(response.status_code))
326
+ raise PowerStoreException(
327
+ PowerStoreException.HTTP_ERR,
328
+ "HTTP code: "
329
+ + str(response.status_code)
330
+ + ", "
331
+ + response.reason
332
+ + " ["
333
+ + error_msg
334
+ + "]",
335
+ str(response.status_code),
336
+ )
276
337
 
277
338
  def get_total_size_from_content_range(self, content_range):
278
- """ Extract & return total_size from content_range
339
+ """Extract & return total_size from content_range
279
340
 
280
341
  :param http_method: HTTP Method
281
342
  :type http_method: str
@@ -286,8 +347,7 @@ class Client():
286
347
  total_size = int(total_size)
287
348
  return total_size
288
349
 
289
- def request(self, http_method, url, payload=None, querystring=None,
290
- all_pages=None):
350
+ def request(self, http_method, url, payload=None, querystring=None, all_pages=None):
291
351
  """Method which serves requests to PowerStore.
292
352
 
293
353
  :param http_method: HTTP Method
@@ -304,71 +364,77 @@ class Client():
304
364
  :return: Request's response.
305
365
  :rtype: dict or list of dict
306
366
  """
307
-
308
367
  try:
309
368
 
310
369
  response = self.fetch_response(
311
- http_method, url, payload=payload, querystring=querystring)
370
+ http_method, url, payload=payload, querystring=querystring,
371
+ )
312
372
  try:
313
373
  if self.is_valid_response(response):
314
374
  response_json = None
315
375
  if response.status_code != 204:
316
- if response.status_code == 201 and response.content == b'':
376
+ if response.status_code == 201 and response.content == b"":
317
377
  pass
318
378
  else:
319
379
  response_json = response.json()
320
380
  # check 'all_pages' required, response received is
321
381
  # partial(code 206) and contains info about total size of
322
382
  # the collection
323
- content_range = response.headers.get('content-range')
324
- if all_pages and response.status_code == 206 and\
325
- content_range:
383
+ content_range = response.headers.get("content-range")
384
+ if all_pages and response.status_code == 206 and content_range:
326
385
  # 'content-range': '0-99/789'
327
386
  total_size = self.get_total_size_from_content_range(
328
- content_range)
387
+ content_range,
388
+ )
329
389
  myranges = [
330
- "{0}-{1}".format(i, i + constants.MAX_LIMIT)
331
- for i in range(constants.OFFSET, total_size,
332
- constants.MAX_LIMIT)]
390
+ f"{i}-{i + constants.MAX_LIMIT}"
391
+ for i in range(
392
+ constants.OFFSET, total_size, constants.MAX_LIMIT,
393
+ )
394
+ ]
333
395
  for myrange in myranges:
334
396
  response = self.fetch_response(
335
- http_method, url, payload=payload,
336
- querystring=querystring, myrange=myrange)
397
+ http_method,
398
+ url,
399
+ payload=payload,
400
+ querystring=querystring,
401
+ myrange=myrange,
402
+ )
337
403
  if self.is_valid_response(response):
338
404
  response_json.extend(response.json())
339
405
  else:
340
406
  self.raise_http_exception(response)
341
407
 
342
408
  return response_json
343
- else:
344
- self.raise_http_exception(response)
409
+ self.raise_http_exception(response)
410
+ return None
345
411
 
346
412
  except ValueError as ex:
347
413
  # its low-level or response level error caused by
348
414
  # response.json() and not in requests.exceptions
349
- error_msg = "ValueError: '{0}' for Method: '{1}' URL: '{2}'"\
350
- " PayLoad: '{3}' QueryString: '{4}'".format(
351
- str(ex), http_method, url, payload, querystring)
415
+ error_msg = (
416
+ f"ValueError: '{ex!s}' for Method: '{http_method}' URL: '{url}'"
417
+ f" PayLoad: '{payload}' QueryString: '{querystring}'"
418
+ )
352
419
  LOG.error(error_msg)
353
- raise PowerStoreException(PowerStoreException.VALUE_ERROR,
354
- error_msg)
355
- except socket.error as exception:
356
- LOG.error(str(exception))
357
- raise PowerStoreException(PowerStoreException.SOCKET_ERR,
358
- str(exception))
420
+ raise PowerStoreException(PowerStoreException.VALUE_ERROR, error_msg) from ex
359
421
  except SSLError as exception:
360
422
  LOG.error(str(exception))
361
- raise PowerStoreException(PowerStoreException.SSL_ERROR,
362
- str(exception))
423
+ raise PowerStoreException(PowerStoreException.SSL_ERROR, str(exception)) from exception
363
424
  except ConnectionError as exception:
364
425
  LOG.error(str(exception))
365
- raise PowerStoreException(PowerStoreException.CONNECTION_ERROR,
366
- str(exception))
426
+ raise PowerStoreException(
427
+ PowerStoreException.CONNECTION_ERROR, str(exception),
428
+ ) from exception
367
429
  except TooManyRedirects as exception:
368
430
  LOG.error(str(exception))
369
431
  raise PowerStoreException(
370
- PowerStoreException.TOO_MANY_REDIRECTS_ERROR, str(exception))
432
+ PowerStoreException.TOO_MANY_REDIRECTS_ERROR, str(exception),
433
+ ) from exception
371
434
  except Timeout as exception:
372
435
  LOG.error(str(exception))
373
- raise PowerStoreException(PowerStoreException.TIMEOUT_ERROR,
374
- str(exception))
436
+ raise PowerStoreException(PowerStoreException.TIMEOUT_ERROR, str(exception)
437
+ ) from exception
438
+ except OSError as exception:
439
+ LOG.error(str(exception))
440
+ raise PowerStoreException(PowerStoreException.SOCKET_ERR, str(exception)) from exception