kaqing 2.0.115__py3-none-any.whl → 2.0.172__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 (187) 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 +18 -0
  13. adam/commands/alter_tables.py +43 -47
  14. adam/commands/audit/audit.py +24 -25
  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 -14
  20. adam/commands/audit/utils_show_top10.py +2 -3
  21. adam/commands/bash/__init__.py +5 -0
  22. adam/commands/bash/bash.py +8 -96
  23. adam/commands/bash/utils_bash.py +16 -0
  24. adam/commands/cat.py +14 -19
  25. adam/commands/cd.py +12 -100
  26. adam/commands/check.py +20 -21
  27. adam/commands/cli_commands.py +2 -3
  28. adam/commands/code.py +20 -23
  29. adam/commands/command.py +123 -39
  30. adam/commands/commands_utils.py +8 -17
  31. adam/commands/cp.py +33 -39
  32. adam/commands/cql/cql_completions.py +28 -10
  33. adam/commands/cql/cqlsh.py +10 -30
  34. adam/commands/cql/utils_cql.py +343 -0
  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 +65 -73
  42. adam/commands/deploy/deploy_utils.py +14 -24
  43. adam/commands/deploy/undeploy.py +4 -27
  44. adam/commands/deploy/undeploy_frontend.py +4 -7
  45. adam/commands/deploy/undeploy_pg_agent.py +5 -7
  46. adam/commands/deploy/undeploy_pod.py +11 -12
  47. adam/commands/devices/__init__.py +0 -0
  48. adam/commands/devices/device.py +118 -0
  49. adam/commands/devices/device_app.py +173 -0
  50. adam/commands/devices/device_auit_log.py +49 -0
  51. adam/commands/devices/device_cass.py +185 -0
  52. adam/commands/devices/device_export.py +86 -0
  53. adam/commands/devices/device_postgres.py +144 -0
  54. adam/commands/devices/devices.py +25 -0
  55. adam/commands/exit.py +1 -4
  56. adam/commands/export/clean_up_all_export_sessions.py +37 -0
  57. adam/commands/export/clean_up_export_sessions.py +51 -0
  58. adam/commands/export/drop_export_database.py +55 -0
  59. adam/commands/export/drop_export_databases.py +43 -0
  60. adam/commands/export/export.py +19 -26
  61. adam/commands/export/export_databases.py +174 -0
  62. adam/commands/export/export_handlers.py +71 -0
  63. adam/commands/export/export_select.py +48 -22
  64. adam/commands/export/export_select_x.py +54 -0
  65. adam/commands/export/export_use.py +19 -23
  66. adam/commands/export/exporter.py +353 -0
  67. adam/commands/export/import_session.py +40 -0
  68. adam/commands/export/importer.py +67 -0
  69. adam/commands/export/importer_athena.py +77 -0
  70. adam/commands/export/importer_sqlite.py +39 -0
  71. adam/commands/export/show_column_counts.py +54 -0
  72. adam/commands/export/show_export_databases.py +36 -0
  73. adam/commands/export/show_export_session.py +48 -0
  74. adam/commands/export/show_export_sessions.py +44 -0
  75. adam/commands/export/utils_export.py +223 -162
  76. adam/commands/help.py +1 -1
  77. adam/commands/intermediate_command.py +49 -0
  78. adam/commands/issues.py +11 -43
  79. adam/commands/kubectl.py +3 -6
  80. adam/commands/login.py +22 -24
  81. adam/commands/logs.py +3 -6
  82. adam/commands/ls.py +11 -128
  83. adam/commands/medusa/medusa.py +4 -22
  84. adam/commands/medusa/medusa_backup.py +20 -24
  85. adam/commands/medusa/medusa_restore.py +29 -33
  86. adam/commands/medusa/medusa_show_backupjobs.py +14 -18
  87. adam/commands/medusa/medusa_show_restorejobs.py +11 -18
  88. adam/commands/nodetool.py +6 -15
  89. adam/commands/param_get.py +11 -12
  90. adam/commands/param_set.py +9 -10
  91. adam/commands/postgres/postgres.py +41 -34
  92. adam/commands/postgres/postgres_context.py +57 -24
  93. adam/commands/postgres/postgres_ls.py +4 -8
  94. adam/commands/postgres/postgres_preview.py +5 -9
  95. adam/commands/postgres/psql_completions.py +1 -1
  96. adam/commands/postgres/utils_postgres.py +66 -0
  97. adam/commands/preview_table.py +5 -44
  98. adam/commands/pwd.py +14 -47
  99. adam/commands/reaper/reaper.py +4 -27
  100. adam/commands/reaper/reaper_forward.py +48 -55
  101. adam/commands/reaper/reaper_forward_session.py +6 -0
  102. adam/commands/reaper/reaper_forward_stop.py +10 -16
  103. adam/commands/reaper/reaper_restart.py +7 -14
  104. adam/commands/reaper/reaper_run_abort.py +11 -30
  105. adam/commands/reaper/reaper_runs.py +42 -57
  106. adam/commands/reaper/reaper_runs_abort.py +29 -49
  107. adam/commands/reaper/reaper_schedule_activate.py +11 -30
  108. adam/commands/reaper/reaper_schedule_start.py +10 -29
  109. adam/commands/reaper/reaper_schedule_stop.py +10 -29
  110. adam/commands/reaper/reaper_schedules.py +4 -14
  111. adam/commands/reaper/reaper_status.py +8 -16
  112. adam/commands/reaper/utils_reaper.py +196 -0
  113. adam/commands/repair/repair.py +4 -22
  114. adam/commands/repair/repair_log.py +5 -11
  115. adam/commands/repair/repair_run.py +27 -34
  116. adam/commands/repair/repair_scan.py +32 -38
  117. adam/commands/repair/repair_stop.py +5 -11
  118. adam/commands/report.py +27 -29
  119. adam/commands/restart.py +25 -26
  120. adam/commands/rollout.py +19 -24
  121. adam/commands/shell.py +10 -4
  122. adam/commands/show/show.py +10 -25
  123. adam/commands/show/show_cassandra_repairs.py +35 -0
  124. adam/commands/show/show_cassandra_status.py +32 -43
  125. adam/commands/show/show_cassandra_version.py +5 -18
  126. adam/commands/show/show_commands.py +19 -24
  127. adam/commands/show/show_host.py +1 -1
  128. adam/commands/show/show_login.py +20 -27
  129. adam/commands/show/show_processes.py +15 -19
  130. adam/commands/show/show_storage.py +10 -20
  131. adam/commands/watch.py +26 -29
  132. adam/config.py +5 -14
  133. adam/embedded_params.py +1 -1
  134. adam/log.py +4 -4
  135. adam/pod_exec_result.py +3 -3
  136. adam/repl.py +40 -103
  137. adam/repl_commands.py +32 -16
  138. adam/repl_state.py +57 -28
  139. adam/sql/sql_completer.py +44 -28
  140. adam/sql/sql_state_machine.py +89 -28
  141. adam/sso/authn_ad.py +6 -8
  142. adam/sso/authn_okta.py +4 -6
  143. adam/sso/cred_cache.py +3 -5
  144. adam/sso/idp.py +9 -12
  145. adam/utils.py +435 -6
  146. adam/utils_athena.py +57 -37
  147. adam/utils_audits.py +12 -14
  148. adam/utils_issues.py +32 -0
  149. adam/utils_k8s/app_clusters.py +13 -18
  150. adam/utils_k8s/app_pods.py +2 -0
  151. adam/utils_k8s/cassandra_clusters.py +22 -19
  152. adam/utils_k8s/cassandra_nodes.py +2 -2
  153. adam/utils_k8s/custom_resources.py +16 -17
  154. adam/utils_k8s/ingresses.py +2 -2
  155. adam/utils_k8s/jobs.py +7 -11
  156. adam/utils_k8s/k8s.py +87 -0
  157. adam/utils_k8s/pods.py +40 -77
  158. adam/utils_k8s/secrets.py +4 -4
  159. adam/utils_k8s/service_accounts.py +5 -4
  160. adam/utils_k8s/services.py +2 -2
  161. adam/utils_k8s/statefulsets.py +1 -12
  162. adam/utils_net.py +4 -4
  163. adam/utils_repl/__init__.py +0 -0
  164. adam/utils_repl/automata_completer.py +48 -0
  165. adam/utils_repl/repl_completer.py +46 -0
  166. adam/utils_repl/state_machine.py +173 -0
  167. adam/utils_sqlite.py +137 -0
  168. adam/version.py +1 -1
  169. {kaqing-2.0.115.dist-info → kaqing-2.0.172.dist-info}/METADATA +1 -1
  170. kaqing-2.0.172.dist-info/RECORD +230 -0
  171. adam/commands/app.py +0 -67
  172. adam/commands/app_ping.py +0 -44
  173. adam/commands/cql/cql_utils.py +0 -204
  174. adam/commands/devices.py +0 -147
  175. adam/commands/export/export_on_x.py +0 -76
  176. adam/commands/export/export_rmdbs.py +0 -65
  177. adam/commands/postgres/postgres_utils.py +0 -31
  178. adam/commands/reaper/reaper_session.py +0 -159
  179. adam/commands/show/show_app_actions.py +0 -56
  180. adam/commands/show/show_app_id.py +0 -47
  181. adam/commands/show/show_app_queues.py +0 -45
  182. adam/commands/show/show_repairs.py +0 -47
  183. adam/utils_export.py +0 -42
  184. kaqing-2.0.115.dist-info/RECORD +0 -203
  185. {kaqing-2.0.115.dist-info → kaqing-2.0.172.dist-info}/WHEEL +0 -0
  186. {kaqing-2.0.115.dist-info → kaqing-2.0.172.dist-info}/entry_points.txt +0 -0
  187. {kaqing-2.0.115.dist-info → kaqing-2.0.172.dist-info}/top_level.txt +0 -0
