kaqing 2.0.214__py3-none-any.whl → 2.0.227__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 (149) hide show
  1. adam/checks/compactionstats.py +2 -1
  2. adam/checks/cpu.py +2 -1
  3. adam/checks/disk.py +6 -5
  4. adam/checks/gossip.py +2 -1
  5. adam/checks/memory.py +2 -1
  6. adam/checks/status.py +2 -1
  7. adam/commands/app/app.py +2 -2
  8. adam/commands/app/app_ping.py +2 -2
  9. adam/commands/app/login.py +2 -2
  10. adam/commands/app/show_app_actions.py +2 -2
  11. adam/commands/app/show_app_id.py +2 -2
  12. adam/commands/app/show_app_queues.py +2 -2
  13. adam/commands/app/show_login.py +2 -2
  14. adam/commands/audit/audit.py +3 -5
  15. adam/commands/audit/audit_repair_tables.py +2 -2
  16. adam/commands/audit/audit_run.py +2 -2
  17. adam/commands/audit/show_last10.py +2 -2
  18. adam/commands/audit/show_slow10.py +2 -2
  19. adam/commands/audit/show_top10.py +2 -2
  20. adam/commands/bash/bash.py +2 -2
  21. adam/commands/cassandra/download_cassandra_log.py +2 -2
  22. adam/commands/cassandra/restart_cluster.py +2 -2
  23. adam/commands/cassandra/restart_node.py +2 -2
  24. adam/commands/cassandra/restart_nodes.py +2 -2
  25. adam/commands/cassandra/rollout.py +2 -2
  26. adam/commands/cassandra/show_cassandra_repairs.py +2 -2
  27. adam/commands/cassandra/show_cassandra_status.py +2 -2
  28. adam/commands/cassandra/show_cassandra_version.py +2 -2
  29. adam/commands/cassandra/show_processes.py +6 -6
  30. adam/commands/cassandra/show_storage.py +2 -2
  31. adam/commands/cassandra/watch.py +2 -2
  32. adam/commands/cli/clipboard_copy.py +2 -2
  33. adam/commands/cli/show_cli_commands.py +3 -3
  34. adam/commands/code.py +2 -2
  35. adam/commands/command.py +32 -5
  36. adam/commands/config/param_get.py +2 -2
  37. adam/commands/config/param_set.py +2 -2
  38. adam/commands/config/show_params.py +2 -2
  39. adam/commands/cql/alter_tables.py +2 -2
  40. adam/commands/cql/cqlsh.py +2 -2
  41. adam/commands/cql/utils_cql.py +13 -3
  42. adam/commands/debug/debug_completes.py +2 -2
  43. adam/commands/debug/debug_timings.py +2 -2
  44. adam/commands/debug/show_offloaded_completes.py +2 -2
  45. adam/commands/deploy/code_start.py +2 -2
  46. adam/commands/deploy/code_stop.py +2 -2
  47. adam/commands/deploy/deploy_frontend.py +2 -2
  48. adam/commands/deploy/deploy_pg_agent.py +2 -2
  49. adam/commands/deploy/deploy_pod.py +2 -2
  50. adam/commands/deploy/undeploy_frontend.py +2 -2
  51. adam/commands/deploy/undeploy_pg_agent.py +2 -2
  52. adam/commands/deploy/undeploy_pod.py +2 -2
  53. adam/commands/devices/device.py +7 -7
  54. adam/commands/devices/device_app.py +6 -6
  55. adam/commands/devices/device_auit_log.py +2 -2
  56. adam/commands/devices/device_cass.py +6 -6
  57. adam/commands/devices/device_export.py +2 -2
  58. adam/commands/devices/device_postgres.py +6 -6
  59. adam/commands/diag/check.py +2 -2
  60. adam/commands/diag/generate_report.py +2 -2
  61. adam/commands/diag/issues.py +3 -2
  62. adam/commands/exit.py +2 -2
  63. adam/commands/export/clean_up_all_export_sessions.py +2 -2
  64. adam/commands/export/clean_up_export_sessions.py +2 -2
  65. adam/commands/export/download_export_session.py +4 -5
  66. adam/commands/export/drop_export_database.py +2 -2
  67. adam/commands/export/drop_export_databases.py +2 -2
  68. adam/commands/export/export.py +3 -3
  69. adam/commands/export/export_databases.py +3 -0
  70. adam/commands/export/export_select.py +2 -2
  71. adam/commands/export/export_sessions.py +10 -9
  72. adam/commands/export/export_use.py +3 -3
  73. adam/commands/export/export_x_select.py +2 -2
  74. adam/commands/export/exporter.py +11 -11
  75. adam/commands/export/import_files.py +3 -7
  76. adam/commands/export/import_session.py +2 -2
  77. adam/commands/export/importer.py +6 -7
  78. adam/commands/export/show_column_counts.py +2 -3
  79. adam/commands/export/show_export_databases.py +3 -4
  80. adam/commands/export/show_export_session.py +4 -4
  81. adam/commands/export/show_export_sessions.py +3 -3
  82. adam/commands/export/utils_export.py +25 -33
  83. adam/commands/fs/cat.py +2 -2
  84. adam/commands/fs/cat_local.py +2 -2
  85. adam/commands/fs/cd.py +2 -2
  86. adam/commands/fs/download_file.py +2 -2
  87. adam/commands/fs/find_files.py +3 -3
  88. adam/commands/fs/find_processes.py +12 -20
  89. adam/commands/fs/head.py +4 -4
  90. adam/commands/fs/head_local.py +46 -0
  91. adam/commands/fs/ls.py +2 -2
  92. adam/commands/fs/ls_local.py +2 -2
  93. adam/commands/fs/pwd.py +2 -2
  94. adam/commands/fs/rm.py +2 -2
  95. adam/commands/fs/rm_downloads.py +2 -2
  96. adam/commands/fs/rm_logs.py +13 -7
  97. adam/commands/fs/rm_logs_local.py +38 -0
  98. adam/commands/fs/shell.py +2 -2
  99. adam/commands/fs/show_adam.py +2 -2
  100. adam/commands/fs/show_host.py +2 -2
  101. adam/commands/fs/show_last_results.py +39 -0
  102. adam/commands/fs/tail.py +36 -0
  103. adam/commands/fs/tail_local.py +46 -0
  104. adam/commands/fs/utils_fs.py +192 -0
  105. adam/commands/help.py +2 -2
  106. adam/commands/kubectl.py +2 -2
  107. adam/commands/medusa/medusa_backup.py +2 -2
  108. adam/commands/medusa/medusa_restore.py +2 -2
  109. adam/commands/medusa/medusa_show_backupjobs.py +2 -2
  110. adam/commands/medusa/medusa_show_restorejobs.py +2 -2
  111. adam/commands/nodetool/nodetool.py +30 -7
  112. adam/commands/nodetool/utils_nodetool.py +44 -0
  113. adam/commands/postgres/postgres.py +3 -6
  114. adam/commands/postgres/postgres_ls.py +2 -2
  115. adam/commands/postgres/postgres_preview.py +2 -2
  116. adam/commands/preview_table.py +2 -3
  117. adam/commands/reaper/reaper_forward.py +2 -2
  118. adam/commands/reaper/reaper_forward_stop.py +2 -2
  119. adam/commands/reaper/reaper_restart.py +2 -2
  120. adam/commands/reaper/reaper_run_abort.py +2 -2
  121. adam/commands/reaper/reaper_runs.py +14 -12
  122. adam/commands/reaper/reaper_runs_abort.py +2 -2
  123. adam/commands/reaper/reaper_schedule_activate.py +2 -2
  124. adam/commands/reaper/reaper_schedule_start.py +2 -2
  125. adam/commands/reaper/reaper_schedule_stop.py +2 -2
  126. adam/commands/reaper/reaper_schedules.py +2 -2
  127. adam/commands/reaper/reaper_status.py +2 -2
  128. adam/commands/reaper/utils_reaper.py +31 -5
  129. adam/commands/repair/repair_log.py +2 -2
  130. adam/commands/repair/repair_run.py +2 -2
  131. adam/commands/repair/repair_scan.py +2 -2
  132. adam/commands/repair/repair_stop.py +2 -2
  133. adam/embedded_params.py +1 -1
  134. adam/repl.py +2 -1
  135. adam/repl_commands.py +25 -10
  136. adam/repl_session.py +10 -3
  137. adam/sql/qingl.lark +58 -59
  138. adam/utils.py +48 -8
  139. adam/utils_async_job.py +73 -0
  140. adam/utils_k8s/cassandra_clusters.py +15 -7
  141. adam/utils_k8s/cassandra_nodes.py +5 -4
  142. adam/utils_k8s/pods.py +152 -51
  143. adam/version.py +1 -1
  144. {kaqing-2.0.214.dist-info → kaqing-2.0.227.dist-info}/METADATA +1 -1
  145. kaqing-2.0.227.dist-info/RECORD +280 -0
  146. kaqing-2.0.214.dist-info/RECORD +0 -272
  147. {kaqing-2.0.214.dist-info → kaqing-2.0.227.dist-info}/WHEEL +0 -0
  148. {kaqing-2.0.214.dist-info → kaqing-2.0.227.dist-info}/entry_points.txt +0 -0
  149. {kaqing-2.0.214.dist-info → kaqing-2.0.227.dist-info}/top_level.txt +0 -0
