kaqing 2.0.171__py3-none-any.whl → 2.0.204__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.
Files changed (194) hide show
  1. adam/app_session.py +5 -10
  2. adam/apps.py +18 -4
  3. adam/batch.py +7 -7
  4. adam/checks/check_utils.py +3 -1
  5. adam/checks/disk.py +2 -3
  6. adam/columns/memory.py +3 -4
  7. adam/commands/__init__.py +15 -6
  8. adam/commands/alter_tables.py +26 -41
  9. adam/commands/app/__init__.py +0 -0
  10. adam/commands/{app_cmd.py → app/app.py} +2 -2
  11. adam/commands/{show → app}/show_app_actions.py +7 -15
  12. adam/commands/{show → app}/show_app_queues.py +1 -4
  13. adam/{utils_app.py → commands/app/utils_app.py} +9 -1
  14. adam/commands/audit/audit.py +9 -26
  15. adam/commands/audit/audit_repair_tables.py +5 -7
  16. adam/commands/audit/audit_run.py +1 -1
  17. adam/commands/audit/completions_l.py +15 -0
  18. adam/commands/audit/show_last10.py +2 -14
  19. adam/commands/audit/show_slow10.py +2 -13
  20. adam/commands/audit/show_top10.py +2 -11
  21. adam/commands/audit/utils_show_top10.py +15 -3
  22. adam/commands/bash/bash.py +1 -1
  23. adam/commands/bash/utils_bash.py +1 -1
  24. adam/commands/cassandra/__init__.py +0 -0
  25. adam/commands/cassandra/download_cassandra_log.py +45 -0
  26. adam/commands/cassandra/nodetool.py +64 -0
  27. adam/commands/cassandra/nodetool_commands.py +120 -0
  28. adam/commands/cassandra/restart_cluster.py +47 -0
  29. adam/commands/cassandra/restart_node.py +51 -0
  30. adam/commands/cassandra/restart_nodes.py +47 -0
  31. adam/commands/cassandra/rollout.py +88 -0
  32. adam/commands/cat.py +5 -19
  33. adam/commands/cd.py +7 -9
  34. adam/commands/check.py +10 -18
  35. adam/commands/cli_commands.py +6 -1
  36. adam/commands/{cp.py → clipboard_copy.py} +34 -36
  37. adam/commands/code.py +2 -2
  38. adam/commands/command.py +139 -22
  39. adam/commands/commands_utils.py +14 -12
  40. adam/commands/cql/alter_tables.py +66 -0
  41. adam/commands/cql/completions_c.py +29 -0
  42. adam/commands/cql/cqlsh.py +3 -7
  43. adam/commands/cql/utils_cql.py +23 -61
  44. adam/commands/debug/__init__.py +0 -0
  45. adam/commands/debug/debug.py +22 -0
  46. adam/commands/debug/debug_completes.py +35 -0
  47. adam/commands/debug/debug_timings.py +35 -0
  48. adam/commands/deploy/deploy_pg_agent.py +2 -2
  49. adam/commands/deploy/deploy_pod.py +2 -4
  50. adam/commands/deploy/undeploy_pg_agent.py +2 -2
  51. adam/commands/devices/device.py +40 -9
  52. adam/commands/devices/device_app.py +19 -29
  53. adam/commands/devices/device_auit_log.py +3 -3
  54. adam/commands/devices/device_cass.py +17 -23
  55. adam/commands/devices/device_export.py +12 -11
  56. adam/commands/devices/device_postgres.py +79 -63
  57. adam/commands/devices/devices.py +1 -1
  58. adam/commands/download_cassandra_log.py +45 -0
  59. adam/commands/download_file.py +47 -0
  60. adam/commands/export/clean_up_all_export_sessions.py +3 -3
  61. adam/commands/export/clean_up_export_sessions.py +7 -19
  62. adam/commands/export/completions_x.py +11 -0
  63. adam/commands/export/download_export_session.py +40 -0
  64. adam/commands/export/drop_export_database.py +6 -22
  65. adam/commands/export/drop_export_databases.py +3 -9
  66. adam/commands/export/export.py +1 -17
  67. adam/commands/export/export_databases.py +109 -32
  68. adam/commands/export/export_select.py +8 -55
  69. adam/commands/export/export_sessions.py +211 -0
  70. adam/commands/export/export_use.py +13 -16
  71. adam/commands/export/export_x_select.py +48 -0
  72. adam/commands/export/exporter.py +176 -167
  73. adam/commands/export/import_files.py +44 -0
  74. adam/commands/export/import_session.py +10 -6
  75. adam/commands/export/importer.py +24 -9
  76. adam/commands/export/importer_athena.py +114 -44
  77. adam/commands/export/importer_sqlite.py +45 -23
  78. adam/commands/export/show_column_counts.py +11 -20
  79. adam/commands/export/show_export_databases.py +5 -2
  80. adam/commands/export/show_export_session.py +6 -15
  81. adam/commands/export/show_export_sessions.py +4 -11
  82. adam/commands/export/utils_export.py +79 -27
  83. adam/commands/find_files.py +51 -0
  84. adam/commands/find_processes.py +76 -0
  85. adam/commands/generate_report.py +52 -0
  86. adam/commands/head.py +36 -0
  87. adam/commands/help.py +2 -2
  88. adam/commands/intermediate_command.py +6 -3
  89. adam/commands/login.py +3 -6
  90. adam/commands/ls.py +2 -2
  91. adam/commands/medusa/medusa_backup.py +13 -16
  92. adam/commands/medusa/medusa_restore.py +26 -37
  93. adam/commands/medusa/medusa_show_backupjobs.py +7 -7
  94. adam/commands/medusa/medusa_show_restorejobs.py +6 -6
  95. adam/commands/medusa/utils_medusa.py +15 -0
  96. adam/commands/nodetool.py +3 -8
  97. adam/commands/os/__init__.py +0 -0
  98. adam/commands/os/cat.py +36 -0
  99. adam/commands/os/download_file.py +47 -0
  100. adam/commands/os/find_files.py +51 -0
  101. adam/commands/os/find_processes.py +76 -0
  102. adam/commands/os/head.py +36 -0
  103. adam/commands/os/shell.py +41 -0
  104. adam/commands/param_get.py +10 -12
  105. adam/commands/param_set.py +7 -10
  106. adam/commands/postgres/completions_p.py +22 -0
  107. adam/commands/postgres/postgres.py +25 -40
  108. adam/commands/postgres/postgres_databases.py +269 -0
  109. adam/commands/postgres/utils_postgres.py +33 -20
  110. adam/commands/preview_table.py +4 -2
  111. adam/commands/pwd.py +4 -6
  112. adam/commands/reaper/reaper_forward.py +2 -2
  113. adam/commands/reaper/reaper_run_abort.py +4 -10
  114. adam/commands/reaper/reaper_runs.py +3 -3
  115. adam/commands/reaper/reaper_schedule_activate.py +12 -12
  116. adam/commands/reaper/reaper_schedule_start.py +7 -12
  117. adam/commands/reaper/reaper_schedule_stop.py +7 -12
  118. adam/commands/reaper/utils_reaper.py +13 -6
  119. adam/commands/repair/repair_log.py +1 -4
  120. adam/commands/repair/repair_run.py +3 -8
  121. adam/commands/repair/repair_scan.py +1 -6
  122. adam/commands/repair/repair_stop.py +1 -5
  123. adam/commands/restart_cluster.py +47 -0
  124. adam/commands/restart_node.py +51 -0
  125. adam/commands/restart_nodes.py +47 -0
  126. adam/commands/shell.py +9 -2
  127. adam/commands/show/show.py +4 -4
  128. adam/commands/show/show_adam.py +3 -3
  129. adam/commands/show/show_cassandra_repairs.py +5 -6
  130. adam/commands/show/show_cassandra_status.py +29 -29
  131. adam/commands/show/show_cassandra_version.py +1 -4
  132. adam/commands/show/{show_commands.py → show_cli_commands.py} +3 -6
  133. adam/commands/show/show_login.py +3 -9
  134. adam/commands/show/show_params.py +2 -5
  135. adam/commands/show/show_processes.py +15 -16
  136. adam/commands/show/show_storage.py +9 -8
  137. adam/config.py +4 -5
  138. adam/embedded_params.py +1 -1
  139. adam/log.py +4 -4
  140. adam/repl.py +26 -18
  141. adam/repl_commands.py +32 -20
  142. adam/repl_session.py +9 -1
  143. adam/repl_state.py +39 -10
  144. adam/sql/async_executor.py +44 -0
  145. adam/sql/lark_completer.py +286 -0
  146. adam/sql/lark_parser.py +604 -0
  147. adam/sql/qingl.lark +1076 -0
  148. adam/sql/sql_completer.py +4 -6
  149. adam/sql/sql_state_machine.py +25 -13
  150. adam/sso/authn_ad.py +2 -5
  151. adam/sso/authn_okta.py +2 -4
  152. adam/sso/cred_cache.py +2 -5
  153. adam/sso/idp.py +8 -11
  154. adam/utils.py +299 -105
  155. adam/utils_athena.py +18 -18
  156. adam/utils_audits.py +3 -7
  157. adam/utils_issues.py +2 -2
  158. adam/utils_k8s/app_clusters.py +4 -4
  159. adam/utils_k8s/app_pods.py +8 -6
  160. adam/utils_k8s/cassandra_clusters.py +16 -5
  161. adam/utils_k8s/cassandra_nodes.py +7 -6
  162. adam/utils_k8s/custom_resources.py +11 -17
  163. adam/utils_k8s/jobs.py +7 -11
  164. adam/utils_k8s/k8s.py +14 -5
  165. adam/utils_k8s/kube_context.py +3 -6
  166. adam/{pod_exec_result.py → utils_k8s/pod_exec_result.py} +4 -4
  167. adam/utils_k8s/pods.py +98 -36
  168. adam/utils_k8s/statefulsets.py +5 -2
  169. adam/utils_local.py +42 -0
  170. adam/utils_repl/appendable_completer.py +6 -0
  171. adam/utils_repl/repl_completer.py +45 -2
  172. adam/utils_repl/state_machine.py +3 -3
  173. adam/utils_sqlite.py +58 -30
  174. adam/version.py +1 -1
  175. {kaqing-2.0.171.dist-info → kaqing-2.0.204.dist-info}/METADATA +1 -1
  176. kaqing-2.0.204.dist-info/RECORD +277 -0
  177. kaqing-2.0.204.dist-info/top_level.txt +2 -0
  178. teddy/__init__.py +0 -0
  179. teddy/lark_parser.py +436 -0
  180. teddy/lark_parser2.py +618 -0
  181. adam/commands/cql/cql_completions.py +0 -33
  182. adam/commands/export/export_handlers.py +0 -71
  183. adam/commands/export/export_select_x.py +0 -54
  184. adam/commands/logs.py +0 -37
  185. adam/commands/postgres/postgres_context.py +0 -274
  186. adam/commands/postgres/psql_completions.py +0 -10
  187. adam/commands/report.py +0 -61
  188. adam/commands/restart.py +0 -60
  189. kaqing-2.0.171.dist-info/RECORD +0 -236
  190. kaqing-2.0.171.dist-info/top_level.txt +0 -1
  191. /adam/commands/{app_ping.py → app/app_ping.py} +0 -0
  192. /adam/commands/{show → app}/show_app_id.py +0 -0
  193. {kaqing-2.0.171.dist-info → kaqing-2.0.204.dist-info}/WHEEL +0 -0
  194. {kaqing-2.0.171.dist-info → kaqing-2.0.204.dist-info}/entry_points.txt +0 -0
adam/utils_athena.py CHANGED
@@ -1,10 +1,11 @@
1
+ from collections.abc import Callable
1
2
  import functools
2
3
  import time
3
4
  import boto3
4
5
  import botocore
5
6
 
6
7
  from adam.config import Config
7
- from adam.utils import lines_to_tabular, log, log2, wait_log
8
+ from adam.utils import tabulize, log, log2, log_exc, wait_log
8
9
 
9
10
  # no state utility class
10
11
  class Athena:
@@ -17,7 +18,7 @@ class Athena:
17
18
  if like:
18
19
  query = f"{query} AND schema_name like '{like}'"
19
20
 
20
- try:
21
+ with log_exc():
21
22
  state, reason, rs = Athena.query(query)
22
23
  if rs:
23
24
  names = []
@@ -26,8 +27,6 @@ class Athena:
26
27
  names.append(row_data[0])
27
28
 
28
29
  return names
29
- except:
30
- pass
31
30
 
32
31
  return []
33
32
 
@@ -64,7 +63,7 @@ class Athena:
64
63
 
65
64
  @functools.lru_cache()
66
65
  def column_names(tables: list[str] = [], database: str = None, function: str = 'audit', partition_cols_only = False):
67
- try:
66
+ with log_exc():
68
67
  if not database:
69
68
  database = Config().get(f'{function}.athena.database', 'audit')
70
69
 
@@ -80,32 +79,33 @@ class Athena:
80
79
  _, _, rs = Athena.query(query)
81
80
  if rs:
82
81
  return [row['Data'][0].get('VarCharValue') for row in rs[1:]]
83
- except:
84
- # aws credentials not found
85
- pass
86
82
 
87
83
  return []
88
84
 
89
- def run_query(sql: str, database: str = None):
85
+ def run_query(sql: str, database: str = None, output: Callable[[str], str] = None):
90
86
  state, reason, rs = Athena.query(sql, database)
91
87
 
88
+ log_file = None
92
89
  if state == 'SUCCEEDED':
93
90
  if rs:
94
91
  column_info = rs[0]['Data']
95
92
  columns = [col.get('VarCharValue') for col in column_info]
96
- lines = []
97
- for row in rs[1:]:
98
- row_data = [col.get('VarCharValue') if col else '' for col in row['Data']]
99
- lines.append('\t'.join(row_data))
100
-
101
- log(lines_to_tabular(lines, header='\t'.join(columns), separator='\t'))
102
-
103
- return len(lines)
93
+ out = tabulize(rs[1:],
94
+ lambda r: '\t'.join(col.get('VarCharValue') if col else '' for col in r['Data']),
95
+ header='\t'.join(columns),
96
+ separator='\t',
97
+ to=0)
98
+ if output:
99
+ log_file = output(out)
100
+ else:
101
+ log(out)
102
+
103
+ return len(rs)-1, log_file
104
104
  else:
105
105
  log2(f"Query failed or was cancelled. State: {state}")
106
106
  log2(f"Reason: {reason}")
107
107
 
108
- return 0
108
+ return 0, log_file
109
109
 
110
110
  def query(sql: str, database: str = None, function: str = 'audit') -> tuple[str, str, list]:
111
111
  region_name = Config().get(f'{function}.athena.region', 'us-west-2')
adam/utils_audits.py CHANGED
@@ -4,7 +4,7 @@ import time
4
4
  import requests
5
5
 
6
6
  from adam.config import Config
7
- from adam.utils import OffloadHandler, debug, log2, offload
7
+ from adam.utils import OffloadHandler, debug, log2, log_exc, offload
8
8
  from adam.utils_athena import Athena
9
9
  from adam.utils_net import get_my_host
10
10
 
@@ -46,12 +46,10 @@ class Audits:
46
46
  state, _, rs = Athena.query(f'select partitions_last_checked, clusters_last_checked from meta')
47
47
  if state == 'SUCCEEDED':
48
48
  if len(rs) > 1:
49
- try:
49
+ with log_exc():
50
50
  row = rs[1]['Data']
51
51
  checked_in = float(row[0]['VarCharValue'])
52
52
  cluster_last_checked = float(row[1]['VarCharValue'])
53
- except:
54
- pass
55
53
 
56
54
  return AuditMeta(checked_in, cluster_last_checked)
57
55
 
@@ -88,10 +86,8 @@ class Audits:
88
86
  state, _, rs = Athena.query(query)
89
87
  if state == 'SUCCEEDED':
90
88
  if len(rs) > 1:
91
- try:
89
+ with log_exc():
92
90
  return [r['Data'][0]['VarCharValue'] for r in rs[1:]]
93
- except:
94
- pass
95
91
 
96
92
  return []
97
93
 
adam/utils_issues.py CHANGED
@@ -1,7 +1,7 @@
1
1
  from adam.checks.check_result import CheckResult
2
2
  from adam.checks.issue import Issue
3
3
  from adam.repl_session import ReplSession
4
- from adam.utils import lines_to_tabular, log, log2
4
+ from adam.utils import tabulize, log2
5
5
 
6
6
  class IssuesUtils:
7
7
  def show(check_results: list[CheckResult], in_repl = False):
@@ -26,7 +26,7 @@ class IssuesUtils:
26
26
  if in_repl:
27
27
  ReplSession().prompt_session.history.append_string(issue.suggestion)
28
28
  suggested += 1
29
- log(lines_to_tabular(lines, separator='||'))
29
+ tabulize(lines, separator='||', to=2)
30
30
  if suggested:
31
31
  log2()
32
32
  log2(f'* {suggested} suggested commands are added to history. Press <Up> arrow to access them.')
@@ -2,7 +2,7 @@ import sys
2
2
  from typing import TypeVar
3
3
 
4
4
  from adam.utils_k8s.app_pods import AppPods
5
- from adam.pod_exec_result import PodExecResult
5
+ from adam.utils_k8s.pod_exec_result import PodExecResult
6
6
  from adam.utils import log, log2
7
7
  from adam.utils_k8s.pods import Pods
8
8
  from .kube_context import KubeContext
@@ -12,17 +12,17 @@ T = TypeVar('T')
12
12
  # utility collection on app clusters; methods are all static
13
13
  class AppClusters:
14
14
  def exec(pods: list[str], namespace: str, command: str, action: str = 'action',
15
- max_workers=0, show_out=True, on_any = False, shell = '/bin/sh', background = False) -> list[PodExecResult]:
15
+ max_workers=0, show_out=True, on_any = False, shell = '/bin/sh', backgrounded = False) -> list[PodExecResult]:
16
16
  samples = 1 if on_any else sys.maxsize
17
17
  msg = 'd`Running|Ran ' + action + ' command onto {size} pods'
18
18
  with Pods.parallelize(pods, max_workers, samples, msg, action=action) as exec:
19
- results: list[PodExecResult] = exec.map(lambda pod: AppPods.exec(pod, namespace, command, False, False, shell, background))
19
+ results: list[PodExecResult] = exec.map(lambda pod: AppPods.exec(pod, namespace, command, False, False, shell, backgrounded))
20
20
  for result in results:
21
21
  if KubeContext.show_out(show_out):
22
22
  log(result.command)
23
23
  if result.stdout:
24
24
  log(result.stdout)
25
25
  if result.stderr:
26
- log2(result.stderr, file=sys.stderr)
26
+ log2(result.stderr)
27
27
 
28
28
  return results
@@ -4,13 +4,16 @@ from kubernetes import client
4
4
 
5
5
  from adam.config import Config
6
6
  from adam.utils_k8s.pods import Pods
7
- from adam.pod_exec_result import PodExecResult
7
+ from adam.utils_k8s.pod_exec_result import PodExecResult
8
8
  from adam.repl_session import ReplSession
9
9
 
10
10
  # utility collection on app pods; methods are all static
11
11
  class AppPods:
12
12
  @functools.lru_cache()
13
13
  def pod_names(namespace: str, env: str, app: str):
14
+ if not env or not app:
15
+ return []
16
+
14
17
  return [pod.metadata.name for pod in AppPods.app_pods(namespace, env, app)]
15
18
 
16
19
  def app_pods(namespace: str, env: str, app: str) -> List[client.V1Pod]:
@@ -22,12 +25,11 @@ class AppPods:
22
25
 
23
26
  return v1.list_namespaced_pod(namespace, label_selector=label_selector).items
24
27
 
25
- def exec(pod_name: str, namespace: str, command: str, show_out = True, throw_err = False, shell = '/bin/sh', background = False) -> PodExecResult:
28
+ def exec(pod_name: str, namespace: str, command: str, show_out = True, throw_err = False, shell = '/bin/sh', backgrounded = False) -> PodExecResult:
26
29
  container = Config().get('app.container-name', 'c3-server')
27
- r = Pods.exec(pod_name, container, namespace, command, show_out = show_out, throw_err = throw_err, shell = shell, background = background)
30
+ r = Pods.exec(pod_name, container, namespace, command, show_out = show_out, throw_err = throw_err, shell = shell, backgrounded = backgrounded)
28
31
 
29
- if r and Config().get('repl.history.push-cat-remote-log-file', True):
30
- if r.log_file and ReplSession().prompt_session:
31
- ReplSession().prompt_session.history.append_string(f'@{r.pod} cat {r.log_file}')
32
+ if r and r.log_file:
33
+ ReplSession().append_history(f'@{r.pod} cat {r.log_file}')
32
34
 
33
35
  return r
@@ -3,7 +3,7 @@ from typing import TypeVar
3
3
 
4
4
  from adam.config import Config
5
5
  from adam.utils_k8s.cassandra_nodes import CassandraNodes
6
- from adam.pod_exec_result import PodExecResult
6
+ from adam.utils_k8s.pod_exec_result import PodExecResult
7
7
  from adam.utils import log, log2
8
8
  from adam.utils_k8s.pods import Pods
9
9
  from adam.utils_k8s.statefulsets import StatefulSets
@@ -12,21 +12,32 @@ T = TypeVar('T')
12
12
 
13
13
  # utility collection on cassandra clusters; methods are all static
14
14
  class CassandraClusters:
15
- def exec(sts: str, namespace: str, command: str, action: str = 'action',
16
- max_workers=0, show_out=True, on_any = False, shell = '/bin/sh', background = False, log_file = None) -> list[PodExecResult]:
15
+ def exec(sts: str,
16
+ namespace: str,
17
+ command: str,
18
+ action: str = 'action',
19
+ max_workers=0,
20
+ show_out=True,
21
+ on_any = False,
22
+ shell = '/bin/sh',
23
+ backgrounded = False,
24
+ log_file = None) -> list[PodExecResult]:
17
25
 
18
26
  pods = StatefulSets.pod_names(sts, namespace)
19
27
  samples = 1 if on_any else sys.maxsize
28
+ if (backgrounded or command.endswith(' &')) and not log_file:
29
+ log_file = Pods.log_file(command)
30
+
20
31
  msg = 'd`Running|Ran ' + action + ' command onto {size} pods'
21
32
  with Pods.parallelize(pods, max_workers, samples, msg, action=action) as exec:
22
- results: list[PodExecResult] = exec.map(lambda pod: CassandraNodes.exec(pod, namespace, command, False, False, shell, background, log_file))
33
+ results: list[PodExecResult] = exec.map(lambda pod: CassandraNodes.exec(pod, namespace, command, False, False, shell, backgrounded, log_file))
23
34
  for result in results:
24
35
  if show_out and not Config().is_debug():
25
36
  log(result.command)
26
37
  if result.stdout:
27
38
  log(result.stdout)
28
39
  if result.stderr:
29
- log2(result.stderr, file=sys.stderr)
40
+ log2(result.stderr)
30
41
 
31
42
  return results
32
43
 
@@ -1,17 +1,18 @@
1
1
  from adam.config import Config
2
2
  from adam.utils_k8s.pods import Pods
3
3
  from adam.utils_k8s.secrets import Secrets
4
- from adam.pod_exec_result import PodExecResult
4
+ from adam.utils_k8s.pod_exec_result import PodExecResult
5
5
  from adam.repl_session import ReplSession
6
6
 
7
7
  # utility collection on cassandra nodes; methods are all static
8
8
  class CassandraNodes:
9
- def exec(pod_name: str, namespace: str, command: str, show_out = True, throw_err = False, shell = '/bin/sh', background = False, log_file = None) -> PodExecResult:
10
- r = Pods.exec(pod_name, "cassandra", namespace, command, show_out = show_out, throw_err = throw_err, shell = shell, background = background, log_file=log_file)
9
+ def exec(pod_name: str, namespace: str, command: str, show_out = True, throw_err = False, shell = '/bin/sh', backgrounded = False, log_file = None, no_history = False) -> PodExecResult:
10
+ r = Pods.exec(pod_name, "cassandra", namespace, command, show_out = show_out, throw_err = throw_err, shell = shell, backgrounded = backgrounded, log_file=log_file)
11
11
 
12
- if r and Config().get('repl.history.push-cat-remote-log-file', True):
13
- if r.log_file and ReplSession().prompt_session:
14
- ReplSession().prompt_session.history.append_string(f'@{r.pod} cat {r.log_file}')
12
+ if not no_history and r and r.log_file:
13
+ entry = f':sh cat {r.log_file}'
14
+
15
+ ReplSession().append_history(entry)
15
16
 
16
17
  return r
17
18
 
@@ -1,11 +1,10 @@
1
1
  import functools
2
2
  import re
3
- import time
4
3
  from kubernetes import client
5
4
 
6
5
  from adam.config import Config
7
6
  from .kube_context import KubeContext
8
- from adam.utils import elapsed_time, lines_to_tabular, log2
7
+ from adam.utils import log2, log_exc
9
8
 
10
9
 
11
10
  # utility collection; methods are all static
@@ -20,14 +19,12 @@ class CustomResources:
20
19
  strip = Config().get('app.strip', '0')
21
20
 
22
21
  v1 = client.CustomObjectsApi()
23
- try:
22
+ with log_exc():
24
23
  c3cassandras = v1.list_cluster_custom_object(group=group, version=v, plural=plural)
25
24
  for c in c3cassandras.items():
26
25
  if c[0] == 'items':
27
26
  for item in c[1]:
28
27
  app_ids_by_ss[f"{item['metadata']['name']}@{item['metadata']['namespace']}"] = item['metadata']['labels'][label].strip(strip)
29
- except Exception:
30
- pass
31
28
 
32
29
  return app_ids_by_ss
33
30
 
@@ -122,11 +119,10 @@ class CustomResources:
122
119
  body = bkspecs
123
120
  pretty = 'true'
124
121
 
125
- try:
122
+ with log_exc(lambda e: "Exception when calling create_medusa_backupjob.create_namespaced_custom_object: %s\n" % e):
126
123
  api_instance.create_namespaced_custom_object(group, version, namespace, plural, body, pretty=pretty)
127
124
  log2(f"create_medusa_backupjob: created Full Backup {bkname}: {api_instance}")
128
- except Exception as e:
129
- log2("Exception when calling create_medusa_backupjob.create_namespaced_custom_object: %s\n" % e)
125
+
130
126
  return None
131
127
 
132
128
  def create_medusa_restorejob(restorejobname: str, bkname: str, dc: str, ns: str):
@@ -155,11 +151,10 @@ class CustomResources:
155
151
  body = rtspecs
156
152
  pretty = 'true'
157
153
 
