kaqing 2.0.145__py3-none-any.whl → 2.0.189__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 (209) 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 +4 -4
  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/alter_tables.py +33 -48
  15. adam/commands/app/__init__.py +0 -0
  16. adam/commands/app/app.py +38 -0
  17. adam/commands/{app_ping.py → app/app_ping.py} +7 -13
  18. adam/commands/app/show_app_actions.py +49 -0
  19. adam/commands/{show → app}/show_app_id.py +8 -11
  20. adam/commands/{show → app}/show_app_queues.py +7 -14
  21. adam/commands/app/utils_app.py +106 -0
  22. adam/commands/audit/audit.py +21 -40
  23. adam/commands/audit/audit_repair_tables.py +14 -19
  24. adam/commands/audit/audit_run.py +14 -22
  25. adam/commands/audit/completions_l.py +15 -0
  26. adam/commands/audit/show_last10.py +4 -19
  27. adam/commands/audit/show_slow10.py +4 -18
  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 +7 -104
  32. adam/commands/bash/utils_bash.py +16 -0
  33. adam/commands/cat.py +7 -27
  34. adam/commands/cd.py +7 -11
  35. adam/commands/check.py +15 -24
  36. adam/commands/cli_commands.py +8 -4
  37. adam/commands/clipboard_copy.py +87 -0
  38. adam/commands/code.py +21 -24
  39. adam/commands/command.py +207 -42
  40. adam/commands/commands_utils.py +25 -27
  41. adam/commands/cql/completions_c.py +28 -0
  42. adam/commands/cql/cqlsh.py +9 -33
  43. adam/commands/cql/{cql_utils.py → utils_cql.py} +111 -15
  44. adam/commands/deploy/code_start.py +7 -10
  45. adam/commands/deploy/code_stop.py +4 -21
  46. adam/commands/deploy/code_utils.py +3 -3
  47. adam/commands/deploy/deploy.py +4 -27
  48. adam/commands/deploy/deploy_frontend.py +14 -17
  49. adam/commands/deploy/deploy_pg_agent.py +3 -6
  50. adam/commands/deploy/deploy_pod.py +64 -68
  51. adam/commands/deploy/undeploy.py +4 -27
  52. adam/commands/deploy/undeploy_frontend.py +4 -7
  53. adam/commands/deploy/undeploy_pg_agent.py +5 -8
  54. adam/commands/deploy/undeploy_pod.py +9 -12
  55. adam/commands/devices/device.py +124 -2
  56. adam/commands/devices/device_app.py +41 -24
  57. adam/commands/devices/device_auit_log.py +10 -4
  58. adam/commands/devices/device_cass.py +48 -14
  59. adam/commands/devices/device_export.py +13 -12
  60. adam/commands/devices/device_postgres.py +105 -54
  61. adam/commands/download_file.py +47 -0
  62. adam/commands/exit.py +1 -4
  63. adam/commands/export/clean_up_all_export_sessions.py +37 -0
  64. adam/commands/export/clean_up_export_sessions.py +9 -10
  65. adam/commands/export/completions_x.py +11 -0
  66. adam/commands/export/download_export_session.py +40 -0
  67. adam/commands/export/drop_export_database.py +7 -26
  68. adam/commands/export/drop_export_databases.py +5 -14
  69. adam/commands/export/export.py +6 -52
  70. adam/commands/export/export_databases.py +108 -32
  71. adam/commands/export/export_select.py +8 -59
  72. adam/commands/export/export_sessions.py +209 -0
  73. adam/commands/export/export_use.py +14 -20
  74. adam/commands/export/export_x_select.py +48 -0
  75. adam/commands/export/exporter.py +135 -167
  76. adam/commands/export/import_files.py +44 -0
  77. adam/commands/export/import_session.py +11 -35
  78. adam/commands/export/importer.py +19 -5
  79. adam/commands/export/importer_athena.py +112 -44
  80. adam/commands/export/importer_sqlite.py +42 -22
  81. adam/commands/export/show_column_counts.py +13 -31
  82. adam/commands/export/show_export_databases.py +7 -7
  83. adam/commands/export/show_export_session.py +8 -20
  84. adam/commands/export/show_export_sessions.py +6 -16
  85. adam/commands/export/utils_export.py +64 -11
  86. adam/commands/find_files.py +51 -0
  87. adam/commands/find_processes.py +76 -0
  88. adam/commands/head.py +36 -0
  89. adam/commands/help.py +2 -2
  90. adam/commands/intermediate_command.py +52 -0
  91. adam/commands/issues.py +11 -43
  92. adam/commands/kubectl.py +3 -6
  93. adam/commands/login.py +22 -24
  94. adam/commands/logs.py +3 -6
  95. adam/commands/ls.py +9 -10
  96. adam/commands/medusa/medusa.py +4 -22
  97. adam/commands/medusa/medusa_backup.py +20 -27
  98. adam/commands/medusa/medusa_restore.py +49 -46
  99. adam/commands/medusa/medusa_show_backupjobs.py +16 -18
  100. adam/commands/medusa/medusa_show_restorejobs.py +13 -18
  101. adam/commands/medusa/utils_medusa.py +15 -0
  102. adam/commands/nodetool.py +7 -21
  103. adam/commands/param_get.py +11 -14
  104. adam/commands/param_set.py +8 -12
  105. adam/commands/postgres/completions_p.py +22 -0
  106. adam/commands/postgres/postgres.py +34 -57
  107. adam/commands/postgres/postgres_databases.py +270 -0
  108. adam/commands/postgres/postgres_ls.py +4 -8
  109. adam/commands/postgres/postgres_preview.py +5 -9
  110. adam/commands/postgres/utils_postgres.py +79 -0
  111. adam/commands/preview_table.py +8 -45
  112. adam/commands/pwd.py +13 -16
  113. adam/commands/reaper/reaper.py +4 -27
  114. adam/commands/reaper/reaper_forward.py +49 -56
  115. adam/commands/reaper/reaper_forward_session.py +6 -0
  116. adam/commands/reaper/reaper_forward_stop.py +10 -16
  117. adam/commands/reaper/reaper_restart.py +7 -14
  118. adam/commands/reaper/reaper_run_abort.py +8 -33
  119. adam/commands/reaper/reaper_runs.py +43 -58
  120. adam/commands/reaper/reaper_runs_abort.py +29 -49
  121. adam/commands/reaper/reaper_schedule_activate.py +14 -33
  122. adam/commands/reaper/reaper_schedule_start.py +9 -33
  123. adam/commands/reaper/reaper_schedule_stop.py +9 -33
  124. adam/commands/reaper/reaper_schedules.py +4 -14
  125. adam/commands/reaper/reaper_status.py +8 -16
  126. adam/commands/reaper/utils_reaper.py +203 -0
  127. adam/commands/repair/repair.py +4 -22
  128. adam/commands/repair/repair_log.py +5 -11
  129. adam/commands/repair/repair_run.py +27 -34
  130. adam/commands/repair/repair_scan.py +32 -40
  131. adam/commands/repair/repair_stop.py +5 -12
  132. adam/commands/report.py +27 -29
  133. adam/commands/restart.py +25 -26
  134. adam/commands/rollout.py +19 -24
  135. adam/commands/shell.py +12 -4
  136. adam/commands/show/show.py +11 -27
  137. adam/commands/show/show_adam.py +3 -3
  138. adam/commands/show/show_cassandra_repairs.py +37 -0
  139. adam/commands/show/show_cassandra_status.py +47 -51
  140. adam/commands/show/show_cassandra_version.py +5 -18
  141. adam/commands/show/show_cli_commands.py +56 -0
  142. adam/commands/show/show_host.py +1 -1
  143. adam/commands/show/show_login.py +20 -27
  144. adam/commands/show/show_params.py +2 -5
  145. adam/commands/show/show_processes.py +18 -21
  146. adam/commands/show/show_storage.py +11 -20
  147. adam/commands/watch.py +26 -29
  148. adam/config.py +5 -16
  149. adam/embedded_params.py +1 -1
  150. adam/log.py +4 -4
  151. adam/pod_exec_result.py +3 -3
  152. adam/repl.py +45 -39
  153. adam/repl_commands.py +26 -19
  154. adam/repl_session.py +8 -1
  155. adam/repl_state.py +85 -36
  156. adam/sql/lark_completer.py +284 -0
  157. adam/sql/lark_parser.py +604 -0
  158. adam/sql/sql_completer.py +4 -6
  159. adam/sql/sql_state_machine.py +29 -16
  160. adam/sso/authn_ad.py +6 -8
  161. adam/sso/authn_okta.py +4 -6
  162. adam/sso/cred_cache.py +3 -5
  163. adam/sso/idp.py +9 -12
  164. adam/utils.py +484 -37
  165. adam/utils_athena.py +19 -19
  166. adam/utils_audits.py +12 -12
  167. adam/utils_issues.py +32 -0
  168. adam/utils_k8s/app_clusters.py +14 -19
  169. adam/utils_k8s/app_pods.py +7 -2
  170. adam/utils_k8s/cassandra_clusters.py +30 -19
  171. adam/utils_k8s/cassandra_nodes.py +2 -2
  172. adam/utils_k8s/custom_resources.py +16 -17
  173. adam/utils_k8s/ingresses.py +2 -2
  174. adam/utils_k8s/jobs.py +7 -11
  175. adam/utils_k8s/k8s.py +96 -0
  176. adam/utils_k8s/kube_context.py +2 -2
  177. adam/utils_k8s/pods.py +37 -81
  178. adam/utils_k8s/secrets.py +4 -4
  179. adam/utils_k8s/service_accounts.py +5 -4
  180. adam/utils_k8s/services.py +2 -2
  181. adam/utils_k8s/statefulsets.py +6 -14
  182. adam/utils_local.py +4 -0
  183. adam/utils_repl/appendable_completer.py +6 -0
  184. adam/utils_repl/repl_completer.py +128 -2
  185. adam/utils_repl/state_machine.py +3 -3
  186. adam/utils_sqlite.py +78 -42
  187. adam/version.py +1 -1
  188. {kaqing-2.0.145.dist-info → kaqing-2.0.189.dist-info}/METADATA +1 -1
  189. kaqing-2.0.189.dist-info/RECORD +253 -0
  190. kaqing-2.0.189.dist-info/top_level.txt +2 -0
  191. teddy/__init__.py +0 -0
  192. teddy/lark_parser.py +436 -0
  193. teddy/lark_parser2.py +618 -0
  194. adam/commands/app.py +0 -67
  195. adam/commands/cp.py +0 -95
  196. adam/commands/cql/cql_completions.py +0 -28
  197. adam/commands/export/clean_up_export_session.py +0 -53
  198. adam/commands/export/export_select_x.py +0 -54
  199. adam/commands/postgres/postgres_context.py +0 -248
  200. adam/commands/postgres/postgres_utils.py +0 -31
  201. adam/commands/postgres/psql_completions.py +0 -10
  202. adam/commands/reaper/reaper_session.py +0 -159
  203. adam/commands/show/show_app_actions.py +0 -56
  204. adam/commands/show/show_commands.py +0 -61
  205. adam/commands/show/show_repairs.py +0 -47
  206. kaqing-2.0.145.dist-info/RECORD +0 -227
  207. kaqing-2.0.145.dist-info/top_level.txt +0 -1
  208. {kaqing-2.0.145.dist-info → kaqing-2.0.189.dist-info}/WHEEL +0 -0
  209. {kaqing-2.0.145.dist-info → kaqing-2.0.189.dist-info}/entry_points.txt +0 -0