@@ -22,20 +22,19 @@ class SetParam(Command):
22
22
  if not(args := self.args(cmd)):
23
23
  return super().run(cmd, state)
24
24
 
25
- state, args = self.apply_state(args, state)
25
+ with self.validate(args, state) as (args, state):
26
+ if len(args) < 2:
27
+ log2('set <key> <value>')
26
28
 
27
- if len(args) < 2:
28
- log2('set <key> <value>')
29
+ return 'invalid args'
29
30
 
30
- return 'invalid args'
31
+ key = args[0]
32
+ value = args[1]
33
+ Config().set(key, value)
31
34
 
32
- key = args[0]
33
- value = args[1]
34
- Config().set(key, value)
35
+ log(Config().get(key, None))
35
36
 
36
- log(Config().get(key, None))
37
-
38
- return value
37
+ return value
39
38
 
40
39
  def completion(self, _: ReplState):
41
40
  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
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,40 +30,36 @@ 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
+ if not args:
36
+ if state.in_repl:
37
+ log2('Please use SQL statement. e.g. pg \l')
38
+ else:
39
+ log2('* Command or SQL statements is missing.')
40
+ Command.display_help()
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 'command-missing'
40
43
 
41
- return 'command-missing'
44
+ if not state.pg_path:
45
+ if state.in_repl:
46
+ log2('Enter "use <pg-name>" first.')
47
+ else:
48
+ log2('* pg-name is missing.')
42
49
 
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
52
-
53
- def cmd_list():
54
- return [PostgresLs(), PostgresPreview()]
50
+ return state
55
51
 
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.')
52
+ if state.in_repl:
53
+ with postgres(state) as pod:
54
+ pod.sql(args, background=backgrounded)
55
+ elif not self.run_subcommand(cmd, state):
56
+ with postgres(state) as pod:
57
+ pod.sql(args, background=backgrounded)
62
58
 
