kaqing 2.0.50__py3-none-any.whl → 2.0.110__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 (123) hide show
  1. adam/apps.py +2 -2
  2. adam/batch.py +11 -15
  3. adam/checks/check_utils.py +4 -4
  4. adam/checks/compactionstats.py +1 -1
  5. adam/checks/cpu.py +2 -2
  6. adam/checks/disk.py +1 -1
  7. adam/checks/gossip.py +1 -1
  8. adam/checks/memory.py +3 -3
  9. adam/checks/status.py +1 -1
  10. adam/commands/alter_tables.py +3 -14
  11. adam/commands/app.py +2 -2
  12. adam/commands/app_ping.py +2 -2
  13. adam/commands/audit/audit.py +85 -0
  14. adam/commands/audit/audit_repair_tables.py +76 -0
  15. adam/commands/audit/audit_run.py +57 -0
  16. adam/commands/audit/show_last10.py +50 -0
  17. adam/commands/audit/show_slow10.py +49 -0
  18. adam/commands/audit/show_top10.py +48 -0
  19. adam/commands/audit/utils_show_top10.py +59 -0
  20. adam/commands/bash.py +76 -13
  21. adam/commands/cd.py +22 -13
  22. adam/commands/check.py +6 -0
  23. adam/commands/cli_commands.py +3 -3
  24. adam/commands/command.py +15 -11
  25. adam/commands/commands_utils.py +4 -5
  26. adam/commands/cql/cql_completions.py +7 -5
  27. adam/commands/cql/cql_utils.py +13 -10
  28. adam/commands/cql/cqlsh.py +6 -3
  29. adam/commands/deploy/code_utils.py +2 -2
  30. adam/commands/deploy/deploy.py +7 -1
  31. adam/commands/deploy/deploy_pg_agent.py +2 -2
  32. adam/commands/deploy/deploy_pod.py +6 -6
  33. adam/commands/deploy/deploy_utils.py +2 -2
  34. adam/commands/deploy/undeploy.py +7 -1
  35. adam/commands/deploy/undeploy_pg_agent.py +2 -2
  36. adam/commands/deploy/undeploy_pod.py +4 -4
  37. adam/commands/devices.py +29 -0
  38. adam/commands/help.py +10 -7
  39. adam/commands/issues.py +6 -0
  40. adam/commands/login.py +6 -3
  41. adam/commands/logs.py +2 -1
  42. adam/commands/ls.py +30 -24
  43. adam/commands/medusa/medusa_backup.py +2 -2
  44. adam/commands/medusa/medusa_restore.py +2 -2
  45. adam/commands/medusa/medusa_show_backupjobs.py +3 -2
  46. adam/commands/medusa/medusa_show_restorejobs.py +2 -2
  47. adam/commands/nodetool.py +5 -3
  48. adam/commands/postgres/postgres.py +3 -3
  49. adam/commands/postgres/{postgres_session.py → postgres_context.py} +29 -30
  50. adam/commands/postgres/postgres_utils.py +5 -5
  51. adam/commands/postgres/psql_completions.py +2 -3
  52. adam/commands/preview_table.py +17 -32
  53. adam/commands/pwd.py +5 -2
  54. adam/commands/reaper/reaper.py +3 -0
  55. adam/commands/reaper/reaper_restart.py +1 -1
  56. adam/commands/reaper/reaper_session.py +1 -1
  57. adam/commands/repair/repair.py +3 -3
  58. adam/commands/repair/repair_log.py +1 -1
  59. adam/commands/repair/repair_run.py +2 -2
  60. adam/commands/repair/repair_scan.py +1 -1
  61. adam/commands/repair/repair_stop.py +1 -1
  62. adam/commands/report.py +6 -0
  63. adam/commands/restart.py +2 -2
  64. adam/commands/rollout.py +1 -1
  65. adam/commands/show/show.py +5 -2
  66. adam/commands/show/show_app_actions.py +3 -0
  67. adam/commands/show/show_app_id.py +1 -1
  68. adam/commands/show/show_app_queues.py +3 -2
  69. adam/commands/show/show_cassandra_status.py +3 -3
  70. adam/commands/show/show_cassandra_version.py +3 -3
  71. adam/commands/show/show_host.py +33 -0
  72. adam/commands/show/show_login.py +3 -0
  73. adam/commands/show/show_processes.py +1 -1
  74. adam/commands/show/show_repairs.py +2 -2
  75. adam/commands/show/show_storage.py +1 -1
  76. adam/commands/watch.py +1 -1
  77. adam/config.py +2 -1
  78. adam/embedded_params.py +1 -1
  79. adam/pod_exec_result.py +7 -2
  80. adam/repl.py +141 -89
  81. adam/repl_commands.py +21 -20
  82. adam/repl_state.py +167 -39
  83. adam/sql/sql_completer.py +89 -49
  84. adam/sql/sql_state_machine.py +518 -0
  85. adam/sql/term_completer.py +76 -0
  86. adam/sso/cred_cache.py +1 -1
  87. adam/sso/idp.py +1 -1
  88. adam/utils.py +0 -1
  89. adam/utils_audits.py +193 -0
  90. adam/{k8s_utils → utils_k8s}/cassandra_clusters.py +6 -8
  91. adam/{k8s_utils → utils_k8s}/cassandra_nodes.py +11 -4
  92. adam/{k8s_utils → utils_k8s}/deployment.py +2 -2
  93. adam/{k8s_utils → utils_k8s}/pods.py +33 -9
  94. adam/{k8s_utils → utils_k8s}/secrets.py +4 -0
  95. adam/{k8s_utils → utils_k8s}/statefulsets.py +4 -4
  96. adam/utils_net.py +24 -0
  97. adam/version.py +1 -1
  98. {kaqing-2.0.50.dist-info → kaqing-2.0.110.dist-info}/METADATA +1 -1
  99. kaqing-2.0.110.dist-info/RECORD +187 -0
  100. adam/commands/cql/cql_table_completer.py +0 -16
  101. adam/commands/describe/describe.py +0 -46
  102. adam/commands/describe/describe_keyspace.py +0 -60
  103. adam/commands/describe/describe_keyspaces.py +0 -50
  104. adam/commands/describe/describe_table.py +0 -60
  105. adam/commands/describe/describe_tables.py +0 -50
  106. adam/commands/postgres/psql_table_completer.py +0 -18
  107. adam/sql/any_completer.py +0 -84
  108. adam/sql/sql_utils.py +0 -5
  109. adam/sql/table_name_completer.py +0 -17
  110. kaqing-2.0.50.dist-info/RECORD +0 -185
  111. /adam/commands/{describe → audit}/__init__.py +0 -0
  112. /adam/{k8s_utils → utils_k8s}/__init__.py +0 -0
  113. /adam/{k8s_utils → utils_k8s}/config_maps.py +0 -0
  114. /adam/{k8s_utils → utils_k8s}/custom_resources.py +0 -0
  115. /adam/{k8s_utils → utils_k8s}/ingresses.py +0 -0
  116. /adam/{k8s_utils → utils_k8s}/jobs.py +0 -0
  117. /adam/{k8s_utils → utils_k8s}/kube_context.py +0 -0
  118. /adam/{k8s_utils → utils_k8s}/service_accounts.py +0 -0
  119. /adam/{k8s_utils → utils_k8s}/services.py +0 -0
  120. /adam/{k8s_utils → utils_k8s}/volumes.py +0 -0
  121. {kaqing-2.0.50.dist-info → kaqing-2.0.110.dist-info}/WHEEL +0 -0
  122. {kaqing-2.0.50.dist-info → kaqing-2.0.110.dist-info}/entry_points.txt +0 -0
  123. {kaqing-2.0.50.dist-info → kaqing-2.0.110.dist-info}/top_level.txt +0 -0
adam/commands/bash.py CHANGED
@@ -1,7 +1,10 @@
1
1
  from adam.commands.command import Command
2
- from adam.k8s_utils.cassandra_clusters import CassandraClusters
3
- from adam.k8s_utils.cassandra_nodes import CassandraNodes
2
+ from adam.utils_k8s.cassandra_clusters import CassandraClusters
3
+ from adam.utils_k8s.cassandra_nodes import CassandraNodes
4
+ from adam.pod_exec_result import PodExecResult
4
5
  from adam.repl_state import BashSession, ReplState, RequiredState
6
+ from adam.utils_repl.automata_completer import AutomataCompleter
7
+ from adam.utils_repl.state_machine import StateMachine
5
8
 
6
9
  class Bash(Command):
7
10
  COMMAND = 'bash'
@@ -25,12 +28,16 @@ class Bash(Command):
25
28
  if not(args := self.args(cmd)):
26
29
  return super().run(cmd, s0)
27
30
 
28
- state, args = self.apply_state(args, s0)
31
+ state, args = self.apply_state(args, s0, args_to_check=2)
29
32
  if not self.validate_state(state):
30
33
  return state
31
34
 
32
35
  if state.in_repl:
33
- r = self.exec_with_dir(s0, args)
36
+ if s0.sts != state.sts or s0.pod != state.pod:
37
+ r = self.exec_with_dir(state, args)
38
+ else:
39
+ r = self.exec_with_dir(s0, args)
40
+
34
41
  if not r:
35
42
  state.exit_bash()
36
43
 
@@ -38,8 +45,7 @@ class Bash(Command):
38
45
 
39
46
  return r
40
47
  else:
41
- a = ' '.join(args)
42
- command = f'bash -c "{a}"'
48
+ command = ' '.join(args)
43
49
 
44
50
  if state.pod:
45
51
  CassandraNodes.exec(state.pod, state.namespace, command, show_out=True)
@@ -48,7 +54,7 @@ class Bash(Command):
48
54
 
49
55
  return state
50
56
 
51
- def exec_with_dir(self, state: ReplState, args: list[str]):
57
+ def exec_with_dir(self, state: ReplState, args: list[str]) -> list[PodExecResult]:
52
58
  session_just_created = False
53
59
  if not args:
54
60
  session_just_created = True
@@ -65,23 +71,80 @@ class Bash(Command):
65
71
  if pwd := state.bash_session.pwd(state):
66
72
  args = ['cd', pwd, '&&'] + args
67
73
 
68
- a = ' '.join(args)
69
- command = f'bash -c "{a}"'
74
+ command = ' '.join(args)
70
75
 
71
76
  rs = []
72
77
 
73
78
  if state.pod:
74
- rs = [CassandraNodes.exec(state.pod, state.namespace, command, show_out=not session_just_created)]
79
+ rs = [CassandraNodes.exec(state.pod, state.namespace, command,
80
+ show_out=not session_just_created, shell='bash')]
75
81
  elif state.sts:
76
- rs = CassandraClusters.exec(state.sts, state.namespace, command, action='bash', show_out=not session_just_created)
82
+ rs = CassandraClusters.exec(state.sts, state.namespace, command, action='bash',
83
+ show_out=not session_just_created, shell='bash')
77
84
 
78
85
  return rs
79
86
 
80
87
  def completion(self, state: ReplState):
81
88
  if state.pod or state.sts:
82
- return {Bash.COMMAND: None}
89
+ return {Bash.COMMAND: AutomataCompleter(BashStateMachine())}
83
90
 
84
91
  return {}
85
92
 
86
93
  def help(self, _: ReplState):
87
- return f'{Bash.COMMAND} [bash-commands]\t run bash on the Cassandra nodes'
94
+ return f'{Bash.COMMAND} [bash-commands]\t run bash on the Cassandra nodes'
95
+
96
+ BASH_SPEC = [
97
+ # <command> ::= <simple_command> | <pipeline> | <conditional_command>
98
+ # <simple_command> ::= <word> <argument>* <redirection>*
99
+ # <pipeline> ::= <command> '|' <command>
100
+ # <conditional_command> ::= <command> '&&' <command> | <command> '||' <command>
101
+ # <word> ::= <letter> <letter_or_digit>*
102
+ # <argument> ::= <word>
103
+ # <redirection> ::= '>' <filename> | '<' <filename>
104
+ # <filename> ::= <word>
105
+ # <letter> ::= 'a' | 'b' | ... | 'z' | 'A' | 'B' | ... | 'Z'
106
+ # <digit> ::= '0' | '1' | ... | '9'
107
+ # <letter_or_digit> ::= <letter> | <digit>
108
+
109
+ ' > word > word',
110
+ 'word > word > word ^ |,>,2>,<,&,&&,||',
111
+ '- > pipe > word_pipe',
112
+ '- > _rdr0_ > word_rdr0',
113
+ '- > _rdr1_ > word_rdr1',
114
+ '- > _rdr2_ > word_rdr2',
115
+ '- > & > word_bg ^ |,>,2>,<,&,&&,||',
116
+ '- > &&|_or_ > word',
117
+ 'word_a > word > word',
118
+ 'word_pipe > word > word',
119
+ 'word_rdr0 > word > word_rdr0_f',
120
+ 'word_rdr1 > word > word_rdr1_f',
121
+ 'word_rdr2 > word > word_rdr2_f',
122
+ 'word_rdr1_f > pipe > word_pipe ^ |,2>,<,&,&&,||',
123
+ '- > _rdr2_ > word_rdr2',
124
+ '- > _rdr0_ > word_rdr0',
125
+ 'word_rdr2_f > pipe > word_pipe ^ |,<,&,&&,||',
126
+ '- > _rdr0_ > word_rdr0',
127
+ '- > & > word_bg ^ |,>,2>,<,&,&&,||',
128
+ '- > &&|_or_ > word',
129
+ 'word_rdr0_f > pipe > word_pipe ^ |,&,&&,||',
130
+ '- > & > word_bg ^ |,>,2>,<,&,&&,||',
131
+ '- > &&|_or_ > word',
132
+ 'word_bg > &&|_or_ > ^ &&,||',
133
+ ]
134
+
135
+ BASH_KEYWORDS = [
136
+ '&',
137
+ '&&',
138
+ '|',
139
+ '||',
140
+ '>',
141
+ '2>',
142
+ '>>',
143
+ '<'
144
+ ]
145
+ class BashStateMachine(StateMachine[str]):
146
+ def spec(self) -> str:
147
+ return BASH_SPEC
148
+
149
+ def keywords(self) -> list[str]:
150
+ return BASH_KEYWORDS
adam/commands/cd.py CHANGED
@@ -1,9 +1,9 @@
1
1
  from adam.commands.command import Command
2
2
  from adam.commands.postgres.postgres_utils import pg_database_names
3
- from adam.commands.postgres.postgres_session import PostgresSession
4
- from adam.k8s_utils.cassandra_clusters import CassandraClusters
5
- from adam.k8s_utils.kube_context import KubeContext
6
- from adam.k8s_utils.statefulsets import StatefulSets
3
+ from adam.commands.postgres.postgres_context import PostgresContext
4
+ from adam.utils_k8s.cassandra_clusters import CassandraClusters
5
+ from adam.utils_k8s.kube_context import KubeContext
6
+ from adam.utils_k8s.statefulsets import StatefulSets
7
7
  from adam.repl_state import ReplState
8
8
  from adam.utils import log2
9
9
  from adam.apps import Apps
@@ -23,10 +23,16 @@ class Cd(Command):
23
23
  def command(self):
24
24
  return Cd.COMMAND
25
25
 
26
+ def required(self):
27
+ return ReplState.NON_L
28
+
26
29
  def run(self, cmd: str, state: ReplState):
27
30
  if not(args := self.args(cmd)):
28
31
  return super().run(cmd, state)
29
32
 
33
+ if not self.validate_state(state):
34
+ return state
35
+
30
36
  if len(args) < 2:
31
37
  return state
32
38
 
@@ -36,11 +42,11 @@ class Cd(Command):
36
42
  if dir == '':
37
43
  state.pg_path = None
38
44
  else:
39
- session = PostgresSession(state.namespace, state.pg_path)
45
+ context: PostgresContext = PostgresContext.apply(state.namespace, state.pg_path, arg=dir)
40
46
  # patch up state.namespace from pg cd
41
- if not state.namespace and (ns := session.find_namespace(arg)):
42
- state.namespace = ns
43
- state.pg_path = session.directory(arg)
47
+ if not state.namespace and context.namespace:
48
+ state.namespace = context.namespace
49
+ state.pg_path = context.path()
44
50
  elif state.device == ReplState.A:
45
51
  if dir == '':
46
52
  state.app_env = None
@@ -59,6 +65,8 @@ class Cd(Command):
59
65
  state.app_env = dir.split('@')[0]
60
66
  else:
61
67
  state.app_app = dir
68
+ elif state.device == ReplState.L:
69
+ pass
62
70
  else:
63
71
  if dir == '':
64
72
  state.sts = None
@@ -72,7 +80,8 @@ class Cd(Command):
72
80
  if not state.sts:
73
81
  ss_and_ns = dir.split('@')
74
82
  state.sts = ss_and_ns[0]
75
- state.namespace = ss_and_ns[1]
83
+ if len(ss_and_ns) > 1:
84
+ state.namespace = ss_and_ns[1]
76
85
  elif not state.pod:
77
86
  p, _ = KubeContext.is_pod_name(dir)
78
87
  if p:
@@ -88,13 +97,13 @@ class Cd(Command):
88
97
 
89
98
  def completion(self, state: ReplState):
90
99
  if state.device == ReplState.P:
91
- pg = PostgresSession(state.namespace, state.pg_path) if state.pg_path else None
100
+ pg: PostgresContext = PostgresContext.apply(state.namespace, state.pg_path) if state.pg_path else None
92
101
  if pg and pg.db:
93
102
  return {Cd.COMMAND: {'..': None}}
94
103
  elif pg and pg.host:
95
- return {Cd.COMMAND: {'..': None} | {p: None for p in pg_database_names(state.namespace, pg.directory())}}
104
+ return {Cd.COMMAND: {'..': None} | {p: None for p in pg_database_names(state.namespace, pg.path())}}
96
105
  else:
97
- return {Cd.COMMAND: {p: None for p in PostgresSession.hosts(state.namespace)}}
106
+ return {Cd.COMMAND: {p: None for p in PostgresContext.hosts(state.namespace)}}
98
107
  elif state.device == ReplState.A:
99
108
  if state.app_app:
100
109
  return {Cd.COMMAND: {'..': None}}
@@ -102,7 +111,7 @@ class Cd(Command):
102
111
  return {Cd.COMMAND: {'..': None} | {app[0].split('-')[1]: None for app in Apps.apps(state.app_env)}}
103
112
  else:
104
113
  return {Cd.COMMAND: {'..': None} | {env[0]: None for env in Apps.envs()}}
105
- else:
114
+ elif state.device == ReplState.C:
106
115
  if state.pod:
107
116
  return {Cd.COMMAND: {'..': None}}
108
117
  elif state.sts:
adam/commands/check.py CHANGED
@@ -23,11 +23,17 @@ class Check(Issues):
23
23
  def command(self):
24
24
  return Check.COMMAND
25
25
 
26
+ def required(self):
27
+ return ReplState.NON_L
28
+
26
29
  def run(self, cmd: str, state: ReplState):
27
30
  if not(args := self.args(cmd)):
28
31
  return super().run(cmd, state)
29
32
 
30
33
  state, args = self.apply_state(args, state)
34
+ if not self.validate_state(state):
35
+ return state
36
+
31
37
  args, show = Command.extract_options(args, ['-s', '--show'])
32
38
 
33
39
  if not args:
@@ -3,9 +3,9 @@ import re
3
3
 
4
4
  from adam.commands.reaper.reaper_session import ReaperSession
5
5
  from adam.config import Config
6
- from adam.k8s_utils.kube_context import KubeContext
7
- from adam.k8s_utils.secrets import Secrets
8
- from adam.k8s_utils.statefulsets import StatefulSets
6
+ from adam.utils_k8s.kube_context import KubeContext
7
+ from adam.utils_k8s.secrets import Secrets
8
+ from adam.utils_k8s.statefulsets import StatefulSets
9
9
  from adam.repl_state import ReplState
10
10
 
11
11
  class CliCommands:
adam/commands/command.py CHANGED
@@ -2,7 +2,6 @@ from abc import abstractmethod
2
2
  import copy
3
3
  import subprocess
4
4
  import sys
5
- from typing import Callable
6
5
 
7
6
  from adam.commands.command_helpers import ClusterCommandHelper
8
7
  from adam.repl_state import ReplState, RequiredState
@@ -29,8 +28,10 @@ class Command:
29
28
 
30
29
  return None
31
30
 
32
- def completion(self, _: ReplState, leaf: dict[str, any] = None) -> dict[str, any]:
33
- # COMMAND = 'reaper activate schedule'
31
+ def completion(self, state: ReplState, leaf: dict[str, any] = None) -> dict[str, any]:
32
+ if not self.validate_state(state, show_err=False):
33
+ return {}
34
+
34
35
  d = leaf
35
36
  for t in reversed(self.command().split(' ')):
36
37
  d = {t: d}
@@ -40,8 +41,8 @@ class Command:
40
41
  def required(self) -> RequiredState:
41
42
  return None
42
43
 
43
- def validate_state(self, state: ReplState, pg_required: RequiredState = None, app_required: RequiredState = None):
44
- return state.validate(self.required(), pg_required=pg_required, app_required=app_required)
44
+ def validate_state(self, state: ReplState, show_err=True):
45
+ return state.validate(self.required(), show_err=show_err)
45
46
 
46
47
  def help(self, _: ReplState) -> str:
47
48
  return None
@@ -54,8 +55,8 @@ class Command:
54
55
 
55
56
  return a
56
57
 
57
- def apply_state(self, args: list[str], state: ReplState, resolve_pg = True) -> tuple[ReplState, list[str]]:
58
- return state.apply_args(args, cmd=self.command_tokens(), resolve_pg=resolve_pg)
58
+ def apply_state(self, args: list[str], state: ReplState, resolve_pg = True, args_to_check = 6) -> tuple[ReplState, list[str]]:
59
+ return state.apply_args(args, cmd=self.command_tokens(), resolve_pg=resolve_pg, args_to_check=args_to_check)
59
60
 
60
61
  def command_tokens(self):
61
62
  return self.command().split(' ')
@@ -105,19 +106,22 @@ class Command:
105
106
  cmd = s
106
107
  print()
107
108
 
108
- def intermediate_run(self, cmd: str, state: ReplState, args: list[str], cmds: list['Command'], separator='\t'):
109
+ def intermediate_run(self, cmd: str, state: ReplState, args: list[str], cmds: list['Command'], separator='\t', display_help=True):
109
110
  state, _ = self.apply_state(args, state)
110
111
 
111
112
  if state.in_repl:
112
- log(lines_to_tabular([c.help(state) for c in cmds], separator=separator))
113
+ if display_help:
114
+ log(lines_to_tabular([c.help(state) for c in cmds], separator=separator))
113
115
 
114
116
  return 'command-missing'
115
117
  else:
116
118
  # head with the Chain of Responsibility pattern
117
119
  cmds = Command.chain(cmds)
118
120
  if not cmds.run(cmd, state):
119
- log2('* Command is missing.')
120
- Command.display_help()
121
+ if display_help:
122
+ log2('* Command is missing.')
123
+ Command.display_help()
124
+ return 'command-missing'
121
125
 
122
126
  return state
123
127
 
@@ -1,16 +1,15 @@
1
1
  from concurrent.futures import ThreadPoolExecutor
2
- import time
3
2
  from kubernetes import client
4
3
  from typing import List
5
4
 
6
5
  from adam.checks.check_utils import run_checks
7
6
  from adam.columns.columns import Columns, collect_checks
8
7
  from adam.commands.issues import Issues
9
- from adam.k8s_utils.cassandra_nodes import CassandraNodes
10
- from adam.k8s_utils.pods import Pods
11
- from adam.k8s_utils.statefulsets import StatefulSets
8
+ from adam.utils_k8s.cassandra_nodes import CassandraNodes
9
+ from adam.utils_k8s.pods import Pods
10
+ from adam.utils_k8s.statefulsets import StatefulSets
12
11
  from adam.repl_state import ReplState
13
- from adam.utils import convert_seconds, duration, lines_to_tabular, log, log2
12
+ from adam.utils import duration, lines_to_tabular, log, log2
14
13
 
