kaqing 2.0.145__py3-none-any.whl → 2.0.174__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 kaqing might be problematic. Click here for more details.

Files changed (174) hide show
  1. adam/__init__.py +0 -2
  2. adam/app_session.py +8 -11
  3. adam/batch.py +3 -3
  4. adam/checks/check_utils.py +14 -46
  5. adam/checks/cpu.py +7 -1
  6. adam/checks/cpu_metrics.py +52 -0
  7. adam/checks/disk.py +2 -3
  8. adam/columns/columns.py +3 -1
  9. adam/columns/cpu.py +3 -1
  10. adam/columns/cpu_metrics.py +22 -0
  11. adam/columns/memory.py +3 -4
  12. adam/commands/__init__.py +22 -0
  13. adam/commands/alter_tables.py +33 -48
  14. adam/commands/audit/audit.py +22 -23
  15. adam/commands/audit/audit_repair_tables.py +14 -17
  16. adam/commands/audit/audit_run.py +15 -23
  17. adam/commands/audit/show_last10.py +10 -13
  18. adam/commands/audit/show_slow10.py +10 -13
  19. adam/commands/audit/show_top10.py +10 -13
  20. adam/commands/audit/utils_show_top10.py +2 -3
  21. adam/commands/bash/__init__.py +5 -0
  22. adam/commands/bash/bash.py +7 -104
  23. adam/commands/bash/utils_bash.py +16 -0
  24. adam/commands/cat.py +7 -23
  25. adam/commands/cd.py +7 -11
  26. adam/commands/check.py +14 -23
  27. adam/commands/cli_commands.py +2 -3
  28. adam/commands/code.py +20 -23
  29. adam/commands/command.py +152 -37
  30. adam/commands/commands_utils.py +8 -17
  31. adam/commands/cp.py +18 -32
  32. adam/commands/cql/cql_completions.py +11 -7
  33. adam/commands/cql/cqlsh.py +10 -30
  34. adam/commands/cql/{cql_utils.py → utils_cql.py} +147 -15
  35. adam/commands/deploy/code_start.py +7 -10
  36. adam/commands/deploy/code_stop.py +4 -21
  37. adam/commands/deploy/code_utils.py +3 -3
  38. adam/commands/deploy/deploy.py +4 -27
  39. adam/commands/deploy/deploy_frontend.py +14 -17
  40. adam/commands/deploy/deploy_pg_agent.py +2 -5
  41. adam/commands/deploy/deploy_pod.py +64 -68
  42. adam/commands/deploy/undeploy.py +4 -27
  43. adam/commands/deploy/undeploy_frontend.py +4 -7
  44. adam/commands/deploy/undeploy_pg_agent.py +4 -7
  45. adam/commands/deploy/undeploy_pod.py +9 -12
  46. adam/commands/devices/device.py +93 -2
  47. adam/commands/devices/device_app.py +37 -10
  48. adam/commands/devices/device_auit_log.py +8 -2
  49. adam/commands/devices/device_cass.py +47 -7
  50. adam/commands/devices/device_export.py +9 -11
  51. adam/commands/devices/device_postgres.py +41 -6
  52. adam/commands/exit.py +1 -4
  53. adam/commands/export/clean_up_all_export_sessions.py +37 -0
  54. adam/commands/export/clean_up_export_sessions.py +12 -8
  55. adam/commands/export/drop_export_database.py +7 -26
  56. adam/commands/export/drop_export_databases.py +5 -14
  57. adam/commands/export/export.py +8 -38
  58. adam/commands/export/export_databases.py +86 -27
  59. adam/commands/export/export_select.py +25 -27
  60. adam/commands/export/export_select_x.py +3 -3
  61. adam/commands/export/export_sessions.py +124 -0
  62. adam/commands/export/export_use.py +8 -17
  63. adam/commands/export/exporter.py +88 -158
  64. adam/commands/export/import_session.py +7 -35
  65. adam/commands/export/importer.py +12 -5
  66. adam/commands/export/importer_athena.py +21 -20
  67. adam/commands/export/importer_sqlite.py +16 -21
  68. adam/commands/export/show_column_counts.py +7 -25
  69. adam/commands/export/show_export_databases.py +4 -6
  70. adam/commands/export/show_export_session.py +7 -18
  71. adam/commands/export/show_export_sessions.py +9 -12
  72. adam/commands/export/utils_export.py +26 -1
  73. adam/commands/intermediate_command.py +49 -0
  74. adam/commands/issues.py +11 -43
  75. adam/commands/kubectl.py +3 -6
  76. adam/commands/login.py +22 -24
  77. adam/commands/logs.py +3 -6
  78. adam/commands/ls.py +8 -9
  79. adam/commands/medusa/medusa.py +4 -22
  80. adam/commands/medusa/medusa_backup.py +20 -25
  81. adam/commands/medusa/medusa_restore.py +34 -36
  82. adam/commands/medusa/medusa_show_backupjobs.py +14 -18
  83. adam/commands/medusa/medusa_show_restorejobs.py +11 -18
  84. adam/commands/nodetool.py +6 -15
  85. adam/commands/param_get.py +11 -13
  86. adam/commands/param_set.py +8 -12
  87. adam/commands/postgres/postgres.py +22 -38
  88. adam/commands/postgres/postgres_context.py +47 -23
  89. adam/commands/postgres/postgres_ls.py +4 -8
  90. adam/commands/postgres/postgres_preview.py +5 -9
  91. adam/commands/postgres/psql_completions.py +1 -1
  92. adam/commands/postgres/utils_postgres.py +70 -0
  93. adam/commands/preview_table.py +6 -45
  94. adam/commands/pwd.py +13 -16
  95. adam/commands/reaper/reaper.py +4 -27
  96. adam/commands/reaper/reaper_forward.py +48 -55
  97. adam/commands/reaper/reaper_forward_session.py +6 -0
  98. adam/commands/reaper/reaper_forward_stop.py +10 -16
  99. adam/commands/reaper/reaper_restart.py +7 -14
  100. adam/commands/reaper/reaper_run_abort.py +8 -33
  101. adam/commands/reaper/reaper_runs.py +42 -57
  102. adam/commands/reaper/reaper_runs_abort.py +29 -49
  103. adam/commands/reaper/reaper_schedule_activate.py +9 -32
  104. adam/commands/reaper/reaper_schedule_start.py +9 -32
  105. adam/commands/reaper/reaper_schedule_stop.py +9 -32
  106. adam/commands/reaper/reaper_schedules.py +4 -14
  107. adam/commands/reaper/reaper_status.py +8 -16
  108. adam/commands/reaper/utils_reaper.py +196 -0
  109. adam/commands/repair/repair.py +4 -22
  110. adam/commands/repair/repair_log.py +5 -11
  111. adam/commands/repair/repair_run.py +27 -34
  112. adam/commands/repair/repair_scan.py +32 -38
  113. adam/commands/repair/repair_stop.py +5 -11
  114. adam/commands/report.py +27 -29
  115. adam/commands/restart.py +25 -26
  116. adam/commands/rollout.py +19 -24
  117. adam/commands/shell.py +10 -4
  118. adam/commands/show/show.py +10 -26
  119. adam/commands/show/show_cassandra_repairs.py +35 -0
  120. adam/commands/show/show_cassandra_status.py +32 -43
  121. adam/commands/show/show_cassandra_version.py +5 -18
  122. adam/commands/show/show_commands.py +19 -24
  123. adam/commands/show/show_host.py +1 -1
  124. adam/commands/show/show_login.py +20 -27
  125. adam/commands/show/show_processes.py +15 -19
  126. adam/commands/show/show_storage.py +10 -20
  127. adam/commands/watch.py +26 -29
  128. adam/config.py +4 -16
  129. adam/embedded_params.py +1 -1
  130. adam/log.py +4 -4
  131. adam/pod_exec_result.py +3 -3
  132. adam/repl.py +31 -32
  133. adam/repl_commands.py +11 -11
  134. adam/repl_state.py +52 -26
  135. adam/sql/sql_completer.py +4 -6
  136. adam/sql/sql_state_machine.py +21 -14
  137. adam/sso/authn_ad.py +6 -8
  138. adam/sso/authn_okta.py +4 -6
  139. adam/sso/cred_cache.py +3 -5
  140. adam/sso/idp.py +9 -12
  141. adam/utils.py +393 -33
  142. adam/utils_athena.py +14 -13
  143. adam/utils_audits.py +12 -12
  144. adam/utils_issues.py +32 -0
  145. adam/utils_k8s/app_clusters.py +13 -18
  146. adam/utils_k8s/app_pods.py +2 -0
  147. adam/utils_k8s/cassandra_clusters.py +21 -18
  148. adam/utils_k8s/custom_resources.py +16 -17
  149. adam/utils_k8s/ingresses.py +2 -2
  150. adam/utils_k8s/jobs.py +7 -11
  151. adam/utils_k8s/k8s.py +87 -0
  152. adam/utils_k8s/pods.py +14 -76
  153. adam/utils_k8s/secrets.py +4 -4
  154. adam/utils_k8s/service_accounts.py +5 -4
  155. adam/utils_k8s/services.py +2 -2
  156. adam/utils_k8s/statefulsets.py +1 -12
  157. adam/utils_repl/state_machine.py +3 -3
  158. adam/utils_sqlite.py +78 -42
  159. adam/version.py +1 -1
  160. {kaqing-2.0.145.dist-info → kaqing-2.0.174.dist-info}/METADATA +1 -1
  161. kaqing-2.0.174.dist-info/RECORD +230 -0
  162. adam/commands/app.py +0 -67
  163. adam/commands/app_ping.py +0 -44
  164. adam/commands/export/clean_up_export_session.py +0 -53
  165. adam/commands/postgres/postgres_utils.py +0 -31
  166. adam/commands/reaper/reaper_session.py +0 -159
  167. adam/commands/show/show_app_actions.py +0 -56
  168. adam/commands/show/show_app_id.py +0 -47
  169. adam/commands/show/show_app_queues.py +0 -45
  170. adam/commands/show/show_repairs.py +0 -47
  171. kaqing-2.0.145.dist-info/RECORD +0 -227
  172. {kaqing-2.0.145.dist-info → kaqing-2.0.174.dist-info}/WHEEL +0 -0
  173. {kaqing-2.0.145.dist-info → kaqing-2.0.174.dist-info}/entry_points.txt +0 -0
  174. {kaqing-2.0.145.dist-info → kaqing-2.0.174.dist-info}/top_level.txt +0 -0