@@ -33,5 +33,5 @@ class RepairStop(Command):
33
33
  def completion(self, state: ReplState):
34
34
  return super().completion(state)
35
35
 
36
- def help(self, _: ReplState):
37
- return f'{RepairStop.COMMAND}\t delete a repair job'
36
+ def help(self, state: ReplState):
37
+ return super().help(state, 'delete a repair job')
adam/embedded_params.py CHANGED
@@ -1,2 +1,2 @@
1
1
  def config():
2
- return {'app': {'console-endpoint': 'https://{host}/{env}/{app}/static/console/index.html', 'container-name': 'c3-server', 'cr': {'cluster-regex': '(.*?-.*?)-.*', 'group': 'ops.c3.ai', 'v': 'v2', 'plural': 'c3cassandras'}, 'label': 'c3__app_id-0', 'login': {'admin-group': '{host}/C3.ClusterAdmin', 'ingress': '{app_id}-k8singr-appleader-001', 'timeout': 5, 'session-check-url': 'https://{host}/{env}/{app}/api/8/C3/userSessionToken', 'cache-creds': True, 'cache-username': True, 'url': 'https://{host}/{env}/{app}', 'another': "You're logged in to {has}. However, for this app, you need to log in to {need}.", 'token-server-url': 'http://localhost:{port}', 'password-max-length': 128}, 'strip': '0'}, 'audit': {'endpoint': 'https://4psvtaxlcb.execute-api.us-west-2.amazonaws.com/prod/', 'workers': 3, 'timeout': 10, 'log-audit-queries': False, 'athena': {'auto-repair': {'elapsed_hours': 12}, 'region': 'us-west-2', 'catalog': 'AwsDataCatalog', 'database': 'audit', 'repair-partition-tables': 'audit', 'output': 's3://s3.ops--audit/ddl/results', 'repair-cluster-tables': 'cluster'}, 'queries': {'last10': "SELECT * FROM audit\nWHERE drive <> 'z' and ({date_condition})\nORDER BY ts DESC LIMIT {limit}", 'slow10': "SELECT * FROM audit\nWHERE drive <> 'z' and ({date_condition})\nORDER BY CAST(duration AS REAL) DESC LIMIT {limit}", 'top10': "SELECT min(c) AS cluster, line, COUNT(*) AS cnt, avg(CAST(duration AS REAL)) AS duration\nFROM audit WHERE drive <> 'z' and ({date_condition})\nGROUP BY line ORDER BY cnt DESC LIMIT {limit}"}}, 'bash': {'workers': 32}, 'cassandra': {'service-name': 'all-pods-service'}, 'cql': {'workers': 32, 'samples': 3, 'secret': {'cluster-regex': '(.*?-.*?)-.*', 'name': '{cluster}-superuser', 'password-item': 'password'}, 'alter-tables': {'excludes': 'system_auth,system_traces,reaper_db,system_distributed,system_views,system,system_schema,system_virtual_schema', 'gc-grace-periods': '3600,86400,864000,7776000', 'batching': True}}, 'checks': {'compactions-threshold': 250, 'cpu-busy-threshold': 98.0, 'cpu-threshold': 0.0, 'cassandra-data-path': '/c3/cassandra', 'root-disk-threshold': 50, 'cassandra-disk-threshold': 50, 'snapshot-size-cmd': "ls /c3/cassandra/data/data/*/*/snapshots | grep snapshots | sed 's/:$//g' | xargs -I {} du -sk {} | awk '{print $1}' | awk '{s+=$1} END {print s}'", 'snapshot-size-threshold': '40G', 'table-sizes-cmd': "ls -Al /c3/cassandra/data/data/ | awk '{print $9}' | sed 's/\\^r//g' | xargs -I {} du -sk /c3/cassandra/data/data/{}"}, 'download': {'workers': 8}, 'export': {'workers': 8, 'csv_dir': '/c3/cassandra/tmp', 'column_counts_query': 'select id, count(id) as columns from {table} group by id order by columns desc limit 10', 'default-importer': 'sqlite', 'sqlite': {'workers': 8, 'columns': '<row-key>', 'local-db-dir': '/tmp/qing-db/q/export/db'}, 'athena': {'workers': 8, 'columns': '<keys>', 'bucket': 'c3.ops--qing'}, 'csv': {'workers': 8, 'columns': '<row-key>'}, 'log-dir': '/tmp/qing-db/q/export/logs'}, 'get-host-id': {'workers': 32}, 'idps': {'ad': {'email-pattern': '.*@c3.ai', 'uri': 'https://login.microsoftonline.com/53ad779a-93e7-485c-ba20-ac8290d7252b/oauth2/v2.0/authorize?response_type=id_token&response_mode=form_post&client_id=00ff94a8-6b0a-4715-98e0-95490012d818&scope=openid+email+profile&redirect_uri=https%3A%2F%2Fplat.c3ci.cloud%2Fc3%2Fc3%2Foidc%2Flogin&nonce={nonce}&state=EMPTY', 'jwks-uri': 'https://login.microsoftonline.com/common/discovery/keys', 'contact': 'Please contact ted.tran@c3.ai.', 'whitelist-file': '/kaqing/members'}, 'okta': {'default': True, 'email-pattern': '.*@c3iot.com', 'uri': 'https://c3energy.okta.com/oauth2/v1/authorize?response_type=id_token&response_mode=form_post&client_id={client_id}&scope=openid+email+profile+groups&redirect_uri=https%3A%2F%2F{host}%2Fc3%2Fc3%2Foidc%2Flogin&nonce={nonce}&state=EMPTY', 'jwks-uri': 'https://c3energy.okta.com/oauth2/v1/keys'}}, 'issues': {'workers': 32}, 'local-qing-dir': '/tmp/qing-db/q', 'local-downloads-dir': '/tmp/qing-db/q/downloads', 'logs': {'path': '/c3/cassandra/logs/system.log'}, 'log-dir': '/tmp/qing-db/q/logs', 'nodetool': {'workers': 96, 'commands_in_line': 40, 'status': {'workers': 32, 'samples': 3, 'commands_in_line': 40}}, 'pg': {'name-pattern': '^{namespace}.*-k8spg-.*', 'excludes': '.helm., -admin-secret', 'agent': {'name': 'ops-pg-agent', 'just-in-time': False, 'timeout': 86400, 'image': 'seanahnsf/kaqing'}, 'default-db': 'postgres', 'default-schema': 'postgres', 'secret': {'endpoint-key': 'postgres-db-endpoint', 'port-key': 'postgres-db-port', 'username-key': 'postgres-admin-username', 'password-key': 'postgres-admin-password'}}, 'pod': {'name': 'ops', 'image': 'seanahnsf/kaqing-cloud', 'sa': {'name': 'ops', 'proto': 'c3', 'additional-cluster-roles': 'c3aiops-k8ssandra-operator'}, 'label-selector': 'run=ops'}, 'preview': {'rows': 10}, 'processes': {'columns': 'pod,cpu-metrics,mem', 'header': 'POD_NAME,M_CPU(USAGE/LIMIT),MEM/LIMIT'}, 'processes-qing': {'columns': 'pod,cpu,mem', 'header': 'POD_NAME,Q_CPU/TOTAL,MEM/LIMIT'}, 'reaper': {'service-name': 'reaper-service', 'port-forward': {'timeout': 86400, 'local-port': 9001}, 'abort-runs-batch': 10, 'show-runs-batch': 100, 'pod': {'cluster-regex': '(.*?-.*?-.*?-.*?)-.*', 'label-selector': 'k8ssandra.io/reaper={cluster}-reaper'}, 'secret': {'cluster-regex': '(.*?-.*?)-.*', 'name': '{cluster}-reaper-ui', 'password-item': 'password'}}, 'repair': {'log-path': '/home/cassrepair/logs/', 'image': 'ci-registry.c3iot.io/cloudops/cassrepair:2.0.14', 'secret': 'ciregistryc3iotio', 'env': {'interval': 24, 'timeout': 60, 'pr': False, 'runs': 1}}, 'repl': {'start-drive': 'c', 'a': {'auto-enter': 'c3/c3'}, 'c': {'auto-enter': 'cluster'}, 'x': {'auto-enter': 'latest'}, 'history': {'push-cat-log-file': True, 'push-cat-remote-log-file': True}, 'background-process': {'auto-nohup': True}}, 'status': {'columns': 'status,address,load,tokens,owns,host_id,gossip,compactions', 'header': '--,Address,Load,Tokens,Owns,Host ID,GOSSIP,COMPACTIONS'}, 'storage': {'columns': 'pod,volume_root,volume_cassandra,snapshots,data,compactions', 'header': 'POD_NAME,VOLUME /,VOLUME CASS,SNAPSHOTS,DATA,COMPACTIONS'}, 'watch': {'auto': 'rollout', 'timeout': 3600, 'interval': 10}, 'auto-complete': {'c': {'tables': 'lazy', 'table-props-value': 'jit'}, 'x': {'tables': 'lazy'}, 'cli': {'cp': 'jit'}, 'export': {'databases': 'jit'}, 'medusa': {'backups': 'jit'}, 'reaper': {'schedules': 'jit'}}, 'debug': False, 'debugs': {'complete': False, 'timings': False, 'exit-on-error': False}}
2
+ return {'app': {'console-endpoint': 'https://{host}/{env}/{app}/static/console/index.html', 'container-name': 'c3-server', 'cr': {'cluster-regex': '(.*?-.*?)-.*', 'group': 'ops.c3.ai', 'v': 'v2', 'plural': 'c3cassandras'}, 'label': 'c3__app_id-0', 'login': {'admin-group': '{host}/C3.ClusterAdmin', 'ingress': '{app_id}-k8singr-appleader-001', 'timeout': 5, 'session-check-url': 'https://{host}/{env}/{app}/api/8/C3/userSessionToken', 'cache-creds': True, 'cache-username': True, 'url': 'https://{host}/{env}/{app}', 'another': "You're logged in to {has}. However, for this app, you need to log in to {need}.", 'token-server-url': 'http://localhost:{port}', 'password-max-length': 128}, 'strip': '0'}, 'audit': {'endpoint': 'https://4psvtaxlcb.execute-api.us-west-2.amazonaws.com/prod/', 'workers': 3, 'timeout': 10, 'log-audit-queries': False, 'athena': {'auto-repair': {'elapsed_hours': 12}, 'region': 'us-west-2', 'catalog': 'AwsDataCatalog', 'database': 'audit', 'repair-partition-tables': 'audit', 'output': 's3://s3.ops--audit/ddl/results', 'repair-cluster-tables': 'cluster'}, 'queries': {'last10': "SELECT * FROM audit\nWHERE drive <> 'z' and ({date_condition})\nORDER BY ts DESC LIMIT {limit}", 'slow10': "SELECT * FROM audit\nWHERE drive <> 'z' and ({date_condition})\nORDER BY CAST(duration AS REAL) DESC LIMIT {limit}", 'top10': "SELECT min(c) AS cluster, line, COUNT(*) AS cnt, avg(CAST(duration AS REAL)) AS duration\nFROM audit WHERE drive <> 'z' and ({date_condition})\nGROUP BY line ORDER BY cnt DESC LIMIT {limit}"}}, 'bash': {'workers': 32}, 'cassandra': {'service-name': 'all-pods-service'}, 'cql': {'workers': 32, 'samples': 3, 'secret': {'cluster-regex': '(.*?-.*?)-.*', 'name': '{cluster}-superuser', 'password-item': 'password'}, 'alter-tables': {'excludes': 'system_auth,system_traces,reaper_db,system_distributed,system_views,system,system_schema,system_virtual_schema', 'gc-grace-periods': '3600,86400,864000,7776000', 'batching': True}}, 'checks': {'compactions-threshold': 250, 'cpu-busy-threshold': 98.0, 'cpu-threshold': 0.0, 'cassandra-data-path': '/c3/cassandra', 'root-disk-threshold': 50, 'cassandra-disk-threshold': 50, 'snapshot-size-cmd': "ls /c3/cassandra/data/data/*/*/snapshots | grep snapshots | sed 's/:$//g' | xargs -I {} du -sk {} | awk '{print $1}' | awk '{s+=$1} END {print s}'", 'snapshot-size-threshold': '40G', 'table-sizes-cmd': "ls -Al /c3/cassandra/data/data/ | awk '{print $9}' | sed 's/\\^r//g' | xargs -I {} du -sk /c3/cassandra/data/data/{}"}, 'download': {'workers': 8}, 'export': {'workers': 8, 'csv_dir': '/c3/cassandra/tmp', 'column_counts_query': 'select id, count(id) as columns from {table} group by id order by columns desc limit 10', 'default-importer': 'sqlite', 'sqlite': {'workers': 8, 'columns': '<row-key>', 'local-db-dir': '/tmp/qing-db/q/export/db'}, 'athena': {'workers': 8, 'columns': '<keys>', 'bucket': 'c3.ops--qing'}, 'csv': {'workers': 8, 'columns': '<row-key>'}, 'log-dir': '/tmp/qing-db/q/export/logs', 'remote': {'log-dir': '/tmp/q/export/logs'}}, 'get-host-id': {'workers': 32}, 'idps': {'ad': {'email-pattern': '.*@c3.ai', 'uri': 'https://login.microsoftonline.com/53ad779a-93e7-485c-ba20-ac8290d7252b/oauth2/v2.0/authorize?response_type=id_token&response_mode=form_post&client_id=00ff94a8-6b0a-4715-98e0-95490012d818&scope=openid+email+profile&redirect_uri=https%3A%2F%2Fplat.c3ci.cloud%2Fc3%2Fc3%2Foidc%2Flogin&nonce={nonce}&state=EMPTY', 'jwks-uri': 'https://login.microsoftonline.com/common/discovery/keys', 'contact': 'Please contact ted.tran@c3.ai.', 'whitelist-file': '/kaqing/members'}, 'okta': {'default': True, 'email-pattern': '.*@c3iot.com', 'uri': 'https://c3energy.okta.com/oauth2/v1/authorize?response_type=id_token&response_mode=form_post&client_id={client_id}&scope=openid+email+profile+groups&redirect_uri=https%3A%2F%2F{host}%2Fc3%2Fc3%2Foidc%2Flogin&nonce={nonce}&state=EMPTY', 'jwks-uri': 'https://c3energy.okta.com/oauth2/v1/keys'}}, 'issues': {'workers': 32}, 'job': {'log-to-pods': True}, 'local-qing-dir': '/tmp/qing-db/q', 'local-downloads-dir': '/tmp/qing-db/q/downloads', 'logs': {'path': '/c3/cassandra/logs/system.log'}, 'log-dir': '/tmp/qing-db/q/logs', 'nodetool': {'workers': 96, 'commands_in_line': 40, 'grace-period-after-abort': 10, 'status': {'workers': 32, 'samples': 3, 'commands_in_line': 40}}, 'pg': {'name-pattern': '^{namespace}.*-k8spg-.*', 'excludes': '.helm., -admin-secret', 'agent': {'name': 'ops-pg-agent', 'just-in-time': False, 'timeout': 86400, 'image': 'seanahnsf/kaqing'}, 'default-db': 'postgres', 'default-schema': 'postgres', 'secret': {'endpoint-key': 'postgres-db-endpoint', 'port-key': 'postgres-db-port', 'username-key': 'postgres-admin-username', 'password-key': 'postgres-admin-password'}}, 'pod': {'name': 'ops', 'image': 'seanahnsf/kaqing-cloud', 'sa': {'name': 'ops', 'proto': 'c3', 'additional-cluster-roles': 'c3aiops-k8ssandra-operator'}, 'label-selector': 'run=ops'}, 'preview': {'rows': 10}, 'processes': {'columns': 'pod,cpu-metrics,mem', 'header': 'POD_NAME,M_CPU(USAGE/LIMIT),MEM/LIMIT'}, 'processes-mpstat': {'columns': 'pod,cpu,mem', 'header': 'POD_NAME,Q_CPU/TOTAL,MEM/LIMIT'}, 'reaper': {'service-name': 'reaper-service', 'port-forward': {'timeout': 86400, 'local-port': 9001}, 'abort-runs-batch': 10, 'show-runs-batch': 100, 'pod': {'cluster-regex': '(.*?-.*?-.*?-.*?)-.*', 'label-selector': 'k8ssandra.io/reaper={cluster}-reaper'}, 'secret': {'cluster-regex': '(.*?-.*?)-.*', 'name': '{cluster}-reaper-ui', 'password-item': 'password'}}, 'repair': {'log-path': '/home/cassrepair/logs/', 'image': 'ci-registry.c3iot.io/cloudops/cassrepair:2.0.14', 'secret': 'ciregistryc3iotio', 'env': {'interval': 24, 'timeout': 60, 'pr': False, 'runs': 1}}, 'repl': {'start-drive': 'c', 'a': {'auto-enter': 'c3/c3'}, 'c': {'auto-enter': 'cluster'}, 'x': {'auto-enter': 'latest'}, 'history': {'push-cat-log-file': True, 'push-cat-remote-log-file': True}, 'background-process': {'auto-nohup': True}}, 'status': {'columns': 'status,address,load,tokens,owns,host_id,gossip,compactions', 'header': '--,Address,Load,Tokens,Owns,Host ID,GOSSIP,COMPACTIONS'}, 'storage': {'columns': 'pod,volume_root,volume_cassandra,snapshots,data,compactions', 'header': 'POD_NAME,VOLUME /,VOLUME CASS,SNAPSHOTS,DATA,COMPACTIONS'}, 'watch': {'auto': 'rollout', 'timeout': 3600, 'interval': 10}, 'auto-complete': {'c': {'tables': 'lazy', 'table-props-value': 'jit'}, 'x': {'tables': 'lazy'}, 'cli': {'cp': 'jit'}, 'export': {'databases': 'jit'}, 'medusa': {'backups': 'jit'}, 'reaper': {'schedules': 'jit'}}, 'debug': False, 'debugs': {'complete': False, 'timings': False, 'exit-on-error': False}}
adam/repl.py CHANGED
@@ -3,6 +3,7 @@ import time
3
3
  from typing import cast
