pyxecm 1.4__py3-none-any.whl → 1.6__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 +5 -0
- pyxecm/avts.py +1065 -0
- pyxecm/coreshare.py +2532 -0
- pyxecm/customizer/__init__.py +4 -0
- pyxecm/customizer/browser_automation.py +164 -54
- pyxecm/customizer/customizer.py +588 -231
- pyxecm/customizer/k8s.py +143 -29
- pyxecm/customizer/m365.py +1434 -1323
- pyxecm/customizer/payload.py +15073 -5933
- pyxecm/customizer/pht.py +926 -0
- pyxecm/customizer/salesforce.py +866 -351
- pyxecm/customizer/sap.py +4 -4
- pyxecm/customizer/servicenow.py +1467 -0
- pyxecm/customizer/successfactors.py +1056 -0
- pyxecm/helper/__init__.py +2 -0
- pyxecm/helper/assoc.py +44 -1
- pyxecm/helper/data.py +1731 -0
- pyxecm/helper/web.py +170 -46
- pyxecm/helper/xml.py +170 -34
- pyxecm/otac.py +309 -23
- pyxecm/otawp.py +1810 -0
- pyxecm/otcs.py +5308 -2985
- pyxecm/otds.py +1909 -1954
- pyxecm/otmm.py +928 -0
- pyxecm/otpd.py +13 -10
- {pyxecm-1.4.dist-info → pyxecm-1.6.dist-info}/METADATA +5 -1
- pyxecm-1.6.dist-info/RECORD +32 -0
- {pyxecm-1.4.dist-info → pyxecm-1.6.dist-info}/WHEEL +1 -1
- pyxecm-1.4.dist-info/RECORD +0 -24
- {pyxecm-1.4.dist-info → pyxecm-1.6.dist-info}/LICENSE +0 -0
- {pyxecm-1.4.dist-info → pyxecm-1.6.dist-info}/top_level.txt +0 -0
pyxecm/customizer/customizer.py
CHANGED
|
@@ -52,6 +52,10 @@ import sys
|
|
|
52
52
|
import time
|
|
53
53
|
from dataclasses import dataclass, field
|
|
54
54
|
from datetime import datetime
|
|
55
|
+
import uuid
|
|
56
|
+
import xml.etree.ElementTree as ET
|
|
57
|
+
import json
|
|
58
|
+
import re
|
|
55
59
|
|
|
56
60
|
# from packaging.version import Version
|
|
57
61
|
|
|
@@ -59,7 +63,8 @@ import requests
|
|
|
59
63
|
|
|
60
64
|
# OpenText specific modules:
|
|
61
65
|
import yaml
|
|
62
|
-
from pyxecm import OTAC, OTCS, OTDS, OTIV, OTPD
|
|
66
|
+
from pyxecm import OTAC, OTCS, OTDS, OTIV, OTPD, OTMM, CoreShare, OTAWP
|
|
67
|
+
from pyxecm.avts import AVTS
|
|
63
68
|
from pyxecm.customizer.k8s import K8s
|
|
64
69
|
from pyxecm.customizer.m365 import M365
|
|
65
70
|
from pyxecm.customizer.payload import Payload
|
|
@@ -74,7 +79,7 @@ class CustomizerSettings:
|
|
|
74
79
|
"""Class to manage settings"""
|
|
75
80
|
|
|
76
81
|
placeholder_values: dict = field(default_factory=dict)
|
|
77
|
-
stop_on_error: bool = os.environ.get("
|
|
82
|
+
stop_on_error: bool = os.environ.get("STOP_ON_ERROR", "false").lower() == "true"
|
|
78
83
|
cust_log_file: str = "/tmp/customizing.log"
|
|
79
84
|
customizer_start_time = customizer_end_time = datetime.now()
|
|
80
85
|
|
|
@@ -105,6 +110,7 @@ class CustomizerSettingsOTDS:
|
|
|
105
110
|
admin_partition: str = "otds.admin"
|
|
106
111
|
public_url: str = os.environ.get("OTDS_PUBLIC_URL")
|
|
107
112
|
password: str = os.environ.get("OTDS_PASSWORD")
|
|
113
|
+
bindPassword: str = os.environ.get("BINB_PASSWORD")
|
|
108
114
|
disable_password_policy: bool = True
|
|
109
115
|
enable_audit: bool = True
|
|
110
116
|
|
|
@@ -123,6 +129,8 @@ class CustomizerSettingsOTCS:
|
|
|
123
129
|
port: int = os.environ.get("OTCS_SERVICE_PORT_OTCS", 8080)
|
|
124
130
|
port_backend: int = os.environ.get("OTCS_SERVICE_PORT_OTCS", 8080)
|
|
125
131
|
port_frontend: int = 80
|
|
132
|
+
base_path: str = "/cs/cs"
|
|
133
|
+
feme_uri: str = os.environ.get("FEME_URI", "ws://feme:4242")
|
|
126
134
|
admin: str = os.environ.get("OTCS_ADMIN", "admin")
|
|
127
135
|
password: str = os.environ.get("OTCS_PASSWORD")
|
|
128
136
|
partition: str = os.environ.get("OTCS_PARTITION", "Content Server Members")
|
|
@@ -142,7 +150,11 @@ class CustomizerSettingsOTCS:
|
|
|
142
150
|
replicas_frontend = 0
|
|
143
151
|
replicas_backend = 0
|
|
144
152
|
|
|
153
|
+
# Add configuration options for Customizer behaviour
|
|
145
154
|
update_admin_user: bool = True
|
|
155
|
+
upload_config_files: bool = True
|
|
156
|
+
upload_status_files: bool = True
|
|
157
|
+
upload_log_file: bool = True
|
|
146
158
|
|
|
147
159
|
|
|
148
160
|
@dataclass
|
|
@@ -212,11 +224,13 @@ class CustomizerSettingsOTAWP:
|
|
|
212
224
|
resource_name: str = "awp"
|
|
213
225
|
access_role_name: str = "Access to " + resource_name
|
|
214
226
|
admin: str = os.environ.get("OTAWP_ADMIN", "sysadmin")
|
|
215
|
-
password: str = os.environ.get("
|
|
227
|
+
password: str = os.environ.get("OTCS_PASSWORD")
|
|
216
228
|
public_protocol: str = os.environ.get("OTAWP_PROTOCOL", "https")
|
|
217
229
|
public_url: str = os.environ.get("OTAWP_PUBLIC_URL")
|
|
218
230
|
k8s_statefulset: str = "appworks"
|
|
219
231
|
k8s_configmap: str = "appworks-config-ymls"
|
|
232
|
+
port: int = os.environ.get("OTAWP_SERVICE_PORT", 8080)
|
|
233
|
+
protocol: str = os.environ.get("OTPD_PROTOCOL", "http")
|
|
220
234
|
|
|
221
235
|
|
|
222
236
|
@dataclass
|
|
@@ -231,7 +245,23 @@ class CustomizerSettingsM365:
|
|
|
231
245
|
password: str = os.environ.get("O365_PASSWORD", "")
|
|
232
246
|
domain: str = os.environ.get("O365_DOMAIN", "")
|
|
233
247
|
sku_id: str = os.environ.get("O365_SKU_ID", "c7df2760-2c81-4ef7-b578-5b5392b571df")
|
|
234
|
-
teams_app_name: str = "OpenText Extended ECM"
|
|
248
|
+
teams_app_name: str = os.environ.get("O365_TEAMS_APP_NAME", "OpenText Extended ECM")
|
|
249
|
+
teams_app_external_id: str = os.environ.get(
|
|
250
|
+
"O365_TEAMS_APP_ID", "dd4af790-d8ff-47a0-87ad-486318272c7a"
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
@dataclass
|
|
255
|
+
class CustomizerSettingsCoreShare:
|
|
256
|
+
"""Class for Core Share related settings"""
|
|
257
|
+
|
|
258
|
+
enabled: bool = os.environ.get("CORE_SHARE_ENABLED", "false").lower() == "true"
|
|
259
|
+
base_url: str = os.environ.get("CORE_SHARE_BASE_URL", "https://core.opentext.com")
|
|
260
|
+
sso_url: str = os.environ.get("CORE_SHARE_SSO_URL", "https://sso.core.opentext.com")
|
|
261
|
+
client_id: str = os.environ.get("CORE_SHARE_CLIENT_ID", "")
|
|
262
|
+
client_secret = os.environ.get("CORE_SHARE_CLIENT_SECRET", "")
|
|
263
|
+
username: str = os.environ.get("CORE_SHARE_USERNAME", "")
|
|
264
|
+
password: str = os.environ.get("CORE_SHARE_PASSWORD", "")
|
|
235
265
|
|
|
236
266
|
|
|
237
267
|
@dataclass
|
|
@@ -241,6 +271,19 @@ class CustomizerSettingsAviator:
|
|
|
241
271
|
enabled: bool = os.environ.get("AVIATOR_ENABLED", "false").lower() == "true"
|
|
242
272
|
|
|
243
273
|
|
|
274
|
+
@dataclass
|
|
275
|
+
class CustomizerSettingsAVTS:
|
|
276
|
+
"""Class for Aviator Search (AVTS) related settings"""
|
|
277
|
+
|
|
278
|
+
enabled: bool = os.environ.get("AVTS_ENABLED", "false").lower() == "true"
|
|
279
|
+
otds_url = os.environ.get("AVTS_OTDS_URL", "")
|
|
280
|
+
client_id = os.environ.get("AVTS_CLIENT_ID", "")
|
|
281
|
+
client_secret = os.environ.get("AVTS_CLIENT_SECRET", "")
|
|
282
|
+
base_url = os.environ.get("AVTS_BASE_URL", "")
|
|
283
|
+
username = os.environ.get("AVTS_USERNAME", "")
|
|
284
|
+
password = os.environ.get("AVTS_PASSWORD", "")
|
|
285
|
+
|
|
286
|
+
|
|
244
287
|
class Customizer:
|
|
245
288
|
"""Customizer Class to control the cusomization automation
|
|
246
289
|
|
|
@@ -258,7 +301,9 @@ class Customizer:
|
|
|
258
301
|
k8s: CustomizerSettingsK8S = CustomizerSettingsK8S(),
|
|
259
302
|
otawp: CustomizerSettingsOTAWP = CustomizerSettingsOTAWP(),
|
|
260
303
|
m365: CustomizerSettingsM365 = CustomizerSettingsM365(),
|
|
304
|
+
core_share: CustomizerSettingsCoreShare = CustomizerSettingsCoreShare(),
|
|
261
305
|
aviator: CustomizerSettingsAviator = CustomizerSettingsAviator(),
|
|
306
|
+
avts: CustomizerSettingsAVTS = CustomizerSettingsAVTS(),
|
|
262
307
|
):
|
|
263
308
|
self.settings = settings
|
|
264
309
|
|
|
@@ -286,9 +331,15 @@ class Customizer:
|
|
|
286
331
|
# Microsoft 365 Environment variables:
|
|
287
332
|
self.m365_settings = m365
|
|
288
333
|
|
|
334
|
+
# Core Share Environment variables:
|
|
335
|
+
self.core_share_settings = core_share
|
|
336
|
+
|
|
289
337
|
# Aviator variables:
|
|
290
338
|
self.aviator_settings = aviator
|
|
291
339
|
|
|
340
|
+
# Aviator Search variables:
|
|
341
|
+
self.avts_settings = avts
|
|
342
|
+
|
|
292
343
|
# Initialize Objects for later assignment
|
|
293
344
|
self.otds_object: OTDS | None = None
|
|
294
345
|
self.otcs_object: OTCS | None = None
|
|
@@ -299,15 +350,19 @@ class Customizer:
|
|
|
299
350
|
self.otiv_object: OTIV | None = None
|
|
300
351
|
self.k8s_object: K8s | None = None
|
|
301
352
|
self.m365_object: M365 | None = None
|
|
353
|
+
self.core_share_object: CoreShare | None = None
|
|
302
354
|
self.browser_automation_object: BrowserAutomation | None = None
|
|
355
|
+
self.otawp_object: OTAWP | None = None
|
|
356
|
+
|
|
357
|
+
# end initializer
|
|
303
358
|
|
|
304
|
-
def log_header(self, text: str, char: str = "=", length: int =
|
|
359
|
+
def log_header(self, text: str, char: str = "=", length: int = 80):
|
|
305
360
|
"""Helper method to output a section header in the log file
|
|
306
361
|
|
|
307
362
|
Args:
|
|
308
|
-
text (str):
|
|
363
|
+
text (str): Headline text to output into the log file.
|
|
309
364
|
char (str, optional): header line character. Defaults to "=".
|
|
310
|
-
length (int, optional): maxium length. Defaults to
|
|
365
|
+
length (int, optional): maxium length. Defaults to 80.
|
|
311
366
|
Returns:
|
|
312
367
|
None
|
|
313
368
|
"""
|
|
@@ -329,7 +384,7 @@ class Customizer:
|
|
|
329
384
|
"%s %s %s", char * char_count, text, char * (char_count + extra_char)
|
|
330
385
|
)
|
|
331
386
|
|
|
332
|
-
|
|
387
|
+
# end method definition
|
|
333
388
|
|
|
334
389
|
def init_m365(self) -> M365:
|
|
335
390
|
"""Initialize the M365 object we use to talk to the Microsoft Graph API.
|
|
@@ -373,9 +428,13 @@ class Customizer:
|
|
|
373
428
|
"Microsoft 365 Default License SKU = %s", self.m365_settings.sku_id
|
|
374
429
|
)
|
|
375
430
|
logger.info(
|
|
376
|
-
"Microsoft 365 Teams App
|
|
431
|
+
"Microsoft 365 Teams App Name = %s",
|
|
377
432
|
self.m365_settings.teams_app_name,
|
|
378
433
|
)
|
|
434
|
+
logger.info(
|
|
435
|
+
"Microsoft 365 Teams App External ID = %s",
|
|
436
|
+
self.m365_settings.teams_app_external_id,
|
|
437
|
+
)
|
|
379
438
|
|
|
380
439
|
m365_object = M365(
|
|
381
440
|
tenant_id=self.m365_settings.tenant_id,
|
|
@@ -384,16 +443,309 @@ class Customizer:
|
|
|
384
443
|
domain=self.m365_settings.domain,
|
|
385
444
|
sku_id=self.m365_settings.sku_id,
|
|
386
445
|
teams_app_name=self.m365_settings.teams_app_name,
|
|
446
|
+
teams_app_external_id=self.m365_settings.teams_app_external_id,
|
|
387
447
|
)
|
|
388
448
|
|
|
389
449
|
if m365_object and m365_object.authenticate():
|
|
390
450
|
logger.info("Connected to Microsoft Graph API.")
|
|
391
|
-
return m365_object
|
|
392
451
|
else:
|
|
393
452
|
logger.error("Failed to connect to Microsoft Graph API.")
|
|
394
453
|
return m365_object
|
|
395
454
|
|
|
396
|
-
|
|
455
|
+
logger.info(
|
|
456
|
+
"Download M365 Teams App -> '%s' (external ID = %s) from Extended ECM (OTCS)...",
|
|
457
|
+
self.m365_settings.teams_app_name,
|
|
458
|
+
self.m365_settings.teams_app_external_id,
|
|
459
|
+
)
|
|
460
|
+
|
|
461
|
+
# Download MS Teams App from OTCS (this has with 23.2 a nasty side-effect
|
|
462
|
+
# of unsetting 2 checkboxes on that config page - we reset these checkboxes
|
|
463
|
+
# with the settings file "O365Settings.xml"):
|
|
464
|
+
response = self.otcs_frontend_object.download_config_file(
|
|
465
|
+
"/cs/cs?func=officegroups.DownloadTeamsPackage",
|
|
466
|
+
"/tmp/ot.xecm.teams.zip",
|
|
467
|
+
)
|
|
468
|
+
# this app upload will be done with the user credentials - this is required:
|
|
469
|
+
m365_object.authenticate_user(
|
|
470
|
+
self.m365_settings.user, self.m365_settings.password
|
|
471
|
+
)
|
|
472
|
+
|
|
473
|
+
# Check if the app is already installed in the apps catalog
|
|
474
|
+
# ideally we want to use the
|
|
475
|
+
app_exist = False
|
|
476
|
+
|
|
477
|
+
# If the App External ID is provided via Env variable then we
|
|
478
|
+
# prefer to use it instead of the App name:
|
|
479
|
+
if self.m365_settings.teams_app_external_id:
|
|
480
|
+
logger.info(
|
|
481
|
+
"Check if M365 Teams App -> '%s' (%s) is already installed in catalog using external app ID...",
|
|
482
|
+
self.m365_settings.teams_app_name,
|
|
483
|
+
self.m365_settings.teams_app_external_id,
|
|
484
|
+
)
|
|
485
|
+
response = m365_object.get_teams_apps(
|
|
486
|
+
filter_expression="externalId eq '{}'".format(
|
|
487
|
+
self.m365_settings.teams_app_external_id
|
|
488
|
+
)
|
|
489
|
+
)
|
|
490
|
+
# this should always be True as ID is unique:
|
|
491
|
+
app_exist = m365_object.exist_result_item(
|
|
492
|
+
response=response,
|
|
493
|
+
key="externalId",
|
|
494
|
+
value=self.m365_settings.teams_app_external_id,
|
|
495
|
+
)
|
|
496
|
+
# If the app could not be found via the external ID we fall back to
|
|
497
|
+
# search for the app by name:
|
|
498
|
+
if not app_exist:
|
|
499
|
+
if self.m365_settings.teams_app_external_id:
|
|
500
|
+
logger.info(
|
|
501
|
+
"Could not find M365 Teams App using the external ID -> %s. Try to lookup the app by name -> '%s' instead...",
|
|
502
|
+
self.m365_settings.teams_app_external_id,
|
|
503
|
+
self.m365_settings.teams_app_name,
|
|
504
|
+
)
|
|
505
|
+
logger.info(
|
|
506
|
+
"Check if M365 Teams App -> '%s' is already installed in catalog (using app name)...",
|
|
507
|
+
self.m365_settings.teams_app_name,
|
|
508
|
+
)
|
|
509
|
+
response = m365_object.get_teams_apps(
|
|
510
|
+
filter_expression="contains(displayName, '{}')".format(
|
|
511
|
+
self.m365_settings.teams_app_name
|
|
512
|
+
)
|
|
513
|
+
)
|
|
514
|
+
app_exist = m365_object.exist_result_item(
|
|
515
|
+
response=response,
|
|
516
|
+
key="displayName",
|
|
517
|
+
value=self.m365_settings.teams_app_name,
|
|
518
|
+
)
|
|
519
|
+
if app_exist:
|
|
520
|
+
# We double check that we have the effective name of the app
|
|
521
|
+
# in the catalog to avoid errors when the app is looked up
|
|
522
|
+
# by its wrong name in the customizer automation. This can
|
|
523
|
+
# happen if the app is installed manually or the environment
|
|
524
|
+
# variable is set to a wrong name.
|
|
525
|
+
app_catalog_name = m365_object.get_result_value(response, "displayName")
|
|
526
|
+
if app_catalog_name != self.m365_settings.teams_app_name:
|
|
527
|
+
logger.warning(
|
|
528
|
+
"The Extended ECM app name -> '%s' in the M365 Teams catalog does not match the defined app name '%s'! Somebody must have manually installed the app with the wrong name!",
|
|
529
|
+
app_catalog_name,
|
|
530
|
+
self.m365_settings.teams_app_name,
|
|
531
|
+
)
|
|
532
|
+
# Align the name in the settings dict with the existing name in the catalog.
|
|
533
|
+
self.m365_settings.teams_app_name = app_catalog_name
|
|
534
|
+
# Align the name in the M365 object config dict with the existing name in the catalog.
|
|
535
|
+
m365_object.config()["teamsAppName"] = app_catalog_name
|
|
536
|
+
app_internal_id = m365_object.get_result_value(
|
|
537
|
+
response=response, key="id", index=0
|
|
538
|
+
) # 0 = Index = first item
|
|
539
|
+
# Store the internal ID for later use
|
|
540
|
+
m365_object.config()["teamsAppInternalId"] = app_internal_id
|
|
541
|
+
app_catalog_version = m365_object.get_result_value(
|
|
542
|
+
response=response,
|
|
543
|
+
key="version",
|
|
544
|
+
index=0,
|
|
545
|
+
sub_dict_name="appDefinitions",
|
|
546
|
+
)
|
|
547
|
+
logger.info(
|
|
548
|
+
"M365 Teams App -> '%s' (external ID = %s) is already in app catalog with app internal ID -> %s and version -> %s. Check if we have a newer version to upload...",
|
|
549
|
+
self.m365_settings.teams_app_name,
|
|
550
|
+
self.m365_settings.teams_app_external_id,
|
|
551
|
+
app_internal_id,
|
|
552
|
+
app_catalog_version,
|
|
553
|
+
)
|
|
554
|
+
app_download_version = m365_object.extract_version_from_app_manifest(
|
|
555
|
+
app_path="/tmp/ot.xecm.teams.zip"
|
|
556
|
+
)
|
|
557
|
+
if app_catalog_version < app_download_version:
|
|
558
|
+
logger.info(
|
|
559
|
+
"Upgrading Extended ECM Teams App in catalog from version -> %s to version -> %s...",
|
|
560
|
+
app_catalog_version,
|
|
561
|
+
app_download_version,
|
|
562
|
+
)
|
|
563
|
+
response = m365_object.upload_teams_app(
|
|
564
|
+
app_path="/tmp/ot.xecm.teams.zip",
|
|
565
|
+
update_existing_app=True,
|
|
566
|
+
app_catalog_id=app_internal_id,
|
|
567
|
+
)
|
|
568
|
+
app_internal_id = m365_object.get_result_value(
|
|
569
|
+
response=response,
|
|
570
|
+
key="teamsAppId",
|
|
571
|
+
)
|
|
572
|
+
if app_internal_id:
|
|
573
|
+
logger.info(
|
|
574
|
+
"Successfully upgraded Extended ECM Teams App -> %s (external ID = %s). Internal App ID -> %s",
|
|
575
|
+
self.m365_settings.teams_app_name,
|
|
576
|
+
self.m365_settings.teams_app_external_id,
|
|
577
|
+
app_internal_id,
|
|
578
|
+
)
|
|
579
|
+
# Store the internal ID for later use
|
|
580
|
+
m365_object.config()["teamsAppInternalId"] = app_internal_id
|
|
581
|
+
else:
|
|
582
|
+
logger.error(
|
|
583
|
+
"Failed to upgrade Extended ECM Teams App -> %s (external ID = %s).",
|
|
584
|
+
self.m365_settings.teams_app_name,
|
|
585
|
+
self.m365_settings.teams_app_external_id,
|
|
586
|
+
)
|
|
587
|
+
else:
|
|
588
|
+
logger.info(
|
|
589
|
+
"No upgrade required. The downloaded version -> %s is not newer than the version -> %s which is already in the M365 app catalog.",
|
|
590
|
+
app_download_version,
|
|
591
|
+
app_catalog_version,
|
|
592
|
+
)
|
|
593
|
+
else: # Extended ECM M365 Teams app is not yet installed...
|
|
594
|
+
logger.info(
|
|
595
|
+
"Extended Teams ECM App -> '%s' (external ID = %s) is not yet in app catalog. Installing as new app...",
|
|
596
|
+
self.m365_settings.teams_app_name,
|
|
597
|
+
self.m365_settings.teams_app_external_id,
|
|
598
|
+
)
|
|
599
|
+
response = m365_object.upload_teams_app(
|
|
600
|
+
app_path="/tmp/ot.xecm.teams.zip", update_existing_app=False
|
|
601
|
+
)
|
|
602
|
+
app_internal_id = m365_object.get_result_value(
|
|
603
|
+
response=response,
|
|
604
|
+
key="id", # for new installs it is NOT "teamsAppId" but "id" as we use a different M365 Graph API endpoint !!!
|
|
605
|
+
)
|
|
606
|
+
if app_internal_id:
|
|
607
|
+
logger.info(
|
|
608
|
+
"Successfully installed Extended ECM Teams App -> '%s' (external ID = %s). Internal App ID -> %s",
|
|
609
|
+
self.m365_settings.teams_app_name,
|
|
610
|
+
self.m365_settings.teams_app_external_id,
|
|
611
|
+
app_internal_id,
|
|
612
|
+
)
|
|
613
|
+
# Store the internal ID for later use
|
|
614
|
+
m365_object.config()["teamsAppInternalId"] = app_internal_id
|
|
615
|
+
else:
|
|
616
|
+
logger.error(
|
|
617
|
+
"Failed to install Extended ECM Teams App -> '%s' (external ID = %s).",
|
|
618
|
+
self.m365_settings.teams_app_name,
|
|
619
|
+
self.m365_settings.teams_app_external_id,
|
|
620
|
+
)
|
|
621
|
+
|
|
622
|
+
# logger.info("======== Upload Outlook Add-In ============")
|
|
623
|
+
|
|
624
|
+
# # Download MS Outlook Add-In from OTCS:
|
|
625
|
+
# MANIFEST_FILE = "/tmp/BusinessWorkspace.Manifest.xml"
|
|
626
|
+
# if not self.otcs_frontend_object.download_config_file(
|
|
627
|
+
# "/cs/cs?func=outlookaddin.DownloadManifest",
|
|
628
|
+
# MANIFEST_FILE,
|
|
629
|
+
# "DeployedContentServer",
|
|
630
|
+
# self.otcs_settings.public_url,
|
|
631
|
+
# ):
|
|
632
|
+
# logger.error("Failed to download M365 Outlook Add-In from Extended ECM!")
|
|
633
|
+
# else:
|
|
634
|
+
# # THIS IS NOT IMPLEMENTED DUE TO LACK OF M365 GRAPH API SUPPORT!
|
|
635
|
+
# # Do it manually for now: https://admin.microsoft.com/#/Settings/IntegratedApps
|
|
636
|
+
# logger.info("Successfully downloaded M365 Outlook Add-In from Extended ECM to %s", MANIFEST_FILE)
|
|
637
|
+
# m365_object.upload_outlook_app(MANIFEST_FILE)
|
|
638
|
+
|
|
639
|
+
return m365_object
|
|
640
|
+
|
|
641
|
+
# end method definition
|
|
642
|
+
|
|
643
|
+
def init_avts(self) -> AVTS:
|
|
644
|
+
"""Initialize the Core Share object we use to talk to the Core Share API.
|
|
645
|
+
|
|
646
|
+
Args:
|
|
647
|
+
None
|
|
648
|
+
Returns:
|
|
649
|
+
object: CoreShare object or None if the object couldn't be created or
|
|
650
|
+
the authentication fails.
|
|
651
|
+
"""
|
|
652
|
+
|
|
653
|
+
logger.info(
|
|
654
|
+
"Aviator Search Base URL = %s", self.avts_settings.base_url
|
|
655
|
+
)
|
|
656
|
+
logger.info(
|
|
657
|
+
"Aviator Search OTDS URL = %s", self.avts_settings.otds_url
|
|
658
|
+
)
|
|
659
|
+
logger.info(
|
|
660
|
+
"Aviator Search Client ID = %s", self.avts_settings.client_id
|
|
661
|
+
)
|
|
662
|
+
logger.debug(
|
|
663
|
+
"Aviator Search Client Secret = %s",
|
|
664
|
+
self.avts_settings.client_secret,
|
|
665
|
+
)
|
|
666
|
+
logger.info(
|
|
667
|
+
"Aviator Search User ID = %s", self.avts_settings.username
|
|
668
|
+
)
|
|
669
|
+
logger.debug(
|
|
670
|
+
"Aviator Search User Password = %s",
|
|
671
|
+
self.avts_settings.password,
|
|
672
|
+
)
|
|
673
|
+
|
|
674
|
+
avts_object = AVTS(
|
|
675
|
+
otds_url=self.avts_settings.otds_url,
|
|
676
|
+
base_url=self.avts_settings.base_url,
|
|
677
|
+
client_id=self.avts_settings.client_id,
|
|
678
|
+
client_secret=self.avts_settings.client_secret,
|
|
679
|
+
username=self.avts_settings.username,
|
|
680
|
+
password=self.avts_settings.password,
|
|
681
|
+
)
|
|
682
|
+
|
|
683
|
+
return avts_object
|
|
684
|
+
|
|
685
|
+
# end method definition
|
|
686
|
+
|
|
687
|
+
def init_coreshare(self) -> CoreShare:
|
|
688
|
+
"""Initialize the Core Share object we use to talk to the Core Share API.
|
|
689
|
+
|
|
690
|
+
Args:
|
|
691
|
+
None
|
|
692
|
+
Returns:
|
|
693
|
+
object: CoreShare object or None if the object couldn't be created or
|
|
694
|
+
the authentication fails.
|
|
695
|
+
"""
|
|
696
|
+
|
|
697
|
+
logger.info(
|
|
698
|
+
"Core Share Base URL = %s", self.core_share_settings.base_url
|
|
699
|
+
)
|
|
700
|
+
logger.info(
|
|
701
|
+
"Core Share SSO URL = %s", self.core_share_settings.sso_url
|
|
702
|
+
)
|
|
703
|
+
logger.info(
|
|
704
|
+
"Core Share Client ID = %s", self.core_share_settings.client_id
|
|
705
|
+
)
|
|
706
|
+
logger.debug(
|
|
707
|
+
"Core Share Client Secret = %s",
|
|
708
|
+
self.core_share_settings.client_secret,
|
|
709
|
+
)
|
|
710
|
+
logger.info(
|
|
711
|
+
"Core Share User = %s",
|
|
712
|
+
(
|
|
713
|
+
self.core_share_settings.username
|
|
714
|
+
if self.core_share_settings.username != ""
|
|
715
|
+
else "<not configured>"
|
|
716
|
+
),
|
|
717
|
+
)
|
|
718
|
+
logger.debug(
|
|
719
|
+
"Core Share Password = %s",
|
|
720
|
+
(
|
|
721
|
+
self.core_share_settings.password
|
|
722
|
+
if self.core_share_settings.password != ""
|
|
723
|
+
else "<not configured>"
|
|
724
|
+
),
|
|
725
|
+
)
|
|
726
|
+
|
|
727
|
+
core_share_object = CoreShare(
|
|
728
|
+
base_url=self.core_share_settings.base_url,
|
|
729
|
+
sso_url=self.core_share_settings.sso_url,
|
|
730
|
+
client_id=self.core_share_settings.client_id,
|
|
731
|
+
client_secret=self.core_share_settings.client_secret,
|
|
732
|
+
username=self.core_share_settings.username,
|
|
733
|
+
password=self.core_share_settings.password,
|
|
734
|
+
)
|
|
735
|
+
|
|
736
|
+
if core_share_object and core_share_object.authenticate_admin():
|
|
737
|
+
logger.info("Connected to Core Share as Tenant Admin.")
|
|
738
|
+
else:
|
|
739
|
+
logger.error("Failed to connect to Core Share as Tenant Admin.")
|
|
740
|
+
|
|
741
|
+
if core_share_object and core_share_object.authenticate_user():
|
|
742
|
+
logger.info("Connected to Core Share as Tenant Service User.")
|
|
743
|
+
else:
|
|
744
|
+
logger.error("Failed to connect to Core Share as Tenant Service User.")
|
|
745
|
+
|
|
746
|
+
return core_share_object
|
|
747
|
+
|
|
748
|
+
# end method definition
|
|
397
749
|
|
|
398
750
|
def init_k8s(self) -> K8s:
|
|
399
751
|
"""Initialize the Kubernetes object we use to talk to the Kubernetes API.
|
|
@@ -407,10 +759,10 @@ class Customizer:
|
|
|
407
759
|
"""
|
|
408
760
|
|
|
409
761
|
logger.info("Connection parameters Kubernetes (K8s):")
|
|
410
|
-
logger.info("K8s inCluster
|
|
411
|
-
logger.info("K8s namespace
|
|
762
|
+
logger.info("K8s inCluster = %s", self.k8s_settings.in_cluster)
|
|
763
|
+
logger.info("K8s namespace = %s", self.k8s_settings.namespace)
|
|
412
764
|
logger.info(
|
|
413
|
-
"K8s kubeconfig file
|
|
765
|
+
"K8s kubeconfig file = %s",
|
|
414
766
|
self.k8s_settings.kubeconfig_file,
|
|
415
767
|
)
|
|
416
768
|
|
|
@@ -430,14 +782,14 @@ class Customizer:
|
|
|
430
782
|
)
|
|
431
783
|
if not otcs_frontend_scale:
|
|
432
784
|
logger.error(
|
|
433
|
-
"Cannot find Kubernetes Stateful Set for OTCS Frontends
|
|
785
|
+
"Cannot find Kubernetes Stateful Set -> '%s' for OTCS Frontends!",
|
|
434
786
|
self.otcs_settings.k8s_statefulset_frontend,
|
|
435
787
|
)
|
|
436
788
|
sys.exit()
|
|
437
789
|
|
|
438
790
|
self.otcs_settings.replicas_frontend = otcs_frontend_scale.spec.replicas # type: ignore
|
|
439
791
|
logger.info(
|
|
440
|
-
"Stateful Set -> %s has -> %s replicas",
|
|
792
|
+
"Stateful Set -> '%s' has -> %s replicas",
|
|
441
793
|
self.otcs_settings.k8s_statefulset_frontend,
|
|
442
794
|
self.otcs_settings.replicas_frontend,
|
|
443
795
|
)
|
|
@@ -448,21 +800,21 @@ class Customizer:
|
|
|
448
800
|
)
|
|
449
801
|
if not otcs_backend_scale:
|
|
450
802
|
logger.error(
|
|
451
|
-
"Cannot find Kubernetes Stateful Set for OTCS Backends
|
|
803
|
+
"Cannot find Kubernetes Stateful Set -> '%s' for OTCS Backends!",
|
|
452
804
|
self.otcs_settings.k8s_statefulset_backend,
|
|
453
805
|
)
|
|
454
806
|
sys.exit()
|
|
455
807
|
|
|
456
808
|
self.otcs_settings.replicas_backend = otcs_backend_scale.spec.replicas # type: ignore
|
|
457
809
|
logger.info(
|
|
458
|
-
"Stateful Set -> %s has -> %s replicas",
|
|
810
|
+
"Stateful Set -> '%s' has -> %s replicas",
|
|
459
811
|
self.otcs_settings.k8s_statefulset_backend,
|
|
460
812
|
self.otcs_settings.replicas_backend,
|
|
461
813
|
)
|
|
462
814
|
|
|
463
815
|
return k8s_object
|
|
464
816
|
|
|
465
|
-
|
|
817
|
+
# end method definition
|
|
466
818
|
|
|
467
819
|
def init_otds(self) -> OTDS:
|
|
468
820
|
"""Initialize the OTDS object and parameters and authenticate at OTDS once it is ready.
|
|
@@ -491,6 +843,7 @@ class Customizer:
|
|
|
491
843
|
username=self.otds_settings.username,
|
|
492
844
|
password=self.otds_settings.password,
|
|
493
845
|
otds_ticket=self.otds_settings.otds_ticket,
|
|
846
|
+
bindPassword=self.otds_settings.bindPassword
|
|
494
847
|
)
|
|
495
848
|
|
|
496
849
|
logger.info("Authenticating to OTDS...")
|
|
@@ -519,7 +872,7 @@ class Customizer:
|
|
|
519
872
|
|
|
520
873
|
return otds_object
|
|
521
874
|
|
|
522
|
-
|
|
875
|
+
# end method definition
|
|
523
876
|
|
|
524
877
|
def init_otac(self) -> OTAC:
|
|
525
878
|
"""Initialize the OTAC object and parameters.
|
|
@@ -557,6 +910,16 @@ class Customizer:
|
|
|
557
910
|
self.otds_settings.password,
|
|
558
911
|
)
|
|
559
912
|
|
|
913
|
+
# This is a work-around as OTCS container automation is not
|
|
914
|
+
# enabling the certificate reliable.
|
|
915
|
+
response = otac_object.enable_certificate(
|
|
916
|
+
cert_name="SP_otcs-admin-0", cert_type="ARC"
|
|
917
|
+
)
|
|
918
|
+
if not response:
|
|
919
|
+
logger.error("Failed to enable OTAC certificate for Extended ECM!")
|
|
920
|
+
else:
|
|
921
|
+
logger.info("Successfully enabled OTAC certificate for Extended ECM!")
|
|
922
|
+
|
|
560
923
|
# is there a known server configured for Archive Center (to sync content with)
|
|
561
924
|
if otac_object and self.otac_settings.known_server != "":
|
|
562
925
|
# wait until the OTAC pod is in ready state
|
|
@@ -587,7 +950,7 @@ class Customizer:
|
|
|
587
950
|
|
|
588
951
|
return otac_object
|
|
589
952
|
|
|
590
|
-
|
|
953
|
+
# end method definition
|
|
591
954
|
|
|
592
955
|
def init_otcs(
|
|
593
956
|
self,
|
|
@@ -630,6 +993,10 @@ class Customizer:
|
|
|
630
993
|
"OTCS K8s Backend Pods = %s",
|
|
631
994
|
self.otcs_settings.k8s_statefulset_backend,
|
|
632
995
|
)
|
|
996
|
+
logger.info(
|
|
997
|
+
"FEME URI = %s",
|
|
998
|
+
self.otcs_settings.feme_uri,
|
|
999
|
+
)
|
|
633
1000
|
|
|
634
1001
|
logger.debug("Checking if OTCS object has already been initialized")
|
|
635
1002
|
|
|
@@ -646,6 +1013,8 @@ class Customizer:
|
|
|
646
1013
|
partition_name,
|
|
647
1014
|
resource_name,
|
|
648
1015
|
otds_ticket=otds_ticket,
|
|
1016
|
+
base_path=self.otcs_settings.base_path,
|
|
1017
|
+
feme_uri=self.otcs_settings.feme_uri,
|
|
649
1018
|
)
|
|
650
1019
|
|
|
651
1020
|
# It is important to wait for OTCS to be configured - otherwise we
|
|
@@ -666,17 +1035,17 @@ class Customizer:
|
|
|
666
1035
|
otcs_cookie = otcs_object.authenticate()
|
|
667
1036
|
logger.info("OTCS is ready now.")
|
|
668
1037
|
|
|
669
|
-
if self.otcs_settings.update_admin_user:
|
|
670
|
-
|
|
671
|
-
otcs_object.update_user(1000, field="first_name", value="Terrarium")
|
|
672
|
-
otcs_object.update_user(1000, field="last_name", value="Admin")
|
|
1038
|
+
# if self.otcs_settings.update_admin_user:
|
|
1039
|
+
# Set first name and last name of Admin user (ID = 1000):
|
|
1040
|
+
# otcs_object.update_user(1000, field="first_name", value="Terrarium")
|
|
1041
|
+
# otcs_object.update_user(1000, field="last_name", value="Admin")
|
|
673
1042
|
|
|
674
1043
|
if "OTCS_RESSOURCE_ID" not in self.settings.placeholder_values:
|
|
675
|
-
self.settings.placeholder_values[
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
1044
|
+
self.settings.placeholder_values["OTCS_RESSOURCE_ID"] = (
|
|
1045
|
+
self.otds_object.get_resource(self.otcs_settings.resource_name)[
|
|
1046
|
+
"resourceID"
|
|
1047
|
+
]
|
|
1048
|
+
)
|
|
680
1049
|
logger.debug(
|
|
681
1050
|
"Placeholder values after OTCS init = %s",
|
|
682
1051
|
self.settings.placeholder_values,
|
|
@@ -686,9 +1055,9 @@ class Customizer:
|
|
|
686
1055
|
otcs_resource = self.otds_object.get_resource(
|
|
687
1056
|
self.otcs_settings.resource_name
|
|
688
1057
|
)
|
|
689
|
-
otcs_resource[
|
|
690
|
-
"
|
|
691
|
-
|
|
1058
|
+
otcs_resource["logoutURL"] = (
|
|
1059
|
+
f"{self.otawp_settings.public_protocol}://{self.otawp_settings.public_url}/home/system/wcp/sso/sso_logout.htm"
|
|
1060
|
+
)
|
|
692
1061
|
otcs_resource["logoutMethod"] = "GET"
|
|
693
1062
|
|
|
694
1063
|
self.otds_object.update_resource(name="cs", resource=otcs_resource)
|
|
@@ -698,7 +1067,7 @@ class Customizer:
|
|
|
698
1067
|
|
|
699
1068
|
return otcs_object
|
|
700
1069
|
|
|
701
|
-
|
|
1070
|
+
# end method definition
|
|
702
1071
|
|
|
703
1072
|
def init_otiv(self) -> OTIV | None:
|
|
704
1073
|
"""Initialize the OTIV (Intelligent Viewing) object and its OTDS settings.
|
|
@@ -750,9 +1119,27 @@ class Customizer:
|
|
|
750
1119
|
)
|
|
751
1120
|
return None
|
|
752
1121
|
|
|
1122
|
+
# Workaround for VAT-4580 (24.2.0)
|
|
1123
|
+
update_publisher = self.otds_object.update_user(
|
|
1124
|
+
partition="Content Server Service Users",
|
|
1125
|
+
user_id="iv-publisher",
|
|
1126
|
+
attribute_name="oTType",
|
|
1127
|
+
attribute_value="ServiceUser",
|
|
1128
|
+
)
|
|
1129
|
+
while update_publisher is None:
|
|
1130
|
+
update_publisher = self.otds_object.update_user(
|
|
1131
|
+
partition="Content Server Service Users",
|
|
1132
|
+
user_id="iv-publisher",
|
|
1133
|
+
attribute_name="oTType",
|
|
1134
|
+
attribute_value="ServiceUser",
|
|
1135
|
+
)
|
|
1136
|
+
time.sleep(30)
|
|
1137
|
+
|
|
1138
|
+
logger.info("OTDS user iv-publisher -> updating oTType=ServiceUser")
|
|
1139
|
+
|
|
753
1140
|
return otiv_object
|
|
754
1141
|
|
|
755
|
-
|
|
1142
|
+
# end method definition
|
|
756
1143
|
|
|
757
1144
|
def init_otpd(self) -> OTPD:
|
|
758
1145
|
"""Initialize the OTPD (PowerDocs) object and parameters.
|
|
@@ -829,7 +1216,7 @@ class Customizer:
|
|
|
829
1216
|
logger.info("OTAWP K8s Config Map = %s", self.otawp_settings.k8s_configmap)
|
|
830
1217
|
|
|
831
1218
|
logger.info(
|
|
832
|
-
"Wait for OTCS to create its OTDS resource with name -> %s...",
|
|
1219
|
+
"Wait for OTCS to create its OTDS resource with name -> '%s'...",
|
|
833
1220
|
self.otcs_settings.resource_name,
|
|
834
1221
|
)
|
|
835
1222
|
|
|
@@ -838,7 +1225,7 @@ class Customizer:
|
|
|
838
1225
|
otcs_resource = self.otds_object.get_resource(self.otcs_settings.resource_name)
|
|
839
1226
|
while otcs_resource is None:
|
|
840
1227
|
logger.warning(
|
|
841
|
-
"OTDS resource for Content Server with name -> %s does not exist yet. Waiting...",
|
|
1228
|
+
"OTDS resource for Content Server with name -> '%s' does not exist yet. Waiting...",
|
|
842
1229
|
self.otcs_settings.resource_name,
|
|
843
1230
|
)
|
|
844
1231
|
time.sleep(30)
|
|
@@ -854,7 +1241,7 @@ class Customizer:
|
|
|
854
1241
|
awp_resource = self.otds_object.get_resource(self.otawp_settings.resource_name)
|
|
855
1242
|
if not awp_resource:
|
|
856
1243
|
logger.info(
|
|
857
|
-
"OTDS resource -> %s for AppWorks Platform does not yet exist. Creating...",
|
|
1244
|
+
"OTDS resource -> '%s' for AppWorks Platform does not yet exist. Creating...",
|
|
858
1245
|
self.otawp_settings.resource_name,
|
|
859
1246
|
)
|
|
860
1247
|
# Create a Python dict with the special payload we need for AppWorks:
|
|
@@ -1067,10 +1454,10 @@ class Customizer:
|
|
|
1067
1454
|
]
|
|
1068
1455
|
|
|
1069
1456
|
awp_resource = self.otds_object.add_resource(
|
|
1070
|
-
self.otawp_settings.resource_name,
|
|
1071
|
-
"AppWorks Platform",
|
|
1072
|
-
"AppWorks Platform",
|
|
1073
|
-
additional_payload,
|
|
1457
|
+
name=self.otawp_settings.resource_name,
|
|
1458
|
+
description="AppWorks Platform",
|
|
1459
|
+
display_name="AppWorks Platform",
|
|
1460
|
+
additional_payload=additional_payload,
|
|
1074
1461
|
)
|
|
1075
1462
|
else:
|
|
1076
1463
|
logger.info(
|
|
@@ -1150,7 +1537,7 @@ class Customizer:
|
|
|
1150
1537
|
)
|
|
1151
1538
|
while otcs_partition is None:
|
|
1152
1539
|
logger.warning(
|
|
1153
|
-
"OTDS user partition for Content Server with name -> %s does not exist yet. Waiting...",
|
|
1540
|
+
"OTDS user partition for Content Server with name -> '%s' does not exist yet. Waiting...",
|
|
1154
1541
|
self.otcs_settings.partition,
|
|
1155
1542
|
)
|
|
1156
1543
|
|
|
@@ -1188,7 +1575,7 @@ class Customizer:
|
|
|
1188
1575
|
# check if the license file exists, otherwise skip for versions pre 24.1
|
|
1189
1576
|
if os.path.isfile(self.otawp_settings.license_file):
|
|
1190
1577
|
logger.info(
|
|
1191
|
-
"OTAWP license file
|
|
1578
|
+
"Found OTAWP license file -> '%s', assiging it to ressource '%s'...",
|
|
1192
1579
|
self.otawp_settings.license_file,
|
|
1193
1580
|
self.otawp_settings.resource_name,
|
|
1194
1581
|
)
|
|
@@ -1201,14 +1588,14 @@ class Customizer:
|
|
|
1201
1588
|
)
|
|
1202
1589
|
if not otawp_license:
|
|
1203
1590
|
logger.error(
|
|
1204
|
-
"Couldn't apply license -> %s for product -> %s to OTDS resource -> %s",
|
|
1591
|
+
"Couldn't apply license -> '%s' for product -> '%s' to OTDS resource -> '%s'",
|
|
1205
1592
|
self.otawp_settings.license_file,
|
|
1206
1593
|
self.otawp_settings.product_name,
|
|
1207
1594
|
awp_resource["resourceID"],
|
|
1208
1595
|
)
|
|
1209
1596
|
else:
|
|
1210
1597
|
logger.info(
|
|
1211
|
-
"Successfully applied license -> %s for product -> %s to OTDS resource -> %s",
|
|
1598
|
+
"Successfully applied license -> '%s' for product -> '%s' to OTDS resource -> '%s'",
|
|
1212
1599
|
self.otawp_settings.license_file,
|
|
1213
1600
|
self.otawp_settings.product_name,
|
|
1214
1601
|
awp_resource["resourceID"],
|
|
@@ -1237,20 +1624,29 @@ class Customizer:
|
|
|
1237
1624
|
)
|
|
1238
1625
|
if not assigned_license:
|
|
1239
1626
|
logger.error(
|
|
1240
|
-
"Partition -> %s could not be assigned to license -> %s (%s)",
|
|
1627
|
+
"Partition -> '%s' could not be assigned to license -> '%s' (%s)",
|
|
1241
1628
|
partition_name,
|
|
1242
1629
|
self.otawp_settings.product_name,
|
|
1243
1630
|
"USERS",
|
|
1244
1631
|
)
|
|
1245
1632
|
else:
|
|
1246
1633
|
logger.info(
|
|
1247
|
-
"Partition -> %s successfully assigned to license -> %s (%s)",
|
|
1634
|
+
"Partition -> '%s' successfully assigned to license -> '%s' (%s)",
|
|
1248
1635
|
partition_name,
|
|
1249
1636
|
self.otawp_settings.product_name,
|
|
1250
1637
|
"USERS",
|
|
1251
1638
|
)
|
|
1639
|
+
otawp_object = OTAWP(
|
|
1640
|
+
self.otawp_settings.protocol,
|
|
1641
|
+
self.otawp_settings.k8s_statefulset,
|
|
1642
|
+
str(self.otawp_settings.port),
|
|
1643
|
+
"sysadmin",
|
|
1644
|
+
self.otawp_settings.password,
|
|
1645
|
+
"",
|
|
1646
|
+
)
|
|
1647
|
+
return otawp_object
|
|
1252
1648
|
|
|
1253
|
-
|
|
1649
|
+
# end method definition
|
|
1254
1650
|
|
|
1255
1651
|
def restart_otcs_service(self, otcs_object: OTCS, extra_wait_time: int = 60):
|
|
1256
1652
|
"""Restart the Content Server service in all OTCS pods
|
|
@@ -1273,32 +1669,44 @@ class Customizer:
|
|
|
1273
1669
|
for x in range(0, self.otcs_settings.replicas_frontend):
|
|
1274
1670
|
pod_name = self.otcs_settings.k8s_statefulset_frontend + "-" + str(x)
|
|
1275
1671
|
|
|
1276
|
-
logger.info("Deactivate Liveness probe for pod -> %s", pod_name)
|
|
1672
|
+
logger.info("Deactivate Liveness probe for pod -> '%s'", pod_name)
|
|
1277
1673
|
self.k8s_object.exec_pod_command(
|
|
1278
|
-
pod_name,
|
|
1674
|
+
pod_name,
|
|
1675
|
+
["/bin/sh", "-c", "touch /tmp/keepalive"],
|
|
1676
|
+
container="otcs-frontend-container",
|
|
1279
1677
|
)
|
|
1280
|
-
logger.info("Restarting pod -> %s", pod_name)
|
|
1678
|
+
logger.info("Restarting pod -> '%s'", pod_name)
|
|
1281
1679
|
self.k8s_object.exec_pod_command(
|
|
1282
|
-
pod_name,
|
|
1680
|
+
pod_name,
|
|
1681
|
+
["/bin/sh", "-c", "/opt/opentext/cs/stop_csserver"],
|
|
1682
|
+
container="otcs-frontend-container",
|
|
1283
1683
|
)
|
|
1284
1684
|
self.k8s_object.exec_pod_command(
|
|
1285
|
-
pod_name,
|
|
1685
|
+
pod_name,
|
|
1686
|
+
["/bin/sh", "-c", "/opt/opentext/cs/start_csserver"],
|
|
1687
|
+
container="otcs-frontend-container",
|
|
1286
1688
|
)
|
|
1287
1689
|
|
|
1288
1690
|
# Restart all backends:
|
|
1289
1691
|
for x in range(0, self.otcs_settings.replicas_backend):
|
|
1290
1692
|
pod_name = self.otcs_settings.k8s_statefulset_backend + "-" + str(x)
|
|
1291
1693
|
|
|
1292
|
-
logger.info("Deactivate Liveness probe for pod -> %s", pod_name)
|
|
1694
|
+
logger.info("Deactivate Liveness probe for pod -> '%s'", pod_name)
|
|
1293
1695
|
self.k8s_object.exec_pod_command(
|
|
1294
|
-
pod_name,
|
|
1696
|
+
pod_name,
|
|
1697
|
+
["/bin/sh", "-c", "touch /tmp/keepalive"],
|
|
1698
|
+
container="otcs-admin-container",
|
|
1295
1699
|
)
|
|
1296
|
-
logger.info("Restarting pod -> %s", pod_name)
|
|
1700
|
+
logger.info("Restarting pod -> '%s'", pod_name)
|
|
1297
1701
|
self.k8s_object.exec_pod_command(
|
|
1298
|
-
pod_name,
|
|
1702
|
+
pod_name,
|
|
1703
|
+
["/bin/sh", "-c", "/opt/opentext/cs/stop_csserver"],
|
|
1704
|
+
container="otcs-admin-container",
|
|
1299
1705
|
)
|
|
1300
1706
|
self.k8s_object.exec_pod_command(
|
|
1301
|
-
pod_name,
|
|
1707
|
+
pod_name,
|
|
1708
|
+
["/bin/sh", "-c", "/opt/opentext/cs/start_csserver"],
|
|
1709
|
+
container="otcs-admin-container",
|
|
1302
1710
|
)
|
|
1303
1711
|
|
|
1304
1712
|
logger.info("Re-Authenticating to OTCS after restart of pods...")
|
|
@@ -1313,17 +1721,21 @@ class Customizer:
|
|
|
1313
1721
|
for x in range(0, self.otcs_settings.replicas_frontend):
|
|
1314
1722
|
pod_name = self.otcs_settings.k8s_statefulset_frontend + "-" + str(x)
|
|
1315
1723
|
|
|
1316
|
-
logger.info("Reactivate Liveness probe for pod -> %s", pod_name)
|
|
1724
|
+
logger.info("Reactivate Liveness probe for pod -> '%s'", pod_name)
|
|
1317
1725
|
self.k8s_object.exec_pod_command(
|
|
1318
|
-
pod_name,
|
|
1726
|
+
pod_name,
|
|
1727
|
+
["/bin/sh", "-c", "rm /tmp/keepalive"],
|
|
1728
|
+
container="otcs-frontend-container",
|
|
1319
1729
|
)
|
|
1320
1730
|
|
|
1321
1731
|
for x in range(0, self.otcs_settings.replicas_backend):
|
|
1322
1732
|
pod_name = self.otcs_settings.k8s_statefulset_backend + "-" + str(x)
|
|
1323
1733
|
|
|
1324
|
-
logger.info("Reactivate Liveness probe for pod -> %s", pod_name)
|
|
1734
|
+
logger.info("Reactivate Liveness probe for pod -> '%s'", pod_name)
|
|
1325
1735
|
self.k8s_object.exec_pod_command(
|
|
1326
|
-
pod_name,
|
|
1736
|
+
pod_name,
|
|
1737
|
+
["/bin/sh", "-c", "rm /tmp/keepalive"],
|
|
1738
|
+
container="otcs-admin-container",
|
|
1327
1739
|
)
|
|
1328
1740
|
|
|
1329
1741
|
logger.info("Restart OTCS frontend and backend pods has been completed.")
|
|
@@ -1337,7 +1749,7 @@ class Customizer:
|
|
|
1337
1749
|
time.sleep(extra_wait_time)
|
|
1338
1750
|
logger.info("Continue customizing...")
|
|
1339
1751
|
|
|
1340
|
-
|
|
1752
|
+
# end method definition
|
|
1341
1753
|
|
|
1342
1754
|
def restart_otac_service(self) -> bool:
|
|
1343
1755
|
"""Restart the Archive Center spawner service in OTAC pod
|
|
@@ -1352,7 +1764,7 @@ class Customizer:
|
|
|
1352
1764
|
return False
|
|
1353
1765
|
|
|
1354
1766
|
logger.info(
|
|
1355
|
-
"Restarting spawner service in Archive Center pod -> %s",
|
|
1767
|
+
"Restarting spawner service in Archive Center pod -> '%s'",
|
|
1356
1768
|
self.otac_settings.k8s_pod_name,
|
|
1357
1769
|
)
|
|
1358
1770
|
# The Archive Center Spawner needs to be run in "interactive" mode - otherwise the command will "hang":
|
|
@@ -1370,7 +1782,7 @@ class Customizer:
|
|
|
1370
1782
|
else:
|
|
1371
1783
|
return False
|
|
1372
1784
|
|
|
1373
|
-
|
|
1785
|
+
# end method definition
|
|
1374
1786
|
|
|
1375
1787
|
def restart_otawp_pod(self):
|
|
1376
1788
|
"""Delete the AppWorks Platform Pod to make Kubernetes restart it.
|
|
@@ -1382,7 +1794,7 @@ class Customizer:
|
|
|
1382
1794
|
|
|
1383
1795
|
self.k8s_object.delete_pod(self.otawp_settings.k8s_statefulset + "-0")
|
|
1384
1796
|
|
|
1385
|
-
|
|
1797
|
+
# end method definition
|
|
1386
1798
|
|
|
1387
1799
|
def consolidate_otds(self):
|
|
1388
1800
|
"""Consolidate OTDS resources
|
|
@@ -1395,7 +1807,7 @@ class Customizer:
|
|
|
1395
1807
|
if self.otawp_settings.enabled: # is AppWorks Platform deployed?
|
|
1396
1808
|
self.otds_object.consolidate(self.otawp_settings.resource_name)
|
|
1397
1809
|
|
|
1398
|
-
|
|
1810
|
+
# end method definition
|
|
1399
1811
|
|
|
1400
1812
|
def import_powerdocs_configuration(self, otpd_object: OTPD):
|
|
1401
1813
|
"""Import a database export (zip file) into the PowerDocs database
|
|
@@ -1408,7 +1820,7 @@ class Customizer:
|
|
|
1408
1820
|
# Download file from remote location specified by the OTPD_DBIMPORTFILE
|
|
1409
1821
|
# this must be a public place without authentication:
|
|
1410
1822
|
logger.info(
|
|
1411
|
-
"Download PowerDocs database file from URL -> %s",
|
|
1823
|
+
"Download PowerDocs database file from URL -> '%s'",
|
|
1412
1824
|
self.otpd_settings.db_importfile,
|
|
1413
1825
|
)
|
|
1414
1826
|
|
|
@@ -1416,7 +1828,7 @@ class Customizer:
|
|
|
1416
1828
|
package = requests.get(self.otpd_settings.db_importfile, timeout=60)
|
|
1417
1829
|
package.raise_for_status()
|
|
1418
1830
|
logger.info(
|
|
1419
|
-
"Successfully downloaded PowerDocs database file -> %s; status code -> %s",
|
|
1831
|
+
"Successfully downloaded PowerDocs database file -> '%s'; status code -> %s",
|
|
1420
1832
|
self.otpd_settings.db_importfile,
|
|
1421
1833
|
package.status_code,
|
|
1422
1834
|
)
|
|
@@ -1437,7 +1849,7 @@ class Customizer:
|
|
|
1437
1849
|
except requests.exceptions.HTTPError as err:
|
|
1438
1850
|
logger.error("Request error -> %s", err)
|
|
1439
1851
|
|
|
1440
|
-
|
|
1852
|
+
# end method definition
|
|
1441
1853
|
|
|
1442
1854
|
def set_maintenance_mode(self, enable: bool = True):
|
|
1443
1855
|
"""Enable or Disable Maintenance Mode
|
|
@@ -1475,12 +1887,14 @@ class Customizer:
|
|
|
1475
1887
|
)
|
|
1476
1888
|
logger.info("OTCS frontend is now back in Production Mode!")
|
|
1477
1889
|
|
|
1890
|
+
# end method definition
|
|
1891
|
+
|
|
1478
1892
|
def customization_run(self):
|
|
1479
1893
|
"""Central function to initiate the customization"""
|
|
1480
1894
|
# Set Timer for duration calculation
|
|
1481
|
-
self.settings.customizer_start_time = (
|
|
1482
|
-
|
|
1483
|
-
)
|
|
1895
|
+
self.settings.customizer_start_time = self.settings.customizer_end_time = (
|
|
1896
|
+
datetime.now()
|
|
1897
|
+
)
|
|
1484
1898
|
|
|
1485
1899
|
# Initialize the OTDS, OTCS and OTPD objects and wait for the
|
|
1486
1900
|
# pods to be ready. If any of this fails we bail out:
|
|
@@ -1510,7 +1924,7 @@ class Customizer:
|
|
|
1510
1924
|
self.log_header("Initialize OTAWP")
|
|
1511
1925
|
|
|
1512
1926
|
# Configure required OTDS resources as AppWorks doesn't do this on its own:
|
|
1513
|
-
self.init_otawp()
|
|
1927
|
+
self.otawp_object = self.init_otawp()
|
|
1514
1928
|
else:
|
|
1515
1929
|
self.settings.placeholder_values["OTAWP_RESOURCE_ID"] = ""
|
|
1516
1930
|
|
|
@@ -1563,136 +1977,68 @@ class Customizer:
|
|
|
1563
1977
|
else:
|
|
1564
1978
|
self.otpd_object = None
|
|
1565
1979
|
|
|
1980
|
+
if self.core_share_settings.enabled: # is Core Share enabled?
|
|
1981
|
+
self.log_header("Initialize Core Share")
|
|
1982
|
+
|
|
1983
|
+
self.core_share_object = self.init_coreshare()
|
|
1984
|
+
if not self.core_share_object:
|
|
1985
|
+
logger.error("Failed to initialize Core Share - exiting...")
|
|
1986
|
+
sys.exit()
|
|
1987
|
+
else:
|
|
1988
|
+
self.core_share_object = None
|
|
1989
|
+
|
|
1566
1990
|
if (
|
|
1567
1991
|
self.m365_settings.enabled
|
|
1568
1992
|
and self.m365_settings.user != ""
|
|
1569
1993
|
and self.m365_settings.password != ""
|
|
1570
1994
|
): # is M365 enabled?
|
|
1571
|
-
self.log_header("Initialize
|
|
1995
|
+
self.log_header("Initialize Microsoft 365")
|
|
1572
1996
|
|
|
1573
1997
|
# Initialize the M365 object and connection to M365 Graph API:
|
|
1574
1998
|
self.m365_object = self.init_m365()
|
|
1999
|
+
if not self.m365_object:
|
|
2000
|
+
logger.error("Failed to initialize Microsoft 365!")
|
|
2001
|
+
sys.exit()
|
|
1575
2002
|
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
"/cs/cs?func=officegroups.DownloadTeamsPackage",
|
|
1583
|
-
"/tmp/ot.xecm.teams.zip",
|
|
1584
|
-
)
|
|
1585
|
-
# this app upload will be done with the user credentials - this is required:
|
|
1586
|
-
self.m365_object.authenticate_user(
|
|
1587
|
-
self.m365_settings.user, self.m365_settings.password
|
|
1588
|
-
)
|
|
1589
|
-
|
|
1590
|
-
# Check if the app is already installed in the apps catalog:
|
|
1591
|
-
response = self.m365_object.get_teams_apps(
|
|
1592
|
-
f"contains(displayName, '{self.m365_settings.teams_app_name}')"
|
|
1593
|
-
)
|
|
1594
|
-
if self.m365_object.exist_result_item(
|
|
1595
|
-
response, "displayName", self.m365_settings.teams_app_name
|
|
1596
|
-
):
|
|
1597
|
-
app_catalog_id = self.m365_object.get_result_value(
|
|
1598
|
-
response=response, key="id", index=0
|
|
1599
|
-
) # 0 = Index = first item
|
|
1600
|
-
app_catalog_version = self.m365_object.get_result_value(
|
|
1601
|
-
response=response,
|
|
1602
|
-
key="version",
|
|
1603
|
-
index=0,
|
|
1604
|
-
sub_dict_name="appDefinitions",
|
|
1605
|
-
)
|
|
1606
|
-
logger.info(
|
|
1607
|
-
"Extended ECM Teams App is already in app catalog with app catalog ID -> %s and version -> %s. Check if we have a newer version to upload...",
|
|
1608
|
-
app_catalog_id,
|
|
1609
|
-
app_catalog_version,
|
|
1610
|
-
)
|
|
1611
|
-
app_upload_version = self.m365_object.extract_version_from_app_manifest(
|
|
1612
|
-
app_path="/tmp/ot.xecm.teams.zip"
|
|
1613
|
-
)
|
|
1614
|
-
if app_catalog_version < app_upload_version:
|
|
1615
|
-
logger.info(
|
|
1616
|
-
"Upgrading Extended ECM Teams App in catalog from version -> %s to version -> %s...",
|
|
1617
|
-
app_catalog_version,
|
|
1618
|
-
app_upload_version,
|
|
1619
|
-
)
|
|
1620
|
-
response = self.m365_object.upload_teams_app(
|
|
1621
|
-
app_path="/tmp/ot.xecm.teams.zip",
|
|
1622
|
-
update_existing_app=True,
|
|
1623
|
-
app_catalog_id=app_catalog_id,
|
|
1624
|
-
)
|
|
1625
|
-
else:
|
|
1626
|
-
logger.info(
|
|
1627
|
-
"No upgrade required. The upload version -> %s is not newer than the version -> %s which is in the M365 app catalog.",
|
|
1628
|
-
app_upload_version,
|
|
1629
|
-
app_catalog_version,
|
|
1630
|
-
)
|
|
1631
|
-
else:
|
|
1632
|
-
logger.info(
|
|
1633
|
-
"Extended Teams ECM App is not yet in app catalog. Installing as new app..."
|
|
1634
|
-
)
|
|
1635
|
-
response = self.m365_object.upload_teams_app(
|
|
1636
|
-
app_path="/tmp/ot.xecm.teams.zip"
|
|
1637
|
-
)
|
|
1638
|
-
|
|
1639
|
-
# logger.info("======== Upload Outlook Add-In ============")
|
|
1640
|
-
|
|
1641
|
-
# # Download MS Outlook Add-In from OTCS:
|
|
1642
|
-
# MANIFEST_FILE = "/tmp/BusinessWorkspace.Manifest.xml"
|
|
1643
|
-
# if not self.otcs_frontend_object.download_config_file(
|
|
1644
|
-
# "/cs/cs?func=outlookaddin.DownloadManifest",
|
|
1645
|
-
# MANIFEST_FILE,
|
|
1646
|
-
# "DeployedContentServer",
|
|
1647
|
-
# self.otcs_settings.public_url,
|
|
1648
|
-
# ):
|
|
1649
|
-
# logger.error("Failed to download M365 Outlook Add-In from Extended ECM!")
|
|
1650
|
-
# else:
|
|
1651
|
-
# # THIS IS NOT IMPLEMENTED DUE TO LACK OF M365 GRAPH API SUPPORT!
|
|
1652
|
-
# # Do it manually for now: https://admin.microsoft.com/#/Settings/IntegratedApps
|
|
1653
|
-
# logger.info("Successfully downloaded M365 Outlook Add-In from Extended ECM to %s", MANIFEST_FILE)
|
|
1654
|
-
# self.m365_object.upload_outlook_app(MANIFEST_FILE)
|
|
2003
|
+
if self.avts_settings.enabled:
|
|
2004
|
+
self.log_header("Initialize Aviator Search")
|
|
2005
|
+
self.avts_object = self.init_avts()
|
|
2006
|
+
if not self.avts_object:
|
|
2007
|
+
logger.error("Failed to initialize Aviator Search")
|
|
2008
|
+
sys.exit()
|
|
1655
2009
|
else:
|
|
1656
|
-
self.
|
|
1657
|
-
|
|
1658
|
-
# self.log_header("Initialize Browser Automation...")
|
|
1659
|
-
|
|
1660
|
-
# We initialize a Selenium based browser automation for
|
|
1661
|
-
# those die-hard settings that cannot be automated via REST API
|
|
1662
|
-
# nor LLConfig nor Transport:
|
|
1663
|
-
# self.browser_automation_object = self.init_browser_automation()
|
|
1664
|
-
# if not self.browser_automation_object:
|
|
1665
|
-
# logger.error("Failed to initialize Browser Automation - exiting...")
|
|
1666
|
-
# sys.exit()
|
|
2010
|
+
self.avts_object = None
|
|
1667
2011
|
|
|
1668
2012
|
self.log_header("Processing Payload")
|
|
1669
2013
|
|
|
1670
2014
|
cust_payload_list = []
|
|
1671
2015
|
# Is uncompressed payload provided?
|
|
1672
2016
|
if os.path.exists(self.settings.cust_payload):
|
|
1673
|
-
logger.info("Found payload file -> %s", self.settings.cust_payload)
|
|
2017
|
+
logger.info("Found payload file -> '%s'", self.settings.cust_payload)
|
|
1674
2018
|
cust_payload_list.append(self.settings.cust_payload)
|
|
1675
2019
|
# Is compressed payload provided?
|
|
1676
2020
|
if os.path.exists(self.settings.cust_payload_gz):
|
|
1677
2021
|
logger.info(
|
|
1678
|
-
"Found compressed payload file -> %s", self.settings.cust_payload_gz
|
|
2022
|
+
"Found compressed payload file -> '%s'", self.settings.cust_payload_gz
|
|
1679
2023
|
)
|
|
1680
2024
|
cust_payload_list.append(self.settings.cust_payload_gz)
|
|
1681
2025
|
|
|
1682
2026
|
# do we have additional payload as an external file?
|
|
1683
2027
|
if os.path.exists(self.settings.cust_payload_external):
|
|
1684
|
-
for filename in
|
|
2028
|
+
for filename in sorted(
|
|
2029
|
+
os.scandir(self.settings.cust_payload_external), key=lambda e: e.name
|
|
2030
|
+
):
|
|
1685
2031
|
if filename.is_file() and os.path.getsize(filename) > 0:
|
|
1686
|
-
logger.info("Found external payload file -> %s", filename.path)
|
|
2032
|
+
logger.info("Found external payload file -> '%s'", filename.path)
|
|
1687
2033
|
cust_payload_list.append(filename.path)
|
|
1688
2034
|
else:
|
|
1689
2035
|
logger.info(
|
|
1690
|
-
"No external payload file -> %s", self.settings.cust_payload_external
|
|
2036
|
+
"No external payload file -> '%s'", self.settings.cust_payload_external
|
|
1691
2037
|
)
|
|
1692
2038
|
|
|
1693
2039
|
for cust_payload in cust_payload_list:
|
|
1694
2040
|
# Open the payload file. If this fails we bail out:
|
|
1695
|
-
logger.info("Starting processing of payload -> %s", cust_payload)
|
|
2041
|
+
logger.info("Starting processing of payload -> '%s'", cust_payload)
|
|
1696
2042
|
|
|
1697
2043
|
# Set startTime for duration calculation
|
|
1698
2044
|
start_time = datetime.now()
|
|
@@ -1708,11 +2054,15 @@ class Customizer:
|
|
|
1708
2054
|
otcs_restart_callback=self.restart_otcs_service,
|
|
1709
2055
|
otiv_object=self.otiv_object,
|
|
1710
2056
|
m365_object=self.m365_object,
|
|
2057
|
+
core_share_object=self.core_share_object,
|
|
1711
2058
|
browser_automation_object=self.browser_automation_object,
|
|
1712
2059
|
placeholder_values=self.settings.placeholder_values, # this dict includes placeholder replacements for the Ressource IDs of OTAWP and OTCS
|
|
1713
2060
|
log_header_callback=self.log_header,
|
|
1714
2061
|
stop_on_error=self.settings.stop_on_error,
|
|
1715
2062
|
aviator_enabled=self.aviator_settings.enabled,
|
|
2063
|
+
upload_status_files=self.otcs_settings.upload_status_files,
|
|
2064
|
+
otawp_object=self.otawp_object,
|
|
2065
|
+
avts_object=self.avts_object,
|
|
1716
2066
|
)
|
|
1717
2067
|
# Load the payload file and initialize the payload sections:
|
|
1718
2068
|
if not payload_object.init_payload():
|
|
@@ -1728,50 +2078,53 @@ class Customizer:
|
|
|
1728
2078
|
self.consolidate_otds()
|
|
1729
2079
|
|
|
1730
2080
|
# Upload payload file for later review to Enterprise Workspace
|
|
1731
|
-
self.
|
|
1732
|
-
|
|
1733
|
-
self.
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
2081
|
+
if self.otcs_settings.upload_config_files:
|
|
2082
|
+
self.log_header("Upload Payload file to Extended ECM")
|
|
2083
|
+
response = self.otcs_backend_object.get_node_from_nickname(
|
|
2084
|
+
self.settings.cust_target_folder_nickname
|
|
2085
|
+
)
|
|
2086
|
+
target_folder_id = self.otcs_backend_object.get_result_value(
|
|
2087
|
+
response, "id"
|
|
2088
|
+
)
|
|
2089
|
+
if not target_folder_id:
|
|
2090
|
+
target_folder_id = 2000 # use Enterprise Workspace as fallback
|
|
2091
|
+
# Write YAML file with upadated payload (including IDs, etc.).
|
|
2092
|
+
# We need to write to /tmp as initial location is read-only:
|
|
2093
|
+
payload_file = os.path.basename(cust_payload)
|
|
2094
|
+
payload_file = (
|
|
2095
|
+
payload_file[: -len(".gz.b64")]
|
|
2096
|
+
if payload_file.endswith(".gz.b64")
|
|
2097
|
+
else payload_file
|
|
2098
|
+
)
|
|
2099
|
+
cust_payload = "/tmp/" + payload_file
|
|
1747
2100
|
|
|
1748
|
-
|
|
1749
|
-
|
|
2101
|
+
with open(cust_payload, "w", encoding="utf-8") as file:
|
|
2102
|
+
yaml.dump(payload_object.get_payload(), file)
|
|
1750
2103
|
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
)
|
|
1757
|
-
target_document_id = self.otcs_backend_object.get_result_value(
|
|
1758
|
-
response, "id"
|
|
1759
|
-
)
|
|
1760
|
-
if target_document_id:
|
|
1761
|
-
response = self.otcs_backend_object.add_document_version(
|
|
1762
|
-
int(target_document_id),
|
|
1763
|
-
cust_payload,
|
|
1764
|
-
os.path.basename(cust_payload),
|
|
1765
|
-
"text/plain",
|
|
1766
|
-
"Updated payload file after re-run of customization",
|
|
2104
|
+
# Check if the payload file has been uploaded before.
|
|
2105
|
+
# This can happen if we re-run the python container.
|
|
2106
|
+
# In this case we add a version to the existing document:
|
|
2107
|
+
response = self.otcs_backend_object.get_node_by_parent_and_name(
|
|
2108
|
+
int(target_folder_id), os.path.basename(cust_payload)
|
|
1767
2109
|
)
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
cust_payload,
|
|
1771
|
-
os.path.basename(cust_payload),
|
|
1772
|
-
"text/plain",
|
|
1773
|
-
int(target_folder_id),
|
|
2110
|
+
target_document_id = self.otcs_backend_object.get_result_value(
|
|
2111
|
+
response, "id"
|
|
1774
2112
|
)
|
|
2113
|
+
if target_document_id:
|
|
2114
|
+
response = self.otcs_backend_object.add_document_version(
|
|
2115
|
+
int(target_document_id),
|
|
2116
|
+
cust_payload,
|
|
2117
|
+
os.path.basename(cust_payload),
|
|
2118
|
+
"text/plain",
|
|
2119
|
+
"Updated payload file after re-run of customization",
|
|
2120
|
+
)
|
|
2121
|
+
else:
|
|
2122
|
+
response = self.otcs_backend_object.upload_file_to_parent(
|
|
2123
|
+
cust_payload,
|
|
2124
|
+
os.path.basename(cust_payload),
|
|
2125
|
+
"text/plain",
|
|
2126
|
+
int(target_folder_id),
|
|
2127
|
+
)
|
|
1775
2128
|
|
|
1776
2129
|
duration = datetime.now() - start_time
|
|
1777
2130
|
self.log_header(
|
|
@@ -1819,9 +2172,11 @@ class Customizer:
|
|
|
1819
2172
|
self.otds_object.impersonate_resource(self.otawp_settings.resource_name)
|
|
1820
2173
|
|
|
1821
2174
|
# Upload log file for later review to "Deployment" folder in "Administration" folder
|
|
1822
|
-
if
|
|
2175
|
+
if (
|
|
2176
|
+
os.path.exists(self.settings.cust_log_file)
|
|
2177
|
+
and self.otcs_settings.upload_log_file
|
|
2178
|
+
):
|
|
1823
2179
|
self.log_header("Upload log file to Extended ECM")
|
|
1824
|
-
# logger.info("========== Upload log file to Extended ECM =============")
|
|
1825
2180
|
response = self.otcs_backend_object.get_node_from_nickname(
|
|
1826
2181
|
self.settings.cust_target_folder_nickname
|
|
1827
2182
|
)
|
|
@@ -1839,18 +2194,19 @@ class Customizer:
|
|
|
1839
2194
|
)
|
|
1840
2195
|
if target_document_id:
|
|
1841
2196
|
response = self.otcs_backend_object.add_document_version(
|
|
1842
|
-
int(target_document_id),
|
|
1843
|
-
self.settings.cust_log_file,
|
|
1844
|
-
os.path.basename(self.settings.cust_log_file),
|
|
1845
|
-
"text/plain",
|
|
1846
|
-
"Updated Python Log after re-run of customization",
|
|
2197
|
+
node_id=int(target_document_id),
|
|
2198
|
+
file_url=self.settings.cust_log_file,
|
|
2199
|
+
file_name=os.path.basename(self.settings.cust_log_file),
|
|
2200
|
+
mime_type="text/plain",
|
|
2201
|
+
description="Updated Python Log after re-run of customization",
|
|
1847
2202
|
)
|
|
1848
2203
|
else:
|
|
1849
2204
|
response = self.otcs_backend_object.upload_file_to_parent(
|
|
1850
|
-
self.settings.cust_log_file,
|
|
1851
|
-
os.path.basename(self.settings.cust_log_file),
|
|
1852
|
-
"text/plain",
|
|
1853
|
-
int(target_folder_id),
|
|
2205
|
+
file_url=self.settings.cust_log_file,
|
|
2206
|
+
file_name=os.path.basename(self.settings.cust_log_file),
|
|
2207
|
+
mime_type="text/plain",
|
|
2208
|
+
parent_id=int(target_folder_id),
|
|
2209
|
+
description="Initial Python Log after first run of customization",
|
|
1854
2210
|
)
|
|
1855
2211
|
|
|
1856
2212
|
self.settings.customizer_end_time = datetime.now()
|
|
@@ -1873,16 +2229,17 @@ if __name__ == "__main__":
|
|
|
1873
2229
|
|
|
1874
2230
|
my_customizer = Customizer(
|
|
1875
2231
|
otcs=CustomizerSettingsOTCS(
|
|
1876
|
-
hostname="otcs.
|
|
1877
|
-
hostname_backend="otcs
|
|
1878
|
-
hostname_frontend="otcs
|
|
1879
|
-
protocol="
|
|
1880
|
-
port_backend=
|
|
2232
|
+
hostname="otcs.local.xecm.cloud",
|
|
2233
|
+
hostname_backend="otcs-admin-0",
|
|
2234
|
+
hostname_frontend="otcs-frontend",
|
|
2235
|
+
protocol="http",
|
|
2236
|
+
port_backend=8080,
|
|
1881
2237
|
),
|
|
1882
|
-
otds=CustomizerSettingsOTDS(hostname="otds
|
|
2238
|
+
otds=CustomizerSettingsOTDS(hostname="otds"),
|
|
1883
2239
|
otpd=CustomizerSettingsOTPD(enabled=False),
|
|
1884
|
-
|
|
1885
|
-
|
|
2240
|
+
otac=CustomizerSettingsOTAC(enabled=False),
|
|
2241
|
+
k8s=CustomizerSettingsK8S(enabled=True),
|
|
2242
|
+
otiv=CustomizerSettingsOTIV(enabled=False),
|
|
1886
2243
|
)
|
|
1887
2244
|
|
|
1888
2245
|
my_customizer.customization_run()
|