@@ -1,13 +1,13 @@
1
1
  import click
2
2
 
3
3
  from adam.commands.command import Command
4
+ from adam.commands.intermediate_command import IntermediateCommand
4
5
  from .medusa_backup import MedusaBackup
5
6
  from .medusa_restore import MedusaRestore
6
7
  from .medusa_show_backupjobs import MedusaShowBackupJobs
7
8
  from .medusa_show_restorejobs import MedusaShowRestoreJobs
8
- from adam.repl_state import ReplState, RequiredState
9
9
 
10
- class Medusa(Command):
10
+ class Medusa(IntermediateCommand):
11
11
  COMMAND = 'medusa'
12
12
 
13
13
  # the singleton pattern
@@ -16,30 +16,12 @@ class Medusa(Command):
16
16
 
17
17
  return cls.instance
18
18
 
19
- def __init__(self, successor: Command=None):
20
- super().__init__(successor)
21
-
22
19
  def command(self):
23
20
  return Medusa.COMMAND
24
21
 
25
- def required(self):
26
- return RequiredState.CLUSTER
27
-
28
- def run(self, cmd: str, state: ReplState):
29
- if not(args := self.args(cmd)):
30
- return super().run(cmd, state)
31
-
32
- return super().intermediate_run(cmd, state, args, Medusa.cmd_list())
33
-
34
- def cmd_list():
22
+ def cmd_list(self):
35
23
  return [MedusaBackup(), MedusaRestore(), MedusaShowBackupJobs(), MedusaShowRestoreJobs()]