4
4
  import click
5
5
  from prompt_toolkit.key_binding import KeyBindings
6
+ from prompt_toolkit import HTML
6
7
 
7
8
  from adam.cli_group import cli
8
9
  from adam.commands.command import Command, InvalidArgumentsException, InvalidStateException
@@ -81,7 +82,7 @@ def enter_repl(state: ReplState):
81
82
  # print(json.dumps(completions, indent=4))
82
83
  completer = ReplCompleter.from_nested_dict(completions)
83
84
 
84
- cmd = session.prompt(prompt_msg(), completer=completer, key_bindings=kb)
85
+ cmd = session.prompt(HTML(f'<ansibrightblue>{prompt_msg()}</ansibrightblue>'), completer=completer, key_bindings=kb)
85
86
  s0 = time.time()
86
87
 
87
88
  if state.bash_session:
adam/repl_commands.py CHANGED
@@ -61,8 +61,13 @@ from adam.commands.export.show_export_sessions import ShowExportSessions
61
61
  from adam.commands.fs.find_files import FindLocalFiles
62
62
  from adam.commands.fs.find_processes import FindProcesses
63
63
  from adam.commands.fs.head import Head
64
+ from adam.commands.fs.head_local import HeadLocal
64
65
  from adam.commands.fs.ls_local import LsLocal