63
- return state
59
+ return state
64
60
 
65
- PostgresContext.apply(state.namespace, state.pg_path).run_sql(' '.join(args))
61
+ def cmd_list(self):
62
+ return [PostgresLs(), PostgresPreview(), PostgresPg()]
66
63
 
67
64
  def completion(self, state: ReplState):
68
65
  if state.device != state.P:
@@ -86,12 +83,22 @@ class Postgres(Command):
86
83
  return {}
87
84
 
88
85
  def help(self, _: ReplState):
89
- return f'<sql-statements>\t run queries on Postgres databases'
86
+ return f'<sql-statements> [&]\t run queries on Postgres databases'
90
87
 
91
88
  class PostgresCommandHelper(click.Command):
92
89
  def get_help(self, ctx: click.Context):
93
- Command.intermediate_help(super().get_help(ctx), Postgres.COMMAND, Postgres.cmd_list(), show_cluster_help=True)
90
+ IntermediateCommand.intermediate_help(super().get_help(ctx), Postgres.COMMAND, Postgres().cmd_list(), show_cluster_help=True)
94
91
  log('PG-Name: Kubernetes secret for Postgres credentials')
95
92
  log(' e.g. stgawsscpsr-c3-c3-k8spg-cs-001')
96
93
  log('Database: Postgres database name within a host')