36
24
 
37
- def completion(self, state: ReplState):
38
- if state.sts:
39
- return super().completion(state)
40
-
41
- return {}
42
-
43
25
  class MedusaCommandHelper(click.Command):
44
26
  def get_help(self, ctx: click.Context):
45
- Command.intermediate_help(super().get_help(ctx), Medusa.COMMAND, Medusa.cmd_list(), show_cluster_help=True)
27
+ IntermediateCommand.intermediate_help(super().get_help(ctx), Medusa.COMMAND, Medusa().cmd_list(), show_cluster_help=True)
@@ -1,5 +1,4 @@
1
1
  from datetime import datetime
2
- import re
3
2
 
4
3
  from adam.commands.command import Command
5
4
  from adam.utils_k8s.statefulsets import StatefulSets
@@ -7,7 +6,6 @@ from adam.repl_state import ReplState, RequiredState
7
6
  from adam.utils_k8s.custom_resources import CustomResources
8
7
  from adam.utils import log2
9
8
 
10
-
11
9
  class MedusaBackup(Command):
12
10
  COMMAND = 'backup'
13
11
 
@@ -29,33 +27,30 @@ class MedusaBackup(Command):
29
27
  def run(self, cmd: str, state: ReplState):
30
28
  if not(args := self.args(cmd)):
31
29
  return super().run(cmd, state)
32
- state, args = self.apply_state(args, state)
33
- if not self.validate_state(state):
34
- return state
35
-
36
- ns = state.namespace
37
- sts = state.sts
38
- now_dtformat = datetime.now().strftime("%Y-%m-%d.%H.%M.%S")
39
- bkname = 'medusa-' + now_dtformat + 'full-backup-' + sts
40
- if len(args) == 1:
41
- bkname = str(args[0])
42
- groups = re.match(r'^(.*?-.*?-).*', sts)
43
- dc = StatefulSets.get_datacenter(state.sts, ns)
44
- if not dc:
45
- return state
46
30
 
47
- try:
48
- CustomResources.create_medusa_backupjob(bkname, dc, ns)
49
- except Exception as e:
50
- log2("Exception: MedusaBackup failed: %s\n" % e)
31
+ with self.validate(args, state) as (args, state):
32
+ ns = state.namespace
33
+ sts = state.sts
34
+ now_dtformat = datetime.now().strftime("%Y-%m-%d.%H.%M.%S")
35
+ bkname = 'medusa-' + now_dtformat + 'full-backup-' + sts
36
+ if len(args) == 1:
37
+ bkname = str(args[0])
38
+
39
+ dc = StatefulSets.get_datacenter(state.sts, ns)
40
+ if not dc:
41
+ return state
42
+
43
+ try:
44
+ CustomResources.create_medusa_backupjob(bkname, dc, ns)
45
+ except Exception as e:
46
+ log2("Exception: MedusaBackup failed: %s\n" % e)
47
+ finally:
48
+ CustomResources.clear_caches()
51
49
 
