kaqing 2.0.110__py3-none-any.whl → 2.0.214__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 (251) hide show
  1. adam/__init__.py +0 -2
  2. adam/app_session.py +9 -12
  3. adam/apps.py +18 -4
  4. adam/batch.py +19 -19
  5. adam/checks/check_utils.py +16 -46
  6. adam/checks/cpu.py +7 -1
  7. adam/checks/cpu_metrics.py +52 -0
  8. adam/checks/disk.py +2 -3
  9. adam/columns/columns.py +3 -1
  10. adam/columns/cpu.py +3 -1
  11. adam/columns/cpu_metrics.py +22 -0
  12. adam/columns/memory.py +3 -4
  13. adam/commands/__init__.py +24 -0
  14. adam/commands/app/app.py +38 -0
  15. adam/commands/{app_ping.py → app/app_ping.py} +7 -13
  16. adam/commands/{login.py → app/login.py} +22 -24
  17. adam/commands/app/show_app_actions.py +49 -0
  18. adam/commands/{show → app}/show_app_id.py +8 -11
  19. adam/commands/{show → app}/show_app_queues.py +7 -14
  20. adam/commands/app/show_login.py +56 -0
  21. adam/commands/app/utils_app.py +106 -0
  22. adam/commands/audit/audit.py +22 -40
  23. adam/commands/audit/audit_repair_tables.py +15 -19
  24. adam/commands/audit/audit_run.py +15 -22
  25. adam/commands/audit/completions_l.py +15 -0
  26. adam/commands/audit/show_last10.py +4 -18
  27. adam/commands/audit/show_slow10.py +4 -17
  28. adam/commands/audit/show_top10.py +4 -16
  29. adam/commands/audit/utils_show_top10.py +15 -3
  30. adam/commands/bash/__init__.py +5 -0
  31. adam/commands/bash/bash.py +36 -0
  32. adam/commands/bash/bash_completer.py +93 -0
  33. adam/commands/bash/utils_bash.py +16 -0
  34. adam/commands/cassandra/__init__.py +0 -0
  35. adam/commands/cassandra/download_cassandra_log.py +45 -0
  36. adam/commands/{restart.py → cassandra/restart_cluster.py} +12 -26
  37. adam/commands/cassandra/restart_node.py +51 -0
  38. adam/commands/cassandra/restart_nodes.py +47 -0
  39. adam/commands/{rollout.py → cassandra/rollout.py} +20 -25
  40. adam/commands/cassandra/show_cassandra_repairs.py +37 -0
  41. adam/commands/cassandra/show_cassandra_status.py +117 -0
  42. adam/commands/{show → cassandra}/show_cassandra_version.py +5 -18
  43. adam/commands/cassandra/show_processes.py +50 -0
  44. adam/commands/cassandra/show_storage.py +44 -0
  45. adam/commands/{watch.py → cassandra/watch.py} +26 -29
  46. adam/commands/cli/__init__.py +0 -0
  47. adam/commands/{cli_commands.py → cli/cli_commands.py} +8 -4
  48. adam/commands/cli/clipboard_copy.py +86 -0
  49. adam/commands/cli/show_cli_commands.py +56 -0
  50. adam/commands/code.py +57 -0
  51. adam/commands/command.py +211 -40
  52. adam/commands/commands_utils.py +20 -27
  53. adam/commands/config/__init__.py +0 -0
  54. adam/commands/{param_get.py → config/param_get.py} +11 -14
  55. adam/commands/{param_set.py → config/param_set.py} +8 -12
  56. adam/commands/{show → config}/show_params.py +2 -5
  57. adam/commands/cql/alter_tables.py +66 -0
  58. adam/commands/cql/completions_c.py +29 -0
  59. adam/commands/cql/cqlsh.py +10 -32
  60. adam/commands/cql/utils_cql.py +306 -0
  61. adam/commands/debug/__init__.py +0 -0
  62. adam/commands/debug/debug.py +22 -0
  63. adam/commands/debug/debug_completes.py +35 -0
  64. adam/commands/debug/debug_timings.py +35 -0
  65. adam/commands/debug/show_offloaded_completes.py +45 -0
  66. adam/commands/deploy/code_start.py +7 -10
  67. adam/commands/deploy/code_stop.py +4 -21
  68. adam/commands/deploy/code_utils.py +3 -3
  69. adam/commands/deploy/deploy.py +4 -27
  70. adam/commands/deploy/deploy_frontend.py +14 -17
  71. adam/commands/deploy/deploy_pg_agent.py +3 -6
  72. adam/commands/deploy/deploy_pod.py +65 -73
  73. adam/commands/deploy/deploy_utils.py +14 -24
  74. adam/commands/deploy/undeploy.py +4 -27
  75. adam/commands/deploy/undeploy_frontend.py +4 -7
  76. adam/commands/deploy/undeploy_pg_agent.py +6 -8
  77. adam/commands/deploy/undeploy_pod.py +11 -12
  78. adam/commands/devices/__init__.py +0 -0
  79. adam/commands/devices/device.py +149 -0
  80. adam/commands/devices/device_app.py +163 -0
  81. adam/commands/devices/device_auit_log.py +49 -0
  82. adam/commands/devices/device_cass.py +179 -0
  83. adam/commands/devices/device_export.py +87 -0
  84. adam/commands/devices/device_postgres.py +160 -0
  85. adam/commands/devices/devices.py +25 -0
  86. adam/commands/diag/__init__.py +0 -0
  87. adam/commands/{check.py → diag/check.py} +16 -25
  88. adam/commands/diag/generate_report.py +52 -0
  89. adam/commands/diag/issues.py +43 -0
  90. adam/commands/exit.py +1 -4
  91. adam/commands/export/__init__.py +0 -0
  92. adam/commands/export/clean_up_all_export_sessions.py +37 -0
  93. adam/commands/export/clean_up_export_sessions.py +39 -0
  94. adam/commands/export/completions_x.py +11 -0
  95. adam/commands/export/download_export_session.py +40 -0
  96. adam/commands/export/drop_export_database.py +39 -0
  97. adam/commands/export/drop_export_databases.py +37 -0
  98. adam/commands/export/export.py +37 -0
  99. adam/commands/export/export_databases.py +251 -0
  100. adam/commands/export/export_select.py +34 -0
  101. adam/commands/export/export_sessions.py +210 -0
  102. adam/commands/export/export_use.py +49 -0
  103. adam/commands/export/export_x_select.py +48 -0
  104. adam/commands/export/exporter.py +419 -0
  105. adam/commands/export/import_files.py +44 -0
  106. adam/commands/export/import_session.py +40 -0
  107. adam/commands/export/importer.py +81 -0
  108. adam/commands/export/importer_athena.py +157 -0
  109. adam/commands/export/importer_sqlite.py +78 -0
  110. adam/commands/export/show_column_counts.py +45 -0
  111. adam/commands/export/show_export_databases.py +39 -0
  112. adam/commands/export/show_export_session.py +39 -0
  113. adam/commands/export/show_export_sessions.py +37 -0
  114. adam/commands/export/utils_export.py +366 -0
  115. adam/commands/fs/__init__.py +0 -0
  116. adam/commands/fs/cat.py +36 -0
  117. adam/commands/fs/cat_local.py +42 -0
  118. adam/commands/fs/cd.py +41 -0
  119. adam/commands/fs/download_file.py +47 -0
  120. adam/commands/fs/find_files.py +51 -0
  121. adam/commands/fs/find_processes.py +76 -0
  122. adam/commands/fs/head.py +36 -0
  123. adam/commands/fs/ls.py +41 -0
  124. adam/commands/fs/ls_local.py +40 -0
  125. adam/commands/fs/pwd.py +45 -0
  126. adam/commands/fs/rm.py +18 -0
  127. adam/commands/fs/rm_downloads.py +39 -0
  128. adam/commands/fs/rm_logs.py +38 -0
  129. adam/commands/{shell.py → fs/shell.py} +12 -4
  130. adam/commands/{show → fs}/show_adam.py +3 -3
  131. adam/commands/{show → fs}/show_host.py +1 -1
  132. adam/commands/help.py +5 -3
  133. adam/commands/intermediate_command.py +52 -0
  134. adam/commands/kubectl.py +38 -0
  135. adam/commands/medusa/medusa.py +4 -22
  136. adam/commands/medusa/medusa_backup.py +20 -27
  137. adam/commands/medusa/medusa_restore.py +35 -48
  138. adam/commands/medusa/medusa_show_backupjobs.py +16 -18
  139. adam/commands/medusa/medusa_show_restorejobs.py +13 -18
  140. adam/commands/medusa/utils_medusa.py +15 -0
  141. adam/commands/nodetool/__init__.py +0 -0
  142. adam/commands/{nodetool.py → nodetool/nodetool.py} +9 -20
  143. adam/commands/postgres/completions_p.py +22 -0
  144. adam/commands/postgres/postgres.py +47 -55
  145. adam/commands/postgres/postgres_databases.py +269 -0
  146. adam/commands/postgres/postgres_ls.py +5 -9
  147. adam/commands/postgres/postgres_preview.py +5 -9
  148. adam/commands/postgres/utils_postgres.py +80 -0
  149. adam/commands/preview_table.py +8 -44
  150. adam/commands/reaper/reaper.py +4 -27
  151. adam/commands/reaper/reaper_forward.py +49 -56
  152. adam/commands/reaper/reaper_forward_session.py +6 -0
  153. adam/commands/reaper/reaper_forward_stop.py +10 -16
  154. adam/commands/reaper/reaper_restart.py +7 -14
  155. adam/commands/reaper/reaper_run_abort.py +8 -33
  156. adam/commands/reaper/reaper_runs.py +43 -58
  157. adam/commands/reaper/reaper_runs_abort.py +29 -49
  158. adam/commands/reaper/reaper_schedule_activate.py +14 -33
  159. adam/commands/reaper/reaper_schedule_start.py +9 -33
  160. adam/commands/reaper/reaper_schedule_stop.py +9 -33
  161. adam/commands/reaper/reaper_schedules.py +4 -14
  162. adam/commands/reaper/reaper_status.py +8 -16
  163. adam/commands/reaper/utils_reaper.py +203 -0
  164. adam/commands/repair/repair.py +4 -22
  165. adam/commands/repair/repair_log.py +5 -11
  166. adam/commands/repair/repair_run.py +27 -34
  167. adam/commands/repair/repair_scan.py +32 -40
  168. adam/commands/repair/repair_stop.py +5 -12
  169. adam/commands/show.py +40 -0
  170. adam/config.py +5 -15
  171. adam/embedded_params.py +1 -1
  172. adam/log.py +4 -4
  173. adam/repl.py +83 -116
  174. adam/repl_commands.py +86 -45
  175. adam/repl_session.py +9 -1
  176. adam/repl_state.py +176 -40
  177. adam/sql/async_executor.py +62 -0
  178. adam/sql/lark_completer.py +286 -0
  179. adam/sql/lark_parser.py +604 -0
  180. adam/sql/qingl.lark +1076 -0
  181. adam/sql/sql_completer.py +52 -27
  182. adam/sql/sql_state_machine.py +131 -19
  183. adam/sso/authn_ad.py +6 -8
  184. adam/sso/authn_okta.py +4 -6
  185. adam/sso/cred_cache.py +4 -9
  186. adam/sso/idp.py +9 -12
  187. adam/utils.py +670 -31
  188. adam/utils_athena.py +145 -0
  189. adam/utils_audits.py +12 -103
  190. adam/utils_issues.py +32 -0
  191. adam/utils_k8s/app_clusters.py +35 -0
  192. adam/utils_k8s/app_pods.py +41 -0
  193. adam/utils_k8s/cassandra_clusters.py +35 -20
  194. adam/utils_k8s/cassandra_nodes.py +15 -6
  195. adam/utils_k8s/custom_resources.py +16 -17
  196. adam/utils_k8s/ingresses.py +2 -2
  197. adam/utils_k8s/jobs.py +7 -11
  198. adam/utils_k8s/k8s.py +96 -0
  199. adam/utils_k8s/kube_context.py +3 -6
  200. adam/{pod_exec_result.py → utils_k8s/pod_exec_result.py} +13 -4
  201. adam/utils_k8s/pods.py +159 -89
  202. adam/utils_k8s/secrets.py +4 -4
  203. adam/utils_k8s/service_accounts.py +5 -4
  204. adam/utils_k8s/services.py +2 -2
  205. adam/utils_k8s/statefulsets.py +6 -14
  206. adam/utils_local.py +80 -0
  207. adam/utils_net.py +4 -4
  208. adam/utils_repl/__init__.py +0 -0
  209. adam/utils_repl/appendable_completer.py +6 -0
  210. adam/utils_repl/automata_completer.py +48 -0
  211. adam/utils_repl/repl_completer.py +93 -0
  212. adam/utils_repl/state_machine.py +173 -0
  213. adam/utils_sqlite.py +132 -0
  214. adam/version.py +1 -1
  215. {kaqing-2.0.110.dist-info → kaqing-2.0.214.dist-info}/METADATA +1 -1
  216. kaqing-2.0.214.dist-info/RECORD +272 -0
  217. kaqing-2.0.214.dist-info/top_level.txt +2 -0
  218. teddy/__init__.py +0 -0
  219. teddy/lark_parser.py +436 -0
  220. teddy/lark_parser2.py +618 -0
  221. adam/commands/alter_tables.py +0 -81
  222. adam/commands/app.py +0 -67
  223. adam/commands/bash.py +0 -150
  224. adam/commands/cd.py +0 -125
  225. adam/commands/cp.py +0 -95
  226. adam/commands/cql/cql_completions.py +0 -15
  227. adam/commands/cql/cql_utils.py +0 -112
  228. adam/commands/devices.py +0 -118
  229. adam/commands/issues.py +0 -75
  230. adam/commands/logs.py +0 -40
  231. adam/commands/ls.py +0 -146
  232. adam/commands/postgres/postgres_context.py +0 -239
  233. adam/commands/postgres/postgres_utils.py +0 -31
  234. adam/commands/postgres/psql_completions.py +0 -10
  235. adam/commands/pwd.py +0 -77
  236. adam/commands/reaper/reaper_session.py +0 -159
  237. adam/commands/report.py +0 -63
  238. adam/commands/show/show.py +0 -54
  239. adam/commands/show/show_app_actions.py +0 -56
  240. adam/commands/show/show_cassandra_status.py +0 -128
  241. adam/commands/show/show_commands.py +0 -61
  242. adam/commands/show/show_login.py +0 -63
  243. adam/commands/show/show_processes.py +0 -53
  244. adam/commands/show/show_repairs.py +0 -47
  245. adam/commands/show/show_storage.py +0 -52
  246. kaqing-2.0.110.dist-info/RECORD +0 -187
  247. kaqing-2.0.110.dist-info/top_level.txt +0 -1
  248. /adam/commands/{show → app}/__init__.py +0 -0
  249. /adam/commands/{nodetool_commands.py → nodetool/nodetool_commands.py} +0 -0
  250. {kaqing-2.0.110.dist-info → kaqing-2.0.214.dist-info}/WHEEL +0 -0
  251. {kaqing-2.0.110.dist-info → kaqing-2.0.214.dist-info}/entry_points.txt +0 -0