97
- log(' e.g. stgawsscpsr_c3_c3')
94
+ log(' e.g. stgawsscpsr_c3_c3')
95
+
96
+ # No action body, only for a help entry and auto-completion
97
+ class PostgresPg(Command):
98
+ COMMAND = 'pg'
99
+
100
+ def command(self):
101
+ return PostgresPg.COMMAND
102
+
103
+ def help(self, _: ReplState):
104
+ return f'pg <sql-statements>\t run queries on Postgres databases'
@@ -1,12 +1,14 @@
1
+ from datetime import datetime
1
2
  import functools
2
3
  import re
3
4
  import subprocess
4
5
 
5
6
  from adam.config import Config
7
+ from adam.repl_session import ReplSession
6
8
  from adam.utils_k8s.kube_context import KubeContext
7
9
  from adam.utils_k8s.pods import Pods
8
10
  from adam.utils_k8s.secrets import Secrets
9
- from adam.utils import log2
11
+ from adam.utils import log2, log_exc
10
12
 
11
13
  class PostgresContext:
12
14
  def apply(namespace: str, path: str, arg: str = None) -> 'PostgresContext':
@@ -131,7 +133,7 @@ class PostgresContext:
131
133
 
132
134
  return dbs
133
135
 
134
- def run_sql(self, sql: str, show_out = True):
136
+ def run_sql(self, sql: str, show_out = True, background = False):
135
137
  db = self.db if self.db else PostgresContext.default_db()
136
138
 
137
139
  if KubeContext.in_cluster():
@@ -139,36 +141,69 @@ class PostgresContext:
139
141
  log2(f'{cmd1} "{sql}"')
140
142
  # remove double quotes from the sql argument
141
143
  cmd = cmd1.split(' ') + [sql]
142
- r = subprocess.run(cmd, capture_output=True, text=True)
144
+
145
+ r = subprocess.run(cmd, capture_output=not background, text=True)
143
146
  if show_out:
144
147
  log2(r.stdout)
145
148
  log2(r.stderr)
146
149
 
147
150
  return r
148
151
  else:
149
- ns = self.namespace
150
- pod_name = Config().get('pg.agent.name', 'ops-pg-agent')
152
+ pod_name, container_name = PostgresContext.pod_and_container(self.namespace)
153
+ if not pod_name:
154
+ return
155
+
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
175
+
176
+ cmd = f'psql -h {self.endpoint()} -p {self.port()} -U {self.username()} {db} --pset pager=off -c "{sql}"'
177
+ env_prefix = f'PGPASSWORD="{self.password()}"'
178
+
179
+ r = Pods.exec(pod_name, container_name, self.namespace, cmd, show_out=show_out, background=background, env_prefix=env_prefix)
180
+ if r and Config().get('repl.history.push-cat-remote-log-file', True):
181
+ if r.log_file and ReplSession().prompt_session:
182
+ ReplSession().prompt_session.history.append_string(f'@{r.pod} cat {r.log_file}')
183
+
184
+ return r
185
+
186
+ def pod_and_container(ns: str):
187
+ container_name = Config().get('pg.agent.name', 'ops-pg-agent')
151
188
 
152
- if Config().get('pg.agent.just-in-time', False):
153
- if not PostgresContext.deploy_pg_agent(pod_name, ns):
154
- return
189
+ if Config().get('pg.agent.just-in-time', False):
190
+ if not PostgresContext.deploy_pg_agent(container_name, ns):
191
+ return None
155
192
 
156
- real_pod_name = pod_name
193
+ pod_name = container_name
194
+ try:
195
+ # try with dedicated pg agent pod name configured
196
+ Pods.get(ns, container_name)
197
+ except:
157
198
  try:
158
- # try with dedicated pg agent pod name configured
159
- Pods.get(ns, pod_name)
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
160
202
  except:
161
- try:
162
- # try with the ops pod
163
- pod_name = Config().get('pod.name', 'ops')
164
- real_pod_name = Pods.get_with_selector(ns, label_selector = Config().get('pod.label-selector', 'run=ops')).metadata.name
165
- except:
166
- log2(f"Could not locate {pod_name} pod.")
167
- return None
168
-
169
- cmd = f'PGPASSWORD="{self.password()}" psql -h {self.endpoint()} -p {self.port()} -U {self.username()} {db} --pset pager=off -c "{sql}"'
203
+ log2(f"Could not locate {container_name} pod.")
204
+ return None
170
205
 