52
- return state
50
+ return state
53
51
 
54
52
  def completion(self, state: ReplState):
55
- if state.sts:
56
- return super().completion(state)
57
-
58
- return {}
53
+ return super().completion(state)
59
54
 
60
55
  def help(self, _: ReplState):
61
56
  return f'{MedusaBackup.COMMAND}\t start a backup job'
@@ -1,11 +1,14 @@
1
+ from collections.abc import Callable
1
2
  from datetime import datetime
3
+ from functools import partial
2
4
 
3
- from adam.commands.command import Command
5
+ from adam.commands import validate_args
6
+ from adam.commands.command import Command, InvalidArgumentsException
4
7
  from adam.utils_k8s.statefulsets import StatefulSets
5
8
  from adam.repl_state import ReplState, RequiredState
6
9
  from adam.utils_k8s.custom_resources import CustomResources
7
10
  from adam.config import Config
8
- from adam.utils import lines_to_tabular, log2
11
+ from adam.utils import lines_to_tabular, log2, log_exc
9
12
 
10
13
  class MedusaRestore(Command):
11
14
  COMMAND = 'restore'
@@ -28,47 +31,42 @@ class MedusaRestore(Command):
28
31
  def run(self, cmd: str, state: ReplState):
29
32
  if not(args := self.args(cmd)):
30
33
  return super().run(cmd, state)
31
- state, args = self.apply_state(args, state)
32
- if not self.validate_state(state):
33
- return state
34
-
35
- ns = state.namespace
36
- dc = StatefulSets.get_datacenter(state.sts, ns)
37
- if not dc:
38
- return state
39
-
40
- if len(args) == 1:
41
- bkname = args[0]
42
- job = CustomResources.medusa_get_backupjob(dc, ns, bkname)
43
- if not job:
44
- log2('\n* Backup job name is not valid.')
34
+
35
+ with self.validate(args, state) as (args, state):
36
+ ns = state.namespace
37
+ dc: str = StatefulSets.get_datacenter(state.sts, ns)
38
+ if not dc:
39
+ return state
40
+
41
+ def msg(missing: bool):
42
+ if missing:
43
+ log2('\n* Missing Backup Name')
44
+ log2('Usage: qing restore <backup> <sts@name_space>\n')
45
+ else:
46
+ log2('\n* Backup job name is not valid.')
47
+
45
48
  bklist = [f"{x['metadata']['name']}\t{x['metadata']['creationTimestamp']}\t{x['status'].get('finishTime', '')}" for x in CustomResources.medusa_show_backupjobs(dc, ns)]
46
49
  log2(lines_to_tabular(bklist, 'NAME\tCREATED\tFINISHED', separator='\t'))
47
50
 
48
- return state
51
+ with validate_args(args, state, msg=partial(msg, True)) as bkname:
52
+ if not (job := CustomResources.medusa_get_backupjob(dc, ns, bkname)):
53
+ msg(False)
54
+ raise InvalidArgumentsException()
55
+
56
+ if not input(f"Restoring from {bkname} created at {job['metadata']['creationTimestamp']}. Please enter Yes to continue: ").lower() in ['y', 'yes']:
57
+ return state
58
+
59
+ with log_exc(lambda e: "Exception: MedusaRestore failed: %s\n" % e):
60
+ now_dtformat = datetime.now().strftime("%Y-%m-%d.%H.%M.%S")
61
+ rtname = 'medusa-' + now_dtformat + '-restore-from-' + bkname
62
+ CustomResources.create_medusa_restorejob(rtname, bkname, dc, ns)
49
63
 
50
- if not input(f"Restoring from {bkname} created at {job['metadata']['creationTimestamp']}. Please enter Yes to continue: ").lower() in ['y', 'yes']:
51
64
  return state
52
- else:
53
- bklist = [f"{x['metadata']['name']}\t{x['metadata']['creationTimestamp']}\t{x['status'].get('finishTime', '')}" for x in CustomResources.medusa_show_backupjobs(dc, ns)]
54
- log2('\n* Missing Backup Name')
55
- log2('Usage: qing medusa restore <backup> <sts@name_space>\n')
56
- log2(lines_to_tabular(bklist, 'NAME\tCREATED\tFINISHED', separator='\t'))
57
- return state
58
-
59
- now_dtformat = datetime.now().strftime("%Y-%m-%d.%H.%M.%S")
60
- rtname = 'medusa-' + now_dtformat + '-restore-from-' + bkname
61
- try:
62
- CustomResources.create_medusa_restorejob(rtname, bkname, dc, ns)
63
- except Exception as e:
64
- log2("Exception: MedusaRestore failed: %s\n" % e)
65
-
66
- return state
67
65
 
68
66
  def completion(self, state: ReplState):
69
- if state.sts:
67
+ if sc := super().completion(state):
70
68
  ns = state.namespace
71
- dc = StatefulSets.get_datacenter(state.sts, ns)
69
+ dc: str = StatefulSets.get_datacenter(state.sts, ns)
72
70
  if not dc:
73
71
  return {}
74
72
 
@@ -77,7 +75,7 @@ class MedusaRestore(Command):
77
75
 
78
76
  return super().completion(state, leaf)
79
77
  else:
80
- return super().completion(state)
78
+ return sc
81
79
 
82
80
  return {}
83
81
 
@@ -2,7 +2,7 @@ from adam.commands.command import Command
2
2
  from adam.utils_k8s.statefulsets import StatefulSets
3
3
  from adam.repl_state import ReplState, RequiredState
4
4
  from adam.utils_k8s.custom_resources import CustomResources
5
- from adam.utils import lines_to_tabular, log2
5
+ from adam.utils import lines_to_tabular, log2, log_exc
6
6
 
7
7
 
8
8
  class MedusaShowBackupJobs(Command):
@@ -26,28 +26,24 @@ class MedusaShowBackupJobs(Command):
26
26
  def run(self, cmd: str, state: ReplState):
27
27
  if not(args := self.args(cmd)):
28
28
  return super().run(cmd, state)
29
- state, args = self.apply_state(args, state)
30
- if not self.validate_state(state):
31
- return state
32
29
 
33
- ns = state.namespace
34
- dc = StatefulSets.get_datacenter(state.sts, ns)
35
- if not dc:
36
- return state
30
+ with self.validate(args, state) as (args, state):
31
+ ns = state.namespace
32
+ dc = StatefulSets.get_datacenter(state.sts, ns)
33
+ if not dc:
34
+ return state
37
35
 
38
- try:
39
- bklist = [f"{x['metadata']['name']}\t{x['metadata']['creationTimestamp']}\t{x['status'].get('finishTime', '')}" for x in CustomResources.medusa_show_backupjobs(dc, ns)]
40
- log2(lines_to_tabular(bklist, 'NAME\tCREATED\tFINISHED', separator='\t'))
41
- except Exception as e:
42
- log2("Exception: MedusaShowBackupJobs failed: %s\n" % e)
36
+ # try:
37
+ with log_exc(lambda e: "Exception: MedusaShowBackupJobs failed: %s\n" % e):
38
+ CustomResources.clear_caches()
43
39
 
44
- return state
40
+ bklist = [f"{x['metadata']['name']}\t{x['metadata']['creationTimestamp']}\t{x['status'].get('finishTime', '') if 'status' in x else 'unknown'}" for x in CustomResources.medusa_show_backupjobs(dc, ns)]
41
+ log2(lines_to_tabular(bklist, 'NAME\tCREATED\tFINISHED', separator='\t'))
45
42
 
46
- def completion(self, state: ReplState):
47
- if state.sts:
48
- return super().completion(state)
43
+ return state
49
44
 
50
- return {}
45
+ def completion(self, state: ReplState):
46
+ return super().completion(state)
51
47
 
52
48
  def help(self, _: ReplState):
53
49
  return f'{MedusaShowBackupJobs.COMMAND}\t show Medusa backups'
@@ -2,7 +2,7 @@ from adam.commands.command import Command
2
2
  from adam.utils_k8s.statefulsets import StatefulSets
3
3
  from adam.repl_state import ReplState, RequiredState
4
4
  from adam.utils_k8s.custom_resources import CustomResources
5
- from adam.utils import lines_to_tabular, log2
5
+ from adam.utils import lines_to_tabular, log2, log_exc
6
6
 
7
7
  class MedusaShowRestoreJobs(Command):
8
8
  COMMAND = 'show restores'
@@ -25,28 +25,21 @@ class MedusaShowRestoreJobs(Command):
25
25
  def run(self, cmd: str, state: ReplState):
26
26
  if not(args := self.args(cmd)):
27
27
  return super().run(cmd, state)
28
- state, args = self.apply_state(args, state)
29
- if not self.validate_state(state):
30
- return state
31
28
 
32
- ns = state.namespace
33
- dc = StatefulSets.get_datacenter(state.sts, ns)
34
- if not dc:
35
- return state
29
+ with self.validate(args, state) as (args, state):
30
+ ns = state.namespace
31
+ dc = StatefulSets.get_datacenter(state.sts, ns)
32
+ if not dc:
33
+ return state
36
34
 
37
- try:
38
- rtlist = CustomResources.medusa_show_restorejobs(dc, ns)
39
- log2(lines_to_tabular(rtlist, 'NAME\tCREATED\tFINISHED', separator='\t'))
40
- except Exception as e:
41
- log2("Exception: MedusaShowRestoreJobs failed: %s\n" % e)
35
+ with log_exc(lambda e: "Exception: MedusaShowRestoreJobs failed: %s\n" % e):
36
+ rtlist = CustomResources.medusa_show_restorejobs(dc, ns)
37
+ log2(lines_to_tabular(rtlist, 'NAME\tCREATED\tFINISHED', separator='\t'))
42
38
 
43
- return state
39
+ return state
44
40
 
45
41
  def completion(self, state: ReplState):