@@ -1,8 +1,8 @@
1
1
  from kubernetes import client
2
- import yaml
3
2
 
3
+ from adam.commands import extract_options
4
4
  from adam.commands.command import Command
5
- from adam.commands.deploy.deploy_utils import creating, deploy_frontend, gen_labels
5
+ from adam.commands.deploy.deploy_utils import deploy_frontend, gen_labels
6
6
  from adam.commands.deploy.undeploy_pod import UndeployPod
7
7
  from adam.config import Config
8
8
  from adam.utils_k8s.config_maps import ConfigMaps
@@ -12,7 +12,7 @@ from adam.utils_k8s.pods import Pods
12
12
  from adam.utils_k8s.service_accounts import ServiceAccounts
13
13
  from adam.utils_k8s.volumes import ConfigMapMount
14
14
  from adam.repl_state import ReplState, RequiredState
15
- from adam.utils import log2
15
+ from adam.utils import ing, log2, log_exc
16
16
 
17
17
  class DeployPod(Command):
18
18
  COMMAND = 'deploy pod'
@@ -36,76 +36,68 @@ class DeployPod(Command):
36
36
  if not(args := self.args(cmd)):
37
37
  return super().run(cmd, state)
38
38
 
39
- state, args = self.apply_state(args, state)
40
- if not self.validate_state(state):
41
- return state
42
-
43
- args, forced = Command.extract_options(args, '--force')
44
- if forced:
45
- UndeployPod().run(UndeployPod.COMMAND, state)
46
-
47
- if KubeContext.in_cluster():
48
- log2('This is doable only from outside of the Kubernetes cluster.')
49
- return state
50
-
51
- sa_name = Config().get('pod.sa.name', 'ops')
52
- sa_proto = Config().get('pod.sa.proto', 'c3')
53
- additional_cluster_roles = Config().get('pod.sa.additional-cluster-roles', 'c3aiops-k8ssandra-operator').split(',')
54
- label_selector = Config().get('pod.label-selector', 'run=ops')
55
- labels = gen_labels(label_selector)
56
-
57
- creating('service account', lambda: ServiceAccounts.replicate(sa_name,
58
- state.namespace,
59
- sa_proto, labels=labels,
60
- add_cluster_roles=additional_cluster_roles))
61
-
62
- settings_filename = 'settings.yaml'
63
- settings_path = f'/kaqing/{settings_filename}'
64
- settings_data = None
65
- try:
66
- with open(settings_filename, 'r') as file:
67
- settings_data = file.read()
68
- except:
69
- try:
70
- with open(settings_path, 'r') as file:
71
- settings_data = file.read()
72
- except:
73
- pass
74
-
75
- if not settings_data:
76
- log2(f'{settings_filename} not found.')
77
- return state
78
-
79
- cm_name = Config().get('pod.cm.name', 'ops')
80
- map_data = {
81
- settings_filename : settings_data
82
- }
83
- creating('config map', lambda: ConfigMaps.create(cm_name,
84
- state.namespace,
85
- map_data,
86
- labels=labels))
87
-
88
- pod_name = Config().get('pod.name', 'ops')
89
- image = Config().get('pod.image', 'seanahnsf/kaqing')
90
- security_context = client.V1SecurityContext(
91
- capabilities=client.V1Capabilities(
92
- add=["SYS_PTRACE"]
93
- )
94
- )
95
- creating('deployment', lambda: Deployments.create(state.namespace,
96
- pod_name,
97
- image,
98
- env={'NAMESPACE': state.namespace},
99
- container_security_context=security_context,
100
- labels=labels,
101
- sa_name=sa_name,
102
- config_map_mount=ConfigMapMount(cm_name, settings_filename, settings_path)))
103
-
104
- uri = deploy_frontend(pod_name, state.namespace, label_selector)
105
-
106
- Pods.wait_for_running(state.namespace, pod_name, msg=f'In moments, ops pod will be available at {uri}.', label_selector=label_selector)
107
-
108
- return state
39
+ with self.validate(args, state) as (args, state):
40
+ with extract_options(args, '--force') as (args, forced):
41
+ if forced:
42
+ UndeployPod().run(UndeployPod.COMMAND, state)
43
+
44
+ if KubeContext.in_cluster():
45
+ log2('This is doable only from outside of the Kubernetes cluster.')
46
+ return state
47
+
48
+ sa_name = Config().get('pod.sa.name', 'ops')
49
+ sa_proto = Config().get('pod.sa.proto', 'c3')
50
+ additional_cluster_roles = Config().get('pod.sa.additional-cluster-roles', 'c3aiops-k8ssandra-operator').split(',')
51
+ label_selector = Config().get('pod.label-selector', 'run=ops')
52
+ labels = gen_labels(label_selector)
53
+
54
+ with ing('Creating service account'):
55
+ ServiceAccounts.replicate(sa_name, state.namespace, sa_proto, labels=labels, add_cluster_roles=additional_cluster_roles)
56
+
57
+ settings_filename = 'settings.yaml'
58
+ settings_path = f'/kaqing/{settings_filename}'
59
+ settings_data = None
60
+ try:
61
+ with open(settings_filename, 'r') as file:
62
+ settings_data = file.read()
63
+ except:
64
+ with log_exc():
65
+ with open(settings_path, 'r') as file:
66
+ settings_data = file.read()
67
+
68
+ if not settings_data:
69
+ log2(f'{settings_filename} not found.')
70
+ return state
71
+
72
+ cm_name = Config().get('pod.cm.name', 'ops')
73
+ map_data = {
74
+ settings_filename : settings_data
75
+ }
76
+ with ing('Creating config map'):
77
+ ConfigMaps.create(cm_name, state.namespace, map_data, labels=labels)
78
+
79
+ pod_name = Config().get('pod.name', 'ops')
80
+ image = Config().get('pod.image', 'seanahnsf/kaqing')
81
+ security_context = client.V1SecurityContext(
82
+ capabilities=client.V1Capabilities(
83
+ add=["SYS_PTRACE"]
84
+ )
85
+ )
86
+ with ing('Creating deployment'):
87
+ Deployments.create(state.namespace,
88
+ pod_name,
89
+ image,
90
+ env={'NAMESPACE': state.namespace},
91
+ container_security_context=security_context,
92
+ labels=labels,
93
+ sa_name=sa_name,
94
+ config_map_mount=ConfigMapMount(cm_name, settings_filename, settings_path))
95
+
96
+ uri = deploy_frontend(pod_name, state.namespace, label_selector)
97
+
98
+ Pods.wait_for_running(state.namespace, pod_name, msg=f'In moments, ops pod will be available at {uri}.', label_selector=label_selector)
99
+
100
+ return state
109
101
 