65
66
  from adam.commands.fs.rm import RmLocal
67
+ from adam.commands.fs.rm_logs import RmLogs
68
+ from adam.commands.fs.show_last_results import ShowLastResults
69
+ from adam.commands.fs.tail import Tail
70
+ from adam.commands.fs.tail_local import TailLocal
66
71
  from adam.commands.kubectl import Kubectl
67
72
  from adam.commands.fs.shell import Shell
68
73
  from adam.commands.bash.bash import Bash
@@ -107,18 +112,28 @@ class ReplCommands:
107
112
  return deduped
108
113
 
109
114
  def navigation() -> list[Command]:
110
- return [Ls(), LsLocal(), PreviewTable(), DeviceApp(), DevicePostgres(), DeviceCass(), DeviceAuditLog(), DeviceExport(),
111
- Cd(), Cat(), CatLocal(), Head(), DownloadFile(), FindLocalFiles(), FindProcesses(), Pwd(), ClipboardCopy(),
112
- GetParam(), SetParam(), ShowOffloadedCompletes(), ShowParams(), ShowKubectlCommands(), ShowLogin(), ShowAdam(), ShowHost()] + RmLocal().cmd_list()
115
+ return [Cd(), Cat(), CatLocal(), ClipboardCopy(),
116
+ DeviceApp(), DevicePostgres(), DeviceCass(), DeviceAuditLog(), DeviceExport(),
117
+ DownloadFile(), FindLocalFiles(), FindProcesses(), GetParam(),
118
+ Head(), HeadLocal(), Ls(), LsLocal(), PreviewTable(), Pwd(), RmLogs(),
119
+ SetParam(), ShowAdam(), ShowHost(), ShowKubectlCommands(), ShowLastResults(),
120
+ ShowLogin(), ShowOffloadedCompletes(), ShowParams(),
121
+ Tail(), TailLocal()] + \
122
+ RmLocal().cmd_list()
113
123
 