@@ -1,9 +1,11 @@
1
+ import os
1
2
  import boto3
2
3
 
4
+ from adam.commands.export.export_databases import export_db
3
5
  from adam.commands.export.importer import Importer
4
- from adam.commands.export.utils_export import GeneratorStream
5
6
  from adam.config import Config
6
- from adam.utils import log2, ing
7
+ from adam.repl_state import ReplState
8
+ from adam.utils import GeneratorStream, bytes_generator_from_file, debug, log2, ing
7
9
  from adam.utils_athena import Athena
8
10
  from adam.utils_k8s.pods import Pods
9
11
 
@@ -17,9 +19,14 @@ class AthenaImporter(Importer):
17
19
  def prefix(self):
18
20
  return 'e'
19
21
 
20
- def import_from_csv(self, pod: str, namespace: str, to_session: str, from_session: str, keyspace: str, table: str, target_table: str, columns: str, multi_tables = True, create_db = False):
22
+ def import_from_csv(self, state: ReplState, from_session: str,
23
+ keyspace: str, table: str, target_table: str, columns: str,
24
+ multi_tables = True, create_db = False):
21
25
  csv_file = self.csv_file(from_session, table, target_table)
22
- db = self.db(to_session, keyspace)
26
+ pod = state.pod
27
+ namespace = state.namespace
28
+ to_session = state.export_session
29
+ database = self.db(to_session, keyspace)
23
30
 