171
- return Pods.exec(real_pod_name, pod_name, ns, cmd, show_out=show_out)
206
+ return pod_name, container_name
172
207
 
173
208
  def deploy_pg_agent(pod_name: str, ns: str) -> str:
174
209
  image = Config().get('pg.agent.image', 'seanahnsf/kaqing')
@@ -178,11 +213,9 @@ class PostgresContext:
178
213
  except Exception as e:
179
214
  if e.status == 409:
180
215
  if Pods.completed(ns, pod_name):
181
- try:
216
+ with log_exc(lambda e2: "Exception when calling BatchV1Api->create_pod: %s\n" % e2):
182
217
  Pods.delete(pod_name, ns)
183
218
  Pods.create(ns, pod_name, image, ['sleep', f'{timeout}'], env={'NAMESPACE': ns}, sa_name='c3')
184
- except Exception as e2:
185
- log2("Exception when calling BatchV1Api->create_pod: %s\n" % e2)
186
219
 
187
220
  return
188
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:
@@ -4,7 +4,6 @@ from adam.repl_state import ReplState, RequiredState
4
4
 
5
5
  class PostgresPreview(Command):
6
6
  COMMAND = 'pg preview'
7
- reaper_login = None
8
7
 
9
8
  # the singleton pattern
10
9
  def __new__(cls, *args, **kwargs):
@@ -19,21 +18,18 @@ class PostgresPreview(Command):
19
18
  return PostgresPreview.COMMAND
20
19
 
21
20
  def required(self):
22
- return RequiredState.NAMESPACE
21
+ return RequiredState.PG_DATABASE
23
22
 
24
23
  def run(self, cmd: str, state: ReplState):
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, RequiredState.PG_DATABASE):
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
- PreviewTable().run(f'preview {" ".join(args)}', state)
30
+ PreviewTable().run(f'preview {" ".join(args)}', state)
35
31
 
36
- return state
32
+ return state
37
33
 
38
34
  def completion(self, state: ReplState):
39
35
  if state.sts:
@@ -1,4 +1,4 @@
1
- from adam.commands.postgres.postgres_utils import pg_table_names
1
+ from adam.commands.postgres.utils_postgres import pg_table_names
2
2
  from adam.sql.sql_completer import SqlCompleter
3
3
 
4
4
  def psql_completions(ns: str, pg_path: str):
@@ -0,0 +1,66 @@
1
+ import functools
2
+
3
+ from adam.commands.postgres.postgres_context import PostgresContext
4
+ from adam.repl_state import ReplState
5
+ from adam.utils import log2, wait_log
6
+ from adam.utils_k8s.pods import Pods
7
+
8
+ TestPG = [False]
9
+
10
+ @functools.lru_cache()
11
+ def pg_database_names(ns: str, pg_path: str):
12
+ if TestPG[0]:
13
+ return ['azops88_c3ai_c3']
14
+
15
+ wait_log('Inspecting Postgres Databases...')
16
+
17
+ pg = PostgresContext.apply(ns, pg_path)
18
+ return [db['name'] for db in pg.databases() if db['owner'] == PostgresContext.default_owner()]
19
+
20
+ @functools.lru_cache()
21
+ def pg_table_names(ns: str, pg_path: str):
22
+ if TestPG[0]:
23
+ return ['C3_2_XYZ1']
24
+
25
+ wait_log('Inspecting Postgres Database...')
26
+ return [table['name'] for table in pg_tables(ns, pg_path) if table['schema'] == PostgresContext.default_schema()]
27
+
28
+ def pg_tables(ns: str, pg_path: str):
29
+ pg = PostgresContext.apply(ns, pg_path)
30
+ if pg.db:
31
+ return pg.tables()
32
+
33
+ return []
34
+
35
+ class PostgresPodService:
36
+ def __init__(self, handler: 'PostgresExecHandler'):
37
+ self.handler = handler
38
+
39
+ def exec(self, command: str, show_out=True):
40
+ state = self.handler.state
41
+
42
+ pod, container = PostgresContext.pod_and_container(state.namespace)
43
+ if not pod:
44
+ log2('Cannot locate postgres agent or ops pod.')
45
+ return state
46
+
47
+ return Pods.exec(pod, container, state.namespace, command, show_out=show_out)
48
+
49
+ def sql(self, args: list[str], background=False):
50
+ state = self.handler.state
51
+
52
+ PostgresContext.apply(state.namespace, state.pg_path).run_sql(' '.join(args), background=background)
53
+
54
+ class PostgresExecHandler:
55
+ def __init__(self, state: ReplState, background=False):
56
+ self.state = state
57
+ self.background = background
58
+
59
+ def __enter__(self):
60
+ return PostgresPodService(self)
61
+
62
+ def __exit__(self, exc_type, exc_val, exc_tb):
63
+ return False
64
+
65
+ def postgres(state: ReplState, background=False):
66
+ return PostgresExecHandler(state, background=background)
@@ -1,11 +1,6 @@
1
1
  from adam.commands.command import Command
2
- from adam.commands.cql.cql_utils import cassandra_table_names, run_cql
3
- from adam.commands.postgres.postgres_context import PostgresContext
4
- from adam.config import Config
2
+ from adam.commands.devices.devices import Devices
5
3
  from adam.repl_state import ReplState, RequiredState
6
- from adam.utils import lines_to_tabular, log, log2
7
- from adam.utils_athena import Athena
8
- from adam.utils_audits import Audits
9
4
 
10
5
  class PreviewTable(Command):
11
6
  COMMAND = 'preview'
@@ -29,47 +24,13 @@ class PreviewTable(Command):
29
24
  if not(args := self.args(cmd)):
30
25
  return super().run(cmd, state)
31
26
 
32
- state, args = self.apply_state(args, state)
33
- if not self.validate_state(state):
34
- return state
35
-
36
- if not args:
37
- def show_tables():
38
- if state.device == ReplState.P:
39
- pg = PostgresContext.apply(state.namespace, state.pg_path)
40
- lines = [db["name"] for db in pg.tables() if db["schema"] == PostgresContext.default_schema()]
41
- log(lines_to_tabular(lines, separator=','))
42
- elif state.device == ReplState.L:
43
- log(lines_to_tabular(Athena.table_names(), separator=','))
44
- else:
45
- log(lines_to_tabular(cassandra_table_names(state), separator=','))
46
-
47
- if state.in_repl:
48
- log2('Table is required.')
49
- log2()
50
- log2('Tables:')
51
- show_tables()
52
- else:
53
- log2('* Table is missing.')
54
- show_tables()
55
-
56
- Command.display_help()
27
+ with self.validate(args, state) as (args, state):
28
+ Devices.device(state).preview(args[0] if args else None, state)
57
29
 
58
- return 'command-missing'
59
-
60
- table = args[0]
61
-
62
- rows = Config().get('preview.rows', 10)
63
- if state.device == ReplState.P:
64
- PostgresContext.apply(state.namespace, state.pg_path).run_sql(f'select * from {table} limit {rows}')
65
- elif state.device == ReplState.L:
66
- Athena.run_query(f'select * from {table} limit {rows}')
67
- else:
68
- run_cql(state, f'select * from {table} limit {rows}', show_out=True, use_single_quotes=True, on_any=True)
69
-
70
- return state
30
+ return state
71
31
 
72
32
  def completion(self, _: ReplState):
33
+ # taken care of by the sql completer
73
34
  return {}
74
35
 
75
36
  def help(self, _: ReplState):
adam/commands/pwd.py CHANGED
@@ -1,8 +1,8 @@
1
1
  from adam.app_session import AppSession
2
2
  from adam.commands.command import Command
3
- from adam.commands.postgres.postgres_context import PostgresContext
3
+ from adam.commands.devices.devices import Devices
4
4
  from adam.repl_state import ReplState
5
- from adam.utils import lines_to_tabular, log
5
+ from adam.utils import lines_to_tabular, log, log_exc
6
6
 
7
7
  class Pwd(Command):
8
8
  COMMAND = 'pwd'
@@ -23,53 +23,20 @@ class Pwd(Command):
23
23
  if not(args := self.args(cmd)):
24
24
  return super().run(cmd, state)
25
25
 
26
- state, _ = self.apply_state(args, state)
26
+ with self.validate(args, state) as (_, state):
27
+ host = "unknown"
28
+ with log_exc():
29
+ app_session: AppSession = AppSession.create('c3', 'c3')
30
+ host = app_session.host
27
31
 
28
- def device_line(state: ReplState, device: str):
29
- words = []
32
+ log(lines_to_tabular([device.pwd(state) for device in Devices.all()] + [
33
+ f'',
34
+ f'HOST\t{host}',
35
+ f'NAMESPACE\t{state.namespace if state.namespace else "/"}',
36
+ ], 'DEVICE\tLOCATION', separator='\t'))
37
+ log()
30
38
 