114
124
  def cassandra_ops() -> list[Command]:
115
- return [Cqlsh(), DownloadCassandraLog(), ShowCassandraStatus(), ShowCassandraVersion(), ShowCassandraRepairs(), ShowStorage(), ShowProcesses(),
116
- Check(), Issues(), NodeTool(), GenerateReport(), AlterTables(), Bash(),
117
- ExportTables(), ExportXSelect(), ExportUse(), ShowExportDatabases(), ShowColumnCounts(),
118
- DropExportDatabase(), DropExportDatabases(),
119
- ShowExportSessions(), ShowExportSession(), DownloadExportSession(),
120
- CleanUpExportSessions(), CleanUpAllExportSessions(), ImportSession(), ImportCSVFiles()] + \
121
- Medusa().cmd_list() + [RestartNodes(), RestartNode(), RestartCluster(), RollOut(), Watch()] + Reaper().cmd_list() + Repair().cmd_list() + Debug().cmd_list()
125
+ return [AlterTables(), Bash(), Check(), CleanUpExportSessions(), CleanUpAllExportSessions(), Cqlsh(),
126
+ DownloadCassandraLog(), DropExportDatabase(), DropExportDatabases(), DownloadExportSession(),
127
+ ExportTables(), ExportXSelect(), ExportUse(),
128
+ GenerateReport(), ImportSession(), ImportCSVFiles(), Issues(), NodeTool(),
129
+ RestartNodes(), RestartNode(), RestartCluster(), RollOut(),
130
+ ShowCassandraStatus(), ShowCassandraVersion(), ShowCassandraRepairs(), ShowColumnCounts(),
131
+ ShowStorage(), ShowExportDatabases(), ShowExportSessions(), ShowExportSession(), ShowProcesses(),
132
+ Watch()] + \
133
+ Debug().cmd_list() + \
134
+ Medusa().cmd_list() + \
135
+ Reaper().cmd_list() + \
136
+ Repair().cmd_list()
122
137
 
123
138
  def postgres_ops() -> list[Command]:
124
139
  return [Postgres(), DeployPgAgent(), UndeployPgAgent(), PostgresPg()]
adam/repl_session.py CHANGED
@@ -1,8 +1,9 @@
1
+ from typing import Union
1
2
  from prompt_toolkit import PromptSession
2
3
  from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
3
4
 
4
5
  from adam.config import Config
5
- from adam.utils import ConfigHolder
6
+ from adam.utils import ConfigHolder, LogFile
6
7
 
7
8
  class ReplSession:
8
9
  # the singleton pattern
@@ -16,6 +17,12 @@ class ReplSession:
16
17
  self.prompt_session = PromptSession(auto_suggest=AutoSuggestFromHistory())
17
18
  ConfigHolder().append_command_history = self.append_history
18
19
 
19
- def append_history(self, entry: str):
20
- if entry and self.prompt_session and Config().get('repl.history.push-cat-remote-log-file', True):
20
+ def append_history(self, entry: Union[str, LogFile]):
21
+ if not entry:
22
+ return
23
+
24
+ if self.prompt_session and Config().get('repl.history.push-cat-remote-log-file', True):
25
+ if isinstance(entry, LogFile):
26
+ entry = entry.to_command()
27
+
21
28
  self.prompt_session.history.append_string(entry)
adam/sql/qingl.lark CHANGED
@@ -4,19 +4,18 @@ start: statement_sequence
4
4
  WHITESPACE: (" " | /\t/ | /\n/ | /\r/ )+
5
5
  %ignore WHITESPACE
6
6
 
7
- # SEAN replaced with @host statement ( ";" statement )* ";"? "&"?
8
- statement_sequence: statement ( ";" statement )* ";"? "&"?
9
-
10
- statement: dcl_statement
11
- | ddl_statement
12
- | dml_statement
13
- | dql_statement
14
- | utility_statement
7
+ statement_sequence: statement ( ";" statement )* ";"?
8
+
9
+ statement: dcl_statement "&"?
10
+ | ddl_statement "&"?
11
+ | dml_statement "&"?
12
+ | dql_statement "&"?
13
+ # | utility_statement "&"?
15
14
  | qing_statement
16
15
 
17
16
  ddl_statement: create_statement
18
17
  | drop_statement
19
- | other_statement
18
+ # | other_statement
20
19
 
21
20
  # --------------------- SEAN added -------------------
22
21
 
@@ -27,8 +26,8 @@ host_name: IDENTIFIER
27
26
 
28
27
  # --------------------- p: -------------------
29
28
 
30
- qing_p_statement: preview_table_statement
31
- | alter_table_statement
29
+ qing_p_statement: preview_table_statement "&"?
30
+ | alter_table_statement "&"?
32
31
 
33
32
  preview_table_statement: "PREVIEW"i path
34
33
  alter_table_statement: "ALTER"i "TABLE"i keyspace_ref (add_column_action | drop_column_action | modify_column_action | rename_table_action | add_constraint_action)
@@ -50,11 +49,11 @@ column_name_list: column_name ("," column_name)*
50
49
 
51
50
  # --------------------- c: -------------------
52
51
 