158
- try:
154
+ with log_exc(lambda e: "Exception when calling create_medusa_restorejob.create_namespaced_custom_object: %s\n" % e):
159
155
  api_instance.create_namespaced_custom_object(group, version, namespace, plural, body, pretty=pretty)
160
156
  log2(f"create_medusa_restorejob: created Restore Job {restorejobname}: {api_instance}")
161
- except Exception as e:
162
- log2("Exception when calling create_medusa_restorejob.create_namespaced_custom_object: %s\n" % e)
157
+
163
158
  return None
164
159
 
165
160
  def medusa_show_backup_names(dc: str, ns: str) -> list[dict]:
@@ -185,11 +180,10 @@ class CustomResources:
185
180
  pretty = 'true'
186
181
  label_selector = 'cassandra.datastax.com/datacenter=' + dc
187
182
 
188
- try:
183
+ with log_exc(lambda e: "Exception when calling medusa_show_backupjobs.list_namespaced_custom_object: %s\n" % e):
189
184
  api_response = api_instance.list_namespaced_custom_object(group, version, namespace, plural, pretty=pretty, label_selector=label_selector)
190
185
  return api_response['items']
191
- except Exception as e:
192
- log2("Exception when calling medusa_show_backupjobs.list_namespaced_custom_object: %s\n" % e)
186
+
193
187
  return None
194
188
 
195
189
  def medusa_show_restorejobs(dc: str, ns: str):
@@ -201,11 +195,11 @@ class CustomResources:
201
195
  pretty = 'true'
202
196
  label_selector = 'cassandra.datastax.com/datacenter=' + dc
203
197
  rtlist = []
204
- try:
198
+
199
+ with log_exc(lambda e: "Exception when calling medusa_show_restorejobs.list_namespaced_custom_object: %s\n" % e):
205
200
  api_response = api_instance.list_namespaced_custom_object(group, version, namespace, plural, pretty=pretty, label_selector=label_selector)
206
201
  for x in api_response['items']:
207
202
  rtlist.append(f"{x['metadata']['name']}\t{x['metadata']['creationTimestamp']}\t{x['status'].get('finishTime', '')}")
208
203
  return rtlist
209
- except Exception as e:
210
- log2("Exception when calling medusa_show_restorejobs.list_namespaced_custom_object: %s\n" % e)
204
+
211
205
  return None
adam/utils_k8s/jobs.py CHANGED
@@ -1,7 +1,7 @@
1
1
  from kubernetes import client
2
2
  from time import sleep
3
3
  from .pods import Pods
4
- from adam.utils import log2
4
+ from adam.utils import log2, log_exc
5
5
 
6
6
  # utility collection on jobs; methods are all static
7
7
  class Jobs:
@@ -20,11 +20,10 @@ class Jobs:
20
20
  metadata=client.V1ObjectMeta(name=job_name),
21
21
  spec=spec)
22
22
 
23
- try:
23
+ with log_exc(lambda e: "Exception when calling BatchV1Apii->create_namespaced_job: %s\n" % e):
24
24
  client.BatchV1Api().create_namespaced_job(body=job, namespace=namespace)
25
25
  log2(f"Job {job_name} created in {namespace}")
26
- except Exception as e:
27
- log2("Exception when calling BatchV1Apii->create_namespaced_job: %s\n" % e)
26
+
28
27
  return
29
28
 
30
29
  def get_job_pods(job_name: str, namespace: str):
@@ -32,7 +31,7 @@ class Jobs:
32
31
  return pods
33
32
 
34
33
  def delete(job_name: str, namespace: str, wait=True):
35
- try:
34
+ with log_exc(lambda e: "Exception when calling BatchV1Apii->delete_namespaced_job: %s\n" % e):
36
35
  client.BatchV1Api().delete_namespaced_job(name=job_name, namespace=namespace, propagation_policy='Background')
37
36
  if wait:
38
37
  while True:
@@ -41,14 +40,11 @@ class Jobs:
41
40
  return
42
41
  sleep(5)
43
42
  log2(f"Job {job_name} in {namespace} deleted.")
44
- except Exception as e:
45
- log2("Exception when calling BatchV1Apii->delete_namespaced_job: %s\n" % e)
43
+
46
44
  return
47
45
 
48
46
  def get_logs(job_name: str, namespace: str):
49
47
  v1 = client.CoreV1Api()
50
- try:
48
+ with log_exc(lambda e: "Exception when calling CorV1Apii->list_namespaced_pod, cannot find job pod: %s\n" % e):
51
49
  pod_name = Jobs.get_job_pods(job_name, namespace).items[0].metadata.name