46
- if state.sts:
47
- return super().completion(state)
48
-
49
- return {}
42
+ return super().completion(state)
50
43
 
51
44
  def help(self, _: ReplState):
52
45
  return f'{MedusaShowRestoreJobs.COMMAND}\t show Medusa restores'
adam/commands/nodetool.py CHANGED
@@ -2,10 +2,9 @@ import click
2
2
 
3
3
  from adam.commands.command import Command
4
4
  from adam.commands.command_helpers import ClusterOrPodCommandHelper
5
+ from adam.commands.cql.utils_cql import cassandra
5
6
  from adam.commands.nodetool_commands import NODETOOL_COMMANDS
6
7
  from adam.config import Config
7
- from adam.utils_k8s.cassandra_clusters import CassandraClusters
8
- from adam.utils_k8s.cassandra_nodes import CassandraNodes
9
8
  from adam.repl_state import ReplState, RequiredState
10
9
  from adam.utils import log
11
10
  from adam.utils_k8s.statefulsets import StatefulSets
@@ -32,22 +31,14 @@ class NodeTool(Command):
32
31
  if not(args := self.args(cmd)):
33
32
  return super().run(cmd, state)
34
33
 
35
- state, args = self.apply_state(args, state)
36
- if not self.validate_state(state):
37
- return state
38
-
39
- user, pw = state.user_pass()
40
- command = f"nodetool -u {user} -pw {pw} {' '.join(args)}"
34
+ with self.validate(args, state) as (args, state):
35
+ with cassandra(state) as pods:
36
+ pods.nodetool(' '.join(args))
41
37
 
42
- if state.pod:
43
- return CassandraNodes.exec(state.pod, state.namespace, command, show_out=True)
44
- elif state.sts:
45
- return CassandraClusters.exec(state.sts, state.namespace, command, action='nodetool', show_out=True)
46
-
47
- return state
38
+ return state
48
39
 
49
40
  def completion(self, state: ReplState):
50
- if state.pod or state.sts:
41
+ if super().completion(state):
51
42
  d = {c: {'&': None} for c in NODETOOL_COMMANDS}
52
43
  return {NodeTool.COMMAND: {'help': None} | d} | \
53
44
  {f'@{p}': {NodeTool.COMMAND: d} for p in StatefulSets.pod_names(state.sts, state.namespace)}
@@ -1,3 +1,4 @@
1
+ from adam.commands import validate_args
1
2
  from adam.commands.command import Command
2
3
  from adam.config import Config
3
4
  from adam.repl_state import ReplState
@@ -22,21 +23,18 @@ class GetParam(Command):
22
23
  if not(args := self.args(cmd)):
23
24
  return super().run(cmd, state)
24
25
 
25
- state, args = self.apply_state(args, state)
26
+ with self.validate(args, state) as (args, state):
27
+ def msg():
28
+ lines = [f'{key}\t{Config().get(key, None)}' for key in Config().keys()]
29
+ log(lines_to_tabular(lines, separator='\t'))
26
30
 
27
- if len(args) < 1:
28
- lines = [f'{key}\t{Config().get(key, None)}' for key in Config().keys()]
29
- log(lines_to_tabular(lines, separator='\t'))
31
+ with validate_args(args, state, msg=msg) as key:
32
+ if v := Config().get(key, None):
33
+ log(v)
34
+ else:
35
+ log2(f'{key} is not set.')
30
36
 
31
- return state
32
-
33
- key = args[0]
34
- if v := Config().get(key, None):
35
- log(v)
36
- else:
37
- log2(f'{key} is not set.')
38
-
39
- return v if v else state
37
+ return v if v else state
40
38
 
41
39
  def completion(self, _: ReplState):
42
40
  return {GetParam.COMMAND: {key: None for key in Config().keys()}}
@@ -1,3 +1,4 @@
1
+ from adam.commands import validate_args
1
2
  from adam.commands.command import Command
2
3
  from adam.config import Config
3
4
  from adam.repl_state import ReplState
@@ -22,20 +23,15 @@ class SetParam(Command):
22
23
  if not(args := self.args(cmd)):
23
24
  return super().run(cmd, state)
24
25
 
25
- state, args = self.apply_state(args, state)
26
+ with self.validate(args, state) as (args, state):
27
+ with validate_args(args, state, count_at_least=2, msg=lambda: log2('set <key> <value>')):
28
+ key = args[0]
29
+ value = args[1]
30
+ Config().set(key, value)
26
31
 
27
- if len(args) < 2:
28
- log2('set <key> <value>')
32
+ log(Config().get(key, None))
29
33
 
30
- return 'invalid args'
31
-
32
- key = args[0]
33
- value = args[1]
34
- Config().set(key, value)
35
-
36
- log(Config().get(key, None))
37
-
38
- return value
34
+ return value
39
35
 
40
36
  def completion(self, _: ReplState):
41
37
  return {SetParam.COMMAND: {key: ({'true': None, 'false': None} if Config().get(key, None) in [True, False] else None) for key in Config().keys()}}