53
- qing_c_statement: preview_table_statement
54
- | alter_cql_table_statement
55
- | alter_tables_statement
56
- | describe_statement
57
- | consistency_statement
52
+ qing_c_statement: preview_table_statement "&"?
53
+ | alter_cql_table_statement "&"?
54
+ | alter_tables_statement "&"?
55
+ | describe_statement "&"?
56
+ | consistency_statement "&"?
58
57
  | drop_export_db_statement
59
58
  | use_export_db_statement
60
59
  | "SHOW"i show_c_subcommand
@@ -117,9 +116,9 @@ download_session_statement: "DOWNLOAD"i "EXPORT"i "SESSION"i export_session_name
117
116
 
118
117
  # --------------------- l: -------------------
119
118
 
120
- qing_l_statement: preview_table_statement
121
- | alter_athena_table_statement
122
- | describe_table_statement
119
+ qing_l_statement: preview_table_statement "&"?
120
+ | alter_athena_table_statement "&"?
121
+ | describe_table_statement "&"?
123
122
  | "AUDIT"i ("REPAIR"i | "RUN"i)?
124
123
  | show_topn_statement
125
124
 
@@ -139,8 +138,8 @@ topn_window: IDENTIFIER
139
138
 
140
139
  # --------------------- x: -------------------
141
140
 
142
- qing_x_statement: preview_table_statement
143
- | describe_table_statement
141
+ qing_x_statement: preview_table_statement "&"?
142
+ | describe_table_statement "&"?
144
143
  | drop_export_db_statement
145
144
 
146
145
  qing_x0_statement: drop_export_db_statement
@@ -162,9 +161,9 @@ drop_statement: drop_scope
162
161
  | drop_index
163
162
  | drop_function
164
163
 
165
- other_statement: alter_index
166
- | build_index
167
- | execute_function
164
+ # other_statement: alter_index
165
+ # | build_index
166
+ # | execute_function
168
167
 
169
168
  create_scope: "CREATE"i "SCOPE"i ( namespace_ref ":" )? bucket_ref "." scope_ref if_not_exists?
170
169
 
@@ -219,10 +218,10 @@ index_partition: "PARTITION"i "BY"i "HASH"i LPAREN partition_key_expr \
219
218
 
220
219
  partition_key_expr: expr
221
220
 
222
- alter_index: "ALTER"i "INDEX"i ( ( index_path "." index_name ) | ( index_name "ON"i keyspace_ref ) \
223
- index_using? index_with )
221
+ # alter_index: "ALTER"i "INDEX"i ( ( index_path "." index_name ) | ( index_name "ON"i keyspace_ref ) \
222
+ # index_using? index_with )
224
223
 
225
- build_index: "BUILD"i "INDEX"i "ON"i keyspace_ref LPAREN index_term ( "," index_term )* RPAREN index_using?
224
+ # build_index: "BUILD"i "INDEX"i "ON"i keyspace_ref LPAREN index_term ( "," index_term )* RPAREN index_using?
226
225
 
227
226
  index_term: index_name | subquery_expr
228
227
 
@@ -283,11 +282,11 @@ sequence_with: "WITH"i expr
283
282
 
284
283
  drop_function: "DROP"i "FUNCTION"i function_ref if_exists?
285
284
 
286
- execute_function: "EXECUTE"i "FUNCTION"i function_ref LPAREN ( expr ( "," expr )* )? RPAREN
285
+ # execute_function: "EXECUTE"i "FUNCTION"i function_ref LPAREN ( expr ( "," expr )* )? RPAREN
287
286
 
288
287
  dml_statement: delete_statement
289
288
  | insert_statement
290
- | merge_statement
289
+ # | merge_statement
291
290
  | update_statement
292
291
  | upsert_statement
293
292
 
@@ -307,44 +306,44 @@ insert_select: LPAREN "PRIMARY"i? "KEY"i key_expr ( "," "VALUE"i value_expr )? \
307
306
 
308
307
  options: obj
309
308
 
310
- merge_statement: "MERGE"i "INTO"i ( ansi_merge | lookup_merge ) limit_clause? returning_clause?
309
+ # merge_statement: "MERGE"i "INTO"i ( ansi_merge | lookup_merge ) limit_clause? returning_clause?
311
310
 
312
- ansi_merge: target_keyspace use_index_clause "USING"i ansi_merge_source \
313
- ansi_merge_predicate ansi_merge_actions
311
+ # ansi_merge: target_keyspace use_index_clause "USING"i ansi_merge_source \
312
+ # ansi_merge_predicate ansi_merge_actions
314
313
 
315
- ansi_merge_source: ( merge_source_keyspace | merge_source_subquery | merge_source_expr ) \
316
- ansi_join_hints?
314
+ # ansi_merge_source: ( merge_source_keyspace | merge_source_subquery | merge_source_expr ) \
315
+ # ansi_join_hints?
317
316
 
318
- ansi_merge_predicate: "ON"i expr
317
+ # ansi_merge_predicate: "ON"i expr
319
318
 
320
- ansi_merge_actions: merge_update? merge_delete? ansi_merge_insert?
319
+ # ansi_merge_actions: merge_update? merge_delete? ansi_merge_insert?
321
320
 
322
- ansi_merge_insert: "WHEN"i "NOT"i "MATCHED"i "THEN"i "INSERT"i LPAREN "KEY"i? key_expr \
323
- ( "," "VALUE"i? value_expr )? ( "," "OPTIONS"i? options )? RPAREN where_clause?
321
+ # ansi_merge_insert: "WHEN"i "NOT"i "MATCHED"i "THEN"i "INSERT"i LPAREN "KEY"i? key_expr \
322
+ # ( "," "VALUE"i? value_expr )? ( "," "OPTIONS"i? options )? RPAREN where_clause?
324
323
 
325
324
 
326
- lookup_merge: target_keyspace "USING"i lookup_merge_source lookup_merge_predicate \
327
- lookup_merge_actions
325
+ # lookup_merge: target_keyspace "USING"i lookup_merge_source lookup_merge_predicate \
326
+ # lookup_merge_actions
328
327
 
329
- lookup_merge_source: ( merge_source_keyspace use_clause? )
330
- | merge_source_subquery
331
- | merge_source_expr
328
+ # lookup_merge_source: ( merge_source_keyspace use_clause? )
329
+ # | merge_source_subquery
330
+ # | merge_source_expr
332
331
 
333
- lookup_merge_predicate: "ON"i "PRIMARY"i? "KEY"i expr
332
+ # lookup_merge_predicate: "ON"i "PRIMARY"i? "KEY"i expr
334
333
 
335
- lookup_merge_actions: merge_update? merge_delete? lookup_merge_insert?
334
+ # lookup_merge_actions: merge_update? merge_delete? lookup_merge_insert?
336
335
 
337
- lookup_merge_insert: "WHEN"i "NOT"i "MATCHED"i "THEN"i "INSERT"i expr where_clause?
336
+ # lookup_merge_insert: "WHEN"i "NOT"i "MATCHED"i "THEN"i "INSERT"i expr where_clause?
338
337
 
339
- merge_source_keyspace: keyspace_ref ( "AS"i? alias )?
338
+ # merge_source_keyspace: keyspace_ref ( "AS"i? alias )?
340
339
 
