mas-cli 9.5.0__tar.gz
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-9.5.0/MANIFEST.in +1 -0
- mas_cli-9.5.0/PKG-INFO +63 -0
- mas_cli-9.5.0/README.rst +33 -0
- mas_cli-9.5.0/pyproject.toml +6 -0
- mas_cli-9.5.0/setup.cfg +4 -0
- mas_cli-9.5.0/setup.py +88 -0
- mas_cli-9.5.0/src/mas/cli/__init__.py +11 -0
- mas_cli-9.5.0/src/mas/cli/cli.py +189 -0
- mas_cli-9.5.0/src/mas-uninstall +281 -0
- mas_cli-9.5.0/src/mas-upgrade +156 -0
- mas_cli-9.5.0/src/mas_cli.egg-info/PKG-INFO +63 -0
- mas_cli-9.5.0/src/mas_cli.egg-info/SOURCES.txt +13 -0
- mas_cli-9.5.0/src/mas_cli.egg-info/dependency_links.txt +1 -0
- mas_cli-9.5.0/src/mas_cli.egg-info/requires.txt +11 -0
- mas_cli-9.5.0/src/mas_cli.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
include src/mas/devops/cli/*.yaml
|
mas_cli-9.5.0/PKG-INFO
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: mas-cli
|
|
3
|
+
Version: 9.5.0
|
|
4
|
+
Summary: Python Admin CLI for Maximo Application Suite
|
|
5
|
+
Home-page: https://github.com/ibm-mas/cli
|
|
6
|
+
Author: David Parker
|
|
7
|
+
Author-email: parkerda@uk.ibm.com
|
|
8
|
+
License: Eclipse Public License - v1.0
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
12
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
13
|
+
Classifier: Programming Language :: Python
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Topic :: Communications
|
|
18
|
+
Classifier: Topic :: Internet
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Requires-Dist: mas-devops
|
|
21
|
+
Requires-Dist: halo
|
|
22
|
+
Requires-Dist: prompt_toolkit
|
|
23
|
+
Requires-Dist: openshift
|
|
24
|
+
Requires-Dist: kubernetes
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: build; extra == "dev"
|
|
27
|
+
Requires-Dist: flake8; extra == "dev"
|
|
28
|
+
Requires-Dist: pytest; extra == "dev"
|
|
29
|
+
Requires-Dist: pyinstaller; extra == "dev"
|
|
30
|
+
|
|
31
|
+
mas.devops
|
|
32
|
+
----------
|
|
33
|
+
|
|
34
|
+
Example
|
|
35
|
+
=======
|
|
36
|
+
|
|
37
|
+
.. code:: python
|
|
38
|
+
|
|
39
|
+
from openshift import dynamic
|
|
40
|
+
from kubernetes import config
|
|
41
|
+
from kubernetes.client import api_client
|
|
42
|
+
|
|
43
|
+
from mas.devops.ocp import createNamespace
|
|
44
|
+
from mas.devops.tekton import installOpenShiftPipelines, updateTektonDefinitions, launchUpgradePipeline
|
|
45
|
+
|
|
46
|
+
instanceId = "mymas"
|
|
47
|
+
pipelinesNamespace = f"mas-{instanceId}-pipelines"
|
|
48
|
+
|
|
49
|
+
# Create an OpenShift client
|
|
50
|
+
dynClient = dynamic.DynamicClient(
|
|
51
|
+
api_client.ApiClient(configuration=config.load_kube_config())
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
# Install OpenShift Pipelines Operator
|
|
55
|
+
installOpenShiftPipelines(dynamicClient)
|
|
56
|
+
|
|
57
|
+
# Create the pipelines namespace and install the MAS tekton definitions
|
|
58
|
+
createNamespace(dynamicClient, pipelinesNamespace)
|
|
59
|
+
updateTektonDefinitions(pipelinesNamespace)
|
|
60
|
+
|
|
61
|
+
# Launch the upgrade pipeline and print the URL to view the pipeline run
|
|
62
|
+
pipelineURL = launchUpgradePipeline(self.dynamicClient, instanceId)
|
|
63
|
+
print(pipelineURL)
|
mas_cli-9.5.0/README.rst
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
mas.devops
|
|
2
|
+
----------
|
|
3
|
+
|
|
4
|
+
Example
|
|
5
|
+
=======
|
|
6
|
+
|
|
7
|
+
.. code:: python
|
|
8
|
+
|
|
9
|
+
from openshift import dynamic
|
|
10
|
+
from kubernetes import config
|
|
11
|
+
from kubernetes.client import api_client
|
|
12
|
+
|
|
13
|
+
from mas.devops.ocp import createNamespace
|
|
14
|
+
from mas.devops.tekton import installOpenShiftPipelines, updateTektonDefinitions, launchUpgradePipeline
|
|
15
|
+
|
|
16
|
+
instanceId = "mymas"
|
|
17
|
+
pipelinesNamespace = f"mas-{instanceId}-pipelines"
|
|
18
|
+
|
|
19
|
+
# Create an OpenShift client
|
|
20
|
+
dynClient = dynamic.DynamicClient(
|
|
21
|
+
api_client.ApiClient(configuration=config.load_kube_config())
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
# Install OpenShift Pipelines Operator
|
|
25
|
+
installOpenShiftPipelines(dynamicClient)
|
|
26
|
+
|
|
27
|
+
# Create the pipelines namespace and install the MAS tekton definitions
|
|
28
|
+
createNamespace(dynamicClient, pipelinesNamespace)
|
|
29
|
+
updateTektonDefinitions(pipelinesNamespace)
|
|
30
|
+
|
|
31
|
+
# Launch the upgrade pipeline and print the URL to view the pipeline run
|
|
32
|
+
pipelineURL = launchUpgradePipeline(self.dynamicClient, instanceId)
|
|
33
|
+
print(pipelineURL)
|
mas_cli-9.5.0/setup.cfg
ADDED
mas_cli-9.5.0/setup.py
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
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
|
+
import codecs
|
|
11
|
+
import sys
|
|
12
|
+
import os
|
|
13
|
+
sys.path.insert(0, 'src')
|
|
14
|
+
|
|
15
|
+
from setuptools import setup, find_namespace_packages
|
|
16
|
+
|
|
17
|
+
if not os.path.exists('README.rst'):
|
|
18
|
+
import pypandoc
|
|
19
|
+
pypandoc.download_pandoc(targetfolder='~/bin/')
|
|
20
|
+
pypandoc.convert_file('README.md', 'rst', outputfile='README.rst')
|
|
21
|
+
|
|
22
|
+
here = os.path.abspath(os.path.dirname(__file__))
|
|
23
|
+
with open(os.path.join(here, 'README.rst'), encoding='utf-8') as f:
|
|
24
|
+
long_description = f.read()
|
|
25
|
+
|
|
26
|
+
# Maintain a single source of versioning
|
|
27
|
+
# https://packaging.python.org/en/latest/guides/single-sourcing-package-version/
|
|
28
|
+
def read(rel_path):
|
|
29
|
+
here = os.path.abspath(os.path.dirname(__file__))
|
|
30
|
+
with codecs.open(os.path.join(here, rel_path), 'r') as fp:
|
|
31
|
+
return fp.read()
|
|
32
|
+
|
|
33
|
+
def get_version(rel_path):
|
|
34
|
+
for line in read(rel_path).splitlines():
|
|
35
|
+
if line.startswith('__version__'):
|
|
36
|
+
delim = '"' if '"' in line else "'"
|
|
37
|
+
return line.split(delim)[1]
|
|
38
|
+
else:
|
|
39
|
+
raise RuntimeError("Unable to find version string.")
|
|
40
|
+
|
|
41
|
+
setup(
|
|
42
|
+
name='mas-cli',
|
|
43
|
+
version=get_version("src/mas/cli/__init__.py"),
|
|
44
|
+
author='David Parker',
|
|
45
|
+
author_email='parkerda@uk.ibm.com',
|
|
46
|
+
package_dir={'': 'src'},
|
|
47
|
+
packages=find_namespace_packages(where='src', include=[
|
|
48
|
+
'mas.cli',
|
|
49
|
+
'mas.cli.templates'
|
|
50
|
+
]),
|
|
51
|
+
include_package_data=True,
|
|
52
|
+
scripts=[
|
|
53
|
+
'src/mas-upgrade',
|
|
54
|
+
'src/mas-uninstall'
|
|
55
|
+
],
|
|
56
|
+
url='https://github.com/ibm-mas/cli',
|
|
57
|
+
license='Eclipse Public License - v1.0',
|
|
58
|
+
description='Python Admin CLI for Maximo Application Suite',
|
|
59
|
+
long_description=long_description,
|
|
60
|
+
install_requires=[
|
|
61
|
+
'mas-devops', # EPL
|
|
62
|
+
'halo', # MIT License
|
|
63
|
+
'prompt_toolkit', # BSD License
|
|
64
|
+
'openshift', # Apache Software License
|
|
65
|
+
'kubernetes' # Apache Software License
|
|
66
|
+
],
|
|
67
|
+
extras_require={
|
|
68
|
+
'dev': [
|
|
69
|
+
'build', # MIT License
|
|
70
|
+
'flake8', # MIT License
|
|
71
|
+
'pytest', # MIT License
|
|
72
|
+
'pyinstaller' # GPL, https://pyinstaller.org/en/stable/license.html & https://github.com/pyinstaller/pyinstaller/wiki/FAQ#license
|
|
73
|
+
]
|
|
74
|
+
},
|
|
75
|
+
classifiers=[
|
|
76
|
+
'Development Status :: 4 - Beta',
|
|
77
|
+
'Intended Audience :: Developers',
|
|
78
|
+
'Operating System :: Microsoft :: Windows',
|
|
79
|
+
'Operating System :: POSIX :: Linux',
|
|
80
|
+
'Programming Language :: Python',
|
|
81
|
+
'Programming Language :: Python :: 3.9',
|
|
82
|
+
'Programming Language :: Python :: 3.10',
|
|
83
|
+
'Programming Language :: Python :: 3.11',
|
|
84
|
+
'Topic :: Communications',
|
|
85
|
+
'Topic :: Internet',
|
|
86
|
+
'Topic :: Software Development :: Libraries :: Python Modules'
|
|
87
|
+
]
|
|
88
|
+
)
|
|
@@ -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
|
+
__version__ = "9.5.0"
|
|
@@ -0,0 +1,189 @@
|
|
|
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
|
+
from argparse import RawTextHelpFormatter
|
|
11
|
+
from shutil import which
|
|
12
|
+
from os import path
|
|
13
|
+
|
|
14
|
+
# Use of the openshift client rather than the kubernetes client allows us access to "apply"
|
|
15
|
+
from openshift import dynamic
|
|
16
|
+
from kubernetes import config
|
|
17
|
+
from kubernetes.client import api_client
|
|
18
|
+
|
|
19
|
+
from prompt_toolkit import prompt, print_formatted_text, HTML
|
|
20
|
+
from prompt_toolkit.validation import Validator, ValidationError
|
|
21
|
+
|
|
22
|
+
# Available named colours in prompt_toolkit
|
|
23
|
+
# -----------------------------------------------------------------------------
|
|
24
|
+
# AliceBlue AntiqueWhite Aqua Aquamarine Azure Beige Bisque Black BlanchedAlmond Blue BlueViolet
|
|
25
|
+
# Brown BurlyWood CadetBlue Chartreuse Chocolate Coral CornflowerBlue Cornsilk Crimson Cyan
|
|
26
|
+
# DarkBlue DarkCyan DarkGoldenRod DarkGray DarkGreen DarkGrey DarkKhaki DarkMagenta DarkOliveGreen
|
|
27
|
+
# DarkOrange DarkOrchid DarkRed DarkSalmon DarkSeaGreen DarkSlateBlue DarkSlateGray DarkSlateGrey
|
|
28
|
+
# DarkTurquoise DarkViolet DeepPink DeepSkyBlue DimGray DimGrey DodgerBlue FireBrick FloralWhite
|
|
29
|
+
# ForestGreen Fuchsia Gainsboro GhostWhite Gold GoldenRod Gray Green GreenYellow Grey HoneyDew
|
|
30
|
+
# HotPink IndianRed Indigo Ivory Khaki Lavender LavenderBlush LawnGreen LemonChiffon LightBlue
|
|
31
|
+
# LightCoral LightCyan LightGoldenRodYellow LightGray LightGreen LightGrey LightPink LightSalmon
|
|
32
|
+
# LightSeaGreen LightSkyBlue LightSlateGray LightSlateGrey LightSteelBlue LightYellow Lime
|
|
33
|
+
# LimeGreen Linen Magenta Maroon MediumAquaMarine MediumBlue MediumOrchid MediumPurple MediumSeaGreen
|
|
34
|
+
# MediumSlateBlue MediumSpringGreen MediumTurquoise MediumVioletRed MidnightBlue MintCream MistyRose
|
|
35
|
+
# Moccasin NavajoWhite Navy OldLace Olive OliveDrab Orange OrangeRed Orchid PaleGoldenRod PaleGreen
|
|
36
|
+
# PaleTurquoise PaleVioletRed PapayaWhip PeachPuff Peru Pink Plum PowderBlue Purple RebeccaPurple
|
|
37
|
+
# Red RosyBrown RoyalBlue SaddleBrown Salmon SandyBrown SeaGreen SeaShell Sienna Silver SkyBlue
|
|
38
|
+
# SlateBlue SlateGray SlateGrey Snow SpringGreen SteelBlue Tan Teal Thistle Tomato Turquoise
|
|
39
|
+
# Violet Wheat White WhiteSmoke Yellow YellowGreen
|
|
40
|
+
|
|
41
|
+
from mas.cli import __version__ as packageVersion
|
|
42
|
+
from mas.devops.ocp import connect
|
|
43
|
+
from mas.devops.mas import verifyMasInstance
|
|
44
|
+
|
|
45
|
+
from sys import exit
|
|
46
|
+
|
|
47
|
+
import logging
|
|
48
|
+
|
|
49
|
+
logger = logging.getLogger(__name__)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class InstanceIDValidator(Validator):
|
|
53
|
+
def validate(self, document):
|
|
54
|
+
"""
|
|
55
|
+
Validate that a MAS instance ID exists on the target cluster
|
|
56
|
+
"""
|
|
57
|
+
instanceId = document.text
|
|
58
|
+
|
|
59
|
+
dynClient = dynamic.DynamicClient(
|
|
60
|
+
api_client.ApiClient(configuration=config.load_kube_config())
|
|
61
|
+
)
|
|
62
|
+
if not verifyMasInstance(dynClient, instanceId):
|
|
63
|
+
raise ValidationError(message='Not a valid MAS instance ID on this cluster', cursor_position=len(instanceId))
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class YesNoValidator(Validator):
|
|
67
|
+
def validate(self, document):
|
|
68
|
+
"""
|
|
69
|
+
Validate that a response is understandable as a yes/no response
|
|
70
|
+
"""
|
|
71
|
+
response = document.text
|
|
72
|
+
if response.lower() not in ["y", "n", "yes", "no"]:
|
|
73
|
+
raise ValidationError(message='Enter a valid response: y(es), n(o)', cursor_position=len(response))
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def getHelpFormatter(formatter=RawTextHelpFormatter, w=160, h=50):
|
|
77
|
+
"""
|
|
78
|
+
Return a wider HelpFormatter, if possible.
|
|
79
|
+
|
|
80
|
+
https://stackoverflow.com/a/57655311
|
|
81
|
+
"""
|
|
82
|
+
try:
|
|
83
|
+
kwargs = {'width': w, 'max_help_position': h}
|
|
84
|
+
formatter(None, **kwargs)
|
|
85
|
+
return lambda prog: formatter(prog, **kwargs)
|
|
86
|
+
except TypeError:
|
|
87
|
+
logger.warn("argparse help formatter failed, falling back.")
|
|
88
|
+
return formatter
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class BaseApp(object):
|
|
92
|
+
def __init__(self):
|
|
93
|
+
# Set up a log formatter
|
|
94
|
+
chFormatter = logging.Formatter('%(asctime)-25s' + ' %(levelname)-8s %(message)s')
|
|
95
|
+
|
|
96
|
+
# Set up a log handler (5mb rotating log file)
|
|
97
|
+
ch = logging.handlers.RotatingFileHandler(
|
|
98
|
+
"mas.log", maxBytes=(1048576*5), backupCount=2
|
|
99
|
+
)
|
|
100
|
+
ch.setLevel(logging.DEBUG)
|
|
101
|
+
ch.setFormatter(chFormatter)
|
|
102
|
+
|
|
103
|
+
# Configure the root logger
|
|
104
|
+
rootLogger = logging.getLogger()
|
|
105
|
+
rootLogger.addHandler(ch)
|
|
106
|
+
rootLogger.setLevel(logging.DEBUG)
|
|
107
|
+
|
|
108
|
+
self.version = packageVersion
|
|
109
|
+
self.h1count = 0
|
|
110
|
+
|
|
111
|
+
self.tektonDefsPath = path.join(path.abspath(path.dirname(__file__)), "templates", "ibm-mas-tekton.yaml")
|
|
112
|
+
print(self.tektonDefsPath)
|
|
113
|
+
|
|
114
|
+
self.spinner = {
|
|
115
|
+
"interval": 80,
|
|
116
|
+
"frames": [" ⠋", " ⠙", " ⠹", " ⠸", " ⠼", " ⠴", " ⠦", " ⠧", " ⠇", " ⠏"]
|
|
117
|
+
}
|
|
118
|
+
self.successIcon = "✅️"
|
|
119
|
+
self.failureIcon = "❌"
|
|
120
|
+
|
|
121
|
+
self._dynClient = None
|
|
122
|
+
|
|
123
|
+
self.printTitle(f"IBM Maximo Application Suite Admin CLI v{self.version}")
|
|
124
|
+
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>"))
|
|
125
|
+
|
|
126
|
+
if which("kubectl") is None:
|
|
127
|
+
logger.error("Could not find kubectl on the path")
|
|
128
|
+
print_formatted_text(HTML("\n<Red>Error: Could not find kubectl on the path, see <u>https://kubernetes.io/docs/tasks/tools/#kubectl</u> for installation instructions</Red>\n"))
|
|
129
|
+
exit(1)
|
|
130
|
+
|
|
131
|
+
def printTitle(self, message):
|
|
132
|
+
print_formatted_text(HTML(f"<b><u>{message}</u></b>"))
|
|
133
|
+
|
|
134
|
+
def printH1(self, message):
|
|
135
|
+
self.h1count += 1
|
|
136
|
+
print()
|
|
137
|
+
print_formatted_text(HTML(f"<u><SteelBlue>{self.h1count}. {message}</SteelBlue></u>"))
|
|
138
|
+
|
|
139
|
+
@property
|
|
140
|
+
def dynamicClient(self):
|
|
141
|
+
if self._dynClient is not None:
|
|
142
|
+
return self._dynClient
|
|
143
|
+
else:
|
|
144
|
+
return self.reloadDynamicClient()
|
|
145
|
+
|
|
146
|
+
def reloadDynamicClient(self):
|
|
147
|
+
"""
|
|
148
|
+
Configure the Kubernetes API Client using the active context in kubeconfig
|
|
149
|
+
"""
|
|
150
|
+
logger.debug("Reloading Kubernetes Client Configuration")
|
|
151
|
+
try:
|
|
152
|
+
config.load_kube_config()
|
|
153
|
+
self._dynClient = dynamic.DynamicClient(
|
|
154
|
+
api_client.ApiClient(configuration=config.load_kube_config())
|
|
155
|
+
)
|
|
156
|
+
return self._dynClient
|
|
157
|
+
except Exception as e:
|
|
158
|
+
logger.warning(f"Error: Unable to connect to OpenShift Container Platform: {e}")
|
|
159
|
+
return None
|
|
160
|
+
|
|
161
|
+
def connect(self, noConfirm):
|
|
162
|
+
promptForNewServer = False
|
|
163
|
+
self.reloadDynamicClient()
|
|
164
|
+
if self._dynClient is not None:
|
|
165
|
+
try:
|
|
166
|
+
routesAPI = self._dynClient.resources.get(api_version="route.openshift.io/v1", kind="Route")
|
|
167
|
+
consoleRoute = routesAPI.get(name="console", namespace="openshift-console")
|
|
168
|
+
print_formatted_text(HTML(f"Already connected to OCP Cluster:\n <u><Orange>https://{consoleRoute.spec.host}</Orange></u>"))
|
|
169
|
+
print()
|
|
170
|
+
if not noConfirm:
|
|
171
|
+
# We are already connected to a cluster, but prompt the user if they want to use this connection
|
|
172
|
+
continueWithExistingCluster = prompt(HTML('<Yellow>Proceed with this cluster?</Yellow> '), validator=YesNoValidator(), validate_while_typing=False)
|
|
173
|
+
promptForNewServer = continueWithExistingCluster in ["n", "no"]
|
|
174
|
+
except Exception:
|
|
175
|
+
# We are already connected to a cluster, but the connection is not valid so prompt for connection details
|
|
176
|
+
promptForNewServer = True
|
|
177
|
+
else:
|
|
178
|
+
# We are not already connected to any cluster, so prompt for connection details
|
|
179
|
+
promptForNewServer = True
|
|
180
|
+
|
|
181
|
+
if promptForNewServer:
|
|
182
|
+
# Prompt for new connection properties
|
|
183
|
+
server = prompt(HTML('<Yellow>Server URL:</Yellow> '), placeholder="https://...")
|
|
184
|
+
token = prompt(HTML('<Yellow>Login Token:</Yellow> '), is_password=True, placeholder="sha256~...")
|
|
185
|
+
connect(server, token)
|
|
186
|
+
self.reloadDynamicClient()
|
|
187
|
+
if self._dynClient is None:
|
|
188
|
+
print_formatted_text(HTML("<Red>Unable to connect to cluster. See log file for details</Red>"))
|
|
189
|
+
exit(1)
|
|
@@ -0,0 +1,281 @@
|
|
|
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 argparse
|
|
13
|
+
import sys
|
|
14
|
+
import logging
|
|
15
|
+
import logging.handlers
|
|
16
|
+
from prompt_toolkit import prompt, print_formatted_text, HTML
|
|
17
|
+
from prompt_toolkit.completion import WordCompleter
|
|
18
|
+
|
|
19
|
+
from halo import Halo
|
|
20
|
+
|
|
21
|
+
from mas.cli import __version__ as packageVersion
|
|
22
|
+
from mas.cli.cli import InstanceIDValidator, YesNoValidator, BaseApp, getHelpFormatter
|
|
23
|
+
from mas.devops.ocp import createNamespace
|
|
24
|
+
from mas.devops.mas import listMasInstances, verifyMasInstance
|
|
25
|
+
from mas.devops.tekton import installOpenShiftPipelines, updateTektonDefinitions, launchUninstallPipeline
|
|
26
|
+
from openshift.dynamic.exceptions import NotFoundError
|
|
27
|
+
|
|
28
|
+
logger = logging.getLogger(__name__)
|
|
29
|
+
|
|
30
|
+
class App(BaseApp):
|
|
31
|
+
def uninstall(self, args):
|
|
32
|
+
"""
|
|
33
|
+
Uninstall MAS instance
|
|
34
|
+
"""
|
|
35
|
+
instanceId = args.instance_id
|
|
36
|
+
noConfirm = args.no_confirm
|
|
37
|
+
if args.uninstall_all_deps:
|
|
38
|
+
uninstallGrafana = True
|
|
39
|
+
uninstallIBMCatalog = True
|
|
40
|
+
uninstallCommonServices = True
|
|
41
|
+
uninstallCertManager = True
|
|
42
|
+
uninstallUDS = True
|
|
43
|
+
uninstallMongoDb = True
|
|
44
|
+
uninstallSLS = True
|
|
45
|
+
else:
|
|
46
|
+
uninstallGrafana = args.uninstall_grafana
|
|
47
|
+
uninstallIBMCatalog = args.uninstall_ibm_catalog
|
|
48
|
+
uninstallCommonServices = args.uninstall_common_services
|
|
49
|
+
uninstallCertManager = args.uninstall_cert_manager
|
|
50
|
+
uninstallUDS = args.uninstall_uds
|
|
51
|
+
uninstallMongoDb = args.uninstall_mongodb
|
|
52
|
+
uninstallSLS = args.uninstall_sls
|
|
53
|
+
|
|
54
|
+
if instanceId is None:
|
|
55
|
+
self.printH1("Set Target OpenShift Cluster")
|
|
56
|
+
# Connect to the target cluster
|
|
57
|
+
self.connect(noConfirm)
|
|
58
|
+
else:
|
|
59
|
+
logger.debug("MAS instance ID is set, so we assume already connected to the desired OCP")
|
|
60
|
+
|
|
61
|
+
if self.dynamicClient is None:
|
|
62
|
+
print_formatted_text(HTML("<Red>Error: The Kubernetes dynamic Client is not available. See log file for details</Red>"))
|
|
63
|
+
sys.exit(1)
|
|
64
|
+
|
|
65
|
+
if instanceId is None:
|
|
66
|
+
# Interactive mode
|
|
67
|
+
self.printH1("Instance Selection")
|
|
68
|
+
print_formatted_text(HTML("<LightSlateGrey>Select a MAS instance to uninstall from the list below:</LightSlateGrey>"))
|
|
69
|
+
suites = listMasInstances(self.dynamicClient)
|
|
70
|
+
suiteOptions = []
|
|
71
|
+
for suite in suites:
|
|
72
|
+
print_formatted_text(HTML(f"- <u>{suite['metadata']['name']}</u> v{suite['status']['versions']['reconciled']}"))
|
|
73
|
+
suiteOptions.append(suite['metadata']['name'])
|
|
74
|
+
|
|
75
|
+
suiteCompleter = WordCompleter(suiteOptions)
|
|
76
|
+
print()
|
|
77
|
+
instanceId = prompt(HTML(f'<Yellow>Enter MAS instance ID: </Yellow>'), completer=suiteCompleter, validator=InstanceIDValidator(), validate_while_typing=False)
|
|
78
|
+
|
|
79
|
+
self.printH1("Uninstall MAS Dependencies")
|
|
80
|
+
uninstallCertManager = prompt(HTML(f'<Yellow>Uninstall Certificate Manager? </Yellow>'), validator=YesNoValidator()) in ["y", "yes"]
|
|
81
|
+
if uninstallCertManager:
|
|
82
|
+
# If you choose to uninstall Cert-Manager, everything will be uninstalled
|
|
83
|
+
uninstallGrafana = True
|
|
84
|
+
uninstallIBMCatalog = True
|
|
85
|
+
uninstallCommonServices = True
|
|
86
|
+
uninstallUDS = True
|
|
87
|
+
uninstallMongoDb = True
|
|
88
|
+
uninstallSLS = True
|
|
89
|
+
else:
|
|
90
|
+
uninstallMongoDb = prompt(HTML(f'<Yellow>Uninstall MongoDb? </Yellow>'), validator=YesNoValidator()) in ["y", "yes"]
|
|
91
|
+
if uninstallMongoDb:
|
|
92
|
+
# If you are removing MongoDb then SLS needs to be uninstalled too
|
|
93
|
+
uninstallSLS = True
|
|
94
|
+
else:
|
|
95
|
+
uninstallSLS = prompt(HTML(f'<Yellow>Uninstall IBM Suite Licensing Service? </Yellow>'), validator=YesNoValidator()) in ["y", "yes"]
|
|
96
|
+
|
|
97
|
+
uninstallGrafana = prompt(HTML(f'<Yellow>Uninstall Grafana? </Yellow>'), validator=YesNoValidator()) in ["y", "yes"]
|
|
98
|
+
uninstallIBMCatalog = prompt(HTML(f'<Yellow>Uninstall IBM Catalog Source? </Yellow>'), validator=YesNoValidator()) in ["y", "yes"]
|
|
99
|
+
if uninstallIBMCatalog:
|
|
100
|
+
# If you choose to uninstall IBM Operator Catalog, everything from the catalog will be uninstalled
|
|
101
|
+
uninstallCommonServices = True
|
|
102
|
+
uninstallUDS = True
|
|
103
|
+
uninstallMongoDb = True
|
|
104
|
+
uninstallSLS = True
|
|
105
|
+
else:
|
|
106
|
+
uninstallCommonServices = prompt(HTML(f'<Yellow>Uninstall IBM Common Services? </Yellow>'), validator=YesNoValidator()) in ["y", "yes"]
|
|
107
|
+
uninstallUDS = prompt(HTML(f'<Yellow>Uninstall IBM User Data Services? </Yellow>'), validator=YesNoValidator()) in ["y", "yes"]
|
|
108
|
+
|
|
109
|
+
else:
|
|
110
|
+
# Non-interactive mode
|
|
111
|
+
if not verifyMasInstance(self.dynamicClient, instanceId):
|
|
112
|
+
print_formatted_text(HTML(f"<Red>Error: MAS Instance {instanceId} not found on this cluster</Red>"))
|
|
113
|
+
sys.exit(1)
|
|
114
|
+
|
|
115
|
+
# Default to Red Hat Cert-Manager, and check if IBM cert-manager is installed
|
|
116
|
+
certManagerProvider="redhat"
|
|
117
|
+
namespaceAPI = self.dynamicClient.resources.get(api_version="v1", kind="Namespace")
|
|
118
|
+
try:
|
|
119
|
+
# Check if 'ibm-common-services' namespace exist, this will throw NotFoundError exception when not found.
|
|
120
|
+
namespaceAPI.get(name="ibm-common-services")
|
|
121
|
+
podsAPI = self.dynamicClient.resources.get(api_version="v1", kind="Pod")
|
|
122
|
+
podsList = podsAPI.get(namespace="ibm-common-services")
|
|
123
|
+
for pod in podsList:
|
|
124
|
+
if pod is not None and pod.metadata.name.contains("cert-manager-cainjector"):
|
|
125
|
+
certManagerProvider = "ibm"
|
|
126
|
+
except NotFoundError:
|
|
127
|
+
print()
|
|
128
|
+
# ibm cert manager not found, proceed with default redhat.
|
|
129
|
+
|
|
130
|
+
self.printH1("Review Settings")
|
|
131
|
+
print_formatted_text(HTML(f"<LightSlateGrey>Instance ID ..................... {instanceId}</LightSlateGrey>"))
|
|
132
|
+
print_formatted_text(HTML(f"<LightSlateGrey>Uninstall Cert-Manager .......... {uninstallCertManager} ({certManagerProvider})</LightSlateGrey>"))
|
|
133
|
+
print_formatted_text(HTML(f"<LightSlateGrey>Uninstall Grafana ............... {uninstallGrafana}</LightSlateGrey>"))
|
|
134
|
+
print_formatted_text(HTML(f"<LightSlateGrey>Uninstall IBM Operator Catalog .. {uninstallIBMCatalog}</LightSlateGrey>"))
|
|
135
|
+
print_formatted_text(HTML(f"<LightSlateGrey>Uninstall IBM Common Services ... {uninstallCommonServices}</LightSlateGrey>"))
|
|
136
|
+
print_formatted_text(HTML(f"<LightSlateGrey>Uninstall UDS ................... {uninstallUDS}</LightSlateGrey>"))
|
|
137
|
+
print_formatted_text(HTML(f"<LightSlateGrey>Uninstall MongoDb ............... {uninstallMongoDb}</LightSlateGrey>"))
|
|
138
|
+
print_formatted_text(HTML(f"<LightSlateGrey>Uninstall SLS ................... {uninstallSLS}</LightSlateGrey>"))
|
|
139
|
+
|
|
140
|
+
if not noConfirm:
|
|
141
|
+
print()
|
|
142
|
+
continueWithUninstall = prompt(HTML(f'<Yellow>Proceed with these settings?</Yellow> '), validator=YesNoValidator(), validate_while_typing=False)
|
|
143
|
+
|
|
144
|
+
if noConfirm or continueWithUninstall in ["y", "yes"]:
|
|
145
|
+
self.printH1("Launch uninstall")
|
|
146
|
+
pipelinesNamespace = f"mas-{instanceId}-pipelines"
|
|
147
|
+
|
|
148
|
+
with Halo(text='Validating OpenShift Pipelines installation', spinner=self.spinner) as h:
|
|
149
|
+
installOpenShiftPipelines(self.dynamicClient)
|
|
150
|
+
h.stop_and_persist(symbol=self.successIcon, text=f"OpenShift Pipelines Operator is installed and ready to use")
|
|
151
|
+
|
|
152
|
+
with Halo(text=f'Preparing namespace ({pipelinesNamespace})', spinner=self.spinner) as h:
|
|
153
|
+
createNamespace(self.dynamicClient, pipelinesNamespace)
|
|
154
|
+
h.stop_and_persist(symbol=self.successIcon, text=f"Namespace is ready ({pipelinesNamespace})")
|
|
155
|
+
|
|
156
|
+
with Halo(text=f'Installing latest Tekton definitions (v{self.version})', spinner=self.spinner) as h:
|
|
157
|
+
updateTektonDefinitions(pipelinesNamespace, self.tektonDefsPath)
|
|
158
|
+
h.stop_and_persist(symbol=self.successIcon, text=f"Latest Tekton definitions are installed (v{self.version})")
|
|
159
|
+
|
|
160
|
+
with Halo(text='Submitting PipelineRun for {instanceId} uninstall', spinner=self.spinner) as h:
|
|
161
|
+
pipelineURL = launchUninstallPipeline(
|
|
162
|
+
dynClient = self.dynamicClient,
|
|
163
|
+
instanceId = instanceId,
|
|
164
|
+
certManagerProvider = "redhat",
|
|
165
|
+
uninstallCertManager = uninstallCertManager,
|
|
166
|
+
uninstallGrafana = uninstallGrafana,
|
|
167
|
+
uninstallCatalog = uninstallCommonServices,
|
|
168
|
+
uninstallCommonServices = uninstallCommonServices,
|
|
169
|
+
uninstallUDS = uninstallUDS,
|
|
170
|
+
uninstallMongoDb = uninstallMongoDb,
|
|
171
|
+
uninstallSLS = uninstallSLS
|
|
172
|
+
)
|
|
173
|
+
if pipelineURL is not None:
|
|
174
|
+
h.stop_and_persist(symbol=self.successIcon, text=f"PipelineRun for {instanceId} uninstall submitted")
|
|
175
|
+
print_formatted_text(HTML(f"\nView progress:\n <Cyan><u>{pipelineURL}</u></Cyan>\n"))
|
|
176
|
+
else:
|
|
177
|
+
h.stop_and_persist(symbol=self.failureIcon, text=f"Failed to submit PipelineRun for {instanceId} uninstall, see log file for details")
|
|
178
|
+
print()
|
|
179
|
+
|
|
180
|
+
if __name__ == '__main__':
|
|
181
|
+
parser = argparse.ArgumentParser(
|
|
182
|
+
prog='mas uninstall',
|
|
183
|
+
description="\n".join([
|
|
184
|
+
f"IBM Maximo Application Suite Admin CLI v{packageVersion}",
|
|
185
|
+
"Uninstall MAS by configuring and launching the MAS Uninstall Tekton Pipeline.\n",
|
|
186
|
+
"Interactive Mode:",
|
|
187
|
+
"Omitting the --instance-id option will trigger an interactive prompt"
|
|
188
|
+
]),
|
|
189
|
+
epilog="Refer to the online documentation for more information: https://ibm-mas.github.io/cli/",
|
|
190
|
+
formatter_class=getHelpFormatter(),
|
|
191
|
+
add_help=False
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
masArgGroup = parser.add_argument_group('MAS Instance Selection')
|
|
195
|
+
masArgGroup.add_argument(
|
|
196
|
+
'--instance-id',
|
|
197
|
+
required=False,
|
|
198
|
+
help="The MAS instance ID to be uninstalled"
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
depsArgGroup = parser.add_argument_group('MAS Dependencies Selection')
|
|
202
|
+
depsArgGroup.add_argument(
|
|
203
|
+
'--uninstall-all-deps',
|
|
204
|
+
required=False,
|
|
205
|
+
action='store_true',
|
|
206
|
+
default=False,
|
|
207
|
+
help="Uninstall all MAS-related dependencies from the target cluster",
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
depsArgGroup.add_argument(
|
|
211
|
+
'--uninstall-cert-manager',
|
|
212
|
+
required=False,
|
|
213
|
+
action='store_true',
|
|
214
|
+
default=False,
|
|
215
|
+
help="Uninstall Certificate Manager from the target cluster",
|
|
216
|
+
)
|
|
217
|
+
depsArgGroup.add_argument(
|
|
218
|
+
'--uninstall-common-services',
|
|
219
|
+
required=False,
|
|
220
|
+
action='store_true',
|
|
221
|
+
default=False,
|
|
222
|
+
help="Uninstall IBM Common Services from the target cluster",
|
|
223
|
+
)
|
|
224
|
+
depsArgGroup.add_argument(
|
|
225
|
+
'--uninstall-grafana',
|
|
226
|
+
required=False,
|
|
227
|
+
action='store_true',
|
|
228
|
+
default=False,
|
|
229
|
+
help="Uninstall Grafana from the target cluster",
|
|
230
|
+
)
|
|
231
|
+
depsArgGroup.add_argument(
|
|
232
|
+
'--uninstall-ibm-catalog',
|
|
233
|
+
required=False,
|
|
234
|
+
action='store_true',
|
|
235
|
+
default=False,
|
|
236
|
+
help="Uninstall the IBM Maximo Operator Catalog Source (ibm-operator-catalog) from the target cluster",
|
|
237
|
+
)
|
|
238
|
+
depsArgGroup.add_argument(
|
|
239
|
+
'--uninstall-mongodb',
|
|
240
|
+
required=False,
|
|
241
|
+
action='store_true',
|
|
242
|
+
default=False,
|
|
243
|
+
help="Uninstall MongoDb from the target cluster",
|
|
244
|
+
)
|
|
245
|
+
depsArgGroup.add_argument(
|
|
246
|
+
'--uninstall-sls',
|
|
247
|
+
required=False,
|
|
248
|
+
action='store_true',
|
|
249
|
+
default=False,
|
|
250
|
+
help="Uninstall IBM Suite License Service from the target cluster",
|
|
251
|
+
)
|
|
252
|
+
depsArgGroup.add_argument(
|
|
253
|
+
'--uninstall-uds',
|
|
254
|
+
required=False,
|
|
255
|
+
action='store_true',
|
|
256
|
+
default=False,
|
|
257
|
+
help="Uninstall IBM User Data Services from the target cluster",
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
otherArgGroup = parser.add_argument_group('More')
|
|
261
|
+
otherArgGroup.add_argument(
|
|
262
|
+
'--no-confirm',
|
|
263
|
+
required=False,
|
|
264
|
+
action='store_true',
|
|
265
|
+
default=False,
|
|
266
|
+
help="Launch the upgrade without prompting for confirmation",
|
|
267
|
+
)
|
|
268
|
+
otherArgGroup.add_argument(
|
|
269
|
+
'-h', "--help",
|
|
270
|
+
action='help',
|
|
271
|
+
default=False,
|
|
272
|
+
help="Show this help message and exit",
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
args = parser.parse_args()
|
|
276
|
+
|
|
277
|
+
try:
|
|
278
|
+
app = App()
|
|
279
|
+
app.uninstall(args)
|
|
280
|
+
except KeyboardInterrupt as e:
|
|
281
|
+
pass
|
|
@@ -0,0 +1,156 @@
|
|
|
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 argparse
|
|
13
|
+
import sys
|
|
14
|
+
import logging
|
|
15
|
+
import logging.handlers
|
|
16
|
+
from prompt_toolkit import prompt, print_formatted_text, HTML
|
|
17
|
+
from prompt_toolkit.completion import WordCompleter
|
|
18
|
+
|
|
19
|
+
from halo import Halo
|
|
20
|
+
|
|
21
|
+
from mas.cli import __version__ as packageVersion
|
|
22
|
+
from mas.cli.cli import InstanceIDValidator, YesNoValidator, BaseApp, getHelpFormatter
|
|
23
|
+
from mas.devops.ocp import createNamespace
|
|
24
|
+
from mas.devops.mas import listMasInstances, verifyMasInstance
|
|
25
|
+
from mas.devops.tekton import installOpenShiftPipelines, updateTektonDefinitions, launchUpgradePipeline
|
|
26
|
+
|
|
27
|
+
logger = logging.getLogger(__name__)
|
|
28
|
+
|
|
29
|
+
class App(BaseApp):
|
|
30
|
+
def upgrade(self, instanceId, skipPreCheck, noConfirm):
|
|
31
|
+
"""
|
|
32
|
+
Upgrade MAS instance
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
if instanceId is None:
|
|
36
|
+
self.printH1("Set Target OpenShift Cluster")
|
|
37
|
+
# Connect to the target cluster
|
|
38
|
+
self.connect(noConfirm)
|
|
39
|
+
else:
|
|
40
|
+
logger.debug("MAS instance ID is set, so we assume already connected to the desired OCP")
|
|
41
|
+
|
|
42
|
+
if self.dynamicClient is None:
|
|
43
|
+
print_formatted_text(HTML("<Red>Error: The Kubernetes dynamic Client is not available. See log file for details</Red>"))
|
|
44
|
+
sys.exit(1)
|
|
45
|
+
|
|
46
|
+
if instanceId is None:
|
|
47
|
+
# Interactive mode
|
|
48
|
+
self.printH1("Instance Selection")
|
|
49
|
+
print_formatted_text(HTML("<LightSlateGrey>Select a MAS instance to upgrade from the list below:</LightSlateGrey>"))
|
|
50
|
+
suites = listMasInstances(self.dynamicClient)
|
|
51
|
+
suiteOptions = []
|
|
52
|
+
|
|
53
|
+
if len(suites) == 0:
|
|
54
|
+
print_formatted_text(HTML(f"<Red>Error: No MAS instances detected on this cluster</Red>"))
|
|
55
|
+
sys.exit(1)
|
|
56
|
+
|
|
57
|
+
for suite in suites:
|
|
58
|
+
print_formatted_text(HTML(f"- <u>{suite['metadata']['name']}</u> v{suite['status']['versions']['reconciled']}"))
|
|
59
|
+
suiteOptions.append(suite['metadata']['name'])
|
|
60
|
+
|
|
61
|
+
suiteCompleter = WordCompleter(suiteOptions)
|
|
62
|
+
print()
|
|
63
|
+
instanceId = prompt(HTML(f'<Yellow>Enter MAS instance ID: </Yellow>'), completer=suiteCompleter, validator=InstanceIDValidator(), validate_while_typing=False)
|
|
64
|
+
else:
|
|
65
|
+
# Non-interactive mode
|
|
66
|
+
if not verifyMasInstance(self.dynamicClient, instanceId):
|
|
67
|
+
print_formatted_text(HTML(f"<Red>Error: MAS instance {instanceId} not found on this cluster</Red>"))
|
|
68
|
+
sys.exit(1)
|
|
69
|
+
|
|
70
|
+
self.printH1("Review Settings")
|
|
71
|
+
print_formatted_text(HTML(f"<LightSlateGrey>Instance ID ..................... {instanceId}</LightSlateGrey>"))
|
|
72
|
+
print_formatted_text(HTML(f"<LightSlateGrey>Skip Pre-Upgrade Checks ......... {skipPreCheck}</LightSlateGrey>"))
|
|
73
|
+
|
|
74
|
+
if not noConfirm:
|
|
75
|
+
print()
|
|
76
|
+
continueWithUpgrade = prompt(HTML(f'<Yellow>Proceed with these settings?</Yellow> '), validator=YesNoValidator(), validate_while_typing=False)
|
|
77
|
+
|
|
78
|
+
if noConfirm or continueWithUpgrade in ["y", "yes"]:
|
|
79
|
+
self.printH1("Launch Upgrade")
|
|
80
|
+
pipelinesNamespace = f"mas-{instanceId}-pipelines"
|
|
81
|
+
|
|
82
|
+
with Halo(text='Validating OpenShift Pipelines installation', spinner=self.spinner) as h:
|
|
83
|
+
installOpenShiftPipelines(self.dynamicClient)
|
|
84
|
+
h.stop_and_persist(symbol=self.successIcon, text=f"OpenShift Pipelines Operator is installed and ready to use")
|
|
85
|
+
|
|
86
|
+
with Halo(text=f'Preparing namespace ({pipelinesNamespace})', spinner=self.spinner) as h:
|
|
87
|
+
createNamespace(self.dynamicClient, pipelinesNamespace)
|
|
88
|
+
h.stop_and_persist(symbol=self.successIcon, text=f"Namespace is ready ({pipelinesNamespace})")
|
|
89
|
+
|
|
90
|
+
with Halo(text=f'Installing latest Tekton definitions (v{self.version})', spinner=self.spinner) as h:
|
|
91
|
+
updateTektonDefinitions(pipelinesNamespace, self.tektonDefsPath)
|
|
92
|
+
h.stop_and_persist(symbol=self.successIcon, text=f"Latest Tekton definitions are installed (v{self.version})")
|
|
93
|
+
|
|
94
|
+
with Halo(text='Submitting PipelineRun for {instanceId} upgrade', spinner=self.spinner) as h:
|
|
95
|
+
pipelineURL = launchUpgradePipeline(self.dynamicClient, instanceId)
|
|
96
|
+
if pipelineURL is not None:
|
|
97
|
+
h.stop_and_persist(symbol=self.successIcon, text=f"PipelineRun for {instanceId} upgrade submitted")
|
|
98
|
+
print_formatted_text(HTML(f"\nView progress:\n <Cyan><u>{pipelineURL}</u></Cyan>\n"))
|
|
99
|
+
else:
|
|
100
|
+
h.stop_and_persist(symbol=self.failureIcon, text=f"Failed to submit PipelineRun for {instanceId} upgrade, see log file for details")
|
|
101
|
+
print()
|
|
102
|
+
|
|
103
|
+
if __name__ == '__main__':
|
|
104
|
+
parser = argparse.ArgumentParser(
|
|
105
|
+
prog='mas upgrade',
|
|
106
|
+
description="\n".join([
|
|
107
|
+
f"IBM Maximo Application Suite Admin CLI v{packageVersion}",
|
|
108
|
+
"Upgrade MAS by configuring and launching the MAS Upgrade Tekton Pipeline.\n",
|
|
109
|
+
"Interactive Mode:",
|
|
110
|
+
"Omitting the --instance-id option will trigger an interactive prompt"
|
|
111
|
+
]),
|
|
112
|
+
epilog="Refer to the online documentation for more information: https://ibm-mas.github.io/cli/",
|
|
113
|
+
formatter_class=getHelpFormatter(),
|
|
114
|
+
add_help=False
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
masArgGroup = parser.add_argument_group('MAS Instance Selection')
|
|
118
|
+
masArgGroup.add_argument(
|
|
119
|
+
'--instance-id',
|
|
120
|
+
required=False,
|
|
121
|
+
help="The MAS instance ID to be upgraded"
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
otherArgGroup = parser.add_argument_group('More')
|
|
125
|
+
otherArgGroup.add_argument(
|
|
126
|
+
'--skip-pre-check',
|
|
127
|
+
required=False,
|
|
128
|
+
action='store_true',
|
|
129
|
+
default=False,
|
|
130
|
+
help="Disable the 'pre-upgrade-check' and 'post-upgrade-verify' tasks in the upgrade pipeline"
|
|
131
|
+
)
|
|
132
|
+
otherArgGroup.add_argument(
|
|
133
|
+
'--no-confirm',
|
|
134
|
+
required=False,
|
|
135
|
+
action='store_true',
|
|
136
|
+
default=False,
|
|
137
|
+
help="Launch the upgrade without prompting for confirmation",
|
|
138
|
+
)
|
|
139
|
+
otherArgGroup.add_argument(
|
|
140
|
+
'-h', "--help",
|
|
141
|
+
action='help',
|
|
142
|
+
default=False,
|
|
143
|
+
help="Show this help message and exit",
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
args = parser.parse_args()
|
|
147
|
+
|
|
148
|
+
try:
|
|
149
|
+
app = App()
|
|
150
|
+
app.upgrade(
|
|
151
|
+
args.instance_id,
|
|
152
|
+
args.skip_pre_check,
|
|
153
|
+
args.no_confirm
|
|
154
|
+
)
|
|
155
|
+
except KeyboardInterrupt as e:
|
|
156
|
+
pass
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: mas-cli
|
|
3
|
+
Version: 9.5.0
|
|
4
|
+
Summary: Python Admin CLI for Maximo Application Suite
|
|
5
|
+
Home-page: https://github.com/ibm-mas/cli
|
|
6
|
+
Author: David Parker
|
|
7
|
+
Author-email: parkerda@uk.ibm.com
|
|
8
|
+
License: Eclipse Public License - v1.0
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
12
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
13
|
+
Classifier: Programming Language :: Python
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Topic :: Communications
|
|
18
|
+
Classifier: Topic :: Internet
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Requires-Dist: mas-devops
|
|
21
|
+
Requires-Dist: halo
|
|
22
|
+
Requires-Dist: prompt_toolkit
|
|
23
|
+
Requires-Dist: openshift
|
|
24
|
+
Requires-Dist: kubernetes
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: build; extra == "dev"
|
|
27
|
+
Requires-Dist: flake8; extra == "dev"
|
|
28
|
+
Requires-Dist: pytest; extra == "dev"
|
|
29
|
+
Requires-Dist: pyinstaller; extra == "dev"
|
|
30
|
+
|
|
31
|
+
mas.devops
|
|
32
|
+
----------
|
|
33
|
+
|
|
34
|
+
Example
|
|
35
|
+
=======
|
|
36
|
+
|
|
37
|
+
.. code:: python
|
|
38
|
+
|
|
39
|
+
from openshift import dynamic
|
|
40
|
+
from kubernetes import config
|
|
41
|
+
from kubernetes.client import api_client
|
|
42
|
+
|
|
43
|
+
from mas.devops.ocp import createNamespace
|
|
44
|
+
from mas.devops.tekton import installOpenShiftPipelines, updateTektonDefinitions, launchUpgradePipeline
|
|
45
|
+
|
|
46
|
+
instanceId = "mymas"
|
|
47
|
+
pipelinesNamespace = f"mas-{instanceId}-pipelines"
|
|
48
|
+
|
|
49
|
+
# Create an OpenShift client
|
|
50
|
+
dynClient = dynamic.DynamicClient(
|
|
51
|
+
api_client.ApiClient(configuration=config.load_kube_config())
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
# Install OpenShift Pipelines Operator
|
|
55
|
+
installOpenShiftPipelines(dynamicClient)
|
|
56
|
+
|
|
57
|
+
# Create the pipelines namespace and install the MAS tekton definitions
|
|
58
|
+
createNamespace(dynamicClient, pipelinesNamespace)
|
|
59
|
+
updateTektonDefinitions(pipelinesNamespace)
|
|
60
|
+
|
|
61
|
+
# Launch the upgrade pipeline and print the URL to view the pipeline run
|
|
62
|
+
pipelineURL = launchUpgradePipeline(self.dynamicClient, instanceId)
|
|
63
|
+
print(pipelineURL)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
MANIFEST.in
|
|
2
|
+
README.rst
|
|
3
|
+
pyproject.toml
|
|
4
|
+
setup.py
|
|
5
|
+
src/mas-uninstall
|
|
6
|
+
src/mas-upgrade
|
|
7
|
+
src/mas/cli/__init__.py
|
|
8
|
+
src/mas/cli/cli.py
|
|
9
|
+
src/mas_cli.egg-info/PKG-INFO
|
|
10
|
+
src/mas_cli.egg-info/SOURCES.txt
|
|
11
|
+
src/mas_cli.egg-info/dependency_links.txt
|
|
12
|
+
src/mas_cli.egg-info/requires.txt
|
|
13
|
+
src/mas_cli.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
mas
|