31
- if device == ReplState.P:
32
- pg: PostgresContext = PostgresContext.apply(state.namespace, state.pg_path)
33
-
34
- if pg.host:
35
- words.append(f'host/{pg.host}')
36
- if pg.db:
37
- words.append(f'database/{pg.db}')
38
- elif device == ReplState.A:
39
- if state.app_env:
40
- words.append(f'env/{state.app_env}')
41
- if state.app_app:
42
- words.append(f'app/{state.app_app}')
43
- elif device in [ReplState.L, ReplState.X]:
44
- pass
45
- else:
46
- if state.sts:
47
- words.append(f'sts/{state.sts}')
48
- if state.pod:
49
- words.append(f'pod/{state.pod}')
50
-
51
- return '\t'.join([f'{device}:>'] + (words if words else ['/']))
52
-
53
- host = "unknown"
54
- try:
55
- app_session: AppSession = AppSession.create('c3', 'c3')
56
- host = app_session.host
57
- except:
58
- pass
59
-
60
- log(lines_to_tabular([
61
- device_line(state, ReplState.A),
62
- device_line(state, ReplState.C),
63
- device_line(state, ReplState.L),
64
- device_line(state, ReplState.P),
65
- device_line(state, ReplState.X),
66
- f'',
67
- f'HOST\t{host}',
68
- f'NAMESPACE\t{state.namespace if state.namespace else "/"}',
69
- ], 'DEVICE\tLOCATION', separator='\t'))
70
- log()
71
-
72
- return state
39
+ return state
73
40
 
74
41
  def completion(self, state: ReplState):
75
42
  return super().completion(state)
@@ -1,6 +1,6 @@
1
1
  import click
2
2
 
3
- from adam.commands.command import Command
3
+ from adam.commands.intermediate_command import IntermediateCommand
4
4
  from .reaper_forward import ReaperForward
5
5
  from .reaper_forward_stop import ReaperForwardStop
6
6
  from .reaper_restart import ReaperRestart
@@ -12,11 +12,9 @@ from .reaper_schedule_start import ReaperScheduleStart
12
12
  from .reaper_schedule_stop import ReaperScheduleStop
13
13
  from .reaper_schedules import ReaperSchedules
14
14
  from .reaper_status import ReaperStatus
15
- from adam.repl_state import ReplState, RequiredState
16
15
 
17
- class Reaper(Command):
16
+ class Reaper(IntermediateCommand):
18
17
  COMMAND = 'reaper'
19
- reaper_login = None
20
18
 
21
19
  # the singleton pattern
22
20
  def __new__(cls, *args, **kwargs):
@@ -24,35 +22,14 @@ class Reaper(Command):
24
22
 
25
23
  return cls.instance
26
24
 
27
- def __init__(self, successor: Command=None):
28
- super().__init__(successor)
29
-
30
25
  def command(self):
31
26
  return Reaper.COMMAND
32
27
 
33
- def required(self):
34
- return RequiredState.CLUSTER
35
-
36
- def run(self, cmd: str, state: ReplState):
37
- if not(args := self.args(cmd)):
38
- return super().run(cmd, state)
39
-
40
- if not self.validate_state(state):
41
- return state
42
-
43
- return super().intermediate_run(cmd, state, args, Reaper.cmd_list())
44
-
45
- def cmd_list():
28
+ def cmd_list(self):
46
29
  return [ReaperSchedules(), ReaperScheduleStop(), ReaperScheduleActivate(), ReaperScheduleStart(),
47
30
  ReaperForwardStop(), ReaperForward(), ReaperRunAbort(), ReaperRunsAbort(), ReaperRestart(),
48
31
  ReaperRuns(), ReaperStatus()]
49
32
 
50
- def completion(self, state: ReplState):
51
- if state.sts:
52
- return super().completion(state)
53
-
54
- return {}
55
-
56
33
  class ReaperCommandHelper(click.Command):
57
34
  def get_help(self, ctx: click.Context):
58
- Command.intermediate_help(super().get_help(ctx), Reaper.COMMAND, Reaper.cmd_list(), show_cluster_help=True)
35
+ IntermediateCommand.intermediate_help(super().get_help(ctx), Reaper.COMMAND, Reaper().cmd_list(), show_cluster_help=True)