mas-cli 11.6.0__py3-none-any.whl → 11.7.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__ = "11.6.0" # Python module compatible semver
11
+ __version__ = "11.7.0" # Python module compatible semver
mas/cli/cli.py CHANGED
@@ -28,7 +28,7 @@ from openshift.dynamic.exceptions import NotFoundError
28
28
  from prompt_toolkit import prompt, print_formatted_text, HTML
29
29
 
30
30
  from mas.devops.mas import isAirgapInstall
31
- from mas.devops.ocp import connect, isSNO
31
+ from mas.devops.ocp import connect, isSNO, getNodes
32
32
 
33
33
  from .displayMixins import PrintMixin, PromptMixin
34
34
 
@@ -50,7 +50,7 @@ def getHelpFormatter(formatter=RawTextHelpFormatter, w=160, h=50):
50
50
  formatter(None, **kwargs)
51
51
  return lambda prog: formatter(prog, **kwargs)
52
52
  except TypeError:
53
- logger.warn("argparse help formatter failed, falling back.")
53
+ logger.warning("argparse help formatter failed, falling back.")
54
54
  return formatter
55
55
 
56
56
 
@@ -89,6 +89,15 @@ def runCmd(cmdArray, timeout=630):
89
89
  return RunCmdResult(127, 'TimeoutExpired', str(e))
90
90
 
91
91
 
92
+ def logMethodCall(func):
93
+ def wrapper(self, *args, **kwargs):
94
+ logger.debug(f">>> BaseApp.{func.__name__}")
95
+ result = func(self, *args, **kwargs)
96
+ logger.debug(f"<<< BaseApp.{func.__name__}")
97
+ return result
98
+ return wrapper
99
+
100
+
92
101
  class BaseApp(PrintMixin, PromptMixin):
93
102
  def __init__(self):
94
103
  # Set up a log formatter
@@ -105,9 +114,10 @@ class BaseApp(PrintMixin, PromptMixin):
105
114
  rootLogger = logging.getLogger()
106
115
  rootLogger.addHandler(ch)
107
116
  rootLogger.setLevel(logging.DEBUG)
117
+ logging.getLogger('asyncio').setLevel(logging.INFO)
108
118
 
109
119
  # Supports extended semver, unlike mas.cli.__version__
110
- self.version = "11.6.0"
120
+ self.version = "11.7.0"
111
121
  self.h1count = 0
112
122
  self.h2count = 0
113
123
 
@@ -129,6 +139,9 @@ class BaseApp(PrintMixin, PromptMixin):
129
139
 
130
140
  self._isSNO = None
131
141
 
