mas-cli 5.1.4__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 +11 -0
- mas/cli/aiservice/install/__init__.py +11 -0
- mas/cli/aiservice/install/app.py +894 -0
- mas/cli/aiservice/install/argBuilder.py +180 -0
- mas/cli/aiservice/install/argParser.py +507 -0
- mas/cli/aiservice/install/params.py +100 -0
- mas/cli/aiservice/install/summarizer.py +134 -0
- mas/cli/cli.py +432 -0
- mas/cli/displayMixins.py +132 -0
- mas/cli/gencfg.py +113 -0
- mas/cli/install/__init__.py +11 -0
- mas/cli/install/app.py +1316 -0
- mas/cli/install/argBuilder.py +465 -0
- mas/cli/install/argParser.py +1176 -0
- mas/cli/install/catalogs.py +27 -0
- mas/cli/install/params.py +172 -0
- mas/cli/install/settings/__init__.py +23 -0
- mas/cli/install/settings/additionalConfigs.py +227 -0
- mas/cli/install/settings/db2Settings.py +252 -0
- mas/cli/install/settings/kafkaSettings.py +103 -0
- mas/cli/install/settings/manageSettings.py +273 -0
- mas/cli/install/settings/mongodbSettings.py +46 -0
- mas/cli/install/settings/turbonomicSettings.py +29 -0
- mas/cli/install/summarizer.py +398 -0
- mas/cli/templates/facilities-configs.yml.j2 +25 -0
- mas/cli/templates/ibm-mas-tekton.yaml +49772 -0
- mas/cli/templates/jdbccfg.yml.j2 +52 -0
- mas/cli/templates/pod-templates/best-effort/ibm-data-dictionary-assetdatadictionary.yml +26 -0
- mas/cli/templates/pod-templates/best-effort/ibm-mas-bascfg.yml +56 -0
- mas/cli/templates/pod-templates/best-effort/ibm-mas-coreidp.yml +21 -0
- mas/cli/templates/pod-templates/best-effort/ibm-mas-iot-actions.yml +28 -0
- mas/cli/templates/pod-templates/best-effort/ibm-mas-iot-auth.yml +32 -0
- mas/cli/templates/pod-templates/best-effort/ibm-mas-iot-datapower.yml +12 -0
- mas/cli/templates/pod-templates/best-effort/ibm-mas-iot-devops.yml +14 -0
- mas/cli/templates/pod-templates/best-effort/ibm-mas-iot-dm.yml +22 -0
- mas/cli/templates/pod-templates/best-effort/ibm-mas-iot-dsc.yml +40 -0
- mas/cli/templates/pod-templates/best-effort/ibm-mas-iot-edgeconfig.yml +10 -0
- mas/cli/templates/pod-templates/best-effort/ibm-mas-iot-fpl.yml +24 -0
- mas/cli/templates/pod-templates/best-effort/ibm-mas-iot-guardian.yml +20 -0
- mas/cli/templates/pod-templates/best-effort/ibm-mas-iot-iot.yml +10 -0
- mas/cli/templates/pod-templates/best-effort/ibm-mas-iot-mbgx.yml +18 -0
- mas/cli/templates/pod-templates/best-effort/ibm-mas-iot-mfgx.yml +14 -0
- mas/cli/templates/pod-templates/best-effort/ibm-mas-iot-monitor.yml +18 -0
- mas/cli/templates/pod-templates/best-effort/ibm-mas-iot-orgmgmt.yml +48 -0
- mas/cli/templates/pod-templates/best-effort/ibm-mas-iot-provision.yml +28 -0
- mas/cli/templates/pod-templates/best-effort/ibm-mas-iot-registry.yml +26 -0
- mas/cli/templates/pod-templates/best-effort/ibm-mas-iot-state.yml +40 -0
- mas/cli/templates/pod-templates/best-effort/ibm-mas-iot-webui.yml +22 -0
- mas/cli/templates/pod-templates/best-effort/ibm-mas-manage-healthextaccelerator.yml +13 -0
- mas/cli/templates/pod-templates/best-effort/ibm-mas-manage-healthextworkspace.yml +10 -0
- mas/cli/templates/pod-templates/best-effort/ibm-mas-manage-imagestitching.yml +10 -0
- mas/cli/templates/pod-templates/best-effort/ibm-mas-manage-manageaccelerators.yml +10 -0
- mas/cli/templates/pod-templates/best-effort/ibm-mas-manage-manageapp.yml +46 -0
- mas/cli/templates/pod-templates/best-effort/ibm-mas-manage-manageworkspace.yml +48 -0
- mas/cli/templates/pod-templates/best-effort/ibm-mas-manage-slackproxy.yml +10 -0
- mas/cli/templates/pod-templates/best-effort/ibm-mas-pushnotificationcfg.yml +13 -0
- mas/cli/templates/pod-templates/best-effort/ibm-mas-scimcfg.yml +14 -0
- mas/cli/templates/pod-templates/best-effort/ibm-mas-slscfg.yml +10 -0
- mas/cli/templates/pod-templates/best-effort/ibm-mas-smtpcfg.yml +10 -0
- mas/cli/templates/pod-templates/best-effort/ibm-mas-suite.yml +136 -0
- mas/cli/templates/pod-templates/best-effort/ibm-mas-visualinspection.yml +34 -0
- mas/cli/templates/pod-templates/best-effort/ibm-sls-licenseservice.yml +10 -0
- mas/cli/templates/pod-templates/guaranteed/ibm-data-dictionary-assetdatadictionary.yml +56 -0
- mas/cli/templates/pod-templates/guaranteed/ibm-mas-bascfg.yml +140 -0
- mas/cli/templates/pod-templates/guaranteed/ibm-mas-coreidp.yml +45 -0
- mas/cli/templates/pod-templates/guaranteed/ibm-mas-iot-actions.yml +70 -0
- mas/cli/templates/pod-templates/guaranteed/ibm-mas-iot-auth.yml +80 -0
- mas/cli/templates/pod-templates/guaranteed/ibm-mas-iot-datapower.yml +24 -0
- mas/cli/templates/pod-templates/guaranteed/ibm-mas-iot-devops.yml +26 -0
- mas/cli/templates/pod-templates/guaranteed/ibm-mas-iot-dm.yml +52 -0
- mas/cli/templates/pod-templates/guaranteed/ibm-mas-iot-dsc.yml +106 -0
- mas/cli/templates/pod-templates/guaranteed/ibm-mas-iot-edgeconfig.yml +16 -0
- mas/cli/templates/pod-templates/guaranteed/ibm-mas-iot-fpl.yml +62 -0
- mas/cli/templates/pod-templates/guaranteed/ibm-mas-iot-guardian.yml +44 -0
- mas/cli/templates/pod-templates/guaranteed/ibm-mas-iot-iot.yml +16 -0
- mas/cli/templates/pod-templates/guaranteed/ibm-mas-iot-mbgx.yml +42 -0
- mas/cli/templates/pod-templates/guaranteed/ibm-mas-iot-mfgx.yml +32 -0
- mas/cli/templates/pod-templates/guaranteed/ibm-mas-iot-monitor.yml +42 -0
- mas/cli/templates/pod-templates/guaranteed/ibm-mas-iot-orgmgmt.yml +126 -0
- mas/cli/templates/pod-templates/guaranteed/ibm-mas-iot-provision.yml +70 -0
- mas/cli/templates/pod-templates/guaranteed/ibm-mas-iot-registry.yml +62 -0
- mas/cli/templates/pod-templates/guaranteed/ibm-mas-iot-state.yml +106 -0
- mas/cli/templates/pod-templates/guaranteed/ibm-mas-iot-webui.yml +52 -0
- mas/cli/templates/pod-templates/guaranteed/ibm-mas-manage-healthextaccelerator.yml +28 -0
- mas/cli/templates/pod-templates/guaranteed/ibm-mas-manage-healthextworkspace.yml +18 -0
- mas/cli/templates/pod-templates/guaranteed/ibm-mas-manage-imagestitching.yml +16 -0
- mas/cli/templates/pod-templates/guaranteed/ibm-mas-manage-manageaccelerators.yml +16 -0
- mas/cli/templates/pod-templates/guaranteed/ibm-mas-manage-manageapp.yml +106 -0
- mas/cli/templates/pod-templates/guaranteed/ibm-mas-manage-manageworkspace.yml +126 -0
- mas/cli/templates/pod-templates/guaranteed/ibm-mas-manage-slackproxy.yml +16 -0
- mas/cli/templates/pod-templates/guaranteed/ibm-mas-pushnotificationcfg.yml +25 -0
- mas/cli/templates/pod-templates/guaranteed/ibm-mas-scimcfg.yml +26 -0
- mas/cli/templates/pod-templates/guaranteed/ibm-mas-slscfg.yml +16 -0
- mas/cli/templates/pod-templates/guaranteed/ibm-mas-smtpcfg.yml +16 -0
- mas/cli/templates/pod-templates/guaranteed/ibm-mas-suite.yml +340 -0
- mas/cli/templates/pod-templates/guaranteed/ibm-mas-visualinspection.yml +76 -0
- mas/cli/templates/pod-templates/guaranteed/ibm-sls-licenseservice.yml +16 -0
- mas/cli/templates/suite_mongocfg.yml.j2 +55 -0
- mas/cli/uninstall/__init__.py +11 -0
- mas/cli/uninstall/app.py +197 -0
- mas/cli/uninstall/argParser.py +115 -0
- mas/cli/update/__init__.py +11 -0
- mas/cli/update/app.py +673 -0
- mas/cli/update/argParser.py +156 -0
- mas/cli/upgrade/__init__.py +11 -0
- mas/cli/upgrade/app.py +164 -0
- mas/cli/upgrade/argParser.py +68 -0
- mas/cli/upgrade/settings/__init__.py +19 -0
- mas/cli/validators.py +151 -0
- mas_cli-5.1.4.data/scripts/mas-cli +87 -0
- mas_cli-5.1.4.dist-info/METADATA +73 -0
- mas_cli-5.1.4.dist-info/RECORD +114 -0
- mas_cli-5.1.4.dist-info/WHEEL +5 -0
- mas_cli-5.1.4.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# *****************************************************************************
|
|
2
|
+
# Copyright (c) 2024 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
|
+
updateArgParser = argparse.ArgumentParser(
|
|
17
|
+
prog='mas update',
|
|
18
|
+
description="\n".join([
|
|
19
|
+
f"IBM Maximo Application Suite Admin CLI v{packageVersion}",
|
|
20
|
+
"Update the IBM Maximo Operator Catalog, and related MAS dependencies by configuring and launching the MAS Update Tekton Pipeline.\n",
|
|
21
|
+
"Interactive Mode:",
|
|
22
|
+
"Omitting the --catalog 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 = updateArgParser.add_argument_group('Catalog Selection')
|
|
30
|
+
masArgGroup.add_argument(
|
|
31
|
+
'-c', '--catalog',
|
|
32
|
+
dest='mas_catalog_version',
|
|
33
|
+
required=False,
|
|
34
|
+
help="Maximo Operator Catalog Version (e.g. v9-240625-amd64)"
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
depsArgGroup = updateArgParser.add_argument_group('Update Dependencies')
|
|
38
|
+
depsArgGroup.add_argument(
|
|
39
|
+
'--db2-namespace',
|
|
40
|
+
required=False,
|
|
41
|
+
help="Namespace where Db2u operator and instances will be updated",
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
depsArgGroup.add_argument(
|
|
45
|
+
'--mongodb-namespace',
|
|
46
|
+
required=False,
|
|
47
|
+
help="Namespace where MongoCE operator and instances will be updated",
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
depsArgGroup.add_argument(
|
|
51
|
+
'--mongodb-v5-upgrade',
|
|
52
|
+
required=False,
|
|
53
|
+
action="store_const",
|
|
54
|
+
const="true",
|
|
55
|
+
help="Required to confirm a major version update for MongoDb to version 5",
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
depsArgGroup.add_argument(
|
|
59
|
+
'--mongodb-v6-upgrade',
|
|
60
|
+
required=False,
|
|
61
|
+
action="store_const",
|
|
62
|
+
const="true",
|
|
63
|
+
help="Required to confirm a major version update for MongoDb to version 6",
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
depsArgGroup.add_argument(
|
|
67
|
+
'--mongodb-v7-upgrade',
|
|
68
|
+
required=False,
|
|
69
|
+
action="store_const",
|
|
70
|
+
const="true",
|
|
71
|
+
help="Required to confirm a major version update for MongoDb to version 7",
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
depsArgGroup.add_argument(
|
|
75
|
+
'--kafka-namespace',
|
|
76
|
+
required=False,
|
|
77
|
+
help="Namespace where Kafka operator and instances will be updated",
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
depsArgGroup.add_argument(
|
|
81
|
+
'--kafka-provider',
|
|
82
|
+
required=False,
|
|
83
|
+
choices=["redhat", "strimzi"],
|
|
84
|
+
help="The type of Kakfa operator installed in the target namespace for updte",
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
droArgGroup = updateArgParser.add_argument_group('UDS to DRO Migration')
|
|
88
|
+
|
|
89
|
+
droArgGroup.add_argument(
|
|
90
|
+
'--dro-migration',
|
|
91
|
+
required=False,
|
|
92
|
+
help="Required to confirm the migration from IBM User Data Services (UDS) to IBM Data Reporter Operator (DRO)",
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
droArgGroup.add_argument(
|
|
96
|
+
'--dro-storage-class',
|
|
97
|
+
required=False,
|
|
98
|
+
help="Set Custom RWO Storage Class name for DRO as part of the update",
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
droArgGroup.add_argument(
|
|
102
|
+
'--dro-namespace',
|
|
103
|
+
required=False,
|
|
104
|
+
help="Set Custom Namespace for DRO(Default: redhat-marketplace)",
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
# Development Mode
|
|
108
|
+
# -----------------------------------------------------------------------------
|
|
109
|
+
devArgGroup = updateArgParser.add_argument_group("Development Mode")
|
|
110
|
+
devArgGroup.add_argument(
|
|
111
|
+
"--artifactory-username",
|
|
112
|
+
required=False,
|
|
113
|
+
help="Username for access to development builds on Artifactory"
|
|
114
|
+
)
|
|
115
|
+
devArgGroup.add_argument(
|
|
116
|
+
"--artifactory-token",
|
|
117
|
+
required=False,
|
|
118
|
+
help="API Token for access to development builds on Artifactory"
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
# More Options
|
|
122
|
+
# -----------------------------------------------------------------------------
|
|
123
|
+
otherArgGroup = updateArgParser.add_argument_group('More')
|
|
124
|
+
otherArgGroup.add_argument(
|
|
125
|
+
"--dev-mode",
|
|
126
|
+
required=False,
|
|
127
|
+
action="store_true",
|
|
128
|
+
default=False,
|
|
129
|
+
help="Configure installation for development mode",
|
|
130
|
+
)
|
|
131
|
+
otherArgGroup.add_argument(
|
|
132
|
+
"--cp4d-version",
|
|
133
|
+
dest="cpd_product_version",
|
|
134
|
+
required=False,
|
|
135
|
+
help="Product version of CP4D to use"
|
|
136
|
+
)
|
|
137
|
+
otherArgGroup.add_argument(
|
|
138
|
+
'--no-confirm',
|
|
139
|
+
required=False,
|
|
140
|
+
action='store_true',
|
|
141
|
+
default=False,
|
|
142
|
+
help="Launch the upgrade without prompting for confirmation",
|
|
143
|
+
)
|
|
144
|
+
otherArgGroup.add_argument(
|
|
145
|
+
'--skip-pre-check',
|
|
146
|
+
required=False,
|
|
147
|
+
action='store_true',
|
|
148
|
+
default=False,
|
|
149
|
+
help="Skips the 'pre-update-check' and 'post-update-verify' tasks in the update pipeline",
|
|
150
|
+
)
|
|
151
|
+
otherArgGroup.add_argument(
|
|
152
|
+
'-h', "--help",
|
|
153
|
+
action='help',
|
|
154
|
+
default=False,
|
|
155
|
+
help="Show this help message and exit",
|
|
156
|
+
)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# *****************************************************************************
|
|
2
|
+
# Copyright (c) 2024 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
|
mas/cli/upgrade/app.py
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# *****************************************************************************
|
|
3
|
+
# Copyright (c) 2024 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 InstanceIDValidator
|
|
22
|
+
from .argParser import upgradeArgParser
|
|
23
|
+
from .settings import UpgradeSettingsMixin
|
|
24
|
+
|
|
25
|
+
from mas.devops.ocp import createNamespace
|
|
26
|
+
from mas.devops.mas import listMasInstances, getMasChannel, getWorkspaceId, verifyAppInstance
|
|
27
|
+
from mas.devops.tekton import installOpenShiftPipelines, updateTektonDefinitions, launchUpgradePipeline
|
|
28
|
+
|
|
29
|
+
logger = logging.getLogger(__name__)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class UpgradeApp(BaseApp, UpgradeSettingsMixin):
|
|
33
|
+
def upgrade(self, argv):
|
|
34
|
+
"""
|
|
35
|
+
Upgrade MAS instance
|
|
36
|
+
"""
|
|
37
|
+
args = upgradeArgParser.parse_args(args=argv)
|
|
38
|
+
instanceId = args.mas_instance_id
|
|
39
|
+
self.noConfirm = args.no_confirm
|
|
40
|
+
self.skipPreCheck = args.skip_pre_check
|
|
41
|
+
self.licenseAccepted = args.accept_license
|
|
42
|
+
self.devMode = args.dev_mode
|
|
43
|
+
|
|
44
|
+
if instanceId is None:
|
|
45
|
+
self.printH1("Set Target OpenShift Cluster")
|
|
46
|
+
# Connect to the target cluster
|
|
47
|
+
self.connect()
|
|
48
|
+
else:
|
|
49
|
+
logger.debug("MAS instance ID is set, so we assume already connected to the desired OCP")
|
|
50
|
+
# Need to lookup target architecture because configDb2 will try to access self.architecture
|
|
51
|
+
self.lookupTargetArchitecture()
|
|
52
|
+
|
|
53
|
+
if self.dynamicClient is None:
|
|
54
|
+
print_formatted_text(HTML("<Red>Error: The Kubernetes dynamic Client is not available. See log file for details</Red>"))
|
|
55
|
+
sys.exit(1)
|
|
56
|
+
|
|
57
|
+
if instanceId is None:
|
|
58
|
+
# Interactive mode
|
|
59
|
+
self.printH1("Instance Selection")
|
|
60
|
+
print_formatted_text(HTML("<LightSlateGrey>Select a MAS instance to upgrade from the list below:</LightSlateGrey>"))
|
|
61
|
+
suites = listMasInstances(self.dynamicClient)
|
|
62
|
+
suiteOptions = []
|
|
63
|
+
|
|
64
|
+
if len(suites) == 0:
|
|
65
|
+
print_formatted_text(HTML("<Red>Error: No MAS instances detected on this cluster</Red>"))
|
|
66
|
+
sys.exit(1)
|
|
67
|
+
|
|
68
|
+
for suite in suites:
|
|
69
|
+
print_formatted_text(HTML(f"- <u>{suite['metadata']['name']}</u> v{suite['status']['versions']['reconciled']}"))
|
|
70
|
+
suiteOptions.append(suite['metadata']['name'])
|
|
71
|
+
|
|
72
|
+
suiteCompleter = WordCompleter(suiteOptions)
|
|
73
|
+
print()
|
|
74
|
+
instanceId = prompt(HTML('<Yellow>Enter MAS instance ID: </Yellow>'), completer=suiteCompleter, validator=InstanceIDValidator(), validate_while_typing=False)
|
|
75
|
+
|
|
76
|
+
currentChannel = getMasChannel(self.dynamicClient, instanceId)
|
|
77
|
+
if currentChannel is not None:
|
|
78
|
+
if self.devMode:
|
|
79
|
+
# This is mainly used for the scenario where Manage Foundation would be installed, because core-upgrade does not use the value of nextChannel,
|
|
80
|
+
# it uses a compatibility_matrix object in ansible-devops to determine the next channel, so nextChannel is only informative for core upgrade purposes
|
|
81
|
+
nextChannel = prompt(HTML('<Yellow>Custom channel</Yellow> '))
|
|
82
|
+
else:
|
|
83
|
+
if currentChannel not in self.upgrade_path:
|
|
84
|
+
self.fatalError(f"No upgrade available, {instanceId} is are already on the latest release {currentChannel}")
|
|
85
|
+
nextChannel = self.upgrade_path[currentChannel]
|
|
86
|
+
else:
|
|
87
|
+
# We still allow the upgrade to proceed even though we can't detect the MAS instance. The upgrade may be being
|
|
88
|
+
# queued up to run after install for instance
|
|
89
|
+
currentChannel = "Unknown"
|
|
90
|
+
nextChannel = "Unknown"
|
|
91
|
+
|
|
92
|
+
if not self.licenseAccepted and not self.devMode:
|
|
93
|
+
self.printH1("License Terms")
|
|
94
|
+
self.printDescription([
|
|
95
|
+
"To continue with the upgrade, you must accept the license terms:",
|
|
96
|
+
self.licenses[nextChannel]
|
|
97
|
+
])
|
|
98
|
+
|
|
99
|
+
if self.noConfirm:
|
|
100
|
+
self.fatalError("You must accept the license terms with --accept-license when using the --no-confirm flag")
|
|
101
|
+
else:
|
|
102
|
+
if not self.yesOrNo("Do you accept the license terms"):
|
|
103
|
+
exit(1)
|
|
104
|
+
|
|
105
|
+
# The only scenario where Manage Foundation needs to be installed during an upgrade is from 9.0.x to 9.1.x (if Manage was not already installed in 9.0.x).
|
|
106
|
+
self.setParam("should_install_manage_foundation", "false")
|
|
107
|
+
if nextChannel.startswith("9.1") and not verifyAppInstance(self.dynamicClient, instanceId, "manage"):
|
|
108
|
+
self.manageAppName = "Manage foundation"
|
|
109
|
+
self.showAdvancedOptions = False
|
|
110
|
+
self.installIoT = False
|
|
111
|
+
self.installFacilities = False
|
|
112
|
+
self.installManage = True
|
|
113
|
+
self.isManageFoundation = True
|
|
114
|
+
self.printDescription([f"{self.manageAppName} installs the following capabilities: User, Security groups, Application configurator and Mobile configurator."])
|
|
115
|
+
self.printH1("Configure IBM Container Registry")
|
|
116
|
+
self.promptForString("IBM entitlement key", "ibm_entitlement_key", isPassword=True)
|
|
117
|
+
if self.devMode:
|
|
118
|
+
self.promptForString("Artifactory username", "artifactory_username")
|
|
119
|
+
self.promptForString("Artifactory token", "artifactory_token", isPassword=True)
|
|
120
|
+
self.setParam("should_install_manage_foundation", "true")
|
|
121
|
+
self.setParam("mas_appws_components", "")
|
|
122
|
+
self.setParam("mas_app_settings_aio_flag", "false")
|
|
123
|
+
self.setParam("mas_app_channel_manage", nextChannel)
|
|
124
|
+
self.setParam("mas_workspace_id", getWorkspaceId(self.dynamicClient, instanceId))
|
|
125
|
+
# It has been decided that we don't need to ask for any specific Manage Settings
|
|
126
|
+
# self.manageSettings()
|
|
127
|
+
self.configDb2(silentMode=True)
|
|
128
|
+
|
|
129
|
+
self.printH1("Review Settings")
|
|
130
|
+
print_formatted_text(HTML(f"<LightSlateGrey>Instance ID ..................... {instanceId}</LightSlateGrey>"))
|
|
131
|
+
print_formatted_text(HTML(f"<LightSlateGrey>Current MAS Channel ............. {currentChannel}</LightSlateGrey>"))
|
|
132
|
+
print_formatted_text(HTML(f"<LightSlateGrey>Next MAS Channel ................ {nextChannel}</LightSlateGrey>"))
|
|
133
|
+
print_formatted_text(HTML(f"<LightSlateGrey>Skip Pre-Upgrade Checks ......... {self.skipPreCheck}</LightSlateGrey>"))
|
|
134
|
+
|
|
135
|
+
if not self.noConfirm:
|
|
136
|
+
print()
|
|
137
|
+
continueWithUpgrade = self.yesOrNo("Proceed with these settings")
|
|
138
|
+
|
|
139
|
+
if self.noConfirm or continueWithUpgrade:
|
|
140
|
+
self.createTektonFileWithDigest()
|
|
141
|
+
|
|
142
|
+
self.printH1("Launch Upgrade")
|
|
143
|
+
pipelinesNamespace = f"mas-{instanceId}-pipelines"
|
|
144
|
+
|
|
145
|
+
with Halo(text='Validating OpenShift Pipelines installation', spinner=self.spinner) as h:
|
|
146
|
+
installOpenShiftPipelines(self.dynamicClient)
|
|
147
|
+
h.stop_and_persist(symbol=self.successIcon, text="OpenShift Pipelines Operator is installed and ready to use")
|
|
148
|
+
|
|
149
|
+
with Halo(text=f'Preparing namespace ({pipelinesNamespace})', spinner=self.spinner) as h:
|
|
150
|
+
createNamespace(self.dynamicClient, pipelinesNamespace)
|
|
151
|
+
h.stop_and_persist(symbol=self.successIcon, text=f"Namespace is ready ({pipelinesNamespace})")
|
|
152
|
+
|
|
153
|
+
with Halo(text=f'Installing latest Tekton definitions (v{self.version})', spinner=self.spinner) as h:
|
|
154
|
+
updateTektonDefinitions(pipelinesNamespace, self.tektonDefsPath)
|
|
155
|
+
h.stop_and_persist(symbol=self.successIcon, text=f"Latest Tekton definitions are installed (v{self.version})")
|
|
156
|
+
|
|
157
|
+
with Halo(text='Submitting PipelineRun for {instanceId} upgrade', spinner=self.spinner) as h:
|
|
158
|
+
pipelineURL = launchUpgradePipeline(self.dynamicClient, instanceId, self.skipPreCheck, params=self.params)
|
|
159
|
+
if pipelineURL is not None:
|
|
160
|
+
h.stop_and_persist(symbol=self.successIcon, text=f"PipelineRun for {instanceId} upgrade submitted")
|
|
161
|
+
print_formatted_text(HTML(f"\nView progress:\n <Cyan><u>{pipelineURL}</u></Cyan>\n"))
|
|
162
|
+
else:
|
|
163
|
+
h.stop_and_persist(symbol=self.failureIcon, text=f"Failed to submit PipelineRun for {instanceId} upgrade, see log file for details")
|
|
164
|
+
print()
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# *****************************************************************************
|
|
2
|
+
# Copyright (c) 2024 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 upgrade',
|
|
18
|
+
description="\n".join([
|
|
19
|
+
f"IBM Maximo Application Suite Admin CLI v{packageVersion}",
|
|
20
|
+
"Upgrade MAS by configuring and launching the MAS Upgrade Tekton Pipeline.\n",
|
|
21
|
+
"Interactive Mode:",
|
|
22
|
+
"Omitting the --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
|
+
'--mas-instance-id',
|
|
32
|
+
required=False,
|
|
33
|
+
help="The MAS instance ID to be upgraded"
|
|
34
|
+
)
|
|
35
|
+
otherArgGroup = upgradeArgParser.add_argument_group('More')
|
|
36
|
+
otherArgGroup.add_argument(
|
|
37
|
+
'--skip-pre-check',
|
|
38
|
+
required=False,
|
|
39
|
+
action='store_true',
|
|
40
|
+
default=False,
|
|
41
|
+
help="Disable the 'pre-upgrade-check' and 'post-upgrade-verify' tasks in the upgrade pipeline"
|
|
42
|
+
)
|
|
43
|
+
otherArgGroup.add_argument(
|
|
44
|
+
'--no-confirm',
|
|
45
|
+
required=False,
|
|
46
|
+
action='store_true',
|
|
47
|
+
default=False,
|
|
48
|
+
help="Launch the upgrade without prompting for confirmation",
|
|
49
|
+
)
|
|
50
|
+
otherArgGroup.add_argument(
|
|
51
|
+
"--accept-license",
|
|
52
|
+
action="store_true",
|
|
53
|
+
default=False,
|
|
54
|
+
help="Accept all license terms without prompting"
|
|
55
|
+
)
|
|
56
|
+
otherArgGroup.add_argument(
|
|
57
|
+
"--dev-mode",
|
|
58
|
+
required=False,
|
|
59
|
+
action="store_true",
|
|
60
|
+
default=False,
|
|
61
|
+
help="Configure upgrade for development mode",
|
|
62
|
+
)
|
|
63
|
+
otherArgGroup.add_argument(
|
|
64
|
+
'-h', "--help",
|
|
65
|
+
action='help',
|
|
66
|
+
default=False,
|
|
67
|
+
help="Show this help message and exit",
|
|
68
|
+
)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# *****************************************************************************
|
|
2
|
+
# Copyright (c) 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 ...install.settings.db2Settings import Db2SettingsMixin
|
|
12
|
+
from ...install.settings.manageSettings import ManageSettingsMixin
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class UpgradeSettingsMixin(Db2SettingsMixin, ManageSettingsMixin):
|
|
16
|
+
"""
|
|
17
|
+
This class collects all the Mixins providing interactive prompts for mas-upgrade
|
|
18
|
+
"""
|
|
19
|
+
pass
|
mas/cli/validators.py
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# *****************************************************************************
|
|
2
|
+
# Copyright (c) 2024 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 re import match
|
|
12
|
+
from os import path
|
|
13
|
+
from json import loads, JSONDecodeError
|
|
14
|
+
|
|
15
|
+
# Use of the openshift client rather than the kubernetes client allows us access to "apply"
|
|
16
|
+
from openshift import dynamic
|
|
17
|
+
from kubernetes import config
|
|
18
|
+
from kubernetes.client import api_client
|
|
19
|
+
|
|
20
|
+
from prompt_toolkit.validation import Validator, ValidationError
|
|
21
|
+
|
|
22
|
+
from mas.devops.ocp import getStorageClass
|
|
23
|
+
from mas.devops.mas import verifyMasInstance
|
|
24
|
+
|
|
25
|
+
import logging
|
|
26
|
+
|
|
27
|
+
logger = logging.getLogger(__name__)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class InstanceIDFormatValidator(Validator):
|
|
31
|
+
def validate(self, document):
|
|
32
|
+
"""
|
|
33
|
+
Validate that a MAS instance ID exists on the target cluster
|
|
34
|
+
"""
|
|
35
|
+
instanceId = document.text
|
|
36
|
+
|
|
37
|
+
if not match(r"^[a-z][a-z0-9-]{1,10}[a-z0-9]$", instanceId):
|
|
38
|
+
raise ValidationError(message='MAS instance ID does not meet the requirements', cursor_position=len(instanceId))
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class WorkspaceIDFormatValidator(Validator):
|
|
42
|
+
def validate(self, document):
|
|
43
|
+
"""
|
|
44
|
+
Validate that a MAS instance ID exists on the target cluster
|
|
45
|
+
"""
|
|
46
|
+
instanceId = document.text
|
|
47
|
+
|
|
48
|
+
if not match(r"^[a-z][a-z0-9]{2,11}$", instanceId):
|
|
49
|
+
raise ValidationError(message='Workspace ID does not meet the requirements', cursor_position=len(instanceId))
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class TimeoutFormatValidator(Validator):
|
|
53
|
+
def validate(self, document):
|
|
54
|
+
"""
|
|
55
|
+
Validate that a MAS instance ID exists on the target cluster
|
|
56
|
+
"""
|
|
57
|
+
string_to_validate = document.text
|
|
58
|
+
if string_to_validate != "" and not match(r'^([0-9]+)([hm])$', string_to_validate):
|
|
59
|
+
message = f"Error: Your input: {string_to_validate} does not meet the required pattern. Please use it in hours or minutes format (e.g., 12h, 12m)."
|
|
60
|
+
raise ValidationError(message=message, cursor_position=len(string_to_validate))
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class WorkspaceNameFormatValidator(Validator):
|
|
64
|
+
def validate(self, document):
|
|
65
|
+
"""
|
|
66
|
+
Validate that a MAS instance ID exists on the target cluster
|
|
67
|
+
"""
|
|
68
|
+
instanceId = document.text
|
|
69
|
+
|
|
70
|
+
if not match(r"^.{3,300}$", instanceId):
|
|
71
|
+
raise ValidationError(message='Workspace name does not meet the requirements', cursor_position=len(instanceId))
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class InstanceIDValidator(Validator):
|
|
75
|
+
def validate(self, document):
|
|
76
|
+
"""
|
|
77
|
+
Validate that a MAS instance ID exists on the target cluster
|
|
78
|
+
"""
|
|
79
|
+
instanceId = document.text
|
|
80
|
+
|
|
81
|
+
dynClient = dynamic.DynamicClient(
|
|
82
|
+
api_client.ApiClient(configuration=config.load_kube_config())
|
|
83
|
+
)
|
|
84
|
+
if not verifyMasInstance(dynClient, instanceId):
|
|
85
|
+
raise ValidationError(message='Not a valid MAS instance ID on this cluster', cursor_position=len(instanceId))
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class StorageClassValidator(Validator):
|
|
89
|
+
def validate(self, document):
|
|
90
|
+
"""
|
|
91
|
+
Validate that a StorageClass exists on the target cluster
|
|
92
|
+
"""
|
|
93
|
+
name = document.text
|
|
94
|
+
|
|
95
|
+
dynClient = dynamic.DynamicClient(
|
|
96
|
+
api_client.ApiClient(configuration=config.load_kube_config())
|
|
97
|
+
)
|
|
98
|
+
if getStorageClass(dynClient, name) is None:
|
|
99
|
+
raise ValidationError(message='Specified storage class is not available on this cluster', cursor_position=len(name))
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class YesNoValidator(Validator):
|
|
103
|
+
def validate(self, document):
|
|
104
|
+
"""
|
|
105
|
+
Validate that a response is understandable as a yes/no response
|
|
106
|
+
"""
|
|
107
|
+
response = document.text
|
|
108
|
+
if response.lower() not in ["y", "n", "yes", "no"]:
|
|
109
|
+
raise ValidationError(message='Enter a valid response: y(es), n(o)', cursor_position=len(response))
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class FileExistsValidator(Validator):
|
|
113
|
+
def validate(self, document):
|
|
114
|
+
"""
|
|
115
|
+
Validate that a file exists on the local system
|
|
116
|
+
"""
|
|
117
|
+
response = document.text
|
|
118
|
+
if not path.isfile(response):
|
|
119
|
+
raise ValidationError(message=f"{response} does not exist, or is not a file", cursor_position=len(response))
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class DirectoryExistsValidator(Validator):
|
|
123
|
+
def validate(self, document):
|
|
124
|
+
"""
|
|
125
|
+
Validate that a file exists on the local system
|
|
126
|
+
"""
|
|
127
|
+
response = document.text
|
|
128
|
+
if not path.isdir(response):
|
|
129
|
+
raise ValidationError(message=f"{response} does not exist, or is not a directory", cursor_position=len(response))
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
class OptimizerInstallPlanValidator(Validator):
|
|
133
|
+
def validate(self, document):
|
|
134
|
+
"""
|
|
135
|
+
Validate that a response is a valid install plan for Optimizer
|
|
136
|
+
"""
|
|
137
|
+
response = document.text
|
|
138
|
+
if response not in ["full", "limited"]:
|
|
139
|
+
raise ValidationError(message='Enter a valid response: full, limited', cursor_position=len(response))
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class JsonValidator(Validator):
|
|
143
|
+
def validate(self, document):
|
|
144
|
+
"""
|
|
145
|
+
Validate that a response is a valid JSON
|
|
146
|
+
"""
|
|
147
|
+
inputJson = document.text
|
|
148
|
+
try:
|
|
149
|
+
loads(inputJson)
|
|
150
|
+
except JSONDecodeError:
|
|
151
|
+
raise (ValidationError(message='Enter a valid JSON', cursor_position=len(inputJson)))
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!python
|
|
2
|
+
# *****************************************************************************
|
|
3
|
+
# Copyright (c) 2024 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 logging
|
|
13
|
+
import logging.handlers
|
|
14
|
+
from sys import argv
|
|
15
|
+
|
|
16
|
+
from mas.cli import __version__ as VERSION
|
|
17
|
+
from mas.cli.install.app import InstallApp
|
|
18
|
+
from mas.cli.aiservice.install.app import AiServiceInstallApp
|
|
19
|
+
from mas.cli.update.app import UpdateApp
|
|
20
|
+
from mas.cli.upgrade.app import UpgradeApp
|
|
21
|
+
from mas.cli.uninstall.app import UninstallApp
|
|
22
|
+
|
|
23
|
+
from prompt_toolkit import HTML, print_formatted_text
|
|
24
|
+
from urllib3.exceptions import MaxRetryError
|
|
25
|
+
from jinja2.exceptions import TemplateNotFound
|
|
26
|
+
from kubeconfig.exceptions import KubectlCommandError
|
|
27
|
+
from kubernetes.client.exceptions import ApiException
|
|
28
|
+
|
|
29
|
+
logger = logging.getLogger(__name__)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def usage():
|
|
33
|
+
print_formatted_text(HTML(""))
|
|
34
|
+
|
|
35
|
+
print_formatted_text(HTML(f"\n<u>IBM Maximo Application Suite Admin CLI v{VERSION}</u>"))
|
|
36
|
+
print_formatted_text(HTML("Powered by <DarkGoldenRod><u>https://github.com/ibm-mas/ansible-devops/</u></DarkGoldenRod> and <DarkGoldenRod><u>https://tekton.dev/</u></DarkGoldenRod>"))
|
|
37
|
+
print("")
|
|
38
|
+
print_formatted_text(HTML("Important Notice:\nThis standalone CLI (<ForestGreen>mas-cli</ForestGreen>) is still in beta state, not all functions supported by the <ForestGreen>mas</ForestGreen> function in quay.io/ibmmas/cli are supported yet"))
|
|
39
|
+
print("")
|
|
40
|
+
print_formatted_text(HTML(
|
|
41
|
+
"<b>MAS Management Actions:</b>\n"
|
|
42
|
+
+ " - <ForestGreen>mas-cli install</ForestGreen> Install IBM Maximo Application Suite\n" # noqa: W503
|
|
43
|
+
+ " - <ForestGreen>mas-cli update</ForestGreen> Apply updates and security fixes\n" # noqa: W503
|
|
44
|
+
+ " - <ForestGreen>mas-cli upgrade</ForestGreen> Upgrade to a new MAS release\n" # noqa: W503
|
|
45
|
+
+ " - <ForestGreen>mas-cli uninstall</ForestGreen> Remove MAS from the cluster\n" # noqa: W503
|
|
46
|
+
|
|
47
|
+
))
|
|
48
|
+
print_formatted_text(HTML("For usage information run <ForestGreen>mas-cli [action] --help</ForestGreen>\n"))
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
if __name__ == '__main__':
|
|
52
|
+
try:
|
|
53
|
+
function = argv[1]
|
|
54
|
+
|
|
55
|
+
if function == "install":
|
|
56
|
+
app = InstallApp()
|
|
57
|
+
app.install(argv[2:])
|
|
58
|
+
elif function == "aiservice-install":
|
|
59
|
+
app = AiServiceInstallApp()
|
|
60
|
+
app.install(argv[2:])
|
|
61
|
+
elif function == "uninstall":
|
|
62
|
+
app = UninstallApp()
|
|
63
|
+
app.uninstall(argv[2:])
|
|
64
|
+
elif function == "update":
|
|
65
|
+
app = UpdateApp()
|
|
66
|
+
app.update(argv[2:])
|
|
67
|
+
elif function == "upgrade":
|
|
68
|
+
app = UpgradeApp()
|
|
69
|
+
app.upgrade(argv[2:])
|
|
70
|
+
elif function in ["-h", "--help"]:
|
|
71
|
+
usage()
|
|
72
|
+
exit(0)
|
|
73
|
+
else:
|
|
74
|
+
usage()
|
|
75
|
+
print_formatted_text(HTML(f"<Red>Unknown action: {function}</Red>\n"))
|
|
76
|
+
exit(1)
|
|
77
|
+
|
|
78
|
+
except KeyboardInterrupt:
|
|
79
|
+
pass
|
|
80
|
+
except ApiException as e:
|
|
81
|
+
app.fatalError(message=f"[{e.status}:{e.reason}] {e.summary()}")
|
|
82
|
+
except MaxRetryError as e:
|
|
83
|
+
app.fatalError(message="Unable to connect to API server", exception=e)
|
|
84
|
+
except TemplateNotFound as e:
|
|
85
|
+
app.fatalError("Could not find template", exception=e)
|
|
86
|
+
except KubectlCommandError as e:
|
|
87
|
+
app.fatalError("Could not execute kubectl command", exception=e)
|