24
31
  succeeded = False
25
32
  try:
@@ -29,52 +36,113 @@ class AthenaImporter(Importer):
29
36
  bytes = Pods.read_file(pod, 'cassandra', namespace, csv_file)
30
37
 
31
38
  s3 = boto3.client('s3')
32
- s3.upload_fileobj(GeneratorStream(bytes), bucket, f'export/{db}/{keyspace}/{target_table}/{table}.csv')
33
-
34
- msg: str = None
35
- if create_db:
36
- msg = f"[{to_session}] Creating database {db}"
37
- else:
38
- msg = f"[{to_session}] Creating table {target_table}"
39
- with ing(msg, suppress_log=multi_tables):
40
- query = f'CREATE DATABASE IF NOT EXISTS {db};'
41
- if Config().is_debug():
42
- log2(query)
43
- Athena.query(query, 'default')
44
-
45
- query = f'DROP TABLE IF EXISTS {target_table};'
46
- if Config().is_debug():
47
- log2(query)
48
- Athena.query(query, db)
49
-
50
- athena_columns = ', '.join([f'{c} string' for c in columns.split(',')])
51
- query = f'CREATE EXTERNAL TABLE IF NOT EXISTS {target_table}(\n' + \
52
- f' {athena_columns})\n' + \
53
- "ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde'\n" + \
54
- 'WITH SERDEPROPERTIES (\n' + \
55
- ' "separatorChar" = ",",\n' + \
56
- ' "quoteChar" = "\\"")\n' + \
57
- f"LOCATION 's3://{bucket}/export/{db}/{keyspace}/{target_table}'\n" + \
58
- 'TBLPROPERTIES ("skip.header.line.count"="1");'
59
- if Config().is_debug():
60
- log2(query)
61
- try:
62
- Athena.query(query, db)
63
- except Exception as e:
64
- log2(f'*** Failed query:\n{query}')
65
- raise e
66
-
67
- to, _ = self.move_to_done(pod, namespace, to_session, from_session, keyspace, target_table)
39
+ s3.upload_fileobj(GeneratorStream(bytes), bucket, f'export/{database}/{keyspace}/{target_table}/{table}.csv')
40
+
41
+ self.create_schema(to_session, bucket, database, keyspace, table, columns, multi_tables, create_db)
42
+
43
+ to, _ = self.move_to_done(state, from_session, keyspace, target_table)
68
44
 