142
+ # Until we connect to the cluster we don't know what architecture it's worker nodes are
143
+ self.architecture = None
144
+
132
145
  self.compatibilityMatrix = {
133
146
  "9.0.x": {
134
147
  "assist": ["9.0.x", "8.8.x"],
@@ -175,6 +188,7 @@ class BaseApp(PrintMixin, PromptMixin):
175
188
  if which("kubectl") is None:
176
189
  self.fatalError("Could not find kubectl on the path, see <DarkGoldenRod><u>https://kubernetes.io/docs/tasks/tools/#kubectl</u></DarkGoldenRod> for installation instructions")
177
190
 
191
+ @logMethodCall
178
192
  def createTektonFileWithDigest(self) -> None:
179
193
  if path.exists(self.tektonDefsWithDigestPath):
180
194
  logger.debug(f"We have already generated {self.tektonDefsWithDigestPath}")
@@ -217,12 +231,14 @@ class BaseApp(PrintMixin, PromptMixin):
217
231
 
218
232
  self.tektonDefsPath = self.tektonDefsWithDigestPath
219
233
 
234
+ @logMethodCall
220
235
  def getCompatibleVersions(self, coreChannel: str, appId: str) -> list:
221
236
  if coreChannel in self.compatibilityMatrix:
222
237
  return self.compatibilityMatrix[coreChannel][appId]
223
238
  else:
224
239
  return []
225
240
 
241
+ @logMethodCall
226
242
  def fatalError(self, message: str, exception: Exception = None) -> None:
227
243
  if exception is not None:
228
244
  logger.error(message)
@@ -233,6 +249,7 @@ class BaseApp(PrintMixin, PromptMixin):
233
249
  print_formatted_text(HTML(f"<Red>Fatal Error: {message.replace(' & ', ' &amp; ')}</Red>\n"))
234
250
  exit(1)
235
251
 
252
+ @logMethodCall
236
253
  def isSNO(self):
237
254
  if self._isSNO is None:
238
255
  self._isSNO = isSNO(self.dynamicClient)
@@ -257,6 +274,7 @@ class BaseApp(PrintMixin, PromptMixin):
257
274
  else:
258
275
  return self.reloadDynamicClient()
259
276
 
277
+ @logMethodCall
260
278
  def reloadDynamicClient(self):
261
279
  """
262
280
  Configure the Kubernetes API Client using the active context in kubeconfig
@@ -278,6 +296,7 @@ class BaseApp(PrintMixin, PromptMixin):
278
296
  logger.exception(e, stack_info=True)
279
297
  return None
280
298
 
299
+ @logMethodCall
281
300
  def connect(self):
282
301
  promptForNewServer = False
283
302
  self.reloadDynamicClient()
@@ -289,7 +308,7 @@ class BaseApp(PrintMixin, PromptMixin):
289
308
  print()
290
309
  if not self.noConfirm:
291
310
  # We are already connected to a cluster, but prompt the user if they want to use this connection
292
- promptForNewServer = not self.yesOrNo("Proceed with this cluster?")
311
+ promptForNewServer = not self.yesOrNo("Proceed with this cluster")
293
312
  except Exception as e:
294
313
  # We are already connected to a cluster, but the connection is not valid so prompt for connection details
295
314
  logger.debug("Failed looking up OpenShift Console route to verify connection")
@@ -310,6 +329,24 @@ class BaseApp(PrintMixin, PromptMixin):
310
329
  print_formatted_text(HTML("<Red>Unable to connect to cluster. See log file for details</Red>"))
311
330
  exit(1)
312
331
 
332
+ # Now that we are connected, inspect the architecture of the OpenShift cluster
333
+ self.lookupTargetArchitecture()
334
+
335
+ @logMethodCall
336
+ def lookupTargetArchitecture(self, architecture: str = None) -> None:
337
+ logger.debug("Looking up worker node architecture")
338
+ if architecture is not None:
339
+ self.architecture = architecture
340
+ logger.debug(f"Target architecture (overridden): {self.architecture}")
341
+ else:
342
+ nodes = getNodes(self.dynamicClient)
343
+ self.architecture = nodes[0]["status"]["nodeInfo"]["architecture"]
344
+ logger.debug(f"Target architecture: {self.architecture}")
345
+
346
+ if self.architecture not in ["amd64", "s390x"]:
347
+ self.fatalError(f"Unsupported worker node architecture: {self.architecture}")
348
+
349
+ @logMethodCall
313
350
  def initializeApprovalConfigMap(self, namespace: str, id: str, key: str = None, maxRetries: int = 100, delay: int = 300, ignoreFailure: bool = True) -> None:
314
351
  """
315
352
  Set key = None if you don't want approval workflow enabled
mas/cli/gencfg.py CHANGED
@@ -10,17 +10,11 @@
10
10
 
11
11
  from os import path
12
12
  from jinja2 import Template
13
+ from base64 import b64encode
13
14
 
14
15
 
15
16
  class ConfigGeneratorMixin():
16
- def generateJDBCCfg(
17
- self,
18
- instanceId: str,
19
- scope: str,
20
- destination: str,
21
- appId: str = "",
22
- workspaceId: str = "") -> None:
23
-
17
+ def generateJDBCCfg(self, instanceId: str, scope: str, destination: str, appId: str = "", workspaceId: str = "") -> None:
24
18
  templateFile = path.join(self.templatesDir, "jdbccfg.yml.j2")
25
19
  with open(templateFile) as tFile:
26
20
  template = Template(tFile.read())
@@ -64,3 +58,33 @@ class ConfigGeneratorMixin():
64
58
  with open(destination, 'w') as f:
65
59
  f.write(cfg)
66
60
  f.write('\n')
61
+
62
+ def generateMongoCfg(self, instanceId: str, destination: str) -> None:
63
+ templateFile = path.join(self.templatesDir, "suite_mongocfg.yml.j2")
64
+
65
+ with open(templateFile) as tFile:
66
+ template = Template(tFile.read())
67
+
68
+ name = self.promptForString("Configuration Display Name")
69
+ hosts = self.promptForString("MongoDb Hosts (comma-separated list)")
70
+
71
+ username = self.promptForString("MongoDb Username")
72
+ password = self.promptForString("MongoDb Password", isPassword=True)
73
+ encoded_username = b64encode(username.encode('ascii')).decode("ascii")
74
+ encoded_password = b64encode(password.encode('ascii')).decode("ascii")
75
+ sslCertFile = self.promptForFile("Path to certificate file")
76
+ with open(sslCertFile) as cFile:
77
+ certLocalFileContent = cFile.read()
78
+
79
+ cfg = template.render(
80
+ mas_instance_id=instanceId,
81
+ cfg_display_name=name,
82
+ mongodb_hosts=hosts,
83
+ mongodb_admin_username=encoded_username,
84
+ mongodb_admin_password=encoded_password,
85
+ mongodb_ca_pem_local_file=certLocalFileContent
86
+ )
87
+
88
+ with open(destination, 'w') as f:
89
+ f.write(cfg)
90
+ f.write('\n')