@@ -1,17 +1,18 @@
1
1
  import click
2
2
 
3
+ from adam.commands import extract_trailing_options, validate_args
3
4
  from adam.commands.command import Command
5
+ from adam.commands.intermediate_command import IntermediateCommand
4
6
  from adam.commands.postgres.psql_completions import psql_completions
5
- from adam.commands.postgres.postgres_utils import pg_table_names
7
+ from adam.commands.postgres.utils_postgres import pg_table_names, postgres
6
8
  from .postgres_ls import PostgresLs
7
9
  from .postgres_preview import PostgresPreview
8
10
  from .postgres_context import PostgresContext
9
11
  from adam.repl_state import ReplState
10
12
  from adam.utils import log, log2
11
13
 
12
- class Postgres(Command):
14
+ class Postgres(IntermediateCommand):
13
15
  COMMAND = 'pg'
14
- reaper_login = None
15
16
 
16
17
  # the singleton pattern
17
18
  def __new__(cls, *args, **kwargs):
@@ -29,46 +30,29 @@ class Postgres(Command):
29
30
  if not(args := self.args(cmd)):
30
31
  return super().run(cmd, state)
31
32
 
32
- state, args = self.apply_state(args, state)
33
+ with self.validate(args, state) as (args, state):
34
+ with extract_trailing_options(args, '&') as (args, backgrounded):
35
+ with validate_args(args, state, name='SQL statement') as sql:
36
+ if not state.pg_path:
37
+ if state.in_repl:
38
+ log2('Enter "use <pg-name>" first.')
39
+ else:
40
+ log2('* pg-name is missing.')
33
41
 
34
- if not args:
35
- if state.in_repl:
36
- log2('Please use SQL statement. e.g. pg \l')
37
- else:
38
- log2('* Command or SQL statements is missing.')
39
- Command.display_help()
42
+ return state
40
43
 
41
- return 'command-missing'
44
+ if state.in_repl:
45
+ with postgres(state) as pod:
46
+ pod.sql(args, background=backgrounded)
47
+ elif not self.run_subcommand(cmd, state):
48
+ with postgres(state) as pod:
49
+ pod.sql(args, background=backgrounded)
42
50
 
43
- if state.in_repl:
44
- self.run_sql(state, args)
45
- else:
46
- # head with the Chain of Responsibility pattern
47
- cmds = Command.chain(Postgres.cmd_list())
48
- if not cmds.run(cmd, state) :
49
- self.run_sql(state, args)
50
-
51
- return state
51
+ return state
52
52
 
53
- def cmd_list():
53
+ def cmd_list(self):
54
54
  return [PostgresLs(), PostgresPreview(), PostgresPg()]
55
55
 
56
- def run_sql(self, state: ReplState, args: list[str]):
57
- if not state.pg_path:
58
- if state.in_repl:
59
- log2('Enter "use <pg-name>" first.')
60
- else:
61
- log2('* pg-name is missing.')
62
-
63
- return state
64
-
65
- background = False
66
- if args and args[-1] == '&':
67
- args = args[:-1]
68
- background = True
69
-
70
- PostgresContext.apply(state.namespace, state.pg_path).run_sql(' '.join(args), background=background)
71
-
72
56
  def completion(self, state: ReplState):
73
57
  if state.device != state.P:
74
58
  # conflicts with cql completions
@@ -95,7 +79,7 @@ class Postgres(Command):
95
79
 
96
80
  class PostgresCommandHelper(click.Command):
97
81
  def get_help(self, ctx: click.Context):
98
- Command.intermediate_help(super().get_help(ctx), Postgres.COMMAND, Postgres.cmd_list(), show_cluster_help=True)
82
+ IntermediateCommand.intermediate_help(super().get_help(ctx), Postgres.COMMAND, Postgres().cmd_list(), show_cluster_help=True)
99
83
  log('PG-Name: Kubernetes secret for Postgres credentials')
100
84
  log(' e.g. stgawsscpsr-c3-c3-k8spg-cs-001')
101
85
  log('Database: Postgres database name within a host')
@@ -8,7 +8,7 @@ from adam.repl_session import ReplSession
8
8
  from adam.utils_k8s.kube_context import KubeContext
9
9
  from adam.utils_k8s.pods import Pods
10
10
  from adam.utils_k8s.secrets import Secrets
11
- from adam.utils import log2
11
+ from adam.utils import log2, log_exc
12
12
 
13
13
  class PostgresContext:
14
14
  def apply(namespace: str, path: str, arg: str = None) -> 'PostgresContext':
@@ -149,36 +149,62 @@ class PostgresContext:
149
149
 
150
150
  return r
151
151
  else:
152
- ns = self.namespace
153
- pod_name = Config().get('pg.agent.name', 'ops-pg-agent')
154
-
155
- if Config().get('pg.agent.just-in-time', False):
156
- if not PostgresContext.deploy_pg_agent(pod_name, ns):
157
- return
152
+ pod_name, container_name = PostgresContext.pod_and_container(self.namespace)
153
+ if not pod_name:
154
+ return
158
155
 
