mas-cli 15.10.1__py3-none-any.whl → 15.11.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__ = "15.10.1" # Python module compatible semver
11
+ __version__ = "15.11.0" # Python module compatible semver
@@ -454,8 +454,11 @@ class AiServiceInstallApp(BaseApp, aiServiceInstallArgBuilderMixin, aiServiceIns
454
454
  wait = False
455
455
 
456
456
  with Halo(text='Validating OpenShift Pipelines installation', spinner=self.spinner) as h:
457
- installOpenShiftPipelines(self.dynamicClient)
458
- h.stop_and_persist(symbol=self.successIcon, text="OpenShift Pipelines Operator is installed and ready to use")
457
+ if installOpenShiftPipelines(self.dynamicClient):
458
+ h.stop_and_persist(symbol=self.successIcon, text="OpenShift Pipelines Operator is installed and ready to use")
459
+ else:
460
+ h.stop_and_persist(symbol=self.successIcon, text="OpenShift Pipelines Operator installation failed")
461
+ self.fatalError("Installation failed")
459
462
 
460
463
  with Halo(text=f'Preparing namespace ({pipelinesNamespace})', spinner=self.spinner) as h:
461
464
  createNamespace(self.dynamicClient, pipelinesNamespace)
@@ -0,0 +1,11 @@
1
+ # *****************************************************************************
2
+ # Copyright (c) 2024, 2025 IBM Corporation and other Contributors.
3
+ #
4
+ # All rights reserved. This program and the accompanying materials
5
+ # are made available under the terms of the Eclipse Public License v1.0
6
+ # which accompanies this distribution, and is available at
7
+ # http://www.eclipse.org/legal/epl-v10.html
8
+ #
9
+ # *****************************************************************************
10
+
11
+ from ...cli import BaseApp # noqa: F401
@@ -0,0 +1,139 @@
1
+ #!/usr/bin/env python
2
+ # *****************************************************************************
3
+ # Copyright (c) 2024, 2025 IBM Corporation and other Contributors.
4
+ #
5
+ # All rights reserved. This program and the accompanying materials
6
+ # are made available under the terms of the Eclipse Public License v1.0
7
+ # which accompanies this distribution, and is available at
8
+ # http://www.eclipse.org/legal/epl-v10.html
9
+ #
10
+ # *****************************************************************************
11
+
12
+ import sys
13
+ import logging
14
+ import logging.handlers
15
+ from prompt_toolkit import prompt, print_formatted_text, HTML
16
+ from prompt_toolkit.completion import WordCompleter
17
+
18
+ from halo import Halo
19
+
20
+ from ...cli import BaseApp
21
+ from ...validators import AiserviceInstanceIDValidator
22
+ from .argParser import upgradeArgParser
23
+
24
+ from mas.devops.ocp import createNamespace
25
+ from mas.devops.mas import listAiServiceInstances, getAiserviceChannel
26
+ from mas.devops.tekton import installOpenShiftPipelines, updateTektonDefinitions, launchAiServiceUpgradePipeline
27
+ from openshift.dynamic.exceptions import ResourceNotFoundError
28
+ logger = logging.getLogger(__name__)
29
+
30
+
31
+ class AiServiceUpgradeApp(BaseApp):
32
+ def upgrade(self, argv):
33
+ """
34
+ Upgrade AI Service instance
35
+ """
36
+ args = upgradeArgParser.parse_args(args=argv)
37
+ aiserviceInstanceId = args.aiservice_instance_id
38
+ self.noConfirm = args.no_confirm
39
+ self.skipPreCheck = args.skip_pre_check
40
+ self.licenseAccepted = args.accept_license
41
+ self.devMode = args.dev_mode
42
+
43
+ if aiserviceInstanceId is None:
44
+ self.printH1("Set Target OpenShift Cluster")
45
+ # Connect to the target cluster
46
+ self.connect()
47
+ else:
48
+ logger.debug("AI Service instance ID is set, so we assume already connected to the desired OCP")
49
+ # Need to lookup target architecture because configDb2 will try to access self.architecture
50
+ self.lookupTargetArchitecture()
51
+
52
+ if self.dynamicClient is None:
53
+ print_formatted_text(HTML("<Red>Error: The Kubernetes dynamic Client is not available. See log file for details</Red>"))
54
+ sys.exit(1)
55
+
56
+ if aiserviceInstanceId is None:
57
+ # Interactive mode
58
+ self.printH1("AI Service Instance Selection")
59
+ print_formatted_text(HTML("<LightSlateGrey>Select a AI Service instance to upgrade from the list below:</LightSlateGrey>"))
60
+ try:
61
+ aiserviceInstances = listAiServiceInstances(self.dynamicClient)
62
+ except ResourceNotFoundError:
63
+ aiserviceInstances = []
64
+ aiserviceOptions = []
65
+
66
+ if len(aiserviceInstances) == 0:
67
+ print_formatted_text(HTML("<Red>Error: No AI Service instances detected on this cluster</Red>"))
68
+ sys.exit(1)
69
+
70
+ for aiservice in aiserviceInstances:
71
+ print_formatted_text(HTML(f"- <u>{aiservice['metadata']['name']}</u> v{aiservice['status']['versions']['reconciled']}"))
72
+ aiserviceOptions.append(aiservice['metadata']['name'])
73
+
74
+ aiserviceCompleter = WordCompleter(aiserviceOptions)
75
+ print()
76
+ aiserviceInstanceId = prompt(HTML('<Yellow>Enter AI Service instance ID: </Yellow>'), completer=aiserviceCompleter, validator=AiserviceInstanceIDValidator(), validate_while_typing=False)
77
+
78
+ currentAiserviceChannel = getAiserviceChannel(self.dynamicClient, aiserviceInstanceId)
79
+ if currentAiserviceChannel is not None:
80
+ if self.devMode:
81
+ # this enables upgrade of custom channel for AI service
82
+ nextAiserviceChannel = prompt(HTML('<Yellow>Custom channel</Yellow> '))
83
+ else:
84
+ if currentAiserviceChannel not in self.upgrade_path:
85
+ self.fatalError(f"No upgrade available, {aiserviceInstanceId} is are already on the latest release {currentAiserviceChannel}")
86
+ nextAiserviceChannel = self.upgrade_path[currentAiserviceChannel]
87
+
88
+ if not self.licenseAccepted and not self.devMode:
89
+ self.printH1("License Terms")
90
+ self.printDescription([
91
+ "To continue with the upgrade, you must accept the license terms:",
92
+ self.licenses[nextAiserviceChannel]
93
+ ])
94
+
95
+ if self.noConfirm:
96
+ self.fatalError("You must accept the license terms with --accept-license when using the --no-confirm flag")
97
+ else:
98
+ if not self.yesOrNo("Do you accept the license terms"):
99
+ exit(1)
100
+
101
+ self.printH1("Review Settings")
102
+ print_formatted_text(HTML(f"<LightSlateGrey>AI Service Instance ID ..................... {aiserviceInstanceId}</LightSlateGrey>"))
103
+ print_formatted_text(HTML(f"<LightSlateGrey>Current AI Service Channel ............. {currentAiserviceChannel}</LightSlateGrey>"))
104
+ print_formatted_text(HTML(f"<LightSlateGrey>Next AI Service Channel ................ {nextAiserviceChannel}</LightSlateGrey>"))
105
+ print_formatted_text(HTML(f"<LightSlateGrey>Skip Pre-Upgrade Checks ......... {self.skipPreCheck}</LightSlateGrey>"))
106
+
107
+ if not self.noConfirm:
108
+ print()
109
+ continueWithUpgrade = self.yesOrNo("Proceed with these settings")
110
+
111
+ if self.noConfirm or continueWithUpgrade:
112
+ self.createTektonFileWithDigest()
113
+
114
+ self.printH1("Launch Upgrade")
115
+ pipelinesNamespace = f"aiservice-{aiserviceInstanceId}-pipelines"
116
+
117
+ with Halo(text='Validating OpenShift Pipelines installation', spinner=self.spinner) as h:
118
+ if installOpenShiftPipelines(self.dynamicClient):
119
+ h.stop_and_persist(symbol=self.successIcon, text="OpenShift Pipelines Operator is installed and ready to use")
120
+ else:
121
+ h.stop_and_persist(symbol=self.successIcon, text="OpenShift Pipelines Operator installation failed")
122
+ self.fatalError("Installation failed")
123
+
124
+ with Halo(text=f'Preparing namespace ({pipelinesNamespace})', spinner=self.spinner) as h:
125
+ createNamespace(self.dynamicClient, pipelinesNamespace)
126
+ h.stop_and_persist(symbol=self.successIcon, text=f"Namespace is ready ({pipelinesNamespace})")
127
+
128
+ with Halo(text=f'Installing latest Tekton definitions (v{self.version})', spinner=self.spinner) as h:
129
+ updateTektonDefinitions(pipelinesNamespace, self.tektonDefsPath)
130
+ h.stop_and_persist(symbol=self.successIcon, text=f"Latest Tekton definitions are installed (v{self.version})")
131
+
132
+ with Halo(text='Submitting PipelineRun for {aiserviceInstanceId} upgrade', spinner=self.spinner) as h:
133
+ pipelineURL = launchAiServiceUpgradePipeline(self.dynamicClient, aiserviceInstanceId, self.skipPreCheck, aiserviceChannel=nextAiserviceChannel, params=self.params)
134
+ if pipelineURL is not None:
135
+ h.stop_and_persist(symbol=self.successIcon, text=f"PipelineRun for {aiserviceInstanceId} upgrade submitted")
136
+ print_formatted_text(HTML(f"\nView progress:\n <Cyan><u>{pipelineURL}</u></Cyan>\n"))
137
+ else:
138
+ h.stop_and_persist(symbol=self.failureIcon, text=f"Failed to submit PipelineRun for {aiserviceInstanceId} upgrade, see log file for details")
139
+ print()
@@ -0,0 +1,69 @@
1
+ # *****************************************************************************
2
+ # Copyright (c) 2024, 2025 IBM Corporation and other Contributors.
3
+ #
4
+ # All rights reserved. This program and the accompanying materials
5
+ # are made available under the terms of the Eclipse Public License v1.0
6
+ # which accompanies this distribution, and is available at
7
+ # http://www.eclipse.org/legal/epl-v10.html
8
+ #
9
+ # *****************************************************************************
10
+
11
+ import argparse
12
+
13
+ from ... import __version__ as packageVersion
14
+ from ...cli import getHelpFormatter
15
+
16
+ upgradeArgParser = argparse.ArgumentParser(
17
+ prog='mas aiservice-upgrade',
18
+ description="\n".join([
19
+ f"IBM Maximo Application Suite Admin CLI v{packageVersion}",
20
+ "Upgrade AI Service by configuring and launching the AI Service Upgrade Tekton Pipeline.\n",
21
+ "Interactive Mode:",
22
+ "Omitting the --aiservice-instance-id option will trigger an interactive prompt"
23
+ ]),
24
+ epilog="Refer to the online documentation for more information: https://ibm-mas.github.io/cli/",
25
+ formatter_class=getHelpFormatter(),
26
+ add_help=False
27
+ )
28
+
29
+ masArgGroup = upgradeArgParser.add_argument_group('MAS Instance Selection')
30
+ masArgGroup.add_argument(
31
+ '--aiservice-instance-id',
32
+ required=False,
33
+ help="The AI Service Instance ID to be upgraded"
34
+ )
35
+
36
+ otherArgGroup = upgradeArgParser.add_argument_group('More')
37
+ otherArgGroup.add_argument(
38
+ '--skip-pre-check',
39
+ required=False,
40
+ action='store_true',
41
+ default=False,
42
+ help="Disable the 'pre-upgrade-check' and 'post-upgrade-verify' tasks in the upgrade pipeline"
43
+ )
44
+ otherArgGroup.add_argument(
45
+ '--no-confirm',
46
+ required=False,
47
+ action='store_true',
48
+ default=False,
49
+ help="Launch the upgrade without prompting for confirmation",
50
+ )
51
+ otherArgGroup.add_argument(
52
+ "--accept-license",
53
+ action="store_true",
54
+ default=False,
55
+ help="Accept all license terms without prompting"
56
+ )
57
+ otherArgGroup.add_argument(
58
+ "--dev-mode",
59
+ required=False,
60
+ action="store_true",
61
+ default=False,
62
+ help="Configure upgrade for development mode",
63
+ )
64
+ otherArgGroup.add_argument(
65
+ '-h', "--help",
66
+ action='help',
67
+ default=False,
68
+ help="Show this help message and exit",
69
+ )
mas/cli/cli.py CHANGED
@@ -9,6 +9,7 @@
9
9
  # *****************************************************************************
10
10
 
11
11
  import logging
12
+ import logging.handlers
12
13
  import urllib3
13
14
 
14
15
  from argparse import RawTextHelpFormatter
@@ -118,7 +119,7 @@ class BaseApp(PrintMixin, PromptMixin):
118
119
  logging.getLogger('asyncio').setLevel(logging.INFO)
119
120
 
120
121
  # Supports extended semver, unlike mas.cli.__version__
121
- self.version = "15.10.1"
122
+ self.version = "15.11.0"
122
123
  self.h1count = 0
123
124
  self.h2count = 0
124
125
 
mas/cli/install/app.py CHANGED
@@ -1263,8 +1263,11 @@ class InstallApp(BaseApp, InstallSettingsMixin, InstallSummarizerMixin, ConfigGe
1263
1263
  pipelinesNamespace = f"mas-{self.getParam('mas_instance_id')}-pipelines"
1264
1264
 
1265
1265
  with Halo(text='Validating OpenShift Pipelines installation', spinner=self.spinner) as h:
1266
- installOpenShiftPipelines(self.dynamicClient)
1267
- h.stop_and_persist(symbol=self.successIcon, text="OpenShift Pipelines Operator is installed and ready to use")
1266
+ if installOpenShiftPipelines(self.dynamicClient):
1267
+ h.stop_and_persist(symbol=self.successIcon, text="OpenShift Pipelines Operator is installed and ready to use")
1268
+ else:
1269
+ h.stop_and_persist(symbol=self.successIcon, text="OpenShift Pipelines Operator installation failed")
1270
+ self.fatalError("Installation failed")
1268
1271
 
1269
1272
  with Halo(text=f'Preparing namespace ({pipelinesNamespace})', spinner=self.spinner) as h:
1270
1273
  createNamespace(self.dynamicClient, pipelinesNamespace)
@@ -9,20 +9,21 @@
9
9
  # *****************************************************************************
10
10
  supportedCatalogs = {
11
11
  "amd64": [
12
+ "v9-251030-amd64",
12
13
  "v9-251010-amd64",
13
14
  "v9-250925-amd64",
14
15
  "v9-250902-amd64",
15
- "v9-250828-amd64",
16
16
  ],
17
17
  "s390x": [
18
+ "v9-251030-s390x",
18
19
  # No "v9-250925-s390x" catalog for the s390x
19
20
  "v9-250902-s390x",
20
21
  "v9-250828-s390x",
21
22
  ],
22
23
  "ppc64le": [
24
+ "v9-251030-ppc64le",
23
25
  "v9-251010-ppc64le",
24
26
  "v9-250925-ppc64le",
25
27
  "v9-250902-ppc64le",
26
- "v9-250828-ppc64le",
27
28
  ],
28
29
  }
@@ -157,6 +157,8 @@ class Db2SettingsMixin():
157
157
  f"Note that the same settings are applied to both the IoT and {self.manageAppName} Db2 instances",
158
158
  "Use existing node labels and taints to control scheduling of the Db2 workload in your cluster",
159
159
  "For more information refer to the Red Hat documentation:",
160
+ " - <Orange><u>https://docs.redhat.com/en/documentation/openshift_container_platform/4.19/html/nodes/controlling-pod-placement-onto-nodes-scheduling#nodes-scheduler-node-affinity</u></Orange>",
161
+ " - <Orange><u>https://docs.redhat.com/en/documentation/openshift_container_platform/4.19/html/nodes/controlling-pod-placement-onto-nodes-scheduling#nodes-scheduler-taints-tolerations</u></Orange>",
160
162
  " - <Orange><u>https://docs.openshift.com/container-platform/4.18/nodes/scheduling/nodes-scheduler-node-affinity.html</u></Orange>",
161
163
  " - <Orange><u>https://docs.openshift.com/container-platform/4.18/nodes/scheduling/nodes-scheduler-taints-tolerations.html</u></Orange>",
162
164
  " - <Orange><u>https://docs.openshift.com/container-platform/4.17/nodes/scheduling/nodes-scheduler-node-affinity.html</u></Orange>",
@@ -220,8 +222,8 @@ class Db2SettingsMixin():
220
222
  self.params["db2_cpu_requests"] = "300m"
221
223
 
222
224
  else:
223
- self.setParam("db2_meta_storage_size", "20Gi")
224
- self.setParam("db2_backup_storage_size", "100Gi")
225
- self.setParam("db2_logs_storage_size", "100Gi")
226
- self.setParam("db2_temp_storage_size", "100Gi")
227
- self.setParam("db2_data_storage_size", "100Gi")
225
+ self.setParam("db2_meta_storage_size", "10Gi")
226
+ self.setParam("db2_backup_storage_size", "50Gi")
227
+ self.setParam("db2_logs_storage_size", "10Gi")
228
+ self.setParam("db2_temp_storage_size", "10Gi")
229
+ self.setParam("db2_data_storage_size", "50Gi")