15
14
  def show_pods(pods: List[client.V1Pod], ns: str, show_namespace = True, show_host_id = True):
16
15
  if len(pods) == 0:
@@ -1,13 +1,15 @@
1
- from adam.commands.cql.cql_table_completer import CqlTableNameCompleter
2
- from adam.commands.cql.cql_utils import table_names
1
+ from adam.commands.cql.cql_utils import cassandra_table_names
2
+ from adam.config import Config
3
3
  from adam.repl_state import ReplState
4
4
  from adam.sql.sql_completer import SqlCompleter
5
5
 
6
6
  def cql_completions(state: ReplState) -> dict[str, any]:
7
- table_name_completer = CqlTableNameCompleter(table_names(state))
7
+ ps = Config().get('cql.alter-tables.gc-grace-periods', '3600,86400,864000,7776000').split(',')
8
8
  return {
9
9
  'describe': {
10
10
  'keyspaces': None,
11
- 'table': table_name_completer,
11
+ 'table': {t: None for t in cassandra_table_names(state)},
12
12
  'tables': None},
13
- } | SqlCompleter.completions(table_name_completer)
13
+ } | SqlCompleter(lambda: cassandra_table_names(state), table_props=lambda: {
14
+ 'GC_GRACE_SECONDS': ps
15
+ }, variant='cql').completions_for_nesting()
@@ -2,16 +2,19 @@ import functools
2
2
  import re
3
3
 
4
4
  from adam.config import Config
5
- from adam.k8s_utils.cassandra_clusters import CassandraClusters
6
- from adam.k8s_utils.cassandra_nodes import CassandraNodes
7
- from adam.k8s_utils.secrets import Secrets
5
+ from adam.utils_k8s.cassandra_clusters import CassandraClusters
6
+ from adam.utils_k8s.cassandra_nodes import CassandraNodes
7
+ from adam.utils_k8s.secrets import Secrets
8
8
  from adam.pod_exec_result import PodExecResult
9
9
  from adam.repl_state import ReplState
10
10
  from adam.utils import log2
11
11
 
12
12
  @functools.lru_cache()
13
13
  def keyspaces(state: ReplState, on_any=False):
14
- Config().wait_log('Inspecting Cassandra Keyspaces...')
14
+ if state.pod:
15
+ Config().wait_log(f'Inspecting Cassandra Keyspaces on {state.pod}...')
16
+ else:
17
+ Config().wait_log(f'Inspecting Cassandra Keyspaces...')
15
18
 
16
19
  r: list[PodExecResult] = run_cql(state, 'describe keyspaces', show_out=False, on_any=on_any)
17
20
  if not r:
@@ -20,19 +23,19 @@ def keyspaces(state: ReplState, on_any=False):
20
23
 
21
24
  return parse_cql_desc_keyspaces(r.stdout if state.pod else r[0].stdout)
22
25
 
23
- def table_names(state: ReplState):
26
+ def cassandra_table_names(state: ReplState):
24
27
  return [f'{k}.{t}' for k, ts in tables(state, on_any=True).items() for t in ts]
25
28
 
26
29
  @functools.lru_cache()
27
- def tables(state: ReplState, on_any=False):
30
+ def tables(state: ReplState, on_any=False) -> dict[str, list[str]]:
28
31
  r: list[PodExecResult] = run_cql(state, 'describe tables', show_out=False, on_any=on_any)
29
32
  if not r:
30
33
  log2('No pod is available')
31
- return []
34
+ return {}
32
35
 
33
36
  return parse_cql_desc_tables(r.stdout if state.pod else r[0].stdout)
34
37
 
35
- def run_cql(state: ReplState, cql: str, opts: list = [], show_out = False, use_single_quotes = False, on_any = False):
38
+ def run_cql(state: ReplState, cql: str, opts: list = [], show_out = False, use_single_quotes = False, on_any = False, background=False) -> list[PodExecResult]:
36
39
  user, pw = Secrets.get_user_pass(state.sts if state.sts else state.pod, state.namespace, secret_path='cql.secret')
37
40
  if use_single_quotes:
38
41
  command = f"cqlsh -u {user} -p {pw} {' '.join(opts)} -e '{cql}'"