110
102
  def completion(self, state: ReplState):
111
103
  return super().completion(state, {'--force': None})
@@ -1,39 +1,29 @@
1
- from typing import Callable
2
1
  from adam.app_session import AppSession
2
+ from adam.utils import ing
3
3
  from adam.utils_k8s.ingresses import Ingresses
4
4
  from adam.utils_k8s.services import Services
5
- from adam.utils import log2
6
5
 
7
6
  def deploy_frontend(name: str, namespace: str, label_selector: str):
8
7
  app_session: AppSession = AppSession.create('c3', 'c3', namespace)
9
8
  port = 7678
10
9
  labels = gen_labels(label_selector)
11
- creating('service', lambda: Services.create_service(name, namespace, port, labels, labels=labels))
12
- creating('ingress', lambda: Ingresses.create_ingress(name, namespace, app_session.host, '/c3/c3/ops($|/)', port, annotations={
13
- 'kubernetes.io/ingress.class': 'nginx',
14
- 'nginx.ingress.kubernetes.io/use-regex': 'true',
15
- 'nginx.ingress.kubernetes.io/rewrite-target': '/'
16
- }, labels=labels))
10
+ with ing('Creating service'):
11
+ Services.create_service(name, namespace, port, labels, labels=labels)
12
+ with ing('Creating ingress'):
13
+ Ingresses.create_ingress(name, namespace, app_session.host, '/c3/c3/ops($|/)', port, annotations={
14
+ 'kubernetes.io/ingress.class': 'nginx',
15
+ 'nginx.ingress.kubernetes.io/use-regex': 'true',
16
+ 'nginx.ingress.kubernetes.io/rewrite-target': '/'
17
+ }, labels=labels)
17
18
 
18
19
  return f'https://{app_session.host}/c3/c3/ops'
19
20
 
20
21
  def undeploy_frontend(namespace: str, label_selector: str):
21
- deleting('ingress', lambda: Ingresses.delete_ingresses(namespace, label_selector=label_selector))
22
- deleting('service', lambda: Services.delete_services(namespace, label_selector=label_selector))
22
+ with ing('Deleting ingress'):
23
+ Ingresses.delete_ingresses(namespace, label_selector=label_selector)
24
+ with ing('Deleting service'):
25
+ Services.delete_services(namespace, label_selector=label_selector)
23
26
 
24
27
  def gen_labels(label_selector: str):
25
28
  kv = label_selector.split('=')
26
- return {kv[0]: kv[1]}
27
-
28
- def creating(name: str, body: Callable[[], None]):
29
- log2(f'Creating {name}...', nl=False)
30
- body()
31
- log2(' OK')
32
-
33
- def deleting(name: str, body: Callable[[], None]):
34
- try:
35
- log2(f'Deleting {name}...', nl=False)
36
- body()
37
- log2(' OK')
38
- except Exception as e:
39
- log2(e)
29
+ return {kv[0]: kv[1]}
@@ -1,14 +1,12 @@
1
1
  import click
2
2
 
3
- from adam.commands.command import Command
4
3
  from adam.commands.deploy.undeploy_frontend import UndeployFrontend
5
4
  from adam.commands.deploy.undeploy_pg_agent import UndeployPgAgent
6
5
  from adam.commands.deploy.undeploy_pod import UndeployPod
7
- from adam.repl_state import ReplState, RequiredState
6
+ from adam.commands.intermediate_command import IntermediateCommand
8
7
 
9
- class Undeploy(Command):
8
+ class Undeploy(IntermediateCommand):
10
9
  COMMAND = 'undeploy'
11
- reaper_login = None
12
10
 
13
11
  # the singleton pattern
14
12
  def __new__(cls, *args, **kwargs):
@@ -16,33 +14,12 @@ class Undeploy(Command):
16
14
 
17
15
  return cls.instance
18
16
 
19
- def __init__(self, successor: Command=None):
20
- super().__init__(successor)
21
-
22
17
  def command(self):
23
18
  return Undeploy.COMMAND
24
19
 
25
- def required(self):
26
- return RequiredState.NAMESPACE
27
-
28
- def run(self, cmd: str, state: ReplState):
29
- if not(args := self.args(cmd)):
30
- return super().run(cmd, state)
31
-
32
- if not self.validate_state(state):
33
- return state
34
-
35
- return super().intermediate_run(cmd, state, args, Undeploy.cmd_list())
36
-
37
- def cmd_list():
20
+ def cmd_list(self):
38
21
  return [UndeployFrontend(), UndeployPod(), UndeployPgAgent()]
39
22
 
40
- def completion(self, state: ReplState):
41
- if state.sts:
42
- return super().completion(state)
43
-
44
- return {}
45
-
46
23
  class UndeployCommandHelper(click.Command):
47
24
  def get_help(self, ctx: click.Context):
48
- Command.intermediate_help(super().get_help(ctx), Undeploy.COMMAND, Undeploy.cmd_list())
25
+ IntermediateCommand.intermediate_help(super().get_help(ctx), Undeploy.COMMAND, Undeploy().cmd_list())
@@ -25,14 +25,11 @@ class UndeployFrontend(Command):
25
25
  if not(args := self.args(cmd)):
26
26
  return super().run(cmd, state)
27
27
 
28
- state, args = self.apply_state(args, state)
29
- if not self.validate_state(state):
30
- return state
31
-
32
- label_selector = Config().get('pod.label-selector', 'run=ops')
33
- undeploy_frontend(state.namespace, label_selector)
28
+ with self.validate(args, state) as (args, state):
29
+ label_selector = Config().get('pod.label-selector', 'run=ops')
30
+ undeploy_frontend(state.namespace, label_selector)
34
31
 
35
- return state
32
+ return state
36
33
 
37
34
  def completion(self, state: ReplState):
38
35
  return super().completion(state)
@@ -1,8 +1,8 @@
1
1
  from adam.commands.command import Command
2
- from adam.commands.deploy.deploy_utils import deleting
3
- from adam.commands.postgres.postgres_context import PostgresContext
2
+ from adam.commands.postgres.postgres_databases import PostgresDatabases
4
3
  from adam.config import Config
5
4
  from adam.repl_state import ReplState, RequiredState
5
+ from adam.utils import ing
6
6
 
7
7
  class UndeployPgAgent(Command):
8
8
  COMMAND = 'undeploy pg-agent'
@@ -26,13 +26,11 @@ class UndeployPgAgent(Command):
26
26
  if not(args := self.args(cmd)):
27
27
  return super().run(cmd, state)
28
28
 
29
- state, args = self.apply_state(args, state)
30
- if not self.validate_state(state):
31
- return state
32
-
33
- deleting('pod', lambda: PostgresContext.undeploy_pg_agent(Config().get('pg.agent.name', 'ops-pg-agent'), state.namespace))
29
+ with self.validate(args, state) as (args, state):
30
+ with ing('Deleting pod'):
31
+ PostgresDatabases.undeploy_pg_agent(Config().get('pg.agent.name', 'ops-pg-agent'), state.namespace)
34
32
 
35
- return state
33
+ return state
36
34
 
37
35
  def completion(self, state: ReplState):
38
36
  return super().completion(state)
@@ -1,6 +1,7 @@
1
1
  from adam.commands.command import Command
2
- from adam.commands.deploy.deploy_utils import undeploy_frontend, deleting
2
+ from adam.commands.deploy.deploy_utils import undeploy_frontend
3
3
  from adam.config import Config
4
+ from adam.utils import ing
4
5
  from adam.utils_k8s.config_maps import ConfigMaps
5
6
  from adam.utils_k8s.deployment import Deployments
6
7
  from adam.utils_k8s.pods import Pods
