mas-cli 12.1.0__py3-none-any.whl → 13.1.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 CHANGED
@@ -8,4 +8,4 @@
8
8
  #
9
9
  # *****************************************************************************
10
10
 
11
- __version__ = "12.1.0" # Python module compatible semver
11
+ __version__ = "13.1.0" # Python module compatible semver
mas/cli/cli.py CHANGED
@@ -117,7 +117,7 @@ class BaseApp(PrintMixin, PromptMixin):
117
117
  logging.getLogger('asyncio').setLevel(logging.INFO)
118
118
 
119
119
  # Supports extended semver, unlike mas.cli.__version__
120
- self.version = "12.1.0"
120
+ self.version = "13.1.0"
121
121
  self.h1count = 0
122
122
  self.h2count = 0
123
123
 
@@ -138,6 +138,7 @@ class BaseApp(PrintMixin, PromptMixin):
138
138
  self.certsSecret = None
139
139
 
140
140
  self._isSNO = None
141
+ self._isAirgap = None
141
142
 
142
143
  # Until we connect to the cluster we don't know what architecture it's worker nodes are
143
144
  self.architecture = None
@@ -280,6 +281,16 @@ class BaseApp(PrintMixin, PromptMixin):
280
281
  self._isSNO = isSNO(self.dynamicClient)
281
282
  return self._isSNO
282
283
 
284
+ @logMethodCall
285
+ def isAirgap(self):
286
+ if self._isAirgap is None:
287
+ # First check if the legacy ICSP is installed. If it is raise an error and instruct the user to re-run configure-airgap to
288
+ # migrate the cluster from ICSP to IDMS
289
+ if isAirgapInstall(self.dynamicClient, checkICSP=True):
290
+ self.fatalError("Deprecated Maximo Application Suite ImageContentSourcePolicy detected on the target cluster. Run 'mas configure-airgap' to migrate to the replacement ImageDigestMirrorSet beofre proceeding.")
291
+ self._isAirgap = isAirgapInstall(self.dynamicClient)
292
+ return self._isAirgap
293
+
283
294
  def setParam(self, param: str, value: str):
284
295
  self.params[param] = value
285
296
 
@@ -372,7 +383,7 @@ class BaseApp(PrintMixin, PromptMixin):
372
383
  self.fatalError(f"Unsupported worker node architecture: {self.architecture}")
373
384
 
374
385
  @logMethodCall
375
- def initializeApprovalConfigMap(self, namespace: str, id: str, key: str = None, maxRetries: int = 100, delay: int = 300, ignoreFailure: bool = True) -> None:
386
+ def initializeApprovalConfigMap(self, namespace: str, id: str, enabled: bool, maxRetries: int = 100, delay: int = 300, ignoreFailure: bool = True) -> None:
376
387
  """
377
388
  Set key = None if you don't want approval workflow enabled
378
389
  """
@@ -388,8 +399,7 @@ class BaseApp(PrintMixin, PromptMixin):
388
399
  "MAX_RETRIES": str(maxRetries),
389
400
  "DELAY": str(delay),
390
401
  "IGNORE_FAILURE": str(ignoreFailure),
391
- "CONFIGMAP_KEY": key,
392
- key: ""
402
+ "STATUS": ""
393
403
  }
394
404
  }
395
405
 
@@ -400,6 +410,6 @@ class BaseApp(PrintMixin, PromptMixin):
400
410
  except NotFoundError:
401
411
  pass
402
412
 
403
- if key is not None:
404
- logger.debug(f"Enabling approval workflow for {id} using {key} with {maxRetries} max retries on a {delay}s delay ({'ignoring failures' if ignoreFailure else 'abort on failure'})")
413
+ if enabled:
414
+ logger.debug(f"Enabling approval workflow for {id} with {maxRetries} max retries on a {delay}s delay ({'ignoring failures' if ignoreFailure else 'abort on failure'})")
405
415
  cmAPI.create(body=configMap, namespace=namespace)
mas/cli/install/app.py CHANGED
@@ -651,9 +651,12 @@ class InstallApp(BaseApp, InstallSettingsMixin, InstallSummarizerMixin, ConfigGe
651
651
  def optimizerSettings(self) -> None:
652
652
  if self.installOptimizer:
653
653
  self.printH1("Configure Maximo Optimizer")
654
- self.printDescription(["Customize your Optimizer installation, 'full' and 'limited' install plans are available, refer to the product documentation for more information"])
655
-
656
- self.promptForString("Plan [full/limited]", "mas_app_plan_optimizer", default="full", validator=OptimizerInstallPlanValidator())
654
+ if self.isSNO():
655
+ self.printDescription(["Using Optimizer 'limited' plan as it is being installed in a single node cluster"])
656
+ self.setParam("mas_app_plan_optimizer", "limited")
657
+ else:
658
+ self.printDescription(["Customize your Optimizer installation, 'full' and 'limited' install plans are available, refer to the product documentation for more information"])
659
+ self.promptForString("Plan [full/limited]", "mas_app_plan_optimizer", default="full", validator=OptimizerInstallPlanValidator())
657
660
 
658
661
  @logMethodCall
659
662
  def predictSettings(self) -> None:
@@ -904,16 +907,15 @@ class InstallApp(BaseApp, InstallSettingsMixin, InstallSummarizerMixin, ConfigGe
904
907
 
905
908
  if value != "":
906
909
  valueParts = value.split(":")
907
- if len(valueParts) != 4:
908
- self.fatalError(f"Unsupported format for {key} ({value}). Expected APPROVAL_KEY:MAX_RETRIES:RETRY_DELAY:IGNORE_FAILURE")
910
+ if len(valueParts) != 3:
911
+ self.fatalError(f"Unsupported format for {key} ({value}). Expected MAX_RETRIES:RETRY_DELAY:IGNORE_FAILURE")
909
912
  else:
910
913
  try:
911
- self.approvals[key]["approvalKey"] = valueParts[0]
912
- self.approvals[key]["maxRetries"] = int(valueParts[1])
913
- self.approvals[key]["retryDelay"] = int(valueParts[2])
914
- self.approvals[key]["ignoreFailure"] = bool(valueParts[3])
914
+ self.approvals[key]["maxRetries"] = int(valueParts[0])
915
+ self.approvals[key]["retryDelay"] = int(valueParts[1])
916
+ self.approvals[key]["ignoreFailure"] = bool(valueParts[2])
915
917
  except ValueError:
916
- self.fatalError(f"Unsupported format for {key} ({value}). Expected string:int:int:boolean")
918
+ self.fatalError(f"Unsupported format for {key} ({value}). Expected int:int:boolean")
917
919
 
918
920
  # Arguments that we don't need to do anything with
919
921
  elif key in ["accept_license", "dev_mode", "skip_pre_check", "skip_grafana_install", "no_confirm", "no_wait_for_pvc", "help", "advanced", "simplified"]:
@@ -979,6 +981,10 @@ class InstallApp(BaseApp, InstallSettingsMixin, InstallSummarizerMixin, ConfigGe
979
981
  print_formatted_text(HTML("<Red>Error: The Kubernetes dynamic Client is not available. See log file for details</Red>"))
980
982
  exit(1)
981
983
 
984
+ # 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
985
+ # deprecated MaximoApplicationSuite ImageContentSourcePolicy instead of the new ImageDigestMirrorSet
986
+ self.isAirgap()
987
+
982
988
  # Configure the installOptions for the appropriate architecture
983
989
  self.catalogOptions = supportedCatalogs[self.architecture]
984
990
 
@@ -1094,11 +1100,11 @@ class InstallApp(BaseApp, InstallSettingsMixin, InstallSummarizerMixin, ConfigGe
1094
1100
  - present with the chosen state field initialized to ""
1095
1101
  """
1096
1102
  for approval in self.approvals.values():
1097
- if "approvalKey" in approval:
1103
+ if "maxRetries" in approval:
1098
1104
  # Enable this approval workload
1099
- logger.debug(f"Approval workflow for {approval['id']} will be enabled during install ({approval['maxRetries']} / {approval['retryDelay']}s / {approval['approvalKey']} / {approval['ignoreFailure']})")
1100
- self.initializeApprovalConfigMap(namespace, approval['id'], approval['approvalKey'], approval['maxRetries'], approval['retryDelay'], approval['ignoreFailure'])
1105
+ logger.debug(f"Approval workflow for {approval['id']} will be enabled during install ({approval['maxRetries']} / {approval['retryDelay']}s / {approval['ignoreFailure']})")
1106
+ self.initializeApprovalConfigMap(namespace, approval['id'], True, approval['maxRetries'], approval['retryDelay'], approval['ignoreFailure'])
1101
1107
  else:
1102
1108
  # Disable this approval workload
1103
1109
  logger.debug(f"Approval workflow for {approval['id']} will be disabled during install")
1104
- self.initializeApprovalConfigMap(namespace, approval['id'])
1110
+ self.initializeApprovalConfigMap(namespace, approval['id'], False)
@@ -102,9 +102,13 @@ class installArgBuilderMixin():
102
102
  command += f" --domain \"{self.getParam('mas_domain')}\"{newline}"
103
103
 
104
104
  if self.getParam('--dns-provider') == "cis":
105
- command += f" --dns-provider cis --cis-apikey \"{self.getParam('cis_apikey')}"
106
- command += f" --cis-subdomain \"{self.getParam('cis_subdomain')}"
107
- command += f" --cis-crn \"{self.getParam('cis_crn')}\"{newline}"
105
+ command += f" --dns-provider cis --cis-apikey \"{self.getParam('cis_apikey')}\""
106
+ command += f" --cis-subdomain \"{self.getParam('cis_subdomain')}\""
107
+ command += f" --cis-crn \"{self.getParam('cis_crn')}\""
108
+ command += f" --cis-email \"{self.getParam('cis_email')}\"{newline}"
109
+
110
+ if self.getParam('--mas-cluster-issuer') != "":
111
+ command += f" --mas-cluster-issuer \"{self.getParam('mas_cluster_issuer')}\"{newline}"
108
112
 
109
113
  if self.getParam('mas_enable_walkme') == "false":
110
114
  command += f" --disable-walkme{newline}"
@@ -212,6 +216,12 @@ class installArgBuilderMixin():
212
216
  if self.getParam('mas_app_settings_server_timezone') != "":
213
217
  command += f" --manage-server-timezone \"{self.getParam('mas_app_settings_server_timezone')}\"{newline}"
214
218
 
219
+ if self.getParam('mas_manage_attachments_provider') != "":
220
+ command += f" --manage-attachments-provider \"{self.getParam('mas_manage_attachments_provider')}\"{newline}"
221
+
222
+ if self.getParam('mas_manage_attachment_configuration_mode') != "":
223
+ command += f" --manage-attachments-mode \"{self.getParam('mas_manage_attachment_configuration_mode')}\"{newline}"
224
+
215
225
  # IBM Cloud Pak for Data
216
226
  # -----------------------------------------------------------------------------
217
227
  if self.getParam('cpd_product_version') != "":
@@ -321,6 +331,10 @@ class installArgBuilderMixin():
321
331
  command += f" --cos-resourcegroup \"{self.getParam('cos_resourcegroup')}\""
322
332
  if self.getParam('cos_apikey') != "":
323
333
  command += f" --cos-apikey \"{self.getParam('cos_apikey')}\""
334
+ if self.getParam('cos_instance_name') != "":
335
+ command += f" --cos-instance-name \"{self.getParam('cos_instance_name')}\""
336
+ if self.getParam('cos_bucket_name') != "":
337
+ command += f" --cos-bucket-name \"{self.getParam('cos_bucket_name')}\"{newline}"
324
338
  command += newline
325
339
 
326
340
  # Turbonomic Integration
@@ -188,6 +188,13 @@ masAdvancedArgGroup.add_argument(
188
188
  choices=["cloudflare", "cis", "route53"]
189
189
  )
190
190
 
191
+ masAdvancedArgGroup.add_argument(
192
+ "--mas-cluster-issuer",
193
+ dest="mas_cluster_issuer",
194
+ required=False,
195
+ help="Provide the name of the ClusterIssuer to configure MAS to issue certificates",
196
+ )
197
+
191
198
  # DNS Configuration - IBM CIS
192
199
  # -----------------------------------------------------------------------------
193
200
  cisArgGroup = installArgParser.add_argument_group("DNS Configuration - CIS")
@@ -519,7 +526,7 @@ manageArgGroup.add_argument(
519
526
  "--manage-jms",
520
527
  dest="mas_app_settings_default_jms",
521
528
  required=False,
522
- help="",
529
+ help="Set JMS configuration",
523
530
  action="store_const",
524
531
  const="true"
525
532
  )
@@ -651,6 +658,22 @@ manageArgGroup.add_argument(
651
658
  help="Manage server timezone. Default is `GMT`"
652
659
  )
653
660
 
661
+ # Manage Attachments
662
+ # -----------------------------------------------------------------------------
663
+ manageArgGroup.add_argument(
664
+ "--manage-attachments-provider",
665
+ dest="mas_manage_attachments_provider",
666
+ required=False,
667
+ help="Defines the storage provider type to be used to store attachments in Maximo Manage"
668
+ )
669
+ manageArgGroup.add_argument(
670
+ "--manage-attachments-mode",
671
+ dest="mas_manage_attachment_configuration_mode",
672
+ required=False,
673
+ help="Defines how attachment properties will be configured in Manage. Possible values are: cr and db",
674
+ choices=["cr", "db"]
675
+ )
676
+
654
677
  # IBM Cloud Pak for Data
655
678
  # -----------------------------------------------------------------------------
656
679
  cpdAppsArgGroup = installArgParser.add_argument_group("IBM Cloud Pak for Data")
@@ -927,6 +950,18 @@ cosArgGroup.add_argument(
927
950
  required=False,
928
951
  help="When using IBM COS, set COS priviledged apikey for IBM Cloud"
929
952
  )
953
+ cosArgGroup.add_argument(
954
+ "--cos-instance-name",
955
+ dest="cos_instance_name",
956
+ required=False,
957
+ help="When using IBM COS, set COS instance name to be used/created"
958
+ )
959
+ cosArgGroup.add_argument(
960
+ "--cos-bucket-name",
961
+ dest="cos_bucket_name",
962
+ required=False,
963
+ help="When using IBM COS, set COS bucket name to be used/created"
964
+ )
930
965
 
931
966
  # Turbonomic Integration
932
967
  # -----------------------------------------------------------------------------
@@ -1007,7 +1042,7 @@ devArgGroup.add_argument(
1007
1042
 
1008
1043
  # Approvals
1009
1044
  # -----------------------------------------------------------------------------
1010
- approvalsGroup = installArgParser.add_argument_group("Integrated Approval Workflow (APPROVAL_KEY:MAX_RETRIES:RETRY_DELAY:IGNORE_FAILURE)")
1045
+ approvalsGroup = installArgParser.add_argument_group("Integrated Approval Workflow (MAX_RETRIES:RETRY_DELAY:IGNORE_FAILURE)")
1011
1046
  approvalsGroup.add_argument(
1012
1047
  "--approval-core",
1013
1048
  default="",
@@ -9,12 +9,13 @@
9
9
  # *****************************************************************************
10
10
  supportedCatalogs = {
11
11
  "amd64": [
12
+ "v9-250109-amd64",
12
13
  "v9-241205-amd64",
13
14
  "v9-241107-amd64",
14
15
  "v9-241003-amd64",
15
- "v9-240827-amd64",
16
16
  ],
17
17
  "s390x": [
18
+ "v9-250109-s390x",
18
19
  "v9-241205-s390x",
19
20
  "v9-241107-s390x",
20
21
  ],
mas/cli/install/params.py CHANGED
@@ -67,6 +67,7 @@ optionalParams = [
67
67
  "cis_apikey",
68
68
  "cis_crn",
69
69
  "cis_subdomain",
70
+ "mas_cluster_issuer",
70
71
  # DRO
71
72
  "dro_namespace",
72
73
  # MongoDb
@@ -115,6 +116,11 @@ optionalParams = [
115
116
  "cos_type",
116
117
  "cos_resourcegroup",
117
118
  "cos_apikey",
119
+ "cos_instance_name",
120
+ "cos_bucket_name",
121
+ # Attachments
122
+ "mas_manage_attachments_provider",
123
+ "mas_manage_attachment_configuration_mode",
118
124
  # ECK
119
125
  "eck_action",
120
126
  "eck_enable_logstash",
@@ -8,8 +8,6 @@
8
8
  #
9
9
  # *****************************************************************************
10
10
 
11
- from mas.devops.mas import isAirgapInstall
12
-
13
11
 
14
12
  class TurbonomicSettingsMixin():
15
13
 
@@ -21,7 +19,7 @@ class TurbonomicSettingsMixin():
21
19
  " - Learn more: <Orange><u>https://www.ibm.com/products/turbonomic</u></Orange>"
22
20
  ])
23
21
 
24
- if isAirgapInstall(self.dynamicClient):
22
+ if self.isAirgap():
25
23
  self.printHighlight("The Turbonomic Kubernetes Operator does not support disconnected installation at this time")
26
24
  elif self.yesOrNo("Configure IBM Turbonomic integration"):
27
25
  self.promptForString("Turbonomic Target Name", "turbonomic_target_name")
@@ -11,7 +11,6 @@
11
11
  import logging
12
12
  import yaml
13
13
  from prompt_toolkit import print_formatted_text, HTML
14
- from mas.devops.mas import isAirgapInstall
15
14
  from mas.devops.ocp import getConsoleURL
16
15
 
17
16
  logger = logging.getLogger(__name__)
@@ -46,7 +45,7 @@ class InstallSummarizerMixin():
46
45
 
47
46
  print()
48
47
  self.printSummary("Operational Mode", operationalModeNames[self.operationalMode])
49
- if isAirgapInstall(self.dynamicClient):
48
+ if self.isAirgap():
50
49
  self.printSummary("Install Mode", "Disconnected Install")
51
50
  else:
52
51
  self.printSummary("Install Mode", "Connected Install")