341
- merge_source_subquery: subquery_expr "AS"i? alias
340
+ # merge_source_subquery: subquery_expr "AS"i? alias
342
341
 
343
- merge_source_expr: expr ( "AS"i? alias )?
342
+ # merge_source_expr: expr ( "AS"i? alias )?
344
343
 
345
- merge_update: "WHEN"i "MATCHED"i "THEN"i "UPDATE"i set_clause? unset_clause? where_clause?
344
+ # merge_update: "WHEN"i "MATCHED"i "THEN"i "UPDATE"i set_clause? unset_clause? where_clause?
346
345
 
347
- merge_delete: "WHEN"i "MATCHED"i "THEN"i "DELETE"i where_clause?
346
+ # merge_delete: "WHEN"i "MATCHED"i "THEN"i "DELETE"i where_clause?
348
347
 
349
348
  update_statement: "UPDATE"i target_keyspace use_keys_clause? set_clause? unset_clause? \
350
349
  where_clause? limit_clause? returning_clause?
@@ -373,7 +372,7 @@ key_expr: expr
373
372
  value_expr: expr
374
373
 
375
374
  dql_statement: select_statement
376
- | infer_statement
375
+ # | infer_statement
377
376
  | update_statistics
378
377
 
379
378
  select_statement: select_term ( set_op select_term )* order_by_clause? limit_clause? offset_clause?
@@ -1006,16 +1005,16 @@ commit_transaction: "COMMIT"i ( "WORK"i | "TRAN"i | "TRANSACTION"i )?
1006
1005
 
1007
1006
  savepointname: identifier_ref
1008
1007
 
1009
- utility_statement: advise_statement | explain_statement
1008
+ # utility_statement: advise_statement | explain_statement
1010
1009
 
1011
- advise_statement: "ADVISE"i "INDEX"i? ( select_statement
1012
- | update_statement
1013
- | delete_statement
1014
- | merge_statement )
1010
+ # advise_statement: "ADVISE"i "INDEX"i? ( select_statement
1011
+ # | update_statement
1012
+ # | delete_statement
1013
+ # | merge_statement )
1015
1014
 
1016
- explain_statement: "INFER"i ( "COLLECTION"i | "KEYSPACE"i )? keyspace_ref ( "WITH"i options )?
1015
+ # explain_statement: "INFER"i ( "COLLECTION"i | "KEYSPACE"i )? keyspace_ref ( "WITH"i options )?
1017
1016
 
1018
- infer_statement: "INFER"i ( "COLLECTION"i | "KEYSPACE"i )? keyspace_ref ( "WITH"i options )?
1017
+ # infer_statement: "INFER"i ( "COLLECTION"i | "KEYSPACE"i )? keyspace_ref ( "WITH"i options )?
1019
1018
 
1020
1019
  name: identifier_ref
1021
1020
 
adam/utils.py CHANGED
@@ -4,22 +4,23 @@ from contextlib import redirect_stdout
4
4
  import copy
5
5
  import csv
6
6
  from datetime import datetime
7
+ import html
7
8
  import importlib
8
9
  import io
9
- import json
10
10
  import os
11
11
  from pathlib import Path
12
12
  import random
13
13
  import string
14
14
  import threading
15
15
  import traceback
16
- from typing import Callable, Iterator, TextIO, TypeVar, Union
16
+ from typing import Callable, Iterator, TypeVar, Union
17
17
  from dateutil import parser
18
18
  import subprocess
19
19
  import sys
20
20
  import time
21
21
  import click
22
22
  import yaml
23
+ from prompt_toolkit import print_formatted_text, HTML
23
24
  from prompt_toolkit.completion import Completer
24
25
 
25
26
  from . import __version__
@@ -28,6 +29,9 @@ T = TypeVar('T')
28
29
 
29
30
  log_state = threading.local()
30
31
 
32
+ class Color:
33
+ gray = 'gray'
34
+
31
35
  class ConfigReadable:
32
36
  def is_debug() -> bool:
33
37
  pass
@@ -117,19 +121,21 @@ def convert_seconds(total_seconds_float):
117
121
  def epoch(timestamp_string: str):
118
122
  return parser.parse(timestamp_string).timestamp()
119
123
 
120
- def log(s = None):
124
+ def log(s = None, text_color: str = None):
121
125
  if not loggable():
122
126
  return False
123
127
 
124
128
  # want to print empty line for False or empty collection
125
129
  if s == None:
126
130
  print()
131
+ elif text_color:
132
+ print_formatted_text(HTML(f'<ansi{text_color}>{html.escape(s)}</ansi{text_color}>'))
127
133
  else:
128
134
  click.echo(s)
129
135
 
130
136
  return True
131
137
 
132
- def log2(s = None, nl = True, file: str = None):
138
+ def log2(s = None, nl = True, file: str = None, text_color: str = None):
133
139
  if not loggable():
134
140
  return False
135
141
 
@@ -139,12 +145,16 @@ def log2(s = None, nl = True, file: str = None):
139
145
  f.write(s)
140
146
  if nl:
141
147
  f.write('\n')
148
+ elif text_color:
149
+ print_formatted_text(HTML(f'<ansi{text_color}>{html.escape(s)}</ansi{text_color}>'))
142
150
  else:
143
151
  click.echo(s, err=True, nl=nl)
144
152
  else:
145
153
  if file:
146
154
  with open(file, 'at') as f:
147
155
  f.write('\n')
156
+ elif text_color:
157
+ print_formatted_text(HTML(f'<ansi{text_color}>{html.escape(s)}</ansi{text_color}>'), file=sys.stderr)
148
158
  else:
149
159
  print(file=sys.stderr)
150
160
 
@@ -304,15 +314,14 @@ def is_lambda(func):
304
314
 
305
315
  def debug(s = None):
306
316
  if ConfigHolder().config.is_debug():
307
- log2(f'DEBUG {s}')
317
+ log2(f'DEBUG {s}', text_color=Color.gray)
308
318
 
309
319
  def debug_complete(s = None):
310
320
  CommandLog.log(f'DEBUG {s}', config=ConfigHolder().config.get('debugs.complete', 'off'))
311
321
 
312
322
  def debug_trace():
313
323
  if ConfigHolder().config.is_debug():
314
- # if LogConfig.is_debug():
315
- log2(traceback.format_exc())
324
+ log2(traceback.format_exc(), text_color=Color.gray)
316
325
 
317
326
  def in_docker() -> bool:
318
327
  if os.path.exists('/.dockerenv'):
@@ -809,6 +818,12 @@ def kaqing_log_file_name(suffix = 'log'):
809
818
  def log_dir():
810
819
  return creating_dir(ConfigHolder().config.get('log-dir', '/tmp/qing-db/q/logs'))
811
820
 
821
+ def log_to_pods():
822
+ return ConfigHolder().config.get('job.log-to-pods', True)
823
+
824
+ def pod_log_dir():
825
+ return ConfigHolder().config.get('pod-log-dir', '/tmp/q/logs')
826
+
812
827
  class LogFileHandler:
813
828
  def __init__(self, suffix = 'log', condition=True):
814
829
  self.suffix = suffix
@@ -850,7 +865,7 @@ class CommandLog:
850
865
  except:
851
866
  pass