@@ -40,9 +43,9 @@ def run_cql(state: ReplState, cql: str, opts: list = [], show_out = False, use_s
40
43
  command = f'cqlsh -u {user} -p {pw} {" ".join(opts)} -e "{cql}"'
41
44
 
42
45
  if state.pod:
43
- return CassandraNodes.exec(state.pod, state.namespace, command, show_out=show_out)
46
+ return CassandraNodes.exec(state.pod, state.namespace, command, show_out=show_out, background=background)
44
47
  else:
45
- return CassandraClusters.exec(state.sts, state.namespace, command, show_out=show_out, action='cql', on_any=on_any)
48
+ return CassandraClusters.exec(state.sts, state.namespace, command, show_out=show_out, action='cql', on_any=on_any, background=background)
46
49
 
47
50
  def parse_cql_desc_tables(out: str):
48
51
  # Keyspace data_endpoint_auth
@@ -3,7 +3,7 @@ import click
3
3
  from adam.commands.command import Command
4
4
  from adam.commands.command_helpers import ClusterOrPodCommandHelper
5
5
  from adam.commands.cql.cql_completions import cql_completions
6
- from .cql_utils import run_cql, table_names
6
+ from .cql_utils import run_cql, cassandra_table_names
7
7
  from adam.repl_state import ReplState, RequiredState
8
8
  from adam.utils import log, log2
9
9
 
@@ -33,11 +33,14 @@ class Cqlsh(Command):
33
33
  if not self.validate_state(state):
34
34
  return state
35
35
 
36
+ background = False
36
37
  opts = []
37
38
  cqls = []
38
- for arg in args:
39
+ for index, arg in enumerate(args):
39
40
  if arg.startswith('--'):
40
41
  opts.append(arg)
42
+ elif index == len(args) -1 and arg == '&':
43
+ background = True
41
44
  elif arg != '-e':
42
45
  cqls.append(arg)
43
46
  if not cqls:
@@ -51,7 +54,7 @@ class Cqlsh(Command):
51
54
  return 'no-cql'
52
55
 
53
56
  cql = ' '.join(cqls)
54
- return run_cql(state, cql, opts, show_out=True)
57
+ return run_cql(state, cql, opts, show_out=True, background=background)
55
58
 
56
59
  def completion(self, state: ReplState) -> dict[str, any]:
57
60
  if state.device != state.C:
@@ -5,8 +5,8 @@ import subprocess
5
5
 
6
6
  from adam.apps import Apps
7
7
  from adam.config import Config
8
- from adam.k8s_utils.ingresses import Ingresses
9
- from adam.k8s_utils.services import Services
8
+ from adam.utils_k8s.ingresses import Ingresses
9
+ from adam.utils_k8s.services import Services
10
10
  from adam.utils import log2, random_alphanumeric
11
11
 
12
12
  def start_user_code(namespace: str):
@@ -4,7 +4,7 @@ from adam.commands.command import Command
4
4
  from adam.commands.deploy.deploy_pg_agent import DeployPgAgent
5
5
  from adam.commands.deploy.deploy_pod import DeployPod
6
6
  from .deploy_frontend import DeployFrontend
7
- from adam.repl_state import ReplState
7
+ from adam.repl_state import ReplState, RequiredState
8
8
 
9
9
  class Deploy(Command):
10
10
  COMMAND = 'deploy'
@@ -22,10 +22,16 @@ class Deploy(Command):
22
22
  def command(self):
23
23
  return Deploy.COMMAND
24
24
 
25
+ def required(self):
26
+ return RequiredState.NAMESPACE
27
+
25
28
  def run(self, cmd: str, state: ReplState):
26
29
  if not(args := self.args(cmd)):
27
30
  return super().run(cmd, state)
28
31
 
32
+ if not self.validate_state(state):
33
+ return state
34
+
29
35
  return super().intermediate_run(cmd, state, args, Deploy.cmd_list())
30
36
 
31
37
  def cmd_list():
@@ -1,5 +1,5 @@
1
1
  from adam.commands.command import Command
2
- from adam.commands.postgres.postgres_session import PostgresSession
2
+ from adam.commands.postgres.postgres_context import PostgresContext
3
3
  from adam.config import Config
4
4
  from adam.repl_state import ReplState, RequiredState
5
5
 
@@ -29,7 +29,7 @@ class DeployPgAgent(Command):
29
29
  if not self.validate_state(state):
30
30
  return state
31
31
 
32
- PostgresSession.deploy_pg_agent(Config().get('pg.agent.name', 'ops-pg-agent'), state.namespace)
32
+ PostgresContext.deploy_pg_agent(Config().get('pg.agent.name', 'ops-pg-agent'), state.namespace)
33
33
 
34
34
  def completion(self, state: ReplState):
35
35
  return super().completion(state)
@@ -5,12 +5,12 @@ from adam.commands.command import Command
5
5
  from adam.commands.deploy.deploy_utils import creating, deploy_frontend, gen_labels
6
6
  from adam.commands.deploy.undeploy_pod import UndeployPod
7
7
  from adam.config import Config
8
- from adam.k8s_utils.config_maps import ConfigMaps
9
- from adam.k8s_utils.deployment import Deployments
10
- from adam.k8s_utils.kube_context import KubeContext
11
- from adam.k8s_utils.pods import Pods
12
- from adam.k8s_utils.service_accounts import ServiceAccounts
13
- from adam.k8s_utils.volumes import ConfigMapMount
8
+ from adam.utils_k8s.config_maps import ConfigMaps
9
+ from adam.utils_k8s.deployment import Deployments
10
+ from adam.utils_k8s.kube_context import KubeContext
11
+ from adam.utils_k8s.pods import Pods
12
+ from adam.utils_k8s.service_accounts import ServiceAccounts
13
+ from adam.utils_k8s.volumes import ConfigMapMount
14
14
  from adam.repl_state import ReplState, RequiredState
15
15
  from adam.utils import log2
16
16
 
@@ -1,7 +1,7 @@
1
1
  from typing import Callable
2
2
  from adam.app_session import AppSession
3
- from adam.k8s_utils.ingresses import Ingresses
4
- from adam.k8s_utils.services import Services
3
+ from adam.utils_k8s.ingresses import Ingresses
4
+ from adam.utils_k8s.services import Services
5
5
  from adam.utils import log2
6
6
 
7
7
  def deploy_frontend(name: str, namespace: str, label_selector: str):
@@ -4,7 +4,7 @@ from adam.commands.command import Command
4
4
  from adam.commands.deploy.undeploy_frontend import UndeployFrontend
5
5
  from adam.commands.deploy.undeploy_pg_agent import UndeployPgAgent
6
6
  from adam.commands.deploy.undeploy_pod import UndeployPod
7
- from adam.repl_state import ReplState
7
+ from adam.repl_state import ReplState, RequiredState
8
8
 
9
9
  class Undeploy(Command):
10
10
  COMMAND = 'undeploy'
@@ -22,10 +22,16 @@ class Undeploy(Command):
22
22
  def command(self):
23
23
  return Undeploy.COMMAND
24
24
 
25
+ def required(self):
26
+ return RequiredState.NAMESPACE
27
+
25
28
  def run(self, cmd: str, state: ReplState):
26
29
  if not(args := self.args(cmd)):
27
30
  return super().run(cmd, state)
28
31
 
32
+ if not self.validate_state(state):
33
+ return state
34
+
29
35
  return super().intermediate_run(cmd, state, args, Undeploy.cmd_list())
30
36
 
31
37
  def cmd_list():
@@ -1,6 +1,6 @@
1
1
  from adam.commands.command import Command
2
2
  from adam.commands.deploy.deploy_utils import deleting
3
- from adam.commands.postgres.postgres_session import PostgresSession
3
+ from adam.commands.postgres.postgres_context import PostgresContext
4
4
  from adam.config import Config
5
5
  from adam.repl_state import ReplState, RequiredState
6
6
 
@@ -30,7 +30,7 @@ class UndeployPgAgent(Command):
30
30
  if not self.validate_state(state):
31
31
  return state
32
32
 
33
- deleting('pod', lambda: PostgresSession.undeploy_pg_agent(Config().get('pg.agent.name', 'ops-pg-agent'), state.namespace))
33
+ deleting('pod', lambda: PostgresContext.undeploy_pg_agent(Config().get('pg.agent.name', 'ops-pg-agent'), state.namespace))
34
34
 
35
35
  return state
36
36
 
@@ -1,10 +1,10 @@
1
1
  from adam.commands.command import Command
2
2
  from adam.commands.deploy.deploy_utils import undeploy_frontend, deleting
3
3
  from adam.config import Config
4
- from adam.k8s_utils.config_maps import ConfigMaps
5
- from adam.k8s_utils.deployment import Deployments
6
- from adam.k8s_utils.pods import Pods
7
- from adam.k8s_utils.service_accounts import ServiceAccounts
4
+ from adam.utils_k8s.config_maps import ConfigMaps
5
+ from adam.utils_k8s.deployment import Deployments
6
+ from adam.utils_k8s.pods import Pods
7
+ from adam.utils_k8s.service_accounts import ServiceAccounts
8
8
  from adam.repl_state import ReplState, RequiredState
9
9
 
10
10
  class UndeployPod(Command):
adam/commands/devices.py CHANGED
@@ -1,6 +1,35 @@
1
1
  from adam.commands.command import Command
2
2
  from adam.repl_state import ReplState
3
3
 
4
+ class DeviceAuditLog(Command):
5
+ COMMAND = f'{ReplState.L}:'
6
+
7
+ # the singleton pattern
8
+ def __new__(cls, *args, **kwargs):
9
+ if not hasattr(cls, 'instance'): cls.instance = super(DeviceAuditLog, cls).__new__(cls)
10
+
11
+ return cls.instance
12
+
13
+ def __init__(self, successor: Command=None):
14
+ super().__init__(successor)
15
+
16
+ def command(self):
17
+ return DeviceAuditLog.COMMAND
18
+
19
+ def run(self, cmd: str, state: ReplState):
20
+ if not self.args(cmd):
21
+ return super().run(cmd, state)
22
+
23
+ state.device = ReplState.L
24
+
25
+ return state
26
+
27
+ def completion(self, state: ReplState):
28
+ return super().completion(state)
29
+
30
+ def help(self, _: ReplState):
31
+ return f'{DeviceAuditLog.COMMAND}\t move to Audit Log Operations device'
32
+
4
33
  class DeviceCass(Command):
5
34
  COMMAND = f'{ReplState.C}:'
6
35