69
45
  succeeded = True
70
46
 
71
47
  return to, to_session
72
48
  finally:
73
49
  if succeeded:
74
- self.remove_csv(pod, namespace, from_session, table, target_table, multi_tables)
50
+ self.remove_csv(state, from_session, table, target_table, multi_tables)
75
51
  Athena.clear_cache()
76
52
 
77
53
  if not multi_tables:
78
- query = f'select * from {target_table} limit 10'
79
- log2(query)
80
- Athena.run_query(query, db)
54
+ with export_db(state) as dbs:
55
+ dbs.sql(f'select * from {database}.{target_table} limit 10')
56
+
57
+ def import_from_local_csv(self, state: ReplState,
58
+ keyspace: str, table: str, csv_file: str, multi_tables = True, create_db = False):
59
+ to_session = state.export_session
60
+ database = self.db(to_session, keyspace)
61
+
62
+ succeeded = False
63
+ try:
64
+ columns = None
65
+ with open(csv_file, 'r') as f:
66
+ columns = f.readline()
67
+
68
+ bucket = Config().get('export.bucket', 'c3.ops--qing')
69
+
70
+ with ing(f'[{to_session}] Uploading to S3', suppress_log=multi_tables):
71
+ bytes = bytes_generator_from_file(csv_file)
72
+
73
+ s3 = boto3.client('s3')
74
+ s3.upload_fileobj(GeneratorStream(bytes), bucket, f'export/{database}/{keyspace}/{table}/{os.path.basename(csv_file)}')
75
+
76
+ self.create_schema(to_session, bucket, database, keyspace, table, columns, multi_tables, create_db)
77
+ # msg: str = None
78
+ # if create_db:
79
+ # msg = f"[{to_session}] Creating database {database}"
80
+ # else:
81
+ # msg = f"[{to_session}] Creating table {target_table}"
82
+ # with ing(msg, suppress_log=multi_tables):
83
+ # query = f'CREATE DATABASE IF NOT EXISTS {database};'
84
+ # debug(query)
85
+ # Athena.query(query, 'default')
86
+
87
+ # query = f'DROP TABLE IF EXISTS {target_table};'
88
+ # debug(query)
89
+ # Athena.query(query, database)
90
+
91
+ # athena_columns = ', '.join([f'{c} string' for c in columns.split(',')])
92
+ # query = f'CREATE EXTERNAL TABLE IF NOT EXISTS {target_table}(\n' + \
93
+ # f' {athena_columns})\n' + \
94
+ # "ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde'\n" + \
95
+ # 'WITH SERDEPROPERTIES (\n' + \
96
+ # ' "separatorChar" = ",",\n' + \
97
+ # ' "quoteChar" = "\\"")\n' + \
98
+ # f"LOCATION 's3://{bucket}/export/{database}/{keyspace}/{target_table}'\n" + \
99
+ # 'TBLPROPERTIES ("skip.header.line.count"="1");'
100
+ # debug(query)
101
+ # try:
102
+ # Athena.query(query, database)
103
+ # except Exception as e:
104
+ # log2(f'*** Failed query:\n{query}')
105
+ # raise e
106
+
107
+ succeeded = True
108
+
109
+ return csv_file, to_session
110
+ finally:
111
+ if succeeded:
112
+ Athena.clear_cache()
113
+
114
+ if not multi_tables:
115
+ with export_db(state) as dbs:
116
+ dbs.sql(f'select * from {database}.{table} limit 10')
117
+
118
+ def create_schema(self, to_session: str, bucket: str, database: str, keyspace: str, table: str, columns: list[str], multi_tables: bool, create_db = False):
119
+ msg: str = None
120
+ if create_db:
121
+ msg = f"[{to_session}] Creating database {database}"
122
+ else:
123
+ msg = f"[{to_session}] Creating table {table}"
124
+
125
+ with ing(msg, suppress_log=multi_tables):
126
+ query = f'CREATE DATABASE IF NOT EXISTS {database};'
127
+ debug(query)
128
+ Athena.query(query, 'default')
129
+
130
+ query = f'DROP TABLE IF EXISTS {table};'
131
+ debug(query)
132
+ Athena.query(query, database)
133
+
134
+ athena_columns = ', '.join([f'{c} string' for c in columns.split(',')])
135
+ query = f'CREATE EXTERNAL TABLE IF NOT EXISTS {table}(\n' + \
136
+ f' {athena_columns})\n' + \
137
+ "ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde'\n" + \
138
+ 'WITH SERDEPROPERTIES (\n' + \
139
+ ' "separatorChar" = ",",\n' + \
140
+ ' "quoteChar" = "\\"")\n' + \
141
+ f"LOCATION 's3://{bucket}/export/{database}/{keyspace}/{table}'\n" + \
142
+ 'TBLPROPERTIES ("skip.header.line.count"="1");'
143
+ debug(query)
144
+ try:
145
+ Athena.query(query, database)
146
+ except Exception as e:
147
+ log2(f'*** Failed query:\n{query}')
148
+ raise e
@@ -1,47 +1,67 @@
1
- import os
2
- import sqlite3
3
1
  import pandas
4
2
 
3
+ from adam.commands.export.export_databases import export_db
5
4
  from adam.commands.export.importer import Importer
6
- from adam.commands.export.utils_export import GeneratorStream
7
- from adam.utils import log2, ing
5
+ from adam.repl_state import ReplState
6
+ from adam.utils import GeneratorStream, bytes_generator_from_file, ing
8
7
  from adam.utils_k8s.pods import Pods
9
- from adam.utils_sqlite import SQLite
8
+ from adam.utils_sqlite import SQLite, sqlite
10
9
 
11
10
  class SqliteImporter(Importer):
12
11
  def prefix(self):
13
12
  return 's'
14
13
 
15
- def import_from_csv(self, pod: str, namespace: str, to_session: str, from_session: str, keyspace: str, table: str, target_table: str, columns: str, multi_tables = True, create_db = False):
14
+ def import_from_csv(self, state: ReplState, from_session: str,
15
+ keyspace: str, table: str, target_table: str, columns: str,
16
+ multi_tables = True, create_db = False):
16
17
  csv_file = self.csv_file(from_session, table, target_table)
17
- db = self.db(to_session, keyspace)
18
+ pod = state.pod
19
+ namespace = state.namespace
20
+ to_session = state.export_session
18
21
 
19
22
  succeeded = False
20
- conn = None
21
23
  try:
22
- os.makedirs(SQLite.local_db_dir(), exist_ok=True)
23
- conn = sqlite3.connect(f'{SQLite.local_db_dir()}/{db}.db')
24
-
25
24
  with ing(f'[{to_session}] Uploading to Sqlite', suppress_log=multi_tables):
26
- bytes = Pods.read_file(pod, 'cassandra', namespace, csv_file)
27
- df = pandas.read_csv(GeneratorStream(bytes))
28
-
29
- df.to_sql(target_table, conn, index=False, if_exists='replace')
25
+ # create a connection to single keyspace
26
+ with sqlite(to_session, keyspace) as conn:
27
+ bytes = Pods.read_file(pod, 'cassandra', namespace, csv_file)
28
+ df = pandas.read_csv(GeneratorStream(bytes))
29
+ df.to_sql(target_table, conn, index=False, if_exists='replace')
30
30
 
31
- to, _ = self.move_to_done(pod, namespace, to_session, from_session, keyspace, target_table)
31
+ to, _ = self.move_to_done(state, from_session, keyspace, target_table)
32
32
 
33
33
  succeeded = True
34
34
 
35
35
  return to, to_session
36
36
  finally:
37
37
  if succeeded:
38
- self.remove_csv(pod, namespace, from_session, table, target_table, multi_tables)
38
+ self.remove_csv(state, from_session, table, target_table, multi_tables)
39
39
  SQLite.clear_cache()
40
40
 
41
41
  if not multi_tables:
42
- query = f'select * from {target_table} limit 10'
43
- log2(query)
44
- SQLite.run_query(query, conn_passed=conn)
42
+ with export_db(state) as dbs:
43
+ dbs.sql(f'select * from {keyspace}.{target_table} limit 10')
44
+
45
+ def import_from_local_csv(self, state: ReplState,
46
+ keyspace: str, table: str, csv_file: str, multi_tables = True, create_db = False):
47
+ to_session = state.export_session
48
+
49
+ succeeded = False
50
+ try:
51
+ with ing(f'[{to_session}] Uploading to Sqlite', suppress_log=multi_tables):
52
+ # create a connection to single keyspace
53
+ with sqlite(to_session, keyspace) as conn:
54
+ bytes = bytes_generator_from_file(csv_file)
55
+ df = pandas.read_csv(GeneratorStream(bytes))
56
+ df.to_sql(table, conn, index=False, if_exists='replace')
45
57
 
46
- if conn:
47
- conn.close()
58
+ succeeded = True
59
+
60
+ return csv_file, to_session
61
+ finally:
62
+ if succeeded:
63
+ SQLite.clear_cache()
64
+
65
+ if not multi_tables:
66
+ with export_db(state) as dbs:
67
+ dbs.sql(f'select * from {keyspace}.{table} limit 10')
@@ -1,10 +1,9 @@
1
+ from adam.commands import extract_trailing_options, validate_args
1
2
  from adam.commands.command import Command
2
- from adam.commands.export.export_databases import ExportDatabases
3
+ from adam.commands.cql.utils_cql import cassandra_table_names
4
+ from adam.commands.export.export_databases import ExportDatabases, export_db
3
5
  from adam.config import Config
4
6
  from adam.repl_state import ReplState, RequiredState
5
- from adam.utils import log2
6
- from adam.utils_athena import Athena
7
- from adam.utils_sqlite import SQLite
8
7
 
9
8
  class ShowColumnCounts(Command):
10
9
  COMMAND = 'show column counts on'
@@ -28,36 +27,19 @@ class ShowColumnCounts(Command):
28
27
  if not(args := self.args(cmd)):
29
28
  return super().run(cmd, state)
30
29
 
31
- state, args = self.apply_state(args, state)
32
- if not self.validate_state(state):
33
- return state
34
-
35
- if not args:
36
- if state.in_repl:
37
- log2('Use a SQL statement.')
38
- else:
39
- log2('* SQL statement is missing.')
40
-
41
- Command.display_help()
42
-
43
- return 'command-missing'
30
+ with self.validate(args, state) as (args, state):
31
+ with extract_trailing_options(args, '&') as (args, backgrounded):
32
+ with validate_args(args, state, name='SQL statement') as table:
33
+ with export_db(state) as dbs:
34
+ query = Config().get(f'export.column_counts_query', 'select id, count(id) as columns from {table} group by id')
35
+ query = query.replace('{table}', table)
36
+ dbs.sql(query, state.export_session, backgrounded=backgrounded)
44
37
 
45
- copy_or_export = 'copy'
46
- if state.export_session.startswith('e'):
47
- copy_or_export = 'export'
48
-
49
- table = args[0]
50
- query = Config().get(f'{copy_or_export}.column_counts_query', 'select id, count(id) as columns from {table} group by id')
51
- query = query.replace('{table}', table)
52
- ExportDatabases.run_query(query, state.export_session)
53
-
54
- return state
38
+ return state
55
39
 
56
40
  def completion(self, state: ReplState):
57
- if not state.export_session:
58
- return {}
59
-
60
- return super().completion(state, lambda: {t: None for t in ExportDatabases.table_names(state.export_session)})
41
+ return super().completion(state, lambda: {t: None for t in ExportDatabases.table_names(state.export_session)}, auto_key='x.tables')
42
+ # return {}
61
43
 
62
44
  def help(self, _: ReplState):
63
45
  return f'{ShowColumnCounts.COMMAND} <export-table-name>\t show column count per id'
@@ -1,5 +1,6 @@
1
1
  from adam.commands.command import Command
2
2
  from adam.commands.devices.device_export import DeviceExport
3
+ from adam.commands.export.export_databases import export_db
3
4
  from adam.repl_state import ReplState
4
5
 
5
6
  class ShowExportDatabases(Command):
@@ -24,16 +25,15 @@ class ShowExportDatabases(Command):
24
25
  if not(args := self.args(cmd)):
25
26
  return super().run(cmd, state)
26
27
 
27
- state, args = self.apply_state(args, state)
28
- if not self.validate_state(state):
29
- return state
30
-
31
- DeviceExport().show_export_databases()
28
+ with self.validate(args, state) as (args, state):
29
+ with export_db(state) as dbs:
30
+ dbs.show_databases()
32
31
 
33
- return state
32
+ return state
34
33
 
35
34
  def completion(self, state: ReplState):
36
- return DeviceExport().ls_completion(ShowExportDatabases.COMMAND, state, default = super().completion(state))
35
+ return {}
36
+ # return DeviceExport().ls_completion(ShowExportDatabases.COMMAND, state, default = super().completion(state))
37
37
 
38
38
  def help(self, _: ReplState):
39
39
  return f'{ShowExportDatabases.COMMAND}\t list export databases'
@@ -1,8 +1,7 @@
1
+ from adam.commands import validate_args
1
2
  from adam.commands.command import Command
2
- from adam.commands.export.export_databases import ExportDatabases
3
- from adam.commands.export.exporter import Exporter
3
+ from adam.commands.export.export_sessions import ExportSessions, export_session
4
4
  from adam.repl_state import ReplState, RequiredState
5
- from adam.utils import log2
6
5
 
7
6
  class ShowExportSession(Command):
8
7
  COMMAND = 'show export session'
@@ -26,26 +25,15 @@ class ShowExportSession(Command):
26
25
  if not(args := self.args(cmd)):
27
26
  return super().run(cmd, state)
28
27
 
29
- state, args = self.apply_state(args, state)
30
- if not self.validate_state(state):
31
- return state
32
-
33
- if not args:
34
- if state.in_repl:
35
- log2('Specify export database name.')
36
- else:
37
- log2('* Database name is missing.')
38
-
39
- Command.display_help()
28
+ with self.validate(args, state) as (args, state):
29
+ with validate_args(args, state, name='export session') as session:
30
+ with export_session(state) as sessions:
31
+ sessions.show_session(session)
40
32
 
41
- return 'command-missing'
42
-
43
- ExportDatabases.disply_export_session(state.sts, state.pod, state.namespace, args[0])
44
-
45
- return state
33
+ return state
46
34
 
47
35
  def completion(self, state: ReplState):
48
- return super().completion(state, {session: None for session in Exporter.export_session_names(state.sts, state.pod, state.namespace)})
36
+ return {}
49
37
 
50
38
  def help(self, _: ReplState):
51
39
  return f'{ShowExportSession.COMMAND} <export-session-name>\t show export session'
@@ -1,8 +1,6 @@
1
1
  from adam.commands.command import Command
2
- from adam.commands.export.exporter import Exporter
2
+ from adam.commands.export.export_sessions import export_session
3
3
  from adam.repl_state import ReplState, RequiredState
4
- from adam.utils import lines_to_tabular, log
5
- from adam.utils_k8s.statefulsets import StatefulSets
6
4
 
7
5
  class ShowExportSessions(Command):
8
6
  COMMAND = 'show export sessions'
@@ -26,22 +24,14 @@ class ShowExportSessions(Command):
26
24
  if not(args := self.args(cmd)):
27
25
  return super().run(cmd, state)
28
26
 
29
- state, args = self.apply_state(args, state)
30
- if not self.validate_state(state):
31
- return state
32
-
33
- pod = state.pod
34
- if not pod:
35
- pod = StatefulSets.pod_names(state.sts, state.namespace)[0]
27
+ with self.validate(args, state) as (args, state):
28
+ with export_session(state) as sessions:
29
+ sessions.show_all_sessions()
36
30
 
37
- sessions: dict[str, str] = Exporter.find_export_sessions(pod, state.namespace)
38
- log(lines_to_tabular([f'{session}\t{export_state}' for session, export_state in sorted(sessions.items(), reverse=True)],
39
- header='EXPORT_SESSION\tSTATUS', separator='\t'))
40
-
41
- return state
31
+ return state
42
32
 
43
33
  def completion(self, state: ReplState):
44
- return super().completion(state)
34
+ return {}
45
35
 
46
36
  def help(self, _: ReplState):
47
37
  return f'{ShowExportSessions.COMMAND}\t list export sessions'
@@ -3,22 +3,33 @@ import re
3
3
 
4
4
  from adam.config import Config
5
5
  from adam.pod_exec_result import PodExecResult
6
+ from adam.repl_state import ReplState
6
7
  from adam.utils_k8s.cassandra_nodes import CassandraNodes
7
8
  from adam.utils_k8s.pods import log_prefix
9
+ from adam.utils_k8s.statefulsets import StatefulSets
8
10
 
9
11
  class ImportSpec:
10
- def __init__(self, session: str, importer: str):
12
+ def __init__(self, table_name: str, session: str = None, files: list[str] = None, importer: str = None):
13
+ self.table_name = table_name
11
14
  self.session = session
15
+ self.files = files
12
16
  self.importer = importer
13
17
 
14
- def parse_specs(specs_str: str):
15
- session: str = None
18
+ def parse_specs(specs_str: str, files = False):
19
+ session_or_files: str = None
16
20
  importer: str = None
21
+ table_name: str = None
17
22
 
18
23
  if specs_str:
19
- importer, session = ImportSpec._extract_importer(specs_str.strip(' '))
24
+ importer, rest = ImportSpec._extract_importer(specs_str.strip(' '))
25
+
26
+ if rest:
27
+ table_name, session_or_files = ImportSpec._extract_table_name(rest)
28
+
29
+ if not files:
30
+ return ImportSpec(table_name, session=session_or_files, importer=importer)
20
31
 
21
- return ImportSpec(session, importer)
32
+ return ImportSpec(table_name, files=[f.strip(' ') for f in session_or_files.split(',')], importer=importer)
22
33
 
23
34
  def _extract_importer(spec_str: str) -> tuple[str, str]:
24
35
  importer = None
@@ -32,12 +43,25 @@ class ImportSpec:
32
43
 
33
44
  return importer, rest
34
45
 
46
+ def _extract_table_name(spec_str: str) -> tuple[str, str]:
47
+ table_name = None
48
+ rest = spec_str
49
+
50
+ p = re.compile(r"(.*?)as\s+(.*)", re.IGNORECASE)
51
+ match = p.match(spec_str)
52
+ if match:
53
+ rest = match.group(1).strip(' ')
54
+ table_name = match.group(2).strip(' ')
55
+
56
+ return table_name, rest
57
+
35
58
  class ExportSpec(ImportSpec):
36
59
  def __init__(self, keyspace: str, consistency: str, importer: str, tables: list['ExportTableSpec'], session: str = None):
37
60
  super().__init__(None, importer)
38
61
 
39
62
  self.keyspace = keyspace
40
63
  self.consistency = consistency
64
+ self.importer = importer
41
65
  self.tables = tables
42
66
  self.session = session
43
67
 
@@ -152,11 +176,12 @@ class ExportTableSpec:
152
176
  return f'{self.keyspace}.{self.table}({self.columns}) as {self.target_table}'
153
177
 
154
178
  class ExportTableStatus:
155
- def __init__(self, keyspace: str, target_table: str, status: str, table: str = None):
179
+ def __init__(self, keyspace: str, target_table: str, status: str, table: str = None, csv_file: str = ''):
156
180
  self.keyspace = keyspace
157
181
  self.target_table = target_table
158
182
  self.status = status
159
183
  self.table = table
184
+ self.csv_file = csv_file
160
185
 
161
186
  def __str__(self):
162
187
  return f'{self.keyspace}.{self.table} as {self.target_table} = {self.status}'
@@ -167,7 +192,7 @@ class ExportTableStatus:
167
192
 
168
193
  return False
169
194
 
170
- def from_session(sts: str, pod: str, namespace: str, export_session: str):
195
+ def from_session(sts: str, pod: str, namespace: str, export_session: str) -> tuple['ExportTableStatus', str]:
171
196
  statuses: list[ExportTableStatus] = []
172
197
 
173
198
  status_in_whole = 'done'
@@ -202,8 +227,8 @@ class ExportTableStatus:
202
227
  target_table = m.group(2)
203
228
  state = m.group(3)
204
229
  if state == '.pending_import':
205
- _, table = get_csv_files_n_table(target_table)
206
- return ExportTableStatus(keyspace, target_table, 'pending_import', table)
230
+ csv_files, table = get_csv_files_n_table(target_table)
231
+ return ExportTableStatus(keyspace, target_table, 'pending_import', table, csv_files[0] if csv_files else '')
207
232
  elif state == '.done':
208
233
  return ExportTableStatus(keyspace, target_table, 'done', target_table)
209
234
 
@@ -213,7 +238,7 @@ class ExportTableStatus:
213
238
  if r.exit_code() == 0:
214
239
  csv_files, table = get_csv_files_n_table(target_table)
215
240
  if csv_files:
216
- return ExportTableStatus(keyspace, target_table, 'exported', table)
241
+ return ExportTableStatus(keyspace, target_table, 'exported', table, csv_files[0])
217
242
  else:
218
243
  return ExportTableStatus(keyspace, target_table, 'imported', target_table)
219
244
  else:
@@ -288,4 +313,32 @@ class GeneratorStream(io.RawIOBase):
288
313
 
289
314
  data = self._buffer[:size]
290
315
  self._buffer = self._buffer[size:]
291
- return data
316
+ return data
317
+
318
+ class PodPushHandler:
319
+ def __init__(self, state: ReplState, pod: str = None):
320
+ self.state = state
321
+ self.pushed = False
322
+ self.pod = pod
323
+
324
+ def __enter__(self):
325
+ state = self.state
326
+
327
+ if not state.pod:
328
+ self.pushed = True
329
+ state.push()
330
+
331
+ if not self.pod:
332
+ self.pod = StatefulSets.pod_names(state.sts, state.namespace)[0]
333
+ state.pod = self.pod
334
+
335
+ return state
336
+
337
+ def __exit__(self, exc_type, exc_val, exc_tb):
338
+ if self.pushed:
339
+ self.state.pop()
340
+
341
+ return False
342
+
343
+ def state_with_pod(state: ReplState, pod: str = None):
344
+ return PodPushHandler(state, pod=pod)
@@ -0,0 +1,51 @@
1
+ import os
2
+
3
+ from adam.commands.command import Command
4
+ from adam.repl_state import ReplState
5
+ from adam.utils import log2
6
+ from adam.utils_local import local_tmp_dir
7
+
8
+ class FindLocalFiles(Command):
9
+ COMMAND = 'find local'
10
+
11
+ # the singleton pattern
12
+ def __new__(cls, *args, **kwargs):
13
+ if not hasattr(cls, 'instance'): cls.instance = super(FindLocalFiles, cls).__new__(cls)
14
+
15
+ return cls.instance
16
+
17
+ def __init__(self, successor: Command=None):
18
+ super().__init__(successor)
19
+
20
+ def command(self):
21
+ return FindLocalFiles.COMMAND
22
+
23
+ def run(self, cmd: str, state: ReplState):
24
+ if not(args := self.args(cmd)):
25
+ return super().run(cmd, state)
26
+
27
+ with self.validate(args, state) as (args, state):
28
+ cmd = 'find'
29
+
30
+ if not args:
31
+ cmd = f'find {local_tmp_dir()}'
32
+ elif len(args) == 1:
33
+ cmd = f"find {local_tmp_dir()} -name '{args[0]}'"
34
+ else:
35
+ new_args = [f"'{arg}'" if '*' in arg else arg for arg in args]
36
+ cmd = 'find ' + ' '.join(new_args)
37
+
38
+ log2(cmd)
39
+ os.system(cmd)
40
+
41
+ return state
42
+
43
+ def completion(self, state: ReplState):
44
+ return super().completion(state, {
45
+ '*.csv': None,
46
+ '*.db': None,
47
+ '*': None
48
+ })
49
+
50
+ def help(self, _: ReplState):
51
+ return f'{FindLocalFiles.COMMAND} [linux-find-arguments]\t find files from local machine'