852
867
  elif config == 'on':
853
- log2(line)
868
+ log2(line, text_color=Color.gray)
854
869
 
855
870
  def close_log_file():
856
871
  if CommandLog.log_file:
@@ -880,3 +895,28 @@ def creating_dir(dir):
880
895
  os.makedirs(dir, exist_ok=True)
881
896
 
882
897
  return dir
898
+
899
+ class LogFile(str):
900
+ def __init__(self, s: str):
901
+ super().__init__()
902
+
903
+ def __repr__(self):
904
+ return super().__repr__()
905
+
906
+ def to_command(self, cmd: str = ':tail'):
907
+ return f'{cmd} {self}'
908
+
909
+ class PodLogFile(LogFile):
910
+ def __new__(cls, value, pod: str, size: str = None):
911
+ return super().__new__(cls, value)
912
+
913
+ def __init__(self, value, pod: str, size: str = None):
914
+ super().__init__(value)
915
+ self.pod = pod
916
+ self.size = size
917
+
918
+ def __repr__(self):
919
+ return super().__repr__()
920
+
921
+ def to_command(self, cmd: str = 'tail'):
922
+ return f'@{self.pod} {cmd} {self}'
@@ -0,0 +1,73 @@
1
+ from datetime import datetime
2
+ import re
3
+ import traceback
4
+
5
+ from adam.utils import log_dir
6
+
7
+ class AsyncJobs:
8
+ _last_id: str = None
9
+ _last_command: str = None
10
+
11
+ def log_file(command: str, pod_name: str = None, job_id: str = None, pod_suffix: str = None, err = False, dir: str = None):
12
+ try:
13
+ if not job_id:
14
+ job_id = AsyncJobs.new_id()
15
+
16
+ AsyncJobs._last_id = job_id
17
+ AsyncJobs._last_command = command
18
+
19
+ AsyncJobs.write_last_command(job_id, command)
20
+
21
+ cmd_name = ''
22
+ if command.startswith('nodetool '):
23
+ command = command.strip(' &')
24
+ cmd_name = f".{'_'.join(command.split(' ')[5:])}"
25
+
26
+ if pod_suffix is None:
27
+ pod_suffix = '{pod}'
28
+ if pod_name:
29
+ pod_suffix = pod_name
30
+ if groups := re.match(r'.*-(.*)', pod_name):
31
+ pod_suffix = f'-{groups[1]}'
32
+
33
+ if not dir:
34
+ dir = log_dir()
35
+
36
+ return f'{dir}/{job_id}{cmd_name}{pod_suffix}.{"err" if err else "log"}'
37
+ except:
38
+ traceback.print_exc()
39
+
40
+ def new_id(dt: datetime = None):
41
+ if not dt:
42
+ dt = datetime.now()
43
+
44
+ id = dt.strftime("%d%H%M%S")
45
+ AsyncJobs._last_id = id
46
+
47
+ return id
48
+
49
+ def last_command():
50
+ last_id = AsyncJobs._last_id
51
+ last_command = AsyncJobs._last_command
52
+
53
+ if not last_id or not last_command:
54
+ l0, l1 = AsyncJobs.read_last_command()
55
+ if not last_id:
56
+ last_id = l0
57
+ if not last_command:
58
+ last_command = l1
59
+
60
+ return last_id, last_command
61
+
62
+ def write_last_command(job_id: str, command: str):
63
+ with open(f'{log_dir()}/last', 'wt') as f:
64
+ f.write(job_id)
65
+ f.write('\n')
66
+ f.write(command)
67
+
68
+ def read_last_command():
69
+ with open(f'{log_dir()}/last', 'rt') as f:
70
+ job_id = f.readline().strip(' \r\n')
71
+ command = f.readline().strip(' \r\n')
72
+
73
+ return job_id, command
@@ -2,9 +2,10 @@ import sys
2
2
  from typing import TypeVar
3
3
 
4
4
  from adam.config import Config
5
+ from adam.utils_async_job import AsyncJobs
5
6
  from adam.utils_k8s.cassandra_nodes import CassandraNodes
6
7
  from adam.utils_k8s.pod_exec_result import PodExecResult
7
- from adam.utils import log, log2
8
+ from adam.utils import log, log2, log_to_pods, pod_log_dir
8
9
  from adam.utils_k8s.pods import Pods
9
10
  from adam.utils_k8s.statefulsets import StatefulSets
10
11
 
@@ -22,23 +23,30 @@ class CassandraClusters:
22
23
  shell = '/bin/sh',
23
24
  backgrounded = False,
24
25
  log_file = None,
25
- history=True) -> list[PodExecResult]:
26
+ history=True,
27
+ text_color: str = None) -> list[PodExecResult]:
26
28
 
27
29
  pods = StatefulSets.pod_names(sts, namespace)
28
30
  samples = 1 if on_any else sys.maxsize
29
31
  if (backgrounded or command.endswith(' &')) and not log_file:
30
- log_file = Pods.log_file(command)
32
+ pod_suffix = None
33
+ dir = None
34
+ if log_to_pods():
35
+ pod_suffix = ''
36
+ dir = pod_log_dir()
37
+
38
+ log_file = AsyncJobs.log_file(command, job_id=AsyncJobs.new_id(), pod_suffix=pod_suffix, dir=dir)
31
39
 
32
40
  msg = 'd`Running|Ran ' + action + ' command onto {size} pods'
33
41
  with Pods.parallelize(pods, max_workers, samples, msg, action=action) as exec:
34
- results: list[PodExecResult] = exec.map(lambda pod: CassandraNodes.exec(pod, namespace, command, False, False, shell, backgrounded, log_file, history))
42
+ results: list[PodExecResult] = exec.map(lambda pod: CassandraNodes.exec(pod, namespace, command, False, False, shell, backgrounded, log_file, history, text_color))
35
43
  for result in results:
36
44
  if show_out and not Config().is_debug():
37
- log(result.command)
45
+ log(result.command, text_color=text_color)
38
46
  if result.stdout:
39
- log(result.stdout)
47
+ log(result.stdout, text_color=text_color)
40
48
  if result.stderr:
41
- log2(result.stderr)
49
+ log2(result.stderr, text_color=text_color)
42
50
 
43
51
  return results
44
52
 
@@ -14,13 +14,14 @@ class CassandraNodes:
14
14
  shell = '/bin/sh',
15
15
  backgrounded = False,
16
16
  log_file = None,
17
- history = True) -> PodExecResult:
18
- r = Pods.exec(pod_name, "cassandra", namespace, command, show_out = show_out, throw_err = throw_err, shell = shell, backgrounded = backgrounded, log_file=log_file)
17
+ history = True,
18
+ text_color: str = None) -> PodExecResult:
19
+ r: PodExecResult = Pods.exec(pod_name, "cassandra", namespace, command, show_out = show_out, throw_err = throw_err, shell = shell, backgrounded = backgrounded, log_file=log_file, text_color=text_color)
19
20
 
20
21
  if history and r and r.log_file:
21
- entry = f':cat {r.log_file}'
22
+ # entry = f':tail {r.log_file}'
22
23
 
23
- ReplSession().append_history(entry)
24
+ ReplSession().append_history(r.log_file)
24
25
 
25
26
  return r
26
27