159
- real_pod_name = pod_name
160
- try:
161
- # try with dedicated pg agent pod name configured
162
- Pods.get(ns, pod_name)
163
- except:
164
- try:
165
- # try with the ops pod
166
- pod_name = Config().get('pod.name', 'ops')
167
- real_pod_name = Pods.get_with_selector(ns, label_selector = Config().get('pod.label-selector', 'run=ops')).metadata.name
168
- except:
169
- log2(f"Could not locate {pod_name} pod.")
170
- return None
156
+ # ns = self.namespace
157
+ # pod_name = Config().get('pg.agent.name', 'ops-pg-agent')
158
+
159
+ # if Config().get('pg.agent.just-in-time', False):
160
+ # if not PostgresContext.deploy_pg_agent(pod_name, ns):
161
+ # return
162
+
163
+ # real_pod_name = pod_name
164
+ # try:
165
+ # # try with dedicated pg agent pod name configured
166
+ # Pods.get(ns, pod_name)
167
+ # except:
168
+ # try:
169
+ # # try with the ops pod
170
+ # pod_name = Config().get('pod.name', 'ops')
171
+ # real_pod_name = Pods.get_with_selector(ns, label_selector = Config().get('pod.label-selector', 'run=ops')).metadata.name
172
+ # except:
173
+ # log2(f"Could not locate {pod_name} pod.")
174
+ # return None
171
175
 
172
176
  cmd = f'psql -h {self.endpoint()} -p {self.port()} -U {self.username()} {db} --pset pager=off -c "{sql}"'
173
177
  env_prefix = f'PGPASSWORD="{self.password()}"'
174
178
 
175
- r = Pods.exec(real_pod_name, pod_name, ns, cmd, show_out=show_out, background=background, env_prefix=env_prefix)
179
+ r = Pods.exec(pod_name, container_name, self.namespace, cmd, show_out=show_out, background=background, env_prefix=env_prefix)
176
180
  if r and Config().get('repl.history.push-cat-remote-log-file', True):
177
181
  if r.log_file and ReplSession().prompt_session:
178
182
  ReplSession().prompt_session.history.append_string(f'@{r.pod} cat {r.log_file}')
179
183
 
180
184
  return r
181
185
 
186
+ def pod_and_container(ns: str):
187
+ container_name = Config().get('pg.agent.name', 'ops-pg-agent')
188
+
189
+ if Config().get('pg.agent.just-in-time', False):
190
+ if not PostgresContext.deploy_pg_agent(container_name, ns):
191
+ return None
192
+
193
+ pod_name = container_name
194
+ try:
195
+ # try with dedicated pg agent pod name configured
196
+ Pods.get(ns, container_name)
197
+ except:
198
+ try:
199
+ # try with the ops pod
200
+ container_name = Config().get('pod.name', 'ops')
201
+ pod_name = Pods.get_with_selector(ns, label_selector = Config().get('pod.label-selector', 'run=ops')).metadata.name
202
+ except:
203
+ log2(f"Could not locate {container_name} pod.")
204
+ return None
205
+
206
+ return pod_name, container_name
207
+
182
208
  def deploy_pg_agent(pod_name: str, ns: str) -> str:
183
209
  image = Config().get('pg.agent.image', 'seanahnsf/kaqing')
184
210
  timeout = Config().get('pg.agent.timeout', 3600)
@@ -187,11 +213,9 @@ class PostgresContext:
187
213
  except Exception as e:
188
214
  if e.status == 409:
189
215
  if Pods.completed(ns, pod_name):
190
- try:
216
+ with log_exc(lambda e2: "Exception when calling BatchV1Api->create_pod: %s\n" % e2):
191
217
  Pods.delete(pod_name, ns)
192
218
  Pods.create(ns, pod_name, image, ['sleep', f'{timeout}'], env={'NAMESPACE': ns}, sa_name='c3')
193
- except Exception as e2:
194
- log2("Exception when calling BatchV1Api->create_pod: %s\n" % e2)
195
219
 
196
220
  return
197
221
  else:
@@ -4,7 +4,6 @@ from adam.repl_state import ReplState, RequiredState
4
4
 
5
5
  class PostgresLs(Command):
6
6
  COMMAND = 'pg ls'
7
- reaper_login = None
8
7
 
9
8
  # the singleton pattern
10
9
  def __new__(cls, *args, **kwargs):
@@ -25,15 +24,12 @@ class PostgresLs(Command):
25
24
  if not(args := self.args(cmd)):
26
25
  return super().run(cmd, state)
27
26
 
28
- state, args = self.apply_state(args, state)
29
- if not self.validate_state(state):
30
- return state
31
-
32
- state.device = ReplState.P
27
+ with self.validate(args, state) as (args, state):
28
+ state.device = ReplState.P
33
29
 
34
- Ls().run('ls', state)
30
+ Ls().run('ls', state)
35
31
 
36
- return state
32
+ return state
37
33
 
38
34
  def completion(self, state: ReplState):
39
35
  if state.sts: