kaqing 2.0.184__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.
- adam/app_session.py +1 -1
- adam/batch.py +15 -15
- adam/commands/app/app.py +2 -2
- adam/commands/app/show_app_actions.py +1 -1
- adam/commands/{show → app}/show_login.py +1 -1
- adam/commands/app/utils_app.py +9 -1
- adam/commands/audit/audit.py +6 -20
- adam/commands/audit/audit_repair_tables.py +1 -1
- adam/commands/audit/audit_run.py +1 -1
- adam/commands/audit/completions_l.py +15 -0
- adam/commands/audit/show_last10.py +0 -1
- adam/commands/bash/bash.py +1 -1
- adam/commands/bash/utils_bash.py +1 -1
- adam/commands/cassandra/download_cassandra_log.py +45 -0
- adam/commands/cassandra/restart_cluster.py +47 -0
- adam/commands/cassandra/restart_node.py +51 -0
- adam/commands/cassandra/restart_nodes.py +47 -0
- adam/commands/{rollout.py → cassandra/rollout.py} +1 -1
- adam/commands/{show → cassandra}/show_cassandra_repairs.py +5 -3
- adam/commands/{show → cassandra}/show_cassandra_status.py +22 -15
- adam/commands/cassandra/show_processes.py +50 -0
- adam/commands/{show → cassandra}/show_storage.py +10 -8
- adam/commands/cli/__init__.py +0 -0
- adam/commands/{cli_commands.py → cli/cli_commands.py} +6 -1
- adam/commands/{clipboard_copy.py → cli/clipboard_copy.py} +2 -2
- adam/commands/{show/show_commands.py → cli/show_cli_commands.py} +2 -2
- adam/commands/command.py +22 -9
- adam/commands/commands_utils.py +14 -6
- adam/commands/config/__init__.py +0 -0
- adam/commands/{show → config}/show_params.py +1 -1
- adam/commands/{alter_tables.py → cql/alter_tables.py} +1 -1
- adam/commands/cql/completions_c.py +29 -0
- adam/commands/cql/cqlsh.py +2 -6
- adam/commands/cql/utils_cql.py +26 -17
- adam/commands/debug/__init__.py +0 -0
- adam/commands/debug/debug.py +22 -0
- adam/commands/debug/debug_completes.py +35 -0
- adam/commands/debug/debug_timings.py +35 -0
- adam/commands/debug/show_offloaded_completes.py +45 -0
- adam/commands/devices/device.py +30 -4
- adam/commands/devices/device_app.py +1 -1
- adam/commands/devices/device_export.py +5 -2
- adam/commands/devices/device_postgres.py +13 -3
- adam/commands/devices/devices.py +1 -1
- adam/commands/diag/__init__.py +0 -0
- adam/commands/{check.py → diag/check.py} +1 -1
- adam/commands/diag/generate_report.py +52 -0
- adam/commands/export/completions_x.py +11 -0
- adam/commands/export/download_export_session.py +2 -1
- adam/commands/export/export.py +0 -16
- adam/commands/export/export_databases.py +16 -10
- adam/commands/export/export_select.py +8 -33
- adam/commands/export/export_sessions.py +12 -11
- adam/commands/export/export_use.py +3 -3
- adam/commands/export/export_x_select.py +48 -0
- adam/commands/export/exporter.py +140 -53
- adam/commands/export/import_files.py +2 -2
- adam/commands/export/import_session.py +0 -4
- adam/commands/export/importer.py +11 -11
- adam/commands/export/importer_athena.py +15 -35
- adam/commands/export/importer_sqlite.py +19 -8
- adam/commands/export/show_column_counts.py +10 -10
- adam/commands/export/show_export_databases.py +2 -1
- adam/commands/export/show_export_session.py +1 -1
- adam/commands/export/show_export_sessions.py +1 -1
- adam/commands/export/utils_export.py +38 -15
- adam/commands/fs/__init__.py +0 -0
- adam/commands/{cat.py → fs/cat.py} +2 -2
- adam/commands/fs/cat_local.py +42 -0
- adam/commands/{cd.py → fs/cd.py} +2 -2
- adam/commands/{download_file.py → fs/download_file.py} +5 -5
- adam/commands/{find_files.py → fs/find_files.py} +4 -4
- adam/commands/{find_processes.py → fs/find_processes.py} +3 -3
- adam/commands/{head.py → fs/head.py} +2 -2
- adam/commands/{ls.py → fs/ls.py} +2 -2
- adam/commands/fs/ls_local.py +40 -0
- adam/commands/fs/rm.py +18 -0
- adam/commands/fs/rm_downloads.py +39 -0
- adam/commands/fs/rm_logs.py +38 -0
- adam/commands/{show → fs}/show_adam.py +1 -1
- adam/commands/intermediate_command.py +3 -0
- adam/commands/medusa/medusa_restore.py +2 -16
- adam/commands/medusa/utils_medusa.py +15 -0
- adam/commands/nodetool/__init__.py +0 -0
- adam/commands/{nodetool.py → nodetool/nodetool.py} +3 -8
- adam/commands/postgres/completions_p.py +22 -0
- adam/commands/postgres/postgres.py +7 -14
- adam/commands/postgres/postgres_databases.py +3 -3
- adam/commands/postgres/postgres_ls.py +1 -1
- adam/commands/postgres/utils_postgres.py +12 -2
- adam/commands/preview_table.py +1 -1
- adam/commands/reaper/reaper_schedule_activate.py +6 -2
- adam/commands/reaper/reaper_schedule_start.py +1 -2
- adam/commands/reaper/reaper_schedule_stop.py +1 -2
- adam/commands/reaper/utils_reaper.py +10 -1
- adam/commands/repair/repair_scan.py +0 -2
- adam/commands/repair/repair_stop.py +0 -1
- adam/commands/{show/show.py → show.py} +12 -11
- adam/config.py +4 -5
- adam/embedded_params.py +1 -1
- adam/repl.py +22 -9
- adam/repl_commands.py +50 -42
- adam/repl_session.py +9 -1
- adam/repl_state.py +16 -1
- adam/sql/async_executor.py +62 -0
- adam/sql/lark_completer.py +286 -0
- adam/sql/lark_parser.py +604 -0
- adam/sql/qingl.lark +1076 -0
- adam/sso/cred_cache.py +2 -5
- adam/utils.py +216 -79
- adam/utils_k8s/app_clusters.py +11 -4
- adam/utils_k8s/app_pods.py +10 -5
- adam/utils_k8s/cassandra_clusters.py +8 -4
- adam/utils_k8s/cassandra_nodes.py +14 -5
- adam/utils_k8s/k8s.py +9 -0
- adam/utils_k8s/kube_context.py +1 -4
- adam/{pod_exec_result.py → utils_k8s/pod_exec_result.py} +8 -2
- adam/utils_k8s/pods.py +83 -24
- adam/utils_k8s/statefulsets.py +5 -2
- adam/utils_local.py +78 -2
- adam/utils_repl/appendable_completer.py +6 -0
- adam/utils_repl/repl_completer.py +51 -4
- adam/utils_sqlite.py +3 -8
- adam/version.py +1 -1
- {kaqing-2.0.184.dist-info → kaqing-2.0.214.dist-info}/METADATA +1 -1
- kaqing-2.0.214.dist-info/RECORD +272 -0
- kaqing-2.0.214.dist-info/top_level.txt +2 -0
- teddy/__init__.py +0 -0
- teddy/lark_parser.py +436 -0
- teddy/lark_parser2.py +618 -0
- adam/commands/cql/cql_completions.py +0 -32
- adam/commands/export/export_select_x.py +0 -54
- adam/commands/logs.py +0 -37
- adam/commands/postgres/psql_completions.py +0 -11
- adam/commands/report.py +0 -61
- adam/commands/restart.py +0 -60
- adam/commands/show/show_processes.py +0 -49
- kaqing-2.0.184.dist-info/RECORD +0 -244
- kaqing-2.0.184.dist-info/top_level.txt +0 -1
- /adam/commands/{login.py → app/login.py} +0 -0
- /adam/commands/{show → cassandra}/__init__.py +0 -0
- /adam/commands/{show → cassandra}/show_cassandra_version.py +0 -0
- /adam/commands/{watch.py → cassandra/watch.py} +0 -0
- /adam/commands/{param_get.py → config/param_get.py} +0 -0
- /adam/commands/{param_set.py → config/param_set.py} +0 -0
- /adam/commands/{issues.py → diag/issues.py} +0 -0
- /adam/commands/{pwd.py → fs/pwd.py} +0 -0
- /adam/commands/{shell.py → fs/shell.py} +0 -0
- /adam/commands/{show → fs}/show_host.py +0 -0
- /adam/commands/{nodetool_commands.py → nodetool/nodetool_commands.py} +0 -0
- {kaqing-2.0.184.dist-info → kaqing-2.0.214.dist-info}/WHEEL +0 -0
- {kaqing-2.0.184.dist-info → kaqing-2.0.214.dist-info}/entry_points.txt +0 -0
adam/commands/export/exporter.py
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
from datetime import datetime
|
|
2
|
+
import os
|
|
2
3
|
import time
|
|
4
|
+
import traceback
|
|
3
5
|
|
|
4
6
|
from adam.commands.command import InvalidArgumentsException
|
|
5
7
|
from adam.commands.cql.utils_cql import cassandra_table_names, run_cql, table_spec
|
|
@@ -8,13 +10,12 @@ from adam.commands.export.export_sessions import ExportSessions
|
|
|
8
10
|
from adam.commands.export.importer import Importer
|
|
9
11
|
from adam.commands.export.importer_athena import AthenaImporter
|
|
10
12
|
from adam.commands.export.importer_sqlite import SqliteImporter
|
|
11
|
-
from adam.commands.export.utils_export import ExportSpec, ExportTableStatus, ExportTableSpec, ImportSpec, csv_dir, find_files, state_with_pod
|
|
13
|
+
from adam.commands.export.utils_export import ExportSpec, ExportTableStatus, ExportTableSpec, ImportSpec, csv_dir, export_log_dir, find_files, os_system_exec, state_with_pod
|
|
12
14
|
from adam.config import Config
|
|
13
|
-
from adam.
|
|
15
|
+
from adam.repl_session import ReplSession
|
|
14
16
|
from adam.repl_state import ReplState
|
|
15
|
-
from adam.utils import debug, log, parallelize, log2, ing, log_exc
|
|
17
|
+
from adam.utils import debug, kaqing_log_file_name, log, offload, parallelize, log2, ing, log_exc
|
|
16
18
|
from adam.utils_k8s.cassandra_nodes import CassandraNodes
|
|
17
|
-
from adam.utils_k8s.pods import log_prefix
|
|
18
19
|
|
|
19
20
|
class Exporter:
|
|
20
21
|
def export_tables(args: list[str], state: ReplState, export_only: bool = False, max_workers = 0) -> tuple[list[str], ExportSpec]:
|
|
@@ -133,11 +134,9 @@ class Exporter:
|
|
|
133
134
|
|
|
134
135
|
prefix = Importer.prefix_from_importer(spec.importer)
|
|
135
136
|
if spec.session:
|
|
136
|
-
|
|
137
|
+
state.export_session = f'{prefix}{spec.session[1:]}'
|
|
137
138
|
else:
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
state.export_session = spec.session
|
|
139
|
+
state.export_session = f'{prefix}{datetime.now().strftime("%Y%m%d%H%M%S")[3:]}'
|
|
141
140
|
|
|
142
141
|
return spec
|
|
143
142
|
|
|
@@ -154,89 +153,160 @@ class Exporter:
|
|
|
154
153
|
if export_state == 'init':
|
|
155
154
|
CassandraNodes.exec(state.pod, state.namespace, f'rm -rf {csv_dir()}/{spec.session}_*', show_out=Config().is_debug(), shell='bash')
|
|
156
155
|
|
|
157
|
-
|
|
156
|
+
job_log = kaqing_log_file_name()
|
|
157
|
+
|
|
158
|
+
action = f'[{spec.session}] Triggering export of'
|
|
158
159
|
if export_state == 'init':
|
|
159
160
|
action = f'[{spec.session}] Preparing|Prepared'
|
|
160
161
|
elif export_state == 'import':
|
|
161
162
|
action = f'[{spec.session}] Importing|Imported'
|
|
162
163
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
164
|
+
msg = action + ' {size} Cassandra tables'
|
|
165
|
+
|
|
166
|
+
if export_state != 'init':
|
|
167
|
+
log2(f'[{spec.session}] Logging to {job_log}...')
|
|
168
|
+
ReplSession().append_history(f':cat {job_log}')
|
|
169
|
+
|
|
170
|
+
pod = state.pod
|
|
171
|
+
with parallelize(spec.tables, max_workers, msg=msg, collect=export_state == 'init', name='exporter') as exec:
|
|
172
|
+
return exec.map(lambda table: Exporter.export_table(table,
|
|
173
|
+
state.with_pod(pod),
|
|
174
|
+
spec.session,
|
|
175
|
+
spec.importer,
|
|
176
|
+
export_only,
|
|
177
|
+
len(spec.tables) > 1,
|
|
178
|
+
consistency=spec.consistency,
|
|
179
|
+
export_state=export_state,
|
|
180
|
+
job_log=None if export_state == 'init' else job_log)), spec
|
|
181
|
+
|
|
182
|
+
def export_table(spec: ExportTableSpec,
|
|
183
|
+
state: ReplState,
|
|
184
|
+
session: str,
|
|
185
|
+
importer: str,
|
|
186
|
+
export_only = False,
|
|
187
|
+
multi_tables = True,
|
|
188
|
+
consistency: str = None,
|
|
189
|
+
export_state=None,
|
|
190
|
+
job_log: str = None):
|
|
167
191
|
s: str = None
|
|
168
192
|
|
|
169
193
|
table, target_table, columns = Exporter.resove_table_n_columns(spec, state, include_ks_in_target=False, importer=importer)
|
|
170
194
|
|
|
171
|
-
log_file = f'{
|
|
195
|
+
log_file = f'{export_log_dir()}/{session}_{spec.keyspace}.{target_table}.log'
|
|
172
196
|
create_db = not state.export_session
|
|
173
197
|
|
|
174
198
|
if export_state == 'init':
|
|
175
199
|
Exporter.create_table_log(spec, state, session, table, target_table)
|
|
176
200
|
return 'table_log_created'
|
|
177
201
|
else:
|
|
178
|
-
|
|
179
|
-
|
|
202
|
+
try:
|
|
203
|
+
if export_state == 'pending_export':
|
|
204
|
+
Exporter.export_to_csv(spec, state, session, table, target_table, columns, multi_tables=multi_tables, consistency=consistency, job_log=job_log)
|
|
180
205
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
206
|
+
log_files: list[str] = find_files(state.pod, state.namespace, f'{log_file}*')
|
|
207
|
+
if not log_files:
|
|
208
|
+
return s
|
|
184
209
|
|
|
185
|
-
|
|
210
|
+
log_file = log_files[0]
|
|
186
211
|
|
|
187
|
-
|
|
188
|
-
while status.status != 'done':
|
|
189
|
-
if status.status == 'export_in_pregress':
|
|
190
|
-
debug('Exporting to CSV is still in progess, sleeping for 1 sec...')
|
|
191
|
-
time.sleep(1)
|
|
192
|
-
elif status.status == 'exported':
|
|
193
|
-
log_file = Exporter.rename_to_pending_import(spec, state, session, target_table)
|
|
194
|
-
if importer == 'csv' or export_only:
|
|
195
|
-
return 'pending_import'
|
|
196
|
-
elif status.status == 'pending_import':
|
|
197
|
-
log_file, session = Exporter.import_from_csv(spec, state, session, importer, table, target_table, columns, multi_tables=multi_tables, create_db=create_db)
|
|
212
|
+
status: ExportTableStatus = ExportTableStatus.from_log_file(state.pod, state.namespace, session, log_file)
|
|
198
213
|
|
|
199
|
-
|
|
214
|
+
with offload(name='exporter') as exec:
|
|
215
|
+
ctx = ExportTableContext(spec, state, session, importer, export_only, multi_tables, table, target_table, columns, create_db, log_file, status, job_log)
|
|
216
|
+
exec.submit(lambda: Exporter.export_loop(ctx))
|
|
217
|
+
# Exporter.export_loop(ExportTableContext(spec, state, session, importer, export_only, multi_tables, table, target_table, columns, create_db, log_file, status))
|
|
218
|
+
except:
|
|
219
|
+
traceback.print_exc()
|
|
200
220
|
|
|
201
221
|
return status.status
|
|
202
222
|
|
|
223
|
+
def export_loop(ctx: 'ExportTableContext'):
|
|
224
|
+
try:
|
|
225
|
+
while ctx.status.status != 'done':
|
|
226
|
+
if ctx.status.status == 'export_in_pregress':
|
|
227
|
+
debug('Exporting to CSV is still in progess, sleeping for 1 sec...')
|
|
228
|
+
time.sleep(1)
|
|
229
|
+
elif ctx.status.status == 'exported':
|
|
230
|
+
ctx.log_file = Exporter.rename_to_pending_import(ctx.spec, ctx.state, ctx.session, ctx.target_table)
|
|
231
|
+
ExportSessions.clear_export_session_cache()
|
|
232
|
+
if ctx.importer == 'csv' or ctx.export_only:
|
|
233
|
+
return 'pending_import'
|
|
234
|
+
elif ctx.status.status == 'pending_import':
|
|
235
|
+
ctx.log_file, ctx.session = Exporter.import_from_csv(ctx.spec,
|
|
236
|
+
ctx.state,
|
|
237
|
+
ctx.session,
|
|
238
|
+
ctx.importer,
|
|
239
|
+
ctx.table,
|
|
240
|
+
ctx.target_table,
|
|
241
|
+
ctx.columns,
|
|
242
|
+
multi_tables=ctx.multi_tables,
|
|
243
|
+
create_db=ctx.create_db,
|
|
244
|
+
job_log=ctx.f)
|
|
245
|
+
|
|
246
|
+
ctx.status = ExportTableStatus.from_log_file(ctx.state.pod, ctx.state.namespace, ctx.session, ctx.log_file)
|
|
247
|
+
|
|
248
|
+
return ctx.status.status
|
|
249
|
+
except:
|
|
250
|
+
traceback.print_exc()
|
|
251
|
+
|
|
203
252
|
def create_table_log(spec: ExportTableSpec, state: ReplState, session: str, table: str, target_table: str):
|
|
204
|
-
log_file = f'{
|
|
253
|
+
log_file = f'{export_log_dir()}/{session}_{spec.keyspace}.{target_table}.log'
|
|
254
|
+
dir = os.path.dirname(log_file)
|
|
205
255
|
|
|
206
|
-
|
|
256
|
+
cmd = f'rm -f {log_file}* && mkdir -p {dir} && touch {log_file}'
|
|
257
|
+
os_system_exec(cmd, show_out=Config().is_debug())
|
|
207
258
|
|
|
208
259
|
return table
|
|
209
260
|
|
|
210
|
-
def export_to_csv(spec: ExportTableSpec,
|
|
261
|
+
def export_to_csv(spec: ExportTableSpec,
|
|
262
|
+
state: ReplState,
|
|
263
|
+
session: str,
|
|
264
|
+
table: str,
|
|
265
|
+
target_table: str,
|
|
266
|
+
columns: str,
|
|
267
|
+
multi_tables = True,
|
|
268
|
+
consistency: str = None,
|
|
269
|
+
job_log: str = None):
|
|
211
270
|
db = f'{session}_{target_table}'
|
|
212
271
|
|
|
213
272
|
CassandraNodes.exec(state.pod, state.namespace, f'mkdir -p {csv_dir()}/{db}', show_out=Config().is_debug(), shell='bash')
|
|
214
273
|
csv_file = f'{csv_dir()}/{db}/{table}.csv'
|
|
215
|
-
|
|
274
|
+
table_log_file = f'{export_log_dir()}/{session}_{spec.keyspace}.{target_table}.log'
|
|
216
275
|
|
|
217
276
|
suppress_ing_log = Config().is_debug() or multi_tables
|
|
218
277
|
queries = []
|
|
219
278
|
if consistency:
|
|
220
279
|
queries.append(f'CONSISTENCY {consistency}')
|
|
221
280
|
queries.append(f"COPY {spec.keyspace}.{table}({columns}) TO '{csv_file}' WITH HEADER = TRUE")
|
|
222
|
-
r: PodExecResult = ing(
|
|
223
|
-
f'[{session}] Dumping table {spec.keyspace}.{table}{f" with consistency {consistency}" if consistency else ""}',
|
|
224
|
-
lambda: run_cql(state, ';'.join(queries), show_out=Config().is_debug(), backgrounded=True, log_file=log_file),
|
|
225
|
-
suppress_log=suppress_ing_log)
|
|
226
281
|
|
|
227
|
-
|
|
282
|
+
with ing(f'[{session}] Triggering dump of table {spec.keyspace}.{table}{f" with consistency {consistency}" if consistency else ""}',
|
|
283
|
+
suppress_log=suppress_ing_log,
|
|
284
|
+
job_log = job_log):
|
|
285
|
+
run_cql(state, ';'.join(queries), show_out=Config().is_debug(), backgrounded=True, log_file=table_log_file, history=False)
|
|
286
|
+
|
|
287
|
+
return table_log_file
|
|
228
288
|
|
|
229
289
|
def rename_to_pending_import(spec: ExportTableSpec, state: ReplState, session: str, target_table: str):
|
|
230
|
-
log_file = f'{
|
|
290
|
+
log_file = f'{export_log_dir()}/{session}_{spec.keyspace}.{target_table}.log'
|
|
231
291
|
to = f'{log_file}.pending_import'
|
|
232
292
|
|
|
233
|
-
|
|
293
|
+
cmd =f'mv {log_file} {to}'
|
|
294
|
+
os_system_exec(cmd, show_out=Config().is_debug())
|
|
234
295
|
|
|
235
296
|
return to
|
|
236
297
|
|
|
237
|
-
def import_from_csv(spec: ExportTableSpec,
|
|
298
|
+
def import_from_csv(spec: ExportTableSpec,
|
|
299
|
+
state: ReplState,
|
|
300
|
+
session: str,
|
|
301
|
+
importer: str,
|
|
302
|
+
table: str,
|
|
303
|
+
target_table: str,
|
|
304
|
+
columns: str,
|
|
305
|
+
multi_tables = True,
|
|
306
|
+
create_db = False,
|
|
307
|
+
job_log: str = None):
|
|
238
308
|
im = AthenaImporter() if importer == 'athena' else SqliteImporter()
|
|
239
|
-
return im.import_from_csv(state, session if session else state.export_session, spec.keyspace, table, target_table, columns, multi_tables, create_db)
|
|
309
|
+
return im.import_from_csv(state, session if session else state.export_session, spec.keyspace, table, target_table, columns, multi_tables, create_db, job_log=job_log)
|
|
240
310
|
|
|
241
311
|
def resove_table_n_columns(spec: ExportTableSpec, state: ReplState, include_ks_in_target = False, importer = 'sqlite'):
|
|
242
312
|
table = spec.table
|
|
@@ -262,6 +332,22 @@ class Exporter:
|
|
|
262
332
|
|
|
263
333
|
return table, target_table, columns
|
|
264
334
|
|
|
335
|
+
class ExportTableContext:
|
|
336
|
+
def __init__(self, spec: ExportTableSpec, state: ReplState, session: str, importer: str, export_only = False, multi_tables = True, table: str = None, target_table: str = None, columns: str = None, create_db = False, log_file: str = None, status: ExportTableStatus = None, f: str = None):
|
|
337
|
+
self.spec = spec
|
|
338
|
+
self.state = state
|
|
339
|
+
self.session = session
|
|
340
|
+
self.importer = importer
|
|
341
|
+
self.export_only = export_only
|
|
342
|
+
self.multi_tables = multi_tables
|
|
343
|
+
self.table = table
|
|
344
|
+
self.target_table = target_table
|
|
345
|
+
self.columns = columns
|
|
346
|
+
self.create_db = create_db
|
|
347
|
+
self.log_file = log_file
|
|
348
|
+
self.status = status
|
|
349
|
+
self.f = f
|
|
350
|
+
|
|
265
351
|
class ExportService:
|
|
266
352
|
def __init__(self, handler: 'ExporterHandler'):
|
|
267
353
|
self.handler = handler
|
|
@@ -279,16 +365,17 @@ class ExportService:
|
|
|
279
365
|
|
|
280
366
|
ExportSessions.clear_export_session_cache()
|
|
281
367
|
|
|
282
|
-
if spec.importer == 'csv' or export_only:
|
|
283
|
-
|
|
284
|
-
else:
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
368
|
+
# if spec.importer == 'csv' or export_only:
|
|
369
|
+
# ExportSessions.show_session(state.sts, state.pod, state.namespace, spec.session)
|
|
370
|
+
# else:
|
|
371
|
+
# log()
|
|
372
|
+
# with export_db(state) as dbs:
|
|
373
|
+
# dbs.show_database()
|
|
288
374
|
finally:
|
|
375
|
+
pass
|
|
289
376
|
# if exporting to csv, do not bind the new session id to repl state
|
|
290
|
-
if spec and spec.importer == 'csv':
|
|
291
|
-
|
|
377
|
+
# if spec and spec.importer == 'csv':
|
|
378
|
+
# state.export_session = export_session
|
|
292
379
|
|
|
293
380
|
return state
|
|
294
381
|
|
|
@@ -35,8 +35,8 @@ class ImportCSVFiles(Command):
|
|
|
35
35
|
|
|
36
36
|
def completion(self, state: ReplState):
|
|
37
37
|
# warm up cache
|
|
38
|
-
ExportSessions.export_session_names(state.sts, state.pod, state.namespace)
|
|
39
|
-
ExportSessions.export_session_names(state.sts, state.pod, state.namespace, export_state='pending_import')
|
|
38
|
+
# ExportSessions.export_session_names(state.sts, state.pod, state.namespace)
|
|
39
|
+
# ExportSessions.export_session_names(state.sts, state.pod, state.namespace, export_state='pending_import')
|
|
40
40
|
|
|
41
41
|
return {}
|
|
42
42
|
|
|
@@ -34,10 +34,6 @@ class ImportSession(Command):
|
|
|
34
34
|
return exporter.import_session(spec)
|
|
35
35
|
|
|
36
36
|
def completion(self, state: ReplState):
|
|
37
|
-
# warm up cache
|
|
38
|
-
ExportSessions.export_session_names(state.sts, state.pod, state.namespace)
|
|
39
|
-
ExportSessions.export_session_names(state.sts, state.pod, state.namespace, export_state='pending_import')
|
|
40
|
-
|
|
41
37
|
return {}
|
|
42
38
|
|
|
43
39
|
def help(self, _: ReplState):
|
adam/commands/export/importer.py
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
from abc import abstractmethod
|
|
2
2
|
|
|
3
|
-
from adam.commands.export.utils_export import csv_dir
|
|
3
|
+
from adam.commands.export.utils_export import csv_dir, export_log_dir, os_system_exec
|
|
4
4
|
from adam.config import Config
|
|
5
5
|
from adam.repl_state import ReplState
|
|
6
6
|
from adam.utils import ing
|
|
7
|
-
from adam.utils_k8s.cassandra_nodes import CassandraNodes
|
|
8
|
-
from adam.utils_k8s.pods import log_prefix
|
|
9
7
|
|
|
10
8
|
class Importer:
|
|
11
9
|
@abstractmethod
|
|
@@ -13,7 +11,7 @@ class Importer:
|
|
|
13
11
|
pass
|
|
14
12
|
|
|
15
13
|
@abstractmethod
|
|
16
|
-
def import_from_csv(self, state: ReplState, 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, keyspace: str, table: str, target_table: str, columns: str, multi_tables = True, create_db = False, log_file: str = None):
|
|
17
15
|
pass
|
|
18
16
|
|
|
19
17
|
@abstractmethod
|
|
@@ -27,11 +25,12 @@ class Importer:
|
|
|
27
25
|
pod = state.pod
|
|
28
26
|
namespace = state.namespace
|
|
29
27
|
to_session = state.export_session
|
|
30
|
-
log_file = f'{
|
|
28
|
+
log_file = f'{export_log_dir()}/{from_session}_{keyspace}.{target_table}.log.pending_import'
|
|
31
29
|
|
|
32
|
-
to = f'{
|
|
30
|
+
to = f'{export_log_dir()}/{to_session}_{keyspace}.{target_table}.log.done'
|
|
33
31
|
|
|
34
|
-
|
|
32
|
+
cmd = f'mv {log_file} {to}'
|
|
33
|
+
os_system_exec(cmd, show_out=Config().is_debug())
|
|
35
34
|
|
|
36
35
|
return to, to_session
|
|
37
36
|
|
|
@@ -41,12 +40,13 @@ class Importer:
|
|
|
41
40
|
|
|
42
41
|
return session
|
|
43
42
|
|
|
44
|
-
def remove_csv(self, state: ReplState, from_session: str, table: str, target_table: str, multi_tables = True):
|
|
43
|
+
def remove_csv(self, state: ReplState, from_session: str, table: str, target_table: str, multi_tables = True, job_log: str = None):
|
|
45
44
|
pod = state.pod
|
|
46
45
|
namespace = state.namespace
|
|
47
46
|
|
|
48
|
-
with ing(f'[{from_session}] Cleaning up temporary files', suppress_log=multi_tables):
|
|
49
|
-
|
|
47
|
+
with ing(f'[{from_session}] Cleaning up temporary files', suppress_log=multi_tables, job_log=job_log):
|
|
48
|
+
cmd = f'rm -rf {self.csv_file(from_session, table, target_table)}'
|
|
49
|
+
os_system_exec(cmd, show_out=Config().is_debug())
|
|
50
50
|
|
|
51
51
|
def db(self, session: str, keyspace: str):
|
|
52
52
|
return f'{session}_{keyspace}'
|
|
@@ -78,4 +78,4 @@ class Importer:
|
|
|
78
78
|
elif session.startswith('e'):
|
|
79
79
|
importer = 'athena'
|
|
80
80
|
|
|
81
|
-
return importer
|
|
81
|
+
return importer
|
|
@@ -19,9 +19,16 @@ class AthenaImporter(Importer):
|
|
|
19
19
|
def prefix(self):
|
|
20
20
|
return 'e'
|
|
21
21
|
|
|
22
|
-
def import_from_csv(self,
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
def import_from_csv(self,
|
|
23
|
+
state: ReplState,
|
|
24
|
+
from_session: str,
|
|
25
|
+
keyspace: str,
|
|
26
|
+
table: str,
|
|
27
|
+
target_table: str,
|
|
28
|
+
columns: str,
|
|
29
|
+
multi_tables = True,
|
|
30
|
+
create_db = False,
|
|
31
|
+
job_log: str = None):
|
|
25
32
|
csv_file = self.csv_file(from_session, table, target_table)
|
|
26
33
|
pod = state.pod
|
|
27
34
|
namespace = state.namespace
|
|
@@ -39,35 +46,6 @@ class AthenaImporter(Importer):
|
|
|
39
46
|
s3.upload_fileobj(GeneratorStream(bytes), bucket, f'export/{database}/{keyspace}/{target_table}/{table}.csv')
|
|
40
47
|
|
|
41
48
|
self.create_schema(to_session, bucket, database, keyspace, table, columns, multi_tables, create_db)
|
|
42
|
-
# msg: str = None
|
|
43
|
-
# if create_db:
|
|
44
|
-
# msg = f"[{to_session}] Creating database {database}"
|
|
45
|
-
# else:
|
|
46
|
-
# msg = f"[{to_session}] Creating table {target_table}"
|
|
47
|
-
# with ing(msg, suppress_log=multi_tables):
|
|
48
|
-
# query = f'CREATE DATABASE IF NOT EXISTS {database};'
|
|
49
|
-
# debug(query)
|
|
50
|
-
# Athena.query(query, 'default')
|
|
51
|
-
|
|
52
|
-
# query = f'DROP TABLE IF EXISTS {target_table};'
|
|
53
|
-
# debug(query)
|
|
54
|
-
# Athena.query(query, database)
|
|
55
|
-
|
|
56
|
-
# athena_columns = ', '.join([f'{c} string' for c in columns.split(',')])
|
|
57
|
-
# query = f'CREATE EXTERNAL TABLE IF NOT EXISTS {target_table}(\n' + \
|
|
58
|
-
# f' {athena_columns})\n' + \
|
|
59
|
-
# "ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde'\n" + \
|
|
60
|
-
# 'WITH SERDEPROPERTIES (\n' + \
|
|
61
|
-
# ' "separatorChar" = ",",\n' + \
|
|
62
|
-
# ' "quoteChar" = "\\"")\n' + \
|
|
63
|
-
# f"LOCATION 's3://{bucket}/export/{database}/{keyspace}/{target_table}'\n" + \
|
|
64
|
-
# 'TBLPROPERTIES ("skip.header.line.count"="1");'
|
|
65
|
-
# debug(query)
|
|
66
|
-
# try:
|
|
67
|
-
# Athena.query(query, database)
|
|
68
|
-
# except Exception as e:
|
|
69
|
-
# log2(f'*** Failed query:\n{query}')
|
|
70
|
-
# raise e
|
|
71
49
|
|
|
72
50
|
to, _ = self.move_to_done(state, from_session, keyspace, target_table)
|
|
73
51
|
|
|
@@ -76,12 +54,14 @@ class AthenaImporter(Importer):
|
|
|
76
54
|
return to, to_session
|
|
77
55
|
finally:
|
|
78
56
|
if succeeded:
|
|
79
|
-
self.remove_csv(state, from_session, table, target_table, multi_tables)
|
|
57
|
+
self.remove_csv(state, from_session, table, target_table, multi_tables, job_log=job_log)
|
|
80
58
|
Athena.clear_cache()
|
|
81
59
|
|
|
82
|
-
if
|
|
60
|
+
if multi_tables:
|
|
61
|
+
log2(f'[{to_session}] {keyspace}.{target_table} OK', file=job_log)
|
|
62
|
+
else:
|
|
83
63
|
with export_db(state) as dbs:
|
|
84
|
-
dbs.sql(f'select * from {
|
|
64
|
+
dbs.sql(f'select * from {keyspace}.{target_table} limit 10', backgrounded=True, export_log=job_log)
|
|
85
65
|
|
|
86
66
|
def import_from_local_csv(self, state: ReplState,
|
|
87
67
|
keyspace: str, table: str, csv_file: str, multi_tables = True, create_db = False):
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
from typing import TextIO
|
|
1
2
|
import pandas
|
|
2
3
|
|
|
3
4
|
from adam.commands.export.export_databases import export_db
|
|
4
5
|
from adam.commands.export.importer import Importer
|
|
5
6
|
from adam.repl_state import ReplState
|
|
6
|
-
from adam.utils import GeneratorStream, bytes_generator_from_file, ing
|
|
7
|
+
from adam.utils import GeneratorStream, bytes_generator_from_file, ing, log2
|
|
7
8
|
from adam.utils_k8s.pods import Pods
|
|
8
9
|
from adam.utils_sqlite import SQLite, sqlite
|
|
9
10
|
|
|
@@ -11,9 +12,17 @@ class SqliteImporter(Importer):
|
|
|
11
12
|
def prefix(self):
|
|
12
13
|
return 's'
|
|
13
14
|
|
|
14
|
-
def import_from_csv(self,
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
def import_from_csv(self,
|
|
16
|
+
state: ReplState,
|
|
17
|
+
from_session: str,
|
|
18
|
+
keyspace: str,
|
|
19
|
+
table: str,
|
|
20
|
+
target_table: str,
|
|
21
|
+
columns: str,
|
|
22
|
+
multi_tables = True,
|
|
23
|
+
create_db = False,
|
|
24
|
+
job_log: str = None):
|
|
25
|
+
|
|
17
26
|
csv_file = self.csv_file(from_session, table, target_table)
|
|
18
27
|
pod = state.pod
|
|
19
28
|
namespace = state.namespace
|
|
@@ -21,7 +30,7 @@ class SqliteImporter(Importer):
|
|
|
21
30
|
|
|
22
31
|
succeeded = False
|
|
23
32
|
try:
|
|
24
|
-
with ing(f'[{to_session}] Uploading to Sqlite', suppress_log=multi_tables):
|
|
33
|
+
with ing(f'[{to_session}] Uploading to Sqlite', suppress_log=multi_tables, job_log=job_log):
|
|
25
34
|
# create a connection to single keyspace
|
|
26
35
|
with sqlite(to_session, keyspace) as conn:
|
|
27
36
|
bytes = Pods.read_file(pod, 'cassandra', namespace, csv_file)
|
|
@@ -35,12 +44,14 @@ class SqliteImporter(Importer):
|
|
|
35
44
|
return to, to_session
|
|
36
45
|
finally:
|
|
37
46
|
if succeeded:
|
|
38
|
-
self.remove_csv(state, from_session, table, target_table, multi_tables)
|
|
47
|
+
self.remove_csv(state, from_session, table, target_table, multi_tables, job_log=job_log)
|
|
39
48
|
SQLite.clear_cache()
|
|
40
49
|
|
|
41
|
-
if
|
|
50
|
+
if multi_tables:
|
|
51
|
+
log2(f'[{to_session}] {keyspace}.{target_table} OK', file=job_log)
|
|
52
|
+
else:
|
|
42
53
|
with export_db(state) as dbs:
|
|
43
|
-
dbs.sql(f'select * from {keyspace}.{target_table} limit 10')
|
|
54
|
+
dbs.sql(f'select * from {keyspace}.{target_table} limit 10', backgrounded=True, export_log=job_log)
|
|
44
55
|
|
|
45
56
|
def import_from_local_csv(self, state: ReplState,
|
|
46
57
|
keyspace: str, table: str, csv_file: str, multi_tables = True, create_db = False):
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
from adam.commands import validate_args
|
|
1
|
+
from adam.commands import extract_trailing_options, validate_args
|
|
2
2
|
from adam.commands.command import Command
|
|
3
|
+
from adam.commands.cql.utils_cql import cassandra_table_names
|
|
3
4
|
from adam.commands.export.export_databases import ExportDatabases, export_db
|
|
4
5
|
from adam.config import Config
|
|
5
6
|
from adam.repl_state import ReplState, RequiredState
|
|
@@ -27,19 +28,18 @@ class ShowColumnCounts(Command):
|
|
|
27
28
|
return super().run(cmd, state)
|
|
28
29
|
|
|
29
30
|
with self.validate(args, state) as (args, state):
|
|
30
|
-
with
|
|
31
|
-
with
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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)
|
|
35
37
|
|
|
36
38
|
return state
|
|
37
39
|
|
|
38
40
|
def completion(self, state: ReplState):
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
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 {}
|
|
43
43
|
|
|
44
44
|
def help(self, _: ReplState):
|
|
45
45
|
return f'{ShowColumnCounts.COMMAND} <export-table-name>\t show column count per id'
|
|
@@ -32,7 +32,8 @@ class ShowExportDatabases(Command):
|
|
|
32
32
|
return state
|
|
33
33
|
|
|
34
34
|
def completion(self, state: ReplState):
|
|
35
|
-
return
|
|
35
|
+
return {}
|
|
36
|
+
# return DeviceExport().ls_completion(ShowExportDatabases.COMMAND, state, default = super().completion(state))
|
|
36
37
|
|
|
37
38
|
def help(self, _: ReplState):
|
|
38
39
|
return f'{ShowExportDatabases.COMMAND}\t list export databases'
|
|
@@ -33,7 +33,7 @@ class ShowExportSession(Command):
|
|
|
33
33
|
return state
|
|
34
34
|
|
|
35
35
|
def completion(self, state: ReplState):
|
|
36
|
-
return
|
|
36
|
+
return {}
|
|
37
37
|
|
|
38
38
|
def help(self, _: ReplState):
|
|
39
39
|
return f'{ShowExportSession.COMMAND} <export-session-name>\t show export session'
|