@@ -29,18 +30,16 @@ class UndeployPod(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
- if not self.validate_state(state):
34
- return state
35
-
36
- label_selector = Config().get('pod.label-selector', 'run=ops')
37
- deleting('service account', lambda: ServiceAccounts.delete(state.namespace, label_selector=label_selector))
38
- deleting('config map', lambda: ConfigMaps.delete_with_selector(state.namespace, label_selector))
39
- deleting('deployment', lambda: Deployments.delete_with_selector(state.namespace, label_selector, grace_period_seconds=0))
40
- deleting('pod', lambda: Pods.delete_with_selector(state.namespace, label_selector, grace_period_seconds=0))
41
- undeploy_frontend(state.namespace, label_selector)
33
+ with self.validate(args, state) as (args, state):
34
+ label_selector = Config().get('pod.label-selector', 'run=ops')
35
+ with ing('Deleting service account'):
36
+ ServiceAccounts.delete(state.namespace, label_selector=label_selector)
37
+ with ing('Deleting config map'): ConfigMaps.delete_with_selector(state.namespace, label_selector)
38
+ with ing('Deleting deployment'): Deployments.delete_with_selector(state.namespace, label_selector, grace_period_seconds=0)
39
+ with ing('Deleting pod'): Pods.delete_with_selector(state.namespace, label_selector, grace_period_seconds=0)
40
+ undeploy_frontend(state.namespace, label_selector)
42
41
 
43
- return state
42
+ return state
44
43
 
45
44
  def completion(self, state: ReplState):
46
45
  return super().completion(state)
File without changes
@@ -0,0 +1,149 @@
1
+ from abc import abstractmethod
2
+
3
+ from adam.commands.command import Command
4
+ from adam.config import Config
5
+ from adam.utils_k8s.pod_exec_result import PodExecResult
6
+ from adam.repl_state import BashSession, ReplState
7
+ from adam.utils import log2
8
+ from adam.utils_k8s.pods import Pods
9
+
10
+ class Device:
11
+ def pods(self, state: ReplState, me: str = None) -> tuple[list[str], str]:
12
+ return self.pod_names(state), me if me else self.pod(state)
13
+
14
+ def default_pod(self, state: ReplState) -> tuple[list[str], str]:
15
+ if me := self.pod(state):
16
+ return me
17
+
18
+ if pods := self.pod_names(state):
19
+ return pods[0]
20
+
21
+ return None
22
+
23
+ def pod(self, state: ReplState) -> str:
24
+ return None
25
+
26
+ def pod_names(self, state: ReplState) -> list[str]:
27
+ return []
28
+
29
+ def default_container(self, state: ReplState) -> str:
30
+ return None
31
+
32
+ @abstractmethod
33
+ def ls(self, cmd: str, state: ReplState):
34
+ pass
35
+
36
+ def ls_completion(self, cmd: str, state: ReplState, default: dict = {}):
37
+ return default
38
+
39
+ def cd(self, dir: str, state: ReplState):
40
+ pass
41
+
42
+ def cd_completion(self, cmd: str, state: ReplState, default: dict = {}):
43
+ return default
44
+
45
+ def direct_dirs(self, cmd: str, state: ReplState, default: dict = {}) -> list[str]:
46
+ return []
47
+
48
+ @abstractmethod
49
+ def pwd(self, state: ReplState):
50
+ pass
51
+
52
+ def try_fallback_action(self, chain: Command, state: ReplState, cmd: str):
53
+ return False, None
54
+
55
+ def enter(self, state: ReplState):
56
+ pass
57
+
58
+ def preview(self, table: str, state: ReplState):
59
+ if not table:
60
+ if state.in_repl:
61
+ log2('Table is required.')
62
+ log2()
63
+ log2('Tables:')
64
+ self.show_tables(state)
65
+ else:
66
+ log2('* Table is missing.')
67
+ self.show_tables(state)
68
+
69
+ Command.display_help()
70
+
71
+ return 'command-missing'
72
+
73
+ rows = Config().get('preview.rows', 10)
74
+ self.show_table_preview(state, table, rows)
75
+
76
+ return state
77
+
78
+ @abstractmethod
79
+ def show_tables(self, state: ReplState):
80
+ pass
81
+
82
+ @abstractmethod
83
+ def show_table_preview(self, state: ReplState, table: str, rows: int):
84
+ pass
85
+
86
+ def bash(self, s0: ReplState, s1: ReplState, args: list[str]):
87
+ if s1.in_repl:
88
+ if self.bash_target_changed(s0, s1):
89
+ r = self._exec_with_dir(s1, args)
90
+ else:
91
+ r = self._exec_with_dir(s0, args)
92
+
93
+ if not r:
94
+ s1.exit_bash()
95
+
96
+ return 'inconsistent pwd'
97
+
98
+ return r
99
+ else:
100
+ self.exec_no_dir(' '.join(args), s1)
101
+
102
+ return s1
103
+
104
+ def _exec_with_dir(self, state: ReplState, args: list[str]) -> list[PodExecResult]:
105
+ session_just_created = False
106
+ if not args:
107
+ session_just_created = True
108
+ session = BashSession(state.device)
109
+ state.enter_bash(session)
110
+
111
+ if state.bash_session:
112
+ if args != ['pwd']:
113
+ if args:
114
+ args.append('&&')
115
+ args.extend(['pwd', '>', f'/tmp/.qing-{state.bash_session.session_id}'])
116
+
117
+ if not session_just_created:
118
+ if pwd := state.bash_session.pwd(state):
119
+ args = ['cd', pwd, '&&'] + args
120
+
121
+ return self.exec_with_dir(' '.join(args), session_just_created, state)
122
+
123
+ @abstractmethod
124
+ def bash_target_changed(self, s0: ReplState, s1: ReplState):
125
+ pass
126
+
127
+ @abstractmethod
128
+ def exec_no_dir(self, command: str, state: ReplState):
129
+ pass
130
+
131
+ @abstractmethod
132
+ def exec_with_dir(self, command: str, session_just_created: bool, state: ReplState):
133
+ pass
134
+
135
+ def bash_completion(self, cmd: str, state: ReplState, default: dict = {}):
136
+ return default
137
+
138
+ def files(self, state: ReplState):
139
+ r: PodExecResult = Pods.exec(self.default_pod(state), self.default_container(state), state.namespace, f'find -maxdepth 1 -type f', show_out=Config().is_debug(), shell='bash')
140
+
141
+ log_files = []
142
+ for line in r.stdout.split('\n'):
143
+ line = line.strip(' \r')
144
+ if line:
145
+ if line.startswith('./'):
146
+ line = line[2:]
147
+ log_files.append(line)
148
+
149
+ return log_files
@@ -0,0 +1,163 @@
1
+ from adam.apps import Apps
2
+ from adam.commands import app
3
+ from adam.commands.bash.bash_completer import BashCompleter
4
+ from adam.commands.command import Command, InvalidStateException
5
+ from adam.commands.devices.device import Device
6
+ from adam.config import Config
7
+ from adam.repl_state import ReplState
8
+ from adam.utils import tabulize, log, wait_log
9
+ from adam.utils_k8s.app_pods import AppPods
10
+ from adam.utils_k8s.ingresses import Ingresses
11
+
12
+ class DeviceApp(Command, Device):
13
+ COMMAND = f'{ReplState.A}:'
14
+
15
+ # the singleton pattern
16
+ def __new__(cls, *args, **kwargs):
17
+ if not hasattr(cls, 'instance'): cls.instance = super(DeviceApp, cls).__new__(cls)
18
+
19
+ return cls.instance
20
+
21
+ def __init__(self, successor: Command=None):
22
+ super().__init__(successor)
23
+
24
+ def command(self):
25
+ return DeviceApp.COMMAND
26
+
27
+ def run(self, cmd: str, state: ReplState):
28
+ if not self.args(cmd):
29
+ return super().run(cmd, state)
30
+
31
+ state.device = ReplState.A
32
+
33
+ return state
34
+
35
+ def completion(self, state: ReplState):
36
+ return super().completion(state)
37
+
38
+ def help(self, _: ReplState):
39
+ return f'{DeviceApp.COMMAND}\t move to App Operations device'
40
+
41
+ def pod(self, state: ReplState) -> str:
42
+ return state.app_pod
43
+
44
+ def pod_names(self, state: ReplState) -> list[str]:
45
+ return AppPods.pod_names(state.namespace, state.app_env, state.app_app)
46
+
47
+ def default_container(self, state: ReplState) -> str:
48
+ return Config().get('app.container-name', 'c3-server')
49
+
50
+ def ls(self, cmd: str, state: ReplState):
51
+ if state.app_pod:
52
+ return self.bash(state, state, cmd.split(' '))
53
+ elif state.app_app:
54
+ tabulize(self.pod_names(state), header='POD_NAME')
55
+ elif state.app_env:
56
+ def line(n: str, ns: str):
57
+ host = Ingresses.get_host(Config().get('app.login.ingress', '{app_id}-k8singr-appleader-001').replace('{app_id}', f'{ns}-{n}'), ns)
58
+ if not host:
59
+ return None
60
+
61
+ endpoint = Config().get('app.login.url', 'https://{host}/{env}/{app}').replace('{host}', host).replace('{env}', state.app_env).replace('{app}', 'c3')
62
+ if not endpoint:
63
+ return None
64
+
65
+ return f"{n.split('-')[1]},{Ingresses.get_host(f'{ns}-{n}-k8singr-appleader-001', ns)},{endpoint}"
66
+
67
+ svcs = [l for l in [line(n, ns) for n, ns in Apps.apps(state.app_env)] if l]
68
+
69
+ tabulize(svcs, header='APP,HOST,ENDPOINT', separator=',')
70
+ else:
71
+ tabulize(Apps.envs(), lambda a: a[0], header='ENV', separator=',')
72
+
73
+ def ls_completion(self, cmd, state, default: dict = {}):
74
+ if state.app_app:
75
+ return super().completion(state) | {f'@{p}': {cmd: None} for p in self.pod_names(state)}
76
+
77
+ return default
78
+
79
+ def cd(self, dir: str, state: ReplState):
80
+ if dir == '':
81
+ state.app_env = None
82
+ state.app_app = None
83
+ state.app_pod = None
84
+ elif dir == '..':
85
+ if state.app_pod:
86
+ state.app_pod = None
87
+ elif state.app_app:
88
+ state.app_app = None
89
+ else:
90
+ state.app_env = None
91
+ else:
92
+ if state.app_app:
93
+ state.app_pod = dir
94
+ elif not state.app_env:
95
+ tks = dir.split('@')
96
+ if len(tks) > 1:
97
+ state.namespace = tks[1]
98
+
99
+ state.app_env = dir.split('@')[0]
100
+ else:
101
+ state.app_app = dir
102
+
103
+ def cd_completion(self, cmd: str, state: ReplState, default: dict = {}):
104
+ if state.app_app:
105
+ return {cmd: {'..': None} | {pod: None for pod in self.pod_names(state)}}
106
+ elif state.app_env:
107
+ return {cmd: {'..': None} | {app[0].split('-')[1]: None for app in Apps.apps(state.app_env)}}
108
+ else:
109
+ return {cmd: {'..': None} | {env[0]: None for env in Apps.envs()}}
110
+
111
+ def pwd(self, state: ReplState):
112
+ words = []
113
+
114
+ if state.app_env:
115
+ words.append(f'env/{state.app_env}')
116
+ if state.app_app:
117
+ words.append(f'app/{state.app_app}')
118
+
119
+ return '\t'.join([f'{ReplState.A}:>'] + (words if words else ['/']))
120
+
121
+ def try_fallback_action(self, chain: Command, state: ReplState, cmd: str):
122
+ if state.app_app:
123
+ return True, chain.run(f'app {cmd}', state)
124
+
125
+ return False, None
126
+
127
+ def enter(self, state: ReplState):
128
+ if not state.app_env:
129
+ if auto_enter := Config().get('repl.a.auto-enter', 'c3/c3/*'):
130
+ if auto_enter != 'no':
131
+ ea = auto_enter.split('/')
132
+ state.app_env = ea[0]
133
+ if len(ea) > 2:
134
+ state.app_app = ea[1]
135
+ state.app_pod = ea[2]
136
+ if state.app_pod == '*':
137
+ if (pods := self.pod_names(state)):
138
+ state.app_pod = pods[0]
139
+ wait_log(f'Moving to {state.app_env}/{state.app_app}/{state.app_pod}...')
140
+ else:
141
+ wait_log(f'No pods found, moving to {state.app_env}/{state.app_app}...')
142
+ else:
143
+ wait_log(f'Moving to {state.app_env}/{state.app_app}/{state.app_pod}...')
144
+ elif len(ea) > 1:
145
+ state.app_app = ea[1]
146
+ wait_log(f'Moving to {state.app_env}/{state.app_app}...')
147
+ else:
148
+ wait_log(f'Moving to {state.app_env}...')
149
+
150
+ def bash_target_changed(self, s0: ReplState, s1: ReplState):
151
+ return s0.app_env != s1.app_env or s0.app_app != s1.app_app or s0.app_pod != s1.app_pod
152
+
153
+ def exec_no_dir(self, command: str, state: ReplState):
154
+ with app(state) as pods:
155
+ return pods.exec(command)
156
+
157
+ def exec_with_dir(self, command: str, session_just_created: bool, state: ReplState):
158
+ with app(state) as pods:
159
+ return pods.exec(command, not session_just_created)
160
+
161
+ def bash_completion(self, cmd: str, state: ReplState, default: dict = {}):
162
+ return {cmd: BashCompleter(lambda: [])} | \
163
+ {f'@{p}': {cmd: BashCompleter(lambda: [])} for p in self.pod_names(state)}