52
- log2(v1.read_namespaced_pod_log(name=pod_name, namespace=namespace))
53
- except Exception as e:
54
- log2("Exception when calling CorV1Apii->list_namespaced_pod, cannot find job pod: %s\n" % e)
50
+ log2(v1.read_namespaced_pod_log(name=pod_name, namespace=namespace))
adam/utils_k8s/k8s.py CHANGED
@@ -1,8 +1,9 @@
1
1
  from collections.abc import Callable
2
+ import inspect
2
3
  import re
3
4
  import portforward
4
5
 
5
- from adam.commands.command import InvalidState
6
+ from adam.commands.command import InvalidStateException
6
7
  from adam.repl_state import ReplState
7
8
  from adam.utils import log2
8
9
  from adam.utils_k8s.kube_context import KubeContext
@@ -24,14 +25,14 @@ class PortForwardHandler:
24
25
  if not self.svc_or_pod:
25
26
  log2('No service or pod found.')
26
27
 
27
- raise InvalidState(state)
28
+ raise InvalidStateException(state)
28
29
 
29
30
  if KubeContext.in_cluster():
30
31
  svc_name = self.svc_or_pod(True)
31
32
  if not svc_name:
32
33
  log2('No service found.')
33
34
 
34
- raise InvalidState(state)
35
+ raise InvalidStateException(state)
35
36
 
36
37
  # cs-a526330d23-cs-a526330d23-default-sts-0 ->
37
38
  # curl http://cs-a526330d23-cs-a526330d23-reaper-service.stgawsscpsr.svc.cluster.local:8080
@@ -40,15 +41,23 @@ class PortForwardHandler:
40
41
  svc = f'{groups[1]}{svc_name}.{state.namespace}.svc.cluster.local:{self.target_port}'
41
42
  return (svc, svc)
42
43
  else:
43
- raise InvalidState(state)
44
+ raise InvalidStateException(state)
44
45
  else:
45
46
  pod = self.svc_or_pod(False)
46
47
  if not pod:
47
48
  log2('No pod found.')
48
49
 
49
- raise InvalidState(state)
50
+ raise InvalidStateException(state)
50
51
 
51
52
  self.pod = pod
53
+
54
+ # pf = portforward.forward(state.namespace, pod, self.local_port + 1, self.target_port, log_level=portforward.LogLevel.DEBUG)
55
+ # print(inspect.getsource(pf.__enter__))
56
+ # print('test portforward START', state.namespace, pod, self.local_port + 1, self.target_port, pf.__enter__)
57
+ # with pf:
58
+ # print('test portforward BODY')
59
+ # print('test portforward OK')
60
+
52
61
  self.forward_connection = portforward.forward(state.namespace, pod, self.local_port, self.target_port)
53
62
  if self.inc_connection_cnt() == 1:
54
63
  self.forward_connection.__enter__()
@@ -3,7 +3,7 @@ import re
3
3
  from kubernetes import config as kconfig
4
4
 
5
5
  from adam.config import Config
6
- from adam.utils import idp_token_from_env, lines_to_tabular, log2
6
+ from adam.utils import idp_token_from_env, log2, tabulize
7
7
 
8
8
  class KubeContext:
9
9
  _in_cluster = False
@@ -56,7 +56,7 @@ class KubeContext:
56
56
  log2('Use -v <key>=<value> format.')
57
57
  log2()
58
58
  lines = [f'{key}\t{Config().get(key, None)}' for key in Config().keys()]
59
- log2(lines_to_tabular(lines, separator='\t'))
59
+ tabulize(lines, separator='\t', to=2)
60
60
 
61
61
  for p in param_ovrs:
62
62
  tokens = p.split('=')
@@ -102,7 +102,4 @@ class KubeContext:
102
102
  return name if re.match(r"^(?!pg-).*-k8spg-.*$", name) else None
103
103
 
104
104
  def show_out(s: bool):
105
- return s or Config().is_debug()
106
-
107
- def show_parallelism():
108
- return Config().get('debugs.show-parallelism', False)
105
+ return s or Config().is_debug()
@@ -1,6 +1,8 @@
1
1
  import yaml
2
2
 
3
- class PodExecResult:
3
+ from adam.utils import ExecResult, log_exc
4
+
5
+ class PodExecResult(ExecResult):
4
6
  # {
5
7
  # 'metadata': {},
6
8
  # 'status': 'Failure',
@@ -27,10 +29,8 @@ class PodExecResult:
27
29
  def exit_code(self) -> int:
28
30
  code = 0
29
31
 
30
- try:
32
+ with log_exc(False):
31
33
  code = self.error['details']['causes'][0]['message']
32
- except:
33
- pass
34
34
 
35
35
  return code
36
36