mas-cli 12.1.0__py3-none-any.whl → 12.27.0__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 mas-cli might be problematic. Click here for more details.
- mas/cli/__init__.py +1 -1
- mas/cli/aiservice/install/__init__.py +11 -0
- mas/cli/aiservice/install/app.py +810 -0
- mas/cli/aiservice/install/argBuilder.py +232 -0
- mas/cli/aiservice/install/argParser.py +742 -0
- mas/cli/aiservice/install/params.py +120 -0
- mas/cli/aiservice/install/summarizer.py +193 -0
- mas/cli/cli.py +36 -9
- mas/cli/gencfg.py +23 -0
- mas/cli/install/app.py +295 -85
- mas/cli/install/argBuilder.py +92 -14
- mas/cli/install/argParser.py +200 -147
- mas/cli/install/catalogs.py +11 -6
- mas/cli/install/params.py +32 -6
- mas/cli/install/settings/additionalConfigs.py +18 -1
- mas/cli/install/settings/db2Settings.py +121 -72
- mas/cli/install/settings/kafkaSettings.py +2 -2
- mas/cli/install/settings/manageSettings.py +154 -159
- mas/cli/install/settings/mongodbSettings.py +1 -1
- mas/cli/install/settings/turbonomicSettings.py +1 -3
- mas/cli/install/summarizer.py +85 -68
- mas/cli/templates/facilities-configs.yml.j2 +25 -0
- mas/cli/templates/ibm-mas-tekton.yaml +13428 -4725
- mas/cli/update/app.py +42 -8
- mas/cli/upgrade/app.py +52 -15
- mas/cli/upgrade/argParser.py +7 -0
- mas/cli/upgrade/settings/__init__.py +19 -0
- mas/cli/validators.py +13 -0
- {mas_cli-12.1.0.data → mas_cli-12.27.0.data}/scripts/mas-cli +5 -1
- {mas_cli-12.1.0.dist-info → mas_cli-12.27.0.dist-info}/METADATA +12 -3
- {mas_cli-12.1.0.dist-info → mas_cli-12.27.0.dist-info}/RECORD +33 -25
- {mas_cli-12.1.0.dist-info → mas_cli-12.27.0.dist-info}/WHEEL +1 -1
- {mas_cli-12.1.0.dist-info → mas_cli-12.27.0.dist-info}/top_level.txt +0 -0
mas/cli/install/app.py
CHANGED
|
@@ -40,11 +40,17 @@ from mas.cli.validators import (
|
|
|
40
40
|
WorkspaceNameFormatValidator,
|
|
41
41
|
TimeoutFormatValidator,
|
|
42
42
|
StorageClassValidator,
|
|
43
|
+
JsonValidator,
|
|
43
44
|
OptimizerInstallPlanValidator
|
|
44
45
|
)
|
|
45
46
|
|
|
46
47
|
from mas.devops.ocp import createNamespace, getStorageClasses
|
|
47
|
-
from mas.devops.mas import
|
|
48
|
+
from mas.devops.mas import (
|
|
49
|
+
getCurrentCatalog,
|
|
50
|
+
getDefaultStorageClasses,
|
|
51
|
+
isVersionEqualOrAfter
|
|
52
|
+
)
|
|
53
|
+
from mas.devops.sls import findSLSByNamespace
|
|
48
54
|
from mas.devops.data import getCatalog
|
|
49
55
|
from mas.devops.tekton import (
|
|
50
56
|
installOpenShiftPipelines,
|
|
@@ -158,47 +164,69 @@ class InstallApp(BaseApp, InstallSettingsMixin, InstallSummarizerMixin, ConfigGe
|
|
|
158
164
|
year = date[:2]
|
|
159
165
|
return f" - {monthName} 20{year} Update\n <Orange><u>https://ibm-mas.github.io/cli/catalogs/{name}</u></Orange>"
|
|
160
166
|
|
|
161
|
-
def formatRelease(self, release: str) -> str:
|
|
162
|
-
return f"{release} ... {self.catalogReleases[release]['core']}"
|
|
163
|
-
|
|
164
167
|
@logMethodCall
|
|
165
168
|
def processCatalogChoice(self) -> list:
|
|
166
169
|
self.catalogDigest = self.chosenCatalog["catalog_digest"]
|
|
167
|
-
self.catalogCp4dVersion = self.chosenCatalog["cpd_product_version_default"]
|
|
168
170
|
self.catalogMongoDbVersion = self.chosenCatalog["mongo_extras_version_default"]
|
|
171
|
+
if self.architecture != "s390x" and self.architecture != "ppc64le":
|
|
172
|
+
self.catalogCp4dVersion = self.chosenCatalog["cpd_product_version_default"]
|
|
173
|
+
|
|
174
|
+
applications = {
|
|
175
|
+
"Core": "mas_core_version",
|
|
176
|
+
"Manage": "mas_manage_version",
|
|
177
|
+
"IoT": "mas_iot_version",
|
|
178
|
+
"Monitor": "mas_monitor_version",
|
|
179
|
+
"Assist": "mas_assist_version",
|
|
180
|
+
"Optimizer": "mas_optimizer_version",
|
|
181
|
+
"Predict": "mas_predict_version",
|
|
182
|
+
"Inspection": "mas_visualinspection_version",
|
|
183
|
+
"Facilities": "mas_facilities_version",
|
|
184
|
+
}
|
|
185
|
+
else:
|
|
186
|
+
applications = {
|
|
187
|
+
"Core": "mas_core_version",
|
|
188
|
+
"Manage": "mas_manage_version",
|
|
189
|
+
}
|
|
169
190
|
|
|
170
|
-
self.catalogReleases =
|
|
191
|
+
self.catalogReleases = {}
|
|
171
192
|
self.catalogTable = []
|
|
172
193
|
|
|
173
|
-
applications = {
|
|
174
|
-
"Core": "mas_core_version",
|
|
175
|
-
"Manage": "mas_manage_version",
|
|
176
|
-
"IoT": "mas_iot_version",
|
|
177
|
-
"Monitor": "mas_monitor_version",
|
|
178
|
-
"Assist": "mas_assist_version",
|
|
179
|
-
"Optimizer": "mas_optimizer_version",
|
|
180
|
-
"Predict": "mas_predict_version",
|
|
181
|
-
"Inspection": "mas_visualinspection_version",
|
|
182
|
-
}
|
|
183
|
-
|
|
184
194
|
# Dynamically fetch the channels from the chosen catalog
|
|
185
195
|
# based on mas core
|
|
186
196
|
for channel in self.chosenCatalog["mas_core_version"]:
|
|
187
|
-
|
|
197
|
+
# {"9.1-feature": "9.1.x-feature"}
|
|
198
|
+
self.catalogReleases.update({channel.replace('.x', ''): channel})
|
|
188
199
|
|
|
189
200
|
# Generate catalogTable
|
|
190
201
|
for application, key in applications.items():
|
|
191
|
-
|
|
202
|
+
# Add 9.1-feature channel based off 9.0 to those apps that have not onboarded yet
|
|
203
|
+
if key in self.chosenCatalog:
|
|
204
|
+
tempChosenCatalog = self.chosenCatalog[key].copy()
|
|
205
|
+
if '9.1.x-feature' not in tempChosenCatalog:
|
|
206
|
+
tempChosenCatalog.update({"9.1.x-feature": tempChosenCatalog["9.0.x"]})
|
|
207
|
+
|
|
208
|
+
self.catalogTable.append({"": application} | {key.replace(".x", ""): value for key, value in sorted(tempChosenCatalog.items(), reverse=True)})
|
|
209
|
+
|
|
210
|
+
if self.architecture == "s390x" or self.architecture == "ppc64le":
|
|
211
|
+
summary = [
|
|
212
|
+
"",
|
|
213
|
+
"<u>Catalog Details</u>",
|
|
214
|
+
f"Catalog Image: icr.io/cpopen/ibm-maximo-operator-catalog:{self.getParam('mas_catalog_version')}",
|
|
215
|
+
f"Catalog Digest: {self.catalogDigest}",
|
|
216
|
+
f"MAS Releases: {', '.join(sorted(self.catalogReleases, reverse=True))}",
|
|
217
|
+
f"MongoDb: {self.catalogMongoDbVersion}",
|
|
218
|
+
]
|
|
219
|
+
else:
|
|
220
|
+
summary = [
|
|
221
|
+
"",
|
|
222
|
+
"<u>Catalog Details</u>",
|
|
223
|
+
f"Catalog Image: icr.io/cpopen/ibm-maximo-operator-catalog:{self.getParam('mas_catalog_version')}",
|
|
224
|
+
f"Catalog Digest: {self.catalogDigest}",
|
|
225
|
+
f"MAS Releases: {', '.join(sorted(self.catalogReleases, reverse=True))}",
|
|
226
|
+
f"Cloud Pak for Data: {self.catalogCp4dVersion}",
|
|
227
|
+
f"MongoDb: {self.catalogMongoDbVersion}",
|
|
228
|
+
]
|
|
192
229
|
|
|
193
|
-
summary = [
|
|
194
|
-
"",
|
|
195
|
-
"<u>Catalog Details</u>",
|
|
196
|
-
f"Catalog Image: icr.io/cpopen/ibm-maximo-operator-catalog:{self.getParam('mas_catalog_version')}",
|
|
197
|
-
f"Catalog Digest: {self.catalogDigest}",
|
|
198
|
-
f"MAS Releases: {', '.join(self.catalogReleases)}",
|
|
199
|
-
f"Cloud Pak for Data: {self.catalogCp4dVersion}",
|
|
200
|
-
f"MongoDb: {self.catalogMongoDbVersion}",
|
|
201
|
-
]
|
|
202
230
|
return summary
|
|
203
231
|
|
|
204
232
|
@logMethodCall
|
|
@@ -237,28 +265,64 @@ class InstallApp(BaseApp, InstallSettingsMixin, InstallSummarizerMixin, ConfigGe
|
|
|
237
265
|
self.printDescription(catalogSummary)
|
|
238
266
|
self.printDescription([
|
|
239
267
|
"",
|
|
240
|
-
"
|
|
241
|
-
"
|
|
268
|
+
"Two types of release are available:",
|
|
269
|
+
" - GA releases of Maximo Application Suite are supported under IBM's standard 3+1+3 support lifecycle policy.",
|
|
270
|
+
" - 'Feature' releases allow early access to new features for evaluation in non-production environments and are only supported through to the next GA release.",
|
|
242
271
|
""
|
|
243
272
|
])
|
|
244
273
|
|
|
245
274
|
print(tabulate(self.catalogTable, headers="keys", tablefmt="simple_grid"))
|
|
246
275
|
|
|
247
|
-
releaseCompleter = WordCompleter(self.catalogReleases)
|
|
276
|
+
releaseCompleter = WordCompleter(sorted(self.catalogReleases, reverse=True))
|
|
248
277
|
releaseSelection = self.promptForString("Select release", completer=releaseCompleter)
|
|
249
278
|
|
|
250
|
-
self.setParam("mas_channel", releaseSelection)
|
|
279
|
+
self.setParam("mas_channel", self.catalogReleases[releaseSelection])
|
|
251
280
|
|
|
252
281
|
@logMethodCall
|
|
253
282
|
def configSLS(self) -> None:
|
|
254
|
-
self.printH1("Configure
|
|
283
|
+
self.printH1("Configure AppPoint Licensing")
|
|
284
|
+
self.printDescription(
|
|
285
|
+
[
|
|
286
|
+
"By default the MAS instance will be configured to use a cluster-shared License, this provides a shared pool of AppPoints available to all MAS instances on the cluster.",
|
|
287
|
+
"",
|
|
288
|
+
]
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
self.slsMode = 1
|
|
292
|
+
self.slsLicenseFileLocal = None
|
|
293
|
+
|
|
294
|
+
if self.showAdvancedOptions:
|
|
295
|
+
self.printDescription(
|
|
296
|
+
[
|
|
297
|
+
"Alternatively you may choose to install using a dedicated license only available to this MAS instance.",
|
|
298
|
+
" 1. Install MAS with Cluster-Shared License (AppPoints)",
|
|
299
|
+
" 2. Install MAS with Dedicated License (AppPoints)",
|
|
300
|
+
]
|
|
301
|
+
)
|
|
302
|
+
self.slsMode = self.promptForInt("SLS Mode", default=1)
|
|
303
|
+
|
|
304
|
+
if self.slsMode not in [1, 2]:
|
|
305
|
+
self.fatalError(f"Invalid selection: {self.slsMode}")
|
|
306
|
+
|
|
307
|
+
if not (self.slsMode == 2 and not self.getParam("sls_namespace")):
|
|
308
|
+
sls_namespace = "ibm-sls" if self.slsMode == 1 else self.getParam("sls_namespace")
|
|
309
|
+
if findSLSByNamespace(sls_namespace, dynClient=self.dynamicClient):
|
|
310
|
+
print_formatted_text(HTML(f"<MediumSeaGreen>SLS auto-detected: {sls_namespace}</MediumSeaGreen>"))
|
|
311
|
+
print()
|
|
312
|
+
if not self.yesOrNo("Upload/Replace the license file"):
|
|
313
|
+
self.setParam("sls_action", "gencfg")
|
|
314
|
+
return
|
|
315
|
+
|
|
255
316
|
self.slsLicenseFileLocal = self.promptForFile("License file", mustExist=True, envVar="SLS_LICENSE_FILE_LOCAL")
|
|
317
|
+
self.setParam("sls_action", "install")
|
|
318
|
+
|
|
319
|
+
@logMethodCall
|
|
320
|
+
def configDRO(self) -> None:
|
|
256
321
|
self.promptForString("Contact e-mail address", "uds_contact_email")
|
|
257
322
|
self.promptForString("Contact first name", "uds_contact_firstname")
|
|
258
323
|
self.promptForString("Contact last name", "uds_contact_lastname")
|
|
259
324
|
|
|
260
325
|
if self.showAdvancedOptions:
|
|
261
|
-
self.promptForString("IBM Suite License Services (SLS) Namespace", "sls_namespace", default="ibm-sls")
|
|
262
326
|
self.promptForString("IBM Data Reporter Operator (DRO) Namespace", "dro_namespace", default="redhat-marketplace")
|
|
263
327
|
|
|
264
328
|
@logMethodCall
|
|
@@ -269,8 +333,8 @@ class InstallApp(BaseApp, InstallSettingsMixin, InstallSummarizerMixin, ConfigGe
|
|
|
269
333
|
|
|
270
334
|
@logMethodCall
|
|
271
335
|
def configGrafana(self) -> None:
|
|
272
|
-
if self.architecture == "s390x":
|
|
273
|
-
# We are not supporting Grafana on s390x at the moment
|
|
336
|
+
if self.architecture == "s390x" or self.architecture == "ppc64le":
|
|
337
|
+
# We are not supporting Grafana on s390x /ppc64le at the moment
|
|
274
338
|
self.setParam("grafana_action", "none")
|
|
275
339
|
else:
|
|
276
340
|
try:
|
|
@@ -312,7 +376,7 @@ class InstallApp(BaseApp, InstallSettingsMixin, InstallSummarizerMixin, ConfigGe
|
|
|
312
376
|
self.printDescription([
|
|
313
377
|
f"Unknown catalog {self.getParam('mas_catalog_version')}, please manually select the version of Cloud Pak for Data to use"
|
|
314
378
|
])
|
|
315
|
-
self.promptForString("Cloud Pak for Data product version", "cpd_product_version", default="
|
|
379
|
+
self.promptForString("Cloud Pak for Data product version", "cpd_product_version", default="5.1.3")
|
|
316
380
|
logger.debug(f"Using user-provided (prompt) CP4D product version: {self.getParam('cpd_product_version')}")
|
|
317
381
|
else:
|
|
318
382
|
logger.debug(f"Using user-provided (flags) CP4D product version: {self.getParam('cpd_product_version')}")
|
|
@@ -379,6 +443,9 @@ class InstallApp(BaseApp, InstallSettingsMixin, InstallSummarizerMixin, ConfigGe
|
|
|
379
443
|
])
|
|
380
444
|
self.promptForString("Workspace name", "mas_workspace_name", validator=WorkspaceNameFormatValidator())
|
|
381
445
|
|
|
446
|
+
if self.slsMode == 2 and not self.getParam("sls_namespace"):
|
|
447
|
+
self.setParam("sls_namespace", f"mas-{self.getParam('mas_instance_id')}-sls")
|
|
448
|
+
|
|
382
449
|
self.configOperationMode()
|
|
383
450
|
self.configCATrust()
|
|
384
451
|
self.configDNSAndCerts()
|
|
@@ -555,13 +622,27 @@ class InstallApp(BaseApp, InstallSettingsMixin, InstallSummarizerMixin, ConfigGe
|
|
|
555
622
|
if self.installMonitor:
|
|
556
623
|
self.configAppChannel("monitor")
|
|
557
624
|
|
|
558
|
-
self.
|
|
625
|
+
self.manageAppName = "Manage"
|
|
626
|
+
self.isManageFoundation = False
|
|
627
|
+
self.installManage = self.yesOrNo(f"Install {self.manageAppName}")
|
|
628
|
+
|
|
629
|
+
# If the selection was to not install manage but we are in mas_channel 9.1 or later, we need to set self.isManageFoundation to True
|
|
630
|
+
# Also, we need to force self.installManage to be True because Manage must always be installed in MAS 9.1 or later
|
|
631
|
+
if not self.installManage:
|
|
632
|
+
if not self.getParam("mas_channel").startswith("8.") and not self.getParam("mas_channel").startswith("9.0"):
|
|
633
|
+
self.installManage = True
|
|
634
|
+
self.isManageFoundation = True
|
|
635
|
+
self.setParam("is_full_manage", "false")
|
|
636
|
+
self.setParam("mas_app_settings_aio_flag", "false")
|
|
637
|
+
self.manageAppName = "Manage foundation"
|
|
638
|
+
self.printDescription([f"{self.manageAppName} installs the following capabilities: User, Security groups, Application configurator and Mobile configurator."])
|
|
639
|
+
else:
|
|
640
|
+
self.setParam("is_full_manage", "true")
|
|
559
641
|
|
|
560
642
|
if self.installManage:
|
|
561
643
|
self.configAppChannel("manage")
|
|
562
644
|
|
|
563
|
-
|
|
564
|
-
if self.installIoT and self.installManage and self.getParam("mas_channel") != "8.10.x":
|
|
645
|
+
if self.installIoT and self.installManage:
|
|
565
646
|
self.installPredict = self.yesOrNo("Install Predict")
|
|
566
647
|
else:
|
|
567
648
|
self.installPredict = False
|
|
@@ -570,7 +651,7 @@ class InstallApp(BaseApp, InstallSettingsMixin, InstallSummarizerMixin, ConfigGe
|
|
|
570
651
|
self.configAppChannel("predict")
|
|
571
652
|
|
|
572
653
|
# Assist is only installable on MAS 9.0.x due to withdrawal of support for Watson Discovery in our managed dependency stack and the inability of Assist 8.x to support this
|
|
573
|
-
if
|
|
654
|
+
if isVersionEqualOrAfter('9.0.0', self.getParam("mas_channel")):
|
|
574
655
|
self.installAssist = self.yesOrNo("Install Assist")
|
|
575
656
|
if self.installAssist:
|
|
576
657
|
self.configAppChannel("assist")
|
|
@@ -585,9 +666,12 @@ class InstallApp(BaseApp, InstallSettingsMixin, InstallSummarizerMixin, ConfigGe
|
|
|
585
666
|
if self.installInspection:
|
|
586
667
|
self.configAppChannel("visualinspection")
|
|
587
668
|
|
|
588
|
-
self.
|
|
589
|
-
|
|
590
|
-
self.
|
|
669
|
+
if isVersionEqualOrAfter('9.1.0', self.getParam("mas_channel")) and self.getParam("mas_channel") != '9.1.x-feature':
|
|
670
|
+
self.installFacilities = self.yesOrNo("Install Real Estate and Facilities")
|
|
671
|
+
if self.installFacilities:
|
|
672
|
+
self.configAppChannel("facilities")
|
|
673
|
+
else:
|
|
674
|
+
self.installFacilities = False
|
|
591
675
|
|
|
592
676
|
@logMethodCall
|
|
593
677
|
def configAppChannel(self, appId):
|
|
@@ -651,21 +735,23 @@ class InstallApp(BaseApp, InstallSettingsMixin, InstallSummarizerMixin, ConfigGe
|
|
|
651
735
|
def optimizerSettings(self) -> None:
|
|
652
736
|
if self.installOptimizer:
|
|
653
737
|
self.printH1("Configure Maximo Optimizer")
|
|
654
|
-
self.
|
|
655
|
-
|
|
656
|
-
|
|
738
|
+
if self.isSNO():
|
|
739
|
+
self.printDescription(["Using Optimizer 'limited' plan as it is being installed in a single node cluster"])
|
|
740
|
+
self.setParam("mas_app_plan_optimizer", "limited")
|
|
741
|
+
else:
|
|
742
|
+
self.printDescription(["Customize your Optimizer installation, 'full' and 'limited' install plans are available, refer to the product documentation for more information"])
|
|
743
|
+
self.promptForString("Plan [full/limited]", "mas_app_plan_optimizer", default="full", validator=OptimizerInstallPlanValidator())
|
|
657
744
|
|
|
658
745
|
@logMethodCall
|
|
659
746
|
def predictSettings(self) -> None:
|
|
660
747
|
if self.showAdvancedOptions and self.installPredict:
|
|
661
748
|
self.printH1("Configure Maximo Predict")
|
|
662
749
|
self.printDescription([
|
|
663
|
-
"Predict application supports integration with IBM SPSS
|
|
750
|
+
"Predict application supports integration with IBM SPSS which is an optional service installed on top of IBM Cloud Pak for Data",
|
|
664
751
|
"Unless requested these will not be installed"
|
|
665
752
|
])
|
|
666
753
|
self.configCP4D()
|
|
667
754
|
self.yesOrNo("Install IBM SPSS Statistics", "cpd_install_spss")
|
|
668
|
-
self.yesOrNo("Install Watson OpenScale", "cpd_install_openscale")
|
|
669
755
|
|
|
670
756
|
@logMethodCall
|
|
671
757
|
def assistSettings(self) -> None:
|
|
@@ -680,6 +766,81 @@ class InstallApp(BaseApp, InstallSettingsMixin, InstallSummarizerMixin, ConfigGe
|
|
|
680
766
|
self.promptForString("IBM Cloud API Key", "cos_apikey", isPassword=True)
|
|
681
767
|
self.promptForString("IBM Cloud Resource Group", "cos_resourcegroup")
|
|
682
768
|
|
|
769
|
+
@logMethodCall
|
|
770
|
+
def facilitiesSettings(self) -> None:
|
|
771
|
+
if self.installFacilities:
|
|
772
|
+
self.printH1("Configure Maximo Real Estate and Facilities")
|
|
773
|
+
self.printDescription([
|
|
774
|
+
"Real Estate and Facilities custom configurations"
|
|
775
|
+
])
|
|
776
|
+
self.printDescription([
|
|
777
|
+
"Maximo Real Estate and Facilities Size:",
|
|
778
|
+
" 1. Small",
|
|
779
|
+
" 2. Medium",
|
|
780
|
+
" 3. Large"
|
|
781
|
+
])
|
|
782
|
+
self.promptForListSelect("Select the size:", ["small", "medium", "large"], "mas_ws_facilities_size")
|
|
783
|
+
|
|
784
|
+
if self.showAdvancedOptions:
|
|
785
|
+
self.printH2("Maximo Real Estate and Facilities Settings - Advanced")
|
|
786
|
+
self.printDescription([
|
|
787
|
+
"Advanced configurations for Real Estate and Facilities are added through an additional file called facilities-configs.yaml"
|
|
788
|
+
])
|
|
789
|
+
if self.yesOrNo("Supply extra XML tags for Real Estate and Facilities server.xml"):
|
|
790
|
+
self.promptForString("Real Estate and Facilities Liberty Extension Secret Name", "mas_ws_facilities_liberty_extension_XML")
|
|
791
|
+
if self.yesOrNo("Supply custom AES Encryption Password"):
|
|
792
|
+
self.promptForString("Real Estate and Facilities AES Vault Secret Name", "mas_ws_facilities_vault_secret")
|
|
793
|
+
|
|
794
|
+
self.promptForString("Set Real Estate and Facilities Routes Timeout:", "mas_ws_facilities_routes_timeout", default="600s")
|
|
795
|
+
self.promptForInt("Set Facilities maximum connection poll size:", "mas_ws_facilities_db_maxconnpoolsize", default=200)
|
|
796
|
+
|
|
797
|
+
self.printDescription(["Real Estate and Facilities Persistent Volume Storage Configuration"])
|
|
798
|
+
defaultStorageClasses = getDefaultStorageClasses(self.dynamicClient)
|
|
799
|
+
notUseAutodetectedStorageClasses = False
|
|
800
|
+
if defaultStorageClasses.provider is not None:
|
|
801
|
+
self.storageClassProvider = defaultStorageClasses.provider
|
|
802
|
+
print_formatted_text(HTML(f"<MediumSeaGreen>Storage provider auto-detected: {defaultStorageClasses.providerName}</MediumSeaGreen>"))
|
|
803
|
+
print_formatted_text(HTML(f"<LightSlateGrey> - Storage class (ReadWriteMany): {defaultStorageClasses.rwx}</LightSlateGrey>"))
|
|
804
|
+
print_formatted_text(HTML(f"<LightSlateGrey> - Storage class (ReadWriteOnce): {defaultStorageClasses.rwo}</LightSlateGrey>"))
|
|
805
|
+
if self.yesOrNo("Use the auto-detected storage classes"):
|
|
806
|
+
self.printDescription([
|
|
807
|
+
"Storage Mode for Userfiles PVC:",
|
|
808
|
+
" 1. ReadWriteMany",
|
|
809
|
+
" 2. ReadWriteOnce"
|
|
810
|
+
])
|
|
811
|
+
storageMode = self.promptForListSelect("Select the storage mode for user files PVC:", ["ReadWriteMany", "ReadWriteOnce"], "mas_ws_facilities_storage_userfiles_mode", default=1)
|
|
812
|
+
_ = self.setParam("mas_ws_facilities_storage_userfiles_class", defaultStorageClasses.rwx) if storageMode == "ReadWriteMany" else self.setParam("mas_ws_facilities_storage_userfiles_class", defaultStorageClasses.rwo)
|
|
813
|
+
self.promptForInt("User file PVC size (Gb):", "mas_ws_facilities_storage_userfiles_size", default=50)
|
|
814
|
+
storageMode = self.promptForListSelect("Select the storage mode for log PVC:", ["ReadWriteMany", "ReadWriteOnce"], "mas_ws_facilities_storage_log_mode", default=1)
|
|
815
|
+
_ = self.setParam("mas_ws_facilities_storage_log_class", defaultStorageClasses.rwx) if storageMode == "ReadWriteMany" else self.setParam("mas_ws_facilities_storage_log_class", defaultStorageClasses.rwo)
|
|
816
|
+
self.promptForInt("Log PVC size (Gb):", "mas_ws_facilities_storage_log_size", default=30)
|
|
817
|
+
else:
|
|
818
|
+
notUseAutodetectedStorageClasses = True
|
|
819
|
+
if defaultStorageClasses.provider is None or notUseAutodetectedStorageClasses:
|
|
820
|
+
for storageClass in getStorageClasses(self.dynamicClient):
|
|
821
|
+
print_formatted_text(HTML(f"<LightSlateGrey> - {storageClass.metadata.name}</LightSlateGrey>"))
|
|
822
|
+
self.promptForString("Select storage class for user files PVC:", "mas_ws_facilities_storage_userfiles_class")
|
|
823
|
+
self.promptForString("Select storage class for log PVC:", "mas_ws_facilities_storage_log_class")
|
|
824
|
+
self.printDescription([
|
|
825
|
+
"Storage Mode for Userfiles PVC:",
|
|
826
|
+
" 1. ReadWriteMany",
|
|
827
|
+
" 2. ReadWriteOnce"
|
|
828
|
+
])
|
|
829
|
+
self.promptForListSelect("Select the storage mode for user files PVC:", ["ReadWriteMany", "ReadWriteOnce"], "mas_ws_facilities_storage_userfiles_mode", default=1)
|
|
830
|
+
self.promptForListSelect("Select the storage mode for log PVC:", ["ReadWriteMany", "ReadWriteOnce"], "mas_ws_facilities_storage_log_mode", default=1)
|
|
831
|
+
self.promptForInt("User file PVC size (Gb):", "mas_ws_facilities_storage_userfiles_size", default=50)
|
|
832
|
+
self.promptForInt("Log PVC size (Gb):", "mas_ws_facilities_storage_log_size", default=30)
|
|
833
|
+
|
|
834
|
+
if self.yesOrNo("Supply configuration for dedicated workflow agents"):
|
|
835
|
+
print_formatted_text(HTML("<LightSlateGrey> Example: '[{\"name\":\"dwfa1\",\"members\":[{\"name\": \"u1\", \"class\": \"user\"}]}, {\"name\":\"dwfa2\",\"members\":[{\"name\": \"u2\", \"class\": \"user\"},{\"name\":\"g1\", \"class\":\"group\"}]}]' </LightSlateGrey>"))
|
|
836
|
+
self.promptForString("Dedicated Workflow Agent JSON:", "mas_ws_facilities_dwfagents", validator=JsonValidator())
|
|
837
|
+
|
|
838
|
+
# If advanced options is selected, we need to create a file to add props not supported by Tekton
|
|
839
|
+
self.selectLocalConfigDir()
|
|
840
|
+
facilitiesConfigsPath = path.join(self.localConfigDir, "facilities-configs.yaml")
|
|
841
|
+
self.generateFacilitiesCfg(destination=facilitiesConfigsPath)
|
|
842
|
+
self.setParam("mas_ws_facilities_config_file", "/workspace/configs/facilities-configs.yaml")
|
|
843
|
+
|
|
683
844
|
@logMethodCall
|
|
684
845
|
def chooseInstallFlavour(self) -> None:
|
|
685
846
|
self.printH1("Choose Install Mode")
|
|
@@ -695,8 +856,9 @@ class InstallApp(BaseApp, InstallSettingsMixin, InstallSummarizerMixin, ConfigGe
|
|
|
695
856
|
" - Customize Maximo Manage database settings (schema, tablespace, indexspace)",
|
|
696
857
|
" - Customize Maximo Manage server bundle configuration (defaults to \"all\" configuration)",
|
|
697
858
|
" - Enable optional Maximo Manage integration Cognos Analytics and Watson Studio Local",
|
|
698
|
-
" - Enable optional Maximo Predict integration with SPSS
|
|
859
|
+
" - Enable optional Maximo Predict integration with SPSS",
|
|
699
860
|
" - Enable optional IBM Turbonomic integration",
|
|
861
|
+
" - Enable optional Real Estate and Facilities configurations",
|
|
700
862
|
" - Customize Db2 node affinity and tolerations, memory, cpu, and storage settings (when using the IBM Db2 Universal Operator)",
|
|
701
863
|
" - Choose alternative Apache Kafka providers (default to Strimzi)",
|
|
702
864
|
" - Customize Grafana storage settings"
|
|
@@ -727,6 +889,7 @@ class InstallApp(BaseApp, InstallSettingsMixin, InstallSummarizerMixin, ConfigGe
|
|
|
727
889
|
|
|
728
890
|
# Licensing (SLS and DRO)
|
|
729
891
|
self.configSLS()
|
|
892
|
+
self.configDRO()
|
|
730
893
|
self.configICRCredentials()
|
|
731
894
|
|
|
732
895
|
# MAS Core
|
|
@@ -741,7 +904,7 @@ class InstallApp(BaseApp, InstallSettingsMixin, InstallSummarizerMixin, ConfigGe
|
|
|
741
904
|
self.optimizerSettings()
|
|
742
905
|
self.predictSettings()
|
|
743
906
|
self.assistSettings()
|
|
744
|
-
self.
|
|
907
|
+
self.facilitiesSettings()
|
|
745
908
|
|
|
746
909
|
# Dependencies
|
|
747
910
|
self.configMongoDb()
|
|
@@ -771,10 +934,11 @@ class InstallApp(BaseApp, InstallSettingsMixin, InstallSummarizerMixin, ConfigGe
|
|
|
771
934
|
self.installPredict = False
|
|
772
935
|
self.installInspection = False
|
|
773
936
|
self.installOptimizer = False
|
|
774
|
-
self.
|
|
937
|
+
self.installFacilities = False
|
|
775
938
|
self.deployCP4D = False
|
|
776
939
|
self.db2SetAffinity = False
|
|
777
940
|
self.db2SetTolerations = False
|
|
941
|
+
self.slsLicenseFileLocal = None
|
|
778
942
|
|
|
779
943
|
self.approvals = {
|
|
780
944
|
"approval_core": {"id": "suite-verify"}, # After Core Platform verification has completed
|
|
@@ -784,10 +948,13 @@ class InstallApp(BaseApp, InstallSettingsMixin, InstallSummarizerMixin, ConfigGe
|
|
|
784
948
|
"approval_monitor": {"id": "app-cfg-monitor"}, # After Monitor workspace has been configured
|
|
785
949
|
"approval_optimizer": {"id": "app-cfg-optimizer"}, # After Optimizer workspace has been configured
|
|
786
950
|
"approval_predict": {"id": "app-cfg-predict"}, # After Predict workspace has been configured
|
|
787
|
-
"approval_visualinspection": {"id": "app-cfg-visualinspection"} # After Visual Inspection workspace has been configured
|
|
951
|
+
"approval_visualinspection": {"id": "app-cfg-visualinspection"}, # After Visual Inspection workspace has been configured
|
|
952
|
+
"approval_facilities": {"id": "app-cfg-facilities"}, # After Facilities workspace has been configured
|
|
788
953
|
}
|
|
789
954
|
|
|
790
955
|
self.configGrafana()
|
|
956
|
+
self.configSNO()
|
|
957
|
+
self.setDB2DefaultSettings()
|
|
791
958
|
|
|
792
959
|
for key, value in vars(self.args).items():
|
|
793
960
|
# These fields we just pass straight through to the parameters and fail if they are not set
|
|
@@ -865,10 +1032,6 @@ class InstallApp(BaseApp, InstallSettingsMixin, InstallSummarizerMixin, ConfigGe
|
|
|
865
1032
|
if value is not None and value != "":
|
|
866
1033
|
self.setParam("mas_app_channel_visualinspection", value)
|
|
867
1034
|
self.installInspection = True
|
|
868
|
-
elif key == "aibroker_channel":
|
|
869
|
-
if value is not None and value != "":
|
|
870
|
-
self.setParam("mas_app_channel_aibroker", value)
|
|
871
|
-
self.installAiBroker = True
|
|
872
1035
|
elif key == "optimizer_channel":
|
|
873
1036
|
if value is not None and value != "":
|
|
874
1037
|
self.setParam("mas_app_channel_optimizer", value)
|
|
@@ -876,6 +1039,10 @@ class InstallApp(BaseApp, InstallSettingsMixin, InstallSummarizerMixin, ConfigGe
|
|
|
876
1039
|
elif key == "optimizer_plan":
|
|
877
1040
|
if value is not None and value != "":
|
|
878
1041
|
self.setParam("mas_app_plan_optimizer", value)
|
|
1042
|
+
elif key == "facilities_channel":
|
|
1043
|
+
if value is not None and value != "":
|
|
1044
|
+
self.setParam("mas_app_channel_facilities", value)
|
|
1045
|
+
self.installFacilities = True
|
|
879
1046
|
|
|
880
1047
|
# Manage advanced settings that need extra processing
|
|
881
1048
|
elif key == "mas_app_settings_server_bundle_size":
|
|
@@ -884,6 +1051,21 @@ class InstallApp(BaseApp, InstallSettingsMixin, InstallSummarizerMixin, ConfigGe
|
|
|
884
1051
|
if value in ["jms", "snojms"]:
|
|
885
1052
|
self.setParam("mas_app_settings_persistent_volumes_flag", "true")
|
|
886
1053
|
|
|
1054
|
+
# MongoDB
|
|
1055
|
+
elif key == "mongodb_namespace":
|
|
1056
|
+
if value is not None and value != "":
|
|
1057
|
+
self.setParam(key, value)
|
|
1058
|
+
self.setParam("sls_mongodb_cfg_file", f"/workspace/configs/mongo-{value}.yml")
|
|
1059
|
+
|
|
1060
|
+
# SLS
|
|
1061
|
+
elif key == "license_file":
|
|
1062
|
+
if value is not None and value != "":
|
|
1063
|
+
self.slsLicenseFileLocal = value
|
|
1064
|
+
self.setParam("sls_action", "install")
|
|
1065
|
+
elif key == "dedicated_sls":
|
|
1066
|
+
if value:
|
|
1067
|
+
self.setParam("sls_namespace", f"mas-{self.args.mas_instance_id}-sls")
|
|
1068
|
+
|
|
887
1069
|
# These settings are used by the CLI rather than passed to the PipelineRun
|
|
888
1070
|
elif key == "storage_accessmode":
|
|
889
1071
|
if value is None:
|
|
@@ -893,10 +1075,6 @@ class InstallApp(BaseApp, InstallSettingsMixin, InstallSummarizerMixin, ConfigGe
|
|
|
893
1075
|
if value is None:
|
|
894
1076
|
self.fatalError(f"{key} must be set")
|
|
895
1077
|
self.pipelineStorageClass = value
|
|
896
|
-
elif key == "license_file":
|
|
897
|
-
if value is None:
|
|
898
|
-
self.fatalError(f"{key} must be set")
|
|
899
|
-
self.slsLicenseFileLocal = value
|
|
900
1078
|
|
|
901
1079
|
elif key.startswith("approval_"):
|
|
902
1080
|
if key not in self.approvals:
|
|
@@ -904,16 +1082,15 @@ class InstallApp(BaseApp, InstallSettingsMixin, InstallSummarizerMixin, ConfigGe
|
|
|
904
1082
|
|
|
905
1083
|
if value != "":
|
|
906
1084
|
valueParts = value.split(":")
|
|
907
|
-
if len(valueParts) !=
|
|
908
|
-
self.fatalError(f"Unsupported format for {key} ({value}). Expected
|
|
1085
|
+
if len(valueParts) != 3:
|
|
1086
|
+
self.fatalError(f"Unsupported format for {key} ({value}). Expected MAX_RETRIES:RETRY_DELAY:IGNORE_FAILURE")
|
|
909
1087
|
else:
|
|
910
1088
|
try:
|
|
911
|
-
self.approvals[key]["
|
|
912
|
-
self.approvals[key]["
|
|
913
|
-
self.approvals[key]["
|
|
914
|
-
self.approvals[key]["ignoreFailure"] = bool(valueParts[3])
|
|
1089
|
+
self.approvals[key]["maxRetries"] = int(valueParts[0])
|
|
1090
|
+
self.approvals[key]["retryDelay"] = int(valueParts[1])
|
|
1091
|
+
self.approvals[key]["ignoreFailure"] = bool(valueParts[2])
|
|
915
1092
|
except ValueError:
|
|
916
|
-
self.fatalError(f"Unsupported format for {key} ({value}). Expected
|
|
1093
|
+
self.fatalError(f"Unsupported format for {key} ({value}). Expected int:int:boolean")
|
|
917
1094
|
|
|
918
1095
|
# Arguments that we don't need to do anything with
|
|
919
1096
|
elif key in ["accept_license", "dev_mode", "skip_pre_check", "skip_grafana_install", "no_confirm", "no_wait_for_pvc", "help", "advanced", "simplified"]:
|
|
@@ -927,14 +1104,40 @@ class InstallApp(BaseApp, InstallSettingsMixin, InstallSummarizerMixin, ConfigGe
|
|
|
927
1104
|
self.setParam("mas_manual_cert_mgmt", False)
|
|
928
1105
|
self.manualCertsDir = None
|
|
929
1106
|
|
|
1107
|
+
elif key == "enable_ipv6":
|
|
1108
|
+
self.setParam("enable_ipv6", True)
|
|
1109
|
+
|
|
930
1110
|
# Fail if there's any arguments we don't know how to handle
|
|
931
1111
|
else:
|
|
932
1112
|
print(f"Unknown option: {key} {value}")
|
|
933
1113
|
self.fatalError(f"Unknown option: {key} {value}")
|
|
934
1114
|
|
|
1115
|
+
if self.installManage:
|
|
1116
|
+
# If Manage is being installed and --is-full-manage was set to something different than "false", assume it is "true"
|
|
1117
|
+
if self.getParam("is_full_manage") != "false":
|
|
1118
|
+
self.setParam("is_full_manage", "true")
|
|
1119
|
+
|
|
1120
|
+
# Configure Storage and Access mode
|
|
1121
|
+
self.manageStorageAndAccessMode()
|
|
1122
|
+
|
|
1123
|
+
if self.installFacilities:
|
|
1124
|
+
# Verifiy if any of the props that needs to be in a file are given
|
|
1125
|
+
if self.getParam("mas_ws_facilities_storage_log_size") != "" or self.getParam("mas_ws_facilities_storage_userfiles_size") != "" or self.getParam("mas_ws_facilities_db_maxconnpoolsize") or self.getParam("mas_ws_facilities_dwfagents"):
|
|
1126
|
+
self.selectLocalConfigDir()
|
|
1127
|
+
facilitiesConfigsPath = path.join(self.localConfigDir, "facilities-configs.yaml")
|
|
1128
|
+
self.generateFacilitiesCfg(destination=facilitiesConfigsPath)
|
|
1129
|
+
self.setParam("mas_ws_facilities_config_map_name", "facilities-config")
|
|
1130
|
+
|
|
935
1131
|
# Load the catalog information
|
|
936
1132
|
self.chosenCatalog = getCatalog(self.getParam("mas_catalog_version"))
|
|
937
1133
|
|
|
1134
|
+
# License file is only optional for existing SLS instance
|
|
1135
|
+
if self.slsLicenseFileLocal is None:
|
|
1136
|
+
if findSLSByNamespace(self.getParam("sls_namespace"), dynClient=self.dynamicClient):
|
|
1137
|
+
self.setParam("sls_action", "gencfg")
|
|
1138
|
+
else:
|
|
1139
|
+
self.fatalError("--license-file must be set for new SLS install")
|
|
1140
|
+
|
|
938
1141
|
# Once we've processed the inputs, we should validate the catalog source & prompt to accept the license terms
|
|
939
1142
|
if not self.devMode:
|
|
940
1143
|
self.validateCatalogSource()
|
|
@@ -958,6 +1161,10 @@ class InstallApp(BaseApp, InstallSettingsMixin, InstallSummarizerMixin, ConfigGe
|
|
|
958
1161
|
self.devMode = args.dev_mode
|
|
959
1162
|
self.skipGrafanaInstall = args.skip_grafana_install
|
|
960
1163
|
|
|
1164
|
+
# Set image_pull_policy of the CLI in interactive mode
|
|
1165
|
+
if args.image_pull_policy and args.image_pull_policy != "":
|
|
1166
|
+
self.setParam("image_pull_policy", args.image_pull_policy)
|
|
1167
|
+
|
|
961
1168
|
self.approvals = {}
|
|
962
1169
|
|
|
963
1170
|
# Store all args
|
|
@@ -979,6 +1186,10 @@ class InstallApp(BaseApp, InstallSettingsMixin, InstallSummarizerMixin, ConfigGe
|
|
|
979
1186
|
print_formatted_text(HTML("<Red>Error: The Kubernetes dynamic Client is not available. See log file for details</Red>"))
|
|
980
1187
|
exit(1)
|
|
981
1188
|
|
|
1189
|
+
# Perform a check whether the cluster is set up for airgap install, this will trigger an early failure if the cluster is using the now
|
|
1190
|
+
# deprecated MaximoApplicationSuite ImageContentSourcePolicy instead of the new ImageDigestMirrorSet
|
|
1191
|
+
self.isAirgap()
|
|
1192
|
+
|
|
982
1193
|
# Configure the installOptions for the appropriate architecture
|
|
983
1194
|
self.catalogOptions = supportedCatalogs[self.architecture]
|
|
984
1195
|
|
|
@@ -1001,15 +1212,19 @@ class InstallApp(BaseApp, InstallSettingsMixin, InstallSummarizerMixin, ConfigGe
|
|
|
1001
1212
|
if self.deployCP4D:
|
|
1002
1213
|
self.configCP4D()
|
|
1003
1214
|
|
|
1004
|
-
#
|
|
1005
|
-
entitlementFileBaseName = path.basename(self.slsLicenseFileLocal)
|
|
1006
|
-
self.setParam("sls_entitlement_file", f"/workspace/entitlement/{entitlementFileBaseName}")
|
|
1007
|
-
|
|
1008
|
-
# Set up the secrets for additional configs, podtemplates and manual certificates
|
|
1215
|
+
# Set up the secrets for additional configs, podtemplates, sls license file and manual certificates
|
|
1009
1216
|
self.additionalConfigs()
|
|
1010
1217
|
self.podTemplates()
|
|
1218
|
+
self.slsLicenseFile()
|
|
1011
1219
|
self.manualCertificates()
|
|
1012
1220
|
|
|
1221
|
+
if not self.noConfirm and not self.waitForPVC:
|
|
1222
|
+
self.printDescription(["If you are using storage classes that utilize 'WaitForFirstConsumer' binding mode choose 'No' at the prompt below"])
|
|
1223
|
+
self.waitForPVC = self.yesOrNo("Wait for PVCs to bind")
|
|
1224
|
+
|
|
1225
|
+
if not self.waitForPVC:
|
|
1226
|
+
self.setParam("no_wait_for_pvc", True)
|
|
1227
|
+
|
|
1013
1228
|
# Show a summary of the installation configuration
|
|
1014
1229
|
self.printH1("Non-Interactive Install Command")
|
|
1015
1230
|
self.printDescription([
|
|
@@ -1037,12 +1252,6 @@ class InstallApp(BaseApp, InstallSettingsMixin, InstallSummarizerMixin, ConfigGe
|
|
|
1037
1252
|
self.printH1("Launch Install")
|
|
1038
1253
|
pipelinesNamespace = f"mas-{self.getParam('mas_instance_id')}-pipelines"
|
|
1039
1254
|
|
|
1040
|
-
if not self.noConfirm:
|
|
1041
|
-
self.printDescription(["If you are using storage classes that utilize 'WaitForFirstConsumer' binding mode choose 'No' at the prompt below"])
|
|
1042
|
-
wait = self.yesOrNo("Wait for PVCs to bind")
|
|
1043
|
-
else:
|
|
1044
|
-
wait = False
|
|
1045
|
-
|
|
1046
1255
|
with Halo(text='Validating OpenShift Pipelines installation', spinner=self.spinner) as h:
|
|
1047
1256
|
installOpenShiftPipelines(self.dynamicClient)
|
|
1048
1257
|
h.stop_and_persist(symbol=self.successIcon, text="OpenShift Pipelines Operator is installed and ready to use")
|
|
@@ -1054,12 +1263,13 @@ class InstallApp(BaseApp, InstallSettingsMixin, InstallSummarizerMixin, ConfigGe
|
|
|
1054
1263
|
instanceId=self.getParam("mas_instance_id"),
|
|
1055
1264
|
storageClass=self.pipelineStorageClass,
|
|
1056
1265
|
accessMode=self.pipelineStorageAccessMode,
|
|
1057
|
-
waitForBind=
|
|
1266
|
+
waitForBind=self.waitForPVC,
|
|
1267
|
+
configureRBAC=(self.getParam("service_account_name") == "")
|
|
1058
1268
|
)
|
|
1059
1269
|
prepareInstallSecrets(
|
|
1060
1270
|
dynClient=self.dynamicClient,
|
|
1061
1271
|
instanceId=self.getParam("mas_instance_id"),
|
|
1062
|
-
slsLicenseFile=self.
|
|
1272
|
+
slsLicenseFile=self.slsLicenseFileSecret,
|
|
1063
1273
|
additionalConfigs=self.additionalConfigsSecret,
|
|
1064
1274
|
podTemplates=self.podTemplatesSecret,
|
|
1065
1275
|
certs=self.certsSecret
|
|
@@ -1094,11 +1304,11 @@ class InstallApp(BaseApp, InstallSettingsMixin, InstallSummarizerMixin, ConfigGe
|
|
|
1094
1304
|
- present with the chosen state field initialized to ""
|
|
1095
1305
|
"""
|
|
1096
1306
|
for approval in self.approvals.values():
|
|
1097
|
-
if "
|
|
1307
|
+
if "maxRetries" in approval:
|
|
1098
1308
|
# Enable this approval workload
|
|
1099
|
-
logger.debug(f"Approval workflow for {approval['id']} will be enabled during install ({approval['maxRetries']} / {approval['retryDelay']}s / {approval['
|
|
1100
|
-
self.initializeApprovalConfigMap(namespace, approval['id'],
|
|
1309
|
+
logger.debug(f"Approval workflow for {approval['id']} will be enabled during install ({approval['maxRetries']} / {approval['retryDelay']}s / {approval['ignoreFailure']})")
|
|
1310
|
+
self.initializeApprovalConfigMap(namespace, approval['id'], True, approval['maxRetries'], approval['retryDelay'], approval['ignoreFailure'])
|
|
1101
1311
|
else:
|
|
1102
1312
|
# Disable this approval workload
|
|
1103
1313
|
logger.debug(f"Approval workflow for {approval['id']} will be disabled during install")
|
|
1104
|
-
self.initializeApprovalConfigMap(namespace, approval['id'])
|
|
1314
|
+
self.initializeApprovalConfigMap(namespace, approval['id'], False)
|