pyxecm 1.4__py3-none-any.whl → 1.5__py3-none-any.whl
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.
Potentially problematic release.
This version of pyxecm might be problematic. Click here for more details.
- pyxecm/__init__.py +3 -0
- pyxecm/coreshare.py +2636 -0
- pyxecm/customizer/__init__.py +4 -0
- pyxecm/customizer/browser_automation.py +164 -54
- pyxecm/customizer/customizer.py +451 -235
- pyxecm/customizer/k8s.py +6 -6
- pyxecm/customizer/m365.py +1136 -221
- pyxecm/customizer/payload.py +13163 -5844
- pyxecm/customizer/pht.py +503 -0
- pyxecm/customizer/salesforce.py +694 -114
- pyxecm/customizer/sap.py +4 -4
- pyxecm/customizer/servicenow.py +1221 -0
- pyxecm/customizer/successfactors.py +1056 -0
- pyxecm/helper/__init__.py +2 -0
- pyxecm/helper/assoc.py +24 -1
- pyxecm/helper/data.py +1527 -0
- pyxecm/helper/web.py +170 -46
- pyxecm/helper/xml.py +170 -34
- pyxecm/otac.py +309 -23
- pyxecm/otcs.py +2779 -698
- pyxecm/otds.py +347 -108
- pyxecm/otmm.py +808 -0
- pyxecm/otpd.py +13 -10
- {pyxecm-1.4.dist-info → pyxecm-1.5.dist-info}/METADATA +3 -1
- pyxecm-1.5.dist-info/RECORD +30 -0
- {pyxecm-1.4.dist-info → pyxecm-1.5.dist-info}/WHEEL +1 -1
- pyxecm-1.4.dist-info/RECORD +0 -24
- {pyxecm-1.4.dist-info → pyxecm-1.5.dist-info}/LICENSE +0 -0
- {pyxecm-1.4.dist-info → pyxecm-1.5.dist-info}/top_level.txt +0 -0
pyxecm/otac.py
CHANGED
|
@@ -8,10 +8,21 @@ __init__ : class initializer
|
|
|
8
8
|
config : returns config data set
|
|
9
9
|
hostname: returns the Archive Center hostname
|
|
10
10
|
set_hostname: sets the Archive Center hostname
|
|
11
|
+
credentials: Get credentials (username + password)
|
|
12
|
+
set_credentials: Set the credentials for Archive Center for the "ds" and "admin" users
|
|
13
|
+
base_url: Returns the Archive Center base URL
|
|
14
|
+
exec_url: Returns the Archive Center URL to execute commands
|
|
15
|
+
request_form_header: Deliver the FORM request header used for the SOAP calls.
|
|
16
|
+
request_json_header: Deliver the JSON request header used for the CRUD REST API calls.
|
|
17
|
+
parse_request_response: Converts the text property of a request response object to a
|
|
18
|
+
Python dict in a safe way that also handles exceptions.
|
|
19
|
+
authenticate: Authenticates at Archive Center and retrieve Ticket
|
|
20
|
+
authenticate_soap: Authenticate via SOAP with admin User
|
|
11
21
|
exec_command: exec a command on Archive Center
|
|
12
22
|
put_cert: put Certificate on Archive Center
|
|
13
|
-
enable_cert: enables Certitificate on Archive Center
|
|
14
|
-
|
|
23
|
+
enable_cert: enables Certitificate on Archive Center via SOAP
|
|
24
|
+
enable_certificate: Enable a certificate via the new REST API
|
|
25
|
+
(replacing the old SOAP interface)
|
|
15
26
|
"""
|
|
16
27
|
|
|
17
28
|
__author__ = "Dr. Marc Diefenbruch"
|
|
@@ -23,6 +34,7 @@ __email__ = "mdiefenb@opentext.com"
|
|
|
23
34
|
import logging
|
|
24
35
|
import os
|
|
25
36
|
import base64
|
|
37
|
+
import json
|
|
26
38
|
import requests
|
|
27
39
|
|
|
28
40
|
from suds.client import Client
|
|
@@ -30,14 +42,21 @@ from suds import WebFault
|
|
|
30
42
|
|
|
31
43
|
logger = logging.getLogger("pyxecm.otac")
|
|
32
44
|
|
|
33
|
-
|
|
45
|
+
REQUEST_FORM_HEADERS = {"Content-Type": "application/x-www-form-urlencoded"}
|
|
46
|
+
|
|
47
|
+
REQUEST_JSON_HEADERS = {
|
|
48
|
+
"accept": "application/json;charset=utf-8",
|
|
49
|
+
"Content-Type": "application/json",
|
|
50
|
+
}
|
|
34
51
|
|
|
52
|
+
REQUEST_TIMEOUT = 60
|
|
35
53
|
|
|
36
54
|
class OTAC:
|
|
37
55
|
"""Used to automate stettings in OpenText Archive Center."""
|
|
38
56
|
|
|
39
57
|
_config = None
|
|
40
58
|
_soap_token: str = ""
|
|
59
|
+
_otac_ticket = None
|
|
41
60
|
|
|
42
61
|
def __init__(
|
|
43
62
|
self,
|
|
@@ -48,6 +67,7 @@ class OTAC:
|
|
|
48
67
|
ds_password: str,
|
|
49
68
|
admin_username: str,
|
|
50
69
|
admin_password: str,
|
|
70
|
+
otds_ticket: str | None = None,
|
|
51
71
|
):
|
|
52
72
|
"""Initialize the OTAC object
|
|
53
73
|
|
|
@@ -104,8 +124,12 @@ class OTAC:
|
|
|
104
124
|
otac_exec_url = otac_base_url + "/archive/admin/exec"
|
|
105
125
|
otac_config["execUrl"] = otac_exec_url
|
|
106
126
|
otac_config["baseUrl"] = otac_base_url
|
|
127
|
+
otac_config["restUrl"] = otac_base_url + "/ot-admin/rest"
|
|
128
|
+
otac_config["certUrl"] = otac_config["restUrl"] + "/keystore/cert/status"
|
|
129
|
+
otac_config["authenticationUrl"] = otac_config["restUrl"] + "/auth/users/login"
|
|
107
130
|
|
|
108
131
|
self._config = otac_config
|
|
132
|
+
self._otac_ticket = otds_ticket
|
|
109
133
|
|
|
110
134
|
def config(self) -> dict:
|
|
111
135
|
"""Returns the configuration dictionary
|
|
@@ -131,6 +155,17 @@ class OTAC:
|
|
|
131
155
|
"""
|
|
132
156
|
self.config()["hostname"] = hostname
|
|
133
157
|
|
|
158
|
+
def credentials(self) -> dict:
|
|
159
|
+
"""Get credentials (username + password)
|
|
160
|
+
|
|
161
|
+
Returns:
|
|
162
|
+
dict: dictionary with username and password
|
|
163
|
+
"""
|
|
164
|
+
return {
|
|
165
|
+
"username": self.config()["admin_username"],
|
|
166
|
+
"password": self.config()["admin_password"],
|
|
167
|
+
}
|
|
168
|
+
|
|
134
169
|
def set_credentials(
|
|
135
170
|
self,
|
|
136
171
|
ds_username: str = "",
|
|
@@ -182,7 +217,162 @@ class OTAC:
|
|
|
182
217
|
"""
|
|
183
218
|
return self.config()["execUrl"]
|
|
184
219
|
|
|
185
|
-
def
|
|
220
|
+
def request_form_header(self) -> dict:
|
|
221
|
+
"""Deliver the FORM request header used for the SOAP calls.
|
|
222
|
+
Consists of Token + Form Headers (see global variable)
|
|
223
|
+
|
|
224
|
+
Args:
|
|
225
|
+
None.
|
|
226
|
+
Return:
|
|
227
|
+
dict: request header values
|
|
228
|
+
"""
|
|
229
|
+
|
|
230
|
+
# create union of two dicts: cookie and headers
|
|
231
|
+
# (with Python 3.9 this would be easier with the "|" operator)
|
|
232
|
+
request_header = {}
|
|
233
|
+
request_header.update("token" + self._otac_ticket)
|
|
234
|
+
request_header.update(REQUEST_FORM_HEADERS)
|
|
235
|
+
|
|
236
|
+
return request_header
|
|
237
|
+
|
|
238
|
+
# end method definition
|
|
239
|
+
|
|
240
|
+
def request_json_header(self) -> dict:
|
|
241
|
+
"""Deliver the JSON request header used for the CRUD REST API calls.
|
|
242
|
+
Consists of Cookie + JSON Headers (see global variable)
|
|
243
|
+
|
|
244
|
+
Args:
|
|
245
|
+
None.
|
|
246
|
+
Return:
|
|
247
|
+
dict: request header values
|
|
248
|
+
"""
|
|
249
|
+
|
|
250
|
+
if not self._otac_ticket:
|
|
251
|
+
self.authenticate(revalidate=True)
|
|
252
|
+
|
|
253
|
+
# create union of two dicts: cookie and headers
|
|
254
|
+
# (with Python 3.9 this would be easier with the "|" operator)
|
|
255
|
+
request_header = {}
|
|
256
|
+
request_header["Authorization"] = "token " + self._otac_ticket
|
|
257
|
+
request_header.update(REQUEST_JSON_HEADERS)
|
|
258
|
+
|
|
259
|
+
return request_header
|
|
260
|
+
|
|
261
|
+
# end method definition
|
|
262
|
+
|
|
263
|
+
def parse_request_response(
|
|
264
|
+
self,
|
|
265
|
+
response_object: object,
|
|
266
|
+
additional_error_message: str = "",
|
|
267
|
+
show_error: bool = True,
|
|
268
|
+
) -> dict | None:
|
|
269
|
+
"""Converts the text property of a request response object to a
|
|
270
|
+
Python dict in a safe way that also handles exceptions.
|
|
271
|
+
Args:
|
|
272
|
+
response_object (object): this is reponse object delivered by the request call
|
|
273
|
+
additional_error_message (str): print a custom error message
|
|
274
|
+
show_error (bool): if True log an error, if False log a warning
|
|
275
|
+
|
|
276
|
+
Returns:
|
|
277
|
+
dict: response or None in case of an error
|
|
278
|
+
"""
|
|
279
|
+
|
|
280
|
+
if not response_object:
|
|
281
|
+
return None
|
|
282
|
+
|
|
283
|
+
try:
|
|
284
|
+
dict_object = json.loads(response_object.text)
|
|
285
|
+
except json.JSONDecodeError as exception:
|
|
286
|
+
if additional_error_message:
|
|
287
|
+
message = "Cannot decode response as JSon. {}; error -> {}".format(
|
|
288
|
+
additional_error_message, exception
|
|
289
|
+
)
|
|
290
|
+
else:
|
|
291
|
+
message = "Cannot decode response as JSon; error -> {}".format(
|
|
292
|
+
exception
|
|
293
|
+
)
|
|
294
|
+
if show_error:
|
|
295
|
+
logger.error(message)
|
|
296
|
+
else:
|
|
297
|
+
logger.debug(message)
|
|
298
|
+
return None
|
|
299
|
+
else:
|
|
300
|
+
return dict_object
|
|
301
|
+
|
|
302
|
+
# end method definition
|
|
303
|
+
|
|
304
|
+
def authenticate(self, revalidate: bool = False) -> dict | None:
|
|
305
|
+
"""Authenticates at Archive Center and retrieve Ticket.
|
|
306
|
+
|
|
307
|
+
Args:
|
|
308
|
+
revalidate (bool, optional): determinse if a re-athentication is enforced
|
|
309
|
+
(e.g. if session has timed out with 401 error)
|
|
310
|
+
By default we use the OTDS ticket (if exists) for the authentication with OTCS.
|
|
311
|
+
This switch allows the forced usage of username / password for the authentication.
|
|
312
|
+
Returns:
|
|
313
|
+
dict: Cookie information of None in case of an error.
|
|
314
|
+
Also stores cookie information in self._cookie
|
|
315
|
+
"""
|
|
316
|
+
|
|
317
|
+
# Already authenticated and session still valid?
|
|
318
|
+
if self._otac_ticket and not revalidate:
|
|
319
|
+
logger.debug(
|
|
320
|
+
"Session still valid - return existing ticket -> %s",
|
|
321
|
+
str(self._otac_ticket),
|
|
322
|
+
)
|
|
323
|
+
return self._otac_ticket
|
|
324
|
+
|
|
325
|
+
otac_ticket = None
|
|
326
|
+
|
|
327
|
+
request_url = self.config()["authenticationUrl"]
|
|
328
|
+
# Check if previous authentication was not successful.
|
|
329
|
+
# Then we do the normal username + password authentication:
|
|
330
|
+
logger.debug(
|
|
331
|
+
"Requesting OTAC ticket with User/Password; calling -> %s",
|
|
332
|
+
request_url,
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
response = None
|
|
336
|
+
try:
|
|
337
|
+
response = requests.post(
|
|
338
|
+
url=request_url,
|
|
339
|
+
data=json.dumps(
|
|
340
|
+
self.credentials()
|
|
341
|
+
), # this includes username + password
|
|
342
|
+
headers=REQUEST_JSON_HEADERS,
|
|
343
|
+
timeout=REQUEST_TIMEOUT,
|
|
344
|
+
)
|
|
345
|
+
except requests.exceptions.RequestException as exception:
|
|
346
|
+
logger.warning(
|
|
347
|
+
"Unable to connect to -> %s; error -> %s",
|
|
348
|
+
request_url,
|
|
349
|
+
exception.strerror,
|
|
350
|
+
)
|
|
351
|
+
logger.warning("OTAC service may not be ready yet.")
|
|
352
|
+
return None
|
|
353
|
+
|
|
354
|
+
if response.ok:
|
|
355
|
+
authenticate_list = self.parse_request_response(
|
|
356
|
+
response, "This can be normal during restart", False
|
|
357
|
+
)
|
|
358
|
+
if not authenticate_list:
|
|
359
|
+
return None
|
|
360
|
+
else:
|
|
361
|
+
authenticate_dict = authenticate_list[1]
|
|
362
|
+
otac_ticket = authenticate_dict["TOKEN"]
|
|
363
|
+
logger.debug("Ticket -> %s", otac_ticket)
|
|
364
|
+
else:
|
|
365
|
+
logger.error("Failed to request an OTAC ticket; error -> %s", response.text)
|
|
366
|
+
return None
|
|
367
|
+
|
|
368
|
+
# Store authentication ticket:
|
|
369
|
+
self._otac_ticket = otac_ticket
|
|
370
|
+
|
|
371
|
+
return self._otac_ticket
|
|
372
|
+
|
|
373
|
+
# end method definition
|
|
374
|
+
|
|
375
|
+
def authenticate_soap(self) -> str:
|
|
186
376
|
"""Authenticate via SOAP with admin User
|
|
187
377
|
|
|
188
378
|
Args:
|
|
@@ -202,13 +392,13 @@ class OTAC:
|
|
|
202
392
|
|
|
203
393
|
# end method definition
|
|
204
394
|
|
|
205
|
-
def exec_command(self, command: str):
|
|
395
|
+
def exec_command(self, command: str) -> dict:
|
|
206
396
|
"""Execute a command on Archive Center
|
|
207
397
|
|
|
208
398
|
Args:
|
|
209
399
|
command (str): command to execute
|
|
210
400
|
Returns:
|
|
211
|
-
|
|
401
|
+
dict: Response of the HTTP request.
|
|
212
402
|
"""
|
|
213
403
|
|
|
214
404
|
payload = {
|
|
@@ -225,7 +415,7 @@ class OTAC:
|
|
|
225
415
|
request_url,
|
|
226
416
|
)
|
|
227
417
|
response = requests.post(
|
|
228
|
-
url=request_url, data=payload, headers=
|
|
418
|
+
url=request_url, data=payload, headers=REQUEST_FORM_HEADERS, timeout=None
|
|
229
419
|
)
|
|
230
420
|
if not response.ok:
|
|
231
421
|
logger.error(
|
|
@@ -245,7 +435,7 @@ class OTAC:
|
|
|
245
435
|
cert_path: str,
|
|
246
436
|
permissions: str = "rcud",
|
|
247
437
|
):
|
|
248
|
-
"""Put Certificate on Archive Center
|
|
438
|
+
"""Put Certificate on Archive Center via SOAP Call
|
|
249
439
|
|
|
250
440
|
Args:
|
|
251
441
|
auth_id (str): ID of Certification
|
|
@@ -259,7 +449,7 @@ class OTAC:
|
|
|
259
449
|
|
|
260
450
|
# Check if the photo file exists
|
|
261
451
|
if not os.path.isfile(cert_path):
|
|
262
|
-
logger.error("Certificate file -> %s not found!", cert_path)
|
|
452
|
+
logger.error("Certificate file -> '%s' not found!", cert_path)
|
|
263
453
|
return None
|
|
264
454
|
|
|
265
455
|
with open(file=cert_path, mode="r", encoding="utf-8") as cert_file:
|
|
@@ -268,14 +458,16 @@ class OTAC:
|
|
|
268
458
|
# Check that we have the pem certificate file - this is what OTAC expects.
|
|
269
459
|
# If the file content is base64 encoded we will decode it
|
|
270
460
|
if "BEGIN CERTIFICATE" in cert_content:
|
|
271
|
-
logger.
|
|
461
|
+
logger.debug("Certificate file -> '%s' is not base64 encoded", cert_path)
|
|
272
462
|
elif "BEGIN CERTIFICATE" in base64.b64decode(
|
|
273
463
|
cert_content, validate=True
|
|
274
464
|
).decode("utf-8"):
|
|
275
|
-
logger.
|
|
465
|
+
logger.debug("Certificate file -> '%s' is base64 encoded", cert_path)
|
|
276
466
|
cert_content = base64.b64decode(cert_content, validate=True).decode("utf-8")
|
|
277
467
|
else:
|
|
278
|
-
logger.error(
|
|
468
|
+
logger.error(
|
|
469
|
+
"Certificate file -> '%s' is not in the right format", cert_path
|
|
470
|
+
)
|
|
279
471
|
return None
|
|
280
472
|
|
|
281
473
|
request_url = (
|
|
@@ -287,14 +479,17 @@ class OTAC:
|
|
|
287
479
|
+ "&permissions="
|
|
288
480
|
+ permissions
|
|
289
481
|
)
|
|
290
|
-
logger.
|
|
291
|
-
"Putting certificate -> %s on Archive -> %s; calling -> %s",
|
|
482
|
+
logger.debug(
|
|
483
|
+
"Putting certificate -> '%s' on Archive -> '%s'; calling -> %s",
|
|
292
484
|
cert_path,
|
|
293
485
|
logical_archive,
|
|
294
486
|
request_url,
|
|
295
487
|
)
|
|
296
488
|
response = requests.put(
|
|
297
|
-
url=request_url,
|
|
489
|
+
url=request_url,
|
|
490
|
+
data=cert_content,
|
|
491
|
+
headers=REQUEST_FORM_HEADERS,
|
|
492
|
+
timeout=None,
|
|
298
493
|
)
|
|
299
494
|
|
|
300
495
|
if not response.ok:
|
|
@@ -302,7 +497,7 @@ class OTAC:
|
|
|
302
497
|
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN'
|
|
303
498
|
)[0]
|
|
304
499
|
logger.error(
|
|
305
|
-
"Failed to put certificate -> %s on Archive -> %s; error -> %s",
|
|
500
|
+
"Failed to put certificate -> '%s' on Archive -> '%s'; error -> %s",
|
|
306
501
|
cert_path,
|
|
307
502
|
logical_archive,
|
|
308
503
|
message,
|
|
@@ -312,19 +507,21 @@ class OTAC:
|
|
|
312
507
|
|
|
313
508
|
# end method definition
|
|
314
509
|
|
|
315
|
-
def enable_cert(
|
|
316
|
-
|
|
510
|
+
def enable_cert(
|
|
511
|
+
self, auth_id: str, logical_archive: str, enable: bool = True
|
|
512
|
+
) -> bool:
|
|
513
|
+
"""Enables Certitificate on Archive Center via SOAP call
|
|
317
514
|
|
|
318
515
|
Args:
|
|
319
516
|
auth_id (str): Client ID
|
|
320
517
|
logical_archive (str): Archive ID
|
|
321
518
|
enable (bool, optional): Enable or Disable certificate. Defaults to True.
|
|
322
519
|
Returns:
|
|
323
|
-
|
|
520
|
+
True if certificate has been activated, False if an error has occured.
|
|
324
521
|
"""
|
|
325
522
|
|
|
326
523
|
if not self._soap_token:
|
|
327
|
-
self.
|
|
524
|
+
self.authenticate_soap()
|
|
328
525
|
|
|
329
526
|
if enable:
|
|
330
527
|
enabled: int = 1
|
|
@@ -347,15 +544,104 @@ class OTAC:
|
|
|
347
544
|
{"key": "CERT_FLAGS", "data": enabled},
|
|
348
545
|
],
|
|
349
546
|
)
|
|
350
|
-
|
|
547
|
+
# With SOAP, no response is a good response!
|
|
548
|
+
if not response:
|
|
549
|
+
logger.debug("Archive Center certificate has been activated.")
|
|
550
|
+
return True
|
|
551
|
+
elif response.code == 500:
|
|
552
|
+
logger.error(
|
|
553
|
+
"Failed to activate Archive Center certificate for Client -> %s on Archive -> '%s'!",
|
|
554
|
+
auth_id,
|
|
555
|
+
logical_archive,
|
|
556
|
+
)
|
|
557
|
+
return False
|
|
351
558
|
|
|
352
559
|
except WebFault as exception:
|
|
353
560
|
logger.error(
|
|
354
|
-
"Failed to execute SetCertificateFlags for Client -> %s on Archive -> %s; error -> %s",
|
|
561
|
+
"Failed to execute SetCertificateFlags for Client -> %s on Archive -> '%s'; error -> %s",
|
|
355
562
|
auth_id,
|
|
356
563
|
logical_archive,
|
|
357
564
|
exception,
|
|
358
565
|
)
|
|
359
|
-
return
|
|
566
|
+
return False
|
|
567
|
+
|
|
568
|
+
# end method definition
|
|
569
|
+
|
|
570
|
+
def enable_certificate(
|
|
571
|
+
self, cert_name: str, cert_type: str, logical_archive: str | None = None
|
|
572
|
+
) -> dict | None:
|
|
573
|
+
"""Enable a certificate via the new REST API (replacing the old SOAP interface)
|
|
574
|
+
|
|
575
|
+
Args:
|
|
576
|
+
cert_name (str): Name of the certificate
|
|
577
|
+
cert_type (str): Type of the certificate
|
|
578
|
+
logical_archive (str, optional): Logical archive name. If empty it is a global certificate
|
|
579
|
+
for all logical archives in Archive Center.
|
|
580
|
+
|
|
581
|
+
Returns:
|
|
582
|
+
dict | None: REST response or None if the request fails
|
|
583
|
+
|
|
584
|
+
Example response:
|
|
585
|
+
{
|
|
586
|
+
'IDNO': '3',
|
|
587
|
+
'CERT_NAME': 'SP_otcs-admin-0',
|
|
588
|
+
'IMPORT_TIMESTAMP': '1714092017',
|
|
589
|
+
'CERT_TYPE': 'ARC',
|
|
590
|
+
'ASSIGNED_ARCHIVE': None,
|
|
591
|
+
'FINGER_PRINT': 'B9F5 AF66 7CE6 C613 2B3C CAEE 96B6 4F79 97BB 5470 ',
|
|
592
|
+
'ENABLED': True,
|
|
593
|
+
'CERTIFICATE': '...',
|
|
594
|
+
'PRIVILEGES': {'read': True, 'create': True, 'update': True, 'delete': True}
|
|
595
|
+
}
|
|
596
|
+
"""
|
|
597
|
+
|
|
598
|
+
request_url = (
|
|
599
|
+
self.config()["certUrl"]
|
|
600
|
+
+ "?cert_name="
|
|
601
|
+
+ cert_name
|
|
602
|
+
+ "&cert_type="
|
|
603
|
+
+ cert_type
|
|
604
|
+
)
|
|
605
|
+
if logical_archive:
|
|
606
|
+
request_url += "&assigned_archive=" + logical_archive
|
|
607
|
+
|
|
608
|
+
request_header = self.request_json_header()
|
|
609
|
+
|
|
610
|
+
payload = {"ENABLED": True}
|
|
611
|
+
|
|
612
|
+
logger.debug(
|
|
613
|
+
"Enabling certificate -> '%s' of type -> '%s' to Archive Center; calling -> %s",
|
|
614
|
+
cert_name,
|
|
615
|
+
cert_type,
|
|
616
|
+
request_url,
|
|
617
|
+
)
|
|
618
|
+
|
|
619
|
+
retries = 0
|
|
620
|
+
while True:
|
|
621
|
+
response = requests.put(
|
|
622
|
+
url=request_url,
|
|
623
|
+
headers=request_header,
|
|
624
|
+
data=json.dumps(payload),
|
|
625
|
+
timeout=REQUEST_TIMEOUT,
|
|
626
|
+
)
|
|
627
|
+
if response.ok:
|
|
628
|
+
logger.debug(
|
|
629
|
+
"Certificate -> '%s' has been enabled on Archive Center keystore",
|
|
630
|
+
cert_name,
|
|
631
|
+
)
|
|
632
|
+
return self.parse_request_response(response)
|
|
633
|
+
# Check if Session has expired - then re-authenticate and try once more
|
|
634
|
+
elif response.status_code == 401 and retries == 0:
|
|
635
|
+
logger.debug("Session has expired - try to re-authenticate...")
|
|
636
|
+
self.authenticate(revalidate=True)
|
|
637
|
+
retries += 1
|
|
638
|
+
else:
|
|
639
|
+
logger.error(
|
|
640
|
+
"Failed to enable certificate -> '%s' in Archive Center; status -> %s; error -> %s",
|
|
641
|
+
cert_name,
|
|
642
|
+
response.status_code,
|
|
643
|
+
response.text,
|
|
644
|
+
)
|
|
645
|
+
return None
|
|
360
646
|
|
|
361
647
|
# end method definition
|