kaqing 2.0.172__py3-none-any.whl → 2.0.186__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 (140) hide show
  1. adam/app_session.py +2 -2
  2. adam/apps.py +18 -4
  3. adam/batch.py +1 -1
  4. adam/checks/check_utils.py +3 -1
  5. adam/commands/__init__.py +8 -2
  6. adam/commands/alter_tables.py +24 -35
  7. adam/commands/app/__init__.py +0 -0
  8. adam/commands/app/app.py +38 -0
  9. adam/commands/app/app_ping.py +38 -0
  10. adam/commands/app/show_app_actions.py +49 -0
  11. adam/commands/app/show_app_id.py +44 -0
  12. adam/commands/app/show_app_queues.py +38 -0
  13. adam/commands/app/utils_app.py +106 -0
  14. adam/commands/audit/audit.py +9 -27
  15. adam/commands/audit/audit_repair_tables.py +5 -7
  16. adam/commands/audit/audit_run.py +1 -1
  17. adam/commands/audit/completions_l.py +15 -0
  18. adam/commands/audit/show_last10.py +2 -14
  19. adam/commands/audit/show_slow10.py +2 -13
  20. adam/commands/audit/show_top10.py +2 -11
  21. adam/commands/audit/utils_show_top10.py +14 -1
  22. adam/commands/bash/bash.py +1 -1
  23. adam/commands/cat.py +5 -19
  24. adam/commands/cd.py +6 -8
  25. adam/commands/check.py +10 -18
  26. adam/commands/cli_commands.py +6 -1
  27. adam/commands/{cp.py → clipboard_copy.py} +34 -36
  28. adam/commands/code.py +2 -2
  29. adam/commands/command.py +94 -10
  30. adam/commands/commands_utils.py +19 -12
  31. adam/commands/cql/completions_c.py +28 -0
  32. adam/commands/cql/cqlsh.py +3 -7
  33. adam/commands/cql/utils_cql.py +22 -60
  34. adam/commands/deploy/deploy_pg_agent.py +2 -2
  35. adam/commands/deploy/undeploy_pg_agent.py +2 -2
  36. adam/commands/devices/device.py +39 -8
  37. adam/commands/devices/device_app.py +19 -29
  38. adam/commands/devices/device_auit_log.py +3 -3
  39. adam/commands/devices/device_cass.py +17 -23
  40. adam/commands/devices/device_export.py +12 -11
  41. adam/commands/devices/device_postgres.py +79 -63
  42. adam/commands/download_file.py +47 -0
  43. adam/commands/export/clean_up_all_export_sessions.py +3 -3
  44. adam/commands/export/clean_up_export_sessions.py +7 -19
  45. adam/commands/export/completions_x.py +11 -0
  46. adam/commands/export/download_export_session.py +40 -0
  47. adam/commands/export/drop_export_database.py +6 -22
  48. adam/commands/export/drop_export_databases.py +3 -9
  49. adam/commands/export/export.py +1 -17
  50. adam/commands/export/export_databases.py +93 -21
  51. adam/commands/export/export_select.py +8 -68
  52. adam/commands/export/export_sessions.py +209 -0
  53. adam/commands/export/export_use.py +13 -16
  54. adam/commands/export/export_x_select.py +48 -0
  55. adam/commands/export/exporter.py +108 -129
  56. adam/commands/export/import_files.py +44 -0
  57. adam/commands/export/import_session.py +10 -6
  58. adam/commands/export/importer.py +19 -5
  59. adam/commands/export/importer_athena.py +112 -41
  60. adam/commands/export/importer_sqlite.py +47 -19
  61. adam/commands/export/show_column_counts.py +11 -20
  62. adam/commands/export/show_export_databases.py +5 -2
  63. adam/commands/export/show_export_session.py +6 -15
  64. adam/commands/export/show_export_sessions.py +4 -11
  65. adam/commands/export/utils_export.py +46 -16
  66. adam/commands/find_files.py +51 -0
  67. adam/commands/find_processes.py +76 -0
  68. adam/commands/head.py +36 -0
  69. adam/commands/help.py +2 -2
  70. adam/commands/intermediate_command.py +6 -3
  71. adam/commands/ls.py +1 -1
  72. adam/commands/medusa/medusa_backup.py +13 -16
  73. adam/commands/medusa/medusa_restore.py +39 -32
  74. adam/commands/medusa/medusa_show_backupjobs.py +6 -4
  75. adam/commands/medusa/medusa_show_restorejobs.py +5 -3
  76. adam/commands/medusa/utils_medusa.py +15 -0
  77. adam/commands/nodetool.py +3 -8
  78. adam/commands/param_get.py +10 -12
  79. adam/commands/param_set.py +7 -10
  80. adam/commands/postgres/completions_p.py +22 -0
  81. adam/commands/postgres/postgres.py +25 -40
  82. adam/commands/postgres/postgres_databases.py +270 -0
  83. adam/commands/postgres/utils_postgres.py +33 -20
  84. adam/commands/preview_table.py +4 -2
  85. adam/commands/pwd.py +3 -3
  86. adam/commands/reaper/reaper_forward.py +2 -2
  87. adam/commands/reaper/reaper_run_abort.py +4 -10
  88. adam/commands/reaper/reaper_runs.py +3 -3
  89. adam/commands/reaper/reaper_schedule_activate.py +12 -12
  90. adam/commands/reaper/reaper_schedule_start.py +7 -12
  91. adam/commands/reaper/reaper_schedule_stop.py +7 -12
  92. adam/commands/reaper/utils_reaper.py +13 -6
  93. adam/commands/repair/repair_scan.py +0 -2
  94. adam/commands/repair/repair_stop.py +0 -1
  95. adam/commands/shell.py +7 -5
  96. adam/commands/show/show.py +1 -1
  97. adam/commands/show/show_adam.py +3 -3
  98. adam/commands/show/show_cassandra_repairs.py +5 -3
  99. adam/commands/show/show_cassandra_status.py +27 -20
  100. adam/commands/show/{show_commands.py → show_cli_commands.py} +2 -2
  101. adam/commands/show/show_login.py +2 -2
  102. adam/commands/show/show_params.py +2 -5
  103. adam/commands/show/show_processes.py +15 -14
  104. adam/commands/show/show_storage.py +9 -8
  105. adam/config.py +1 -0
  106. adam/embedded_params.py +1 -1
  107. adam/repl.py +20 -11
  108. adam/repl_commands.py +16 -9
  109. adam/repl_session.py +8 -1
  110. adam/repl_state.py +33 -10
  111. adam/sql/lark_completer.py +280 -0
  112. adam/sql/lark_parser.py +604 -0
  113. adam/sql/sql_state_machine.py +8 -2
  114. adam/utils.py +116 -29
  115. adam/utils_athena.py +7 -8
  116. adam/utils_issues.py +2 -2
  117. adam/utils_k8s/app_clusters.py +2 -2
  118. adam/utils_k8s/app_pods.py +5 -2
  119. adam/utils_k8s/cassandra_clusters.py +11 -3
  120. adam/utils_k8s/cassandra_nodes.py +2 -2
  121. adam/utils_k8s/k8s.py +14 -5
  122. adam/utils_k8s/kube_context.py +2 -2
  123. adam/utils_k8s/pods.py +23 -5
  124. adam/utils_k8s/statefulsets.py +5 -2
  125. adam/utils_local.py +4 -0
  126. adam/utils_repl/appendable_completer.py +6 -0
  127. adam/utils_repl/repl_completer.py +128 -2
  128. adam/utils_sqlite.py +14 -14
  129. adam/version.py +1 -1
  130. {kaqing-2.0.172.dist-info → kaqing-2.0.186.dist-info}/METADATA +1 -1
  131. kaqing-2.0.186.dist-info/RECORD +250 -0
  132. adam/commands/cql/cql_completions.py +0 -33
  133. adam/commands/export/export_handlers.py +0 -71
  134. adam/commands/export/export_select_x.py +0 -54
  135. adam/commands/postgres/postgres_context.py +0 -272
  136. adam/commands/postgres/psql_completions.py +0 -10
  137. kaqing-2.0.172.dist-info/RECORD +0 -230
  138. {kaqing-2.0.172.dist-info → kaqing-2.0.186.dist-info}/WHEEL +0 -0
  139. {kaqing-2.0.172.dist-info → kaqing-2.0.186.dist-info}/entry_points.txt +0 -0
  140. {kaqing-2.0.172.dist-info → kaqing-2.0.186.dist-info}/top_level.txt +0 -0
@@ -1,9 +1,7 @@
1
- from adam.commands import extract_options, extract_sequence
1
+ from adam.commands import extract_options, extract_sequence, extract_trailing_options
2
2
  from adam.commands.command import Command
3
- from adam.commands.commands_utils import show_table
4
3
  from adam.commands.cql.utils_cql import cassandra
5
4
  from adam.config import Config
6
- from adam.utils_k8s.statefulsets import StatefulSets
7
5
  from adam.repl_state import ReplState, RequiredState
8
6
 
9
7
  class ShowProcesses(Command):
@@ -29,21 +27,24 @@ class ShowProcesses(Command):
29
27
  return super().run(cmd, state)
30
28
 
31
29
  with self.validate(args, state) as (args, state):
32
- with extract_options(args, ['-s', '--show']) as (args, show_out):
33
- with extract_sequence(args, ['with', 'recipe', '=', 'qing']) as (_, recipe_qing):
34
- cols = Config().get('processes.columns', 'pod,cpu-metrics,mem')
35
- header = Config().get('processes.header', 'POD_NAME,M_CPU(USAGE/LIMIT),MEM/LIMIT')
36
- if recipe_qing:
37
- cols = Config().get('processes-qing.columns', 'pod,cpu,mem')
38
- header = Config().get('processes-qing.header', 'POD_NAME,Q_CPU/TOTAL,MEM/LIMIT')
30
+ with extract_trailing_options(args, '&') as (args, backgrounded):
31
+ with extract_options(args, ['-s', '--show']) as (args, show_out):
32
+ with extract_sequence(args, ['with', 'recipe', '=', 'qing']) as (_, recipe_qing):
33
+ cols = Config().get('processes.columns', 'pod,cpu-metrics,mem')
34
+ header = Config().get('processes.header', 'POD_NAME,M_CPU(USAGE/LIMIT),MEM/LIMIT')
35
+ if recipe_qing:
36
+ cols = Config().get('processes-qing.columns', 'pod,cpu,mem')
37
+ header = Config().get('processes-qing.header', 'POD_NAME,Q_CPU/TOTAL,MEM/LIMIT')
39
38
 
40
- with cassandra(state) as pods:
41
- pods.display_table(cols, header, show_out=show_out)
39
+ with cassandra(state) as pods:
40
+ pods.display_table(cols, header, show_out=show_out, backgrounded=backgrounded)
42
41
 
43
- return state
42
+ return state
44
43
 
45
44
  def completion(self, state: ReplState):
46
- return super().completion(state, {'with': {'recipe': {'=': {'metrics': {'-s': None}, 'qing': {'-s': None}}}}, '-s': None})
45
+ recipes = ['metrics', 'qing']
46
+ return super().completion(state, {'with': {'recipe': {'=': {r: {'-s': {'&': None}, '&': None} for r in recipes}}}, '-s': {'&': None}, '&': None})
47
+ # return super().completion(state, {'with': {'recipe': {'=': {'metrics': {'-s': {'&': None}, '&': None}, 'qing': {'-s': {'&': None}}}}}, '-s': {'&': None}, '&': None})
47
48
 
48
49
  def help(self, _: ReplState):
49
50
  return f'{ShowProcesses.COMMAND} [with recipe qing|metrics] [-s]\t show process overview -s show commands on nodes'
@@ -1,4 +1,4 @@
1
- from adam.commands import extract_options
1
+ from adam.commands import extract_options, extract_trailing_options
2
2
  from adam.commands.command import Command
3
3
  from adam.commands.cql.utils_cql import cassandra
4
4
  from adam.config import Config
@@ -27,16 +27,17 @@ class ShowStorage(Command):
27
27
  return super().run(cmd, state)
28
28
 
29
29
  with self.validate(args, state) as (args, state):
30
- with extract_options(args, ['-s', '--show']) as (args, show_out):
31
- cols = Config().get('storage.columns', 'pod,volume_root,volume_cassandra,snapshots,data,compactions')
32
- header = Config().get('storage.header', 'POD_NAME,VOLUME /,VOLUME CASS,SNAPSHOTS,DATA,COMPACTIONS')
33
- with cassandra(state) as pods:
34
- pods.display_table(cols, header, show_out=show_out)
30
+ with extract_trailing_options(args, '&') as (args, backgrounded):
31
+ with extract_options(args, ['-s', '--show']) as (args, show_out):
32
+ cols = Config().get('storage.columns', 'pod,volume_root,volume_cassandra,snapshots,data,compactions')
33
+ header = Config().get('storage.header', 'POD_NAME,VOLUME /,VOLUME CASS,SNAPSHOTS,DATA,COMPACTIONS')
34
+ with cassandra(state) as pods:
35
+ pods.display_table(cols, header, show_out=show_out, backgrounded=backgrounded)
35
36
 
36
- return state
37
+ return state
37
38
 
38
39
  def completion(self, state: ReplState):
39
- return super().completion(state, {'-s': None})
40
+ return super().completion(state, {'-s': {'&': None}, '&': None})
40
41
 
41
42
  def help(self, _: ReplState):
42
43
  return f'{ShowStorage.COMMAND} [-s]\t show storage overview -s show commands on nodes'
adam/config.py CHANGED
@@ -11,6 +11,7 @@ class Config:
11
11
  EMBEDDED_PARAMS = {}
12
12
 
13
13
  LogConfig.is_debug = lambda: Config().is_debug()
14
+ LogConfig.is_debug_complete = lambda: Config().get('debugs.complete', False)
14
15
  LogConfig.is_debug_timing = lambda: Config().get('debugs.timings', False)
15
16
 
16
17
  # the singleton pattern
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'}}, '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}}, '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'}, 'athena': {'workers': 8, 'columns': '<keys>', 'bucket': 'c3.ops--qing'}, 'csv': {'workers': 8, 'columns': '<row-key>'}, 'log-prefix': '/tmp/qing'}, '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/{}"}, '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}, 'logs': {'path': '/c3/cassandra/logs/system.log'}, 'log-prefix': '/tmp/qing', 'medusa': {'restore-auto-complete': False}, 'nodetool': {'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}, 'debug': False, 'debugs': {'timings': False, 'exit-on-error': False, 'show-parallelism': 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'}, 'athena': {'workers': 8, 'columns': '<keys>', 'bucket': 'c3.ops--qing'}, 'csv': {'workers': 8, 'columns': '<row-key>'}, 'log-prefix': '/tmp/qing'}, '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-tmp-dir': '/tmp/qing-db', 'logs': {'path': '/c3/cassandra/logs/system.log'}, 'log-prefix': '/tmp/qing', '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'}, 'x': {'tables': 'lazy'}, 'cli': {'cp': 'jit'}, 'export': {'databases': 'jit'}, 'medusa': {'backups': 'jit'}, 'reaper': {'schedules': 'lazy'}}, 'debug': False, 'debugs': {'timings': False, 'exit-on-error': False, 'show-parallelism': False}}
adam/repl.py CHANGED
@@ -5,7 +5,7 @@ import click
5
5
  from prompt_toolkit.key_binding import KeyBindings
6
6
 
7
7
  from adam.cli_group import cli
8
- from adam.commands.command import Command, InvalidState
8
+ from adam.commands.command import Command, InvalidArgumentsException, InvalidStateException
9
9
  from adam.commands.command_helpers import ClusterCommandHelper
10
10
  from adam.commands.devices.devices import Devices
11
11
  from adam.commands.help import Help
@@ -16,11 +16,16 @@ from adam.log import Log
16
16
  from adam.repl_commands import ReplCommands
17
17
  from adam.repl_session import ReplSession
18
18
  from adam.repl_state import ReplState
19
- from adam.utils import clear_wait_log_flag, debug, debug_trace, deep_merge_dicts, deep_sort_dict, lines_to_tabular, log2, log_exc, log_timing
19
+ from adam.utils import clear_wait_log_flag, debug_trace, deep_sort_dict, tabulize, log2, log_exc, log_timing
20
20
  from adam.apps import Apps
21
- from adam.utils_repl.repl_completer import ReplCompleter
21
+ from adam.utils_repl.repl_completer import ReplCompleter, merge_completions
22
22
  from . import __version__
23
23
 
24
+ import nest_asyncio
25
+ nest_asyncio.apply()
26
+
27
+ import asyncio
28
+
24
29
  def enter_repl(state: ReplState):
25
30
  if os.getenv('QING_DROPPED', 'false') == 'true':
26
31
  log2('You have dropped to bash from another qing instance. Please enter "exit" to go back to qing.')
@@ -68,7 +73,7 @@ def enter_repl(state: ReplState):
68
73
 
69
74
  for c in sorted_cmds:
70
75
  with log_exc(f'* {c.command()} command returned None completions.'):
71
- completions = log_timing(c.command(), lambda: deep_sort_dict(deep_merge_dicts(completions, c.completion(state))))
76
+ completions = log_timing(c.command(), lambda: deep_sort_dict(merge_completions(completions, c.completion(state))))
72
77
 
73
78
  # print(json.dumps(completions, indent=4))
74
79
  completer = ReplCompleter.from_nested_dict(completions)
@@ -88,17 +93,17 @@ def enter_repl(state: ReplState):
88
93
  return state, cmd
89
94
 
90
95
  if state.device == ReplState.A and state.app_app or state.device == ReplState.P:
91
- state.push()
96
+ state.push(pod_targetted=True)
92
97
 
93
98
  state.app_pod = arry[0].strip('@')
94
99
  cmd = ' '.join(arry[1:])
95
100
  elif state.device == ReplState.P:
96
- state.push()
101
+ state.push(pod_targetted=True)
97
102
 
98
103
  state.app_pod = arry[0].strip('@')
99
104
  cmd = ' '.join(arry[1:])
100
105
  elif state.sts:
101
- state.push()
106
+ state.push(pod_targetted=True)
102
107
 
103
108
  state.pod = arry[0].strip('@')
104
109
  cmd = ' '.join(arry[1:])
@@ -109,7 +114,9 @@ def enter_repl(state: ReplState):
109
114
  try:
110
115
  if cmd and cmd.strip(' ') and not (result := cmds.run(cmd, target)):
111
116
  result = try_device_default_action(target, cmds, cmd_list, cmd)
112
- except InvalidState:
117
+ except InvalidStateException:
118
+ pass
119
+ except InvalidArgumentsException:
113
120
  pass
114
121
 
115
122
  if result and type(result) is ReplState and (s := cast(ReplState, result).export_session) != state.export_session:
@@ -141,8 +148,7 @@ def try_device_default_action(state: ReplState, cmds: Command, cmd_list: list[Co
141
148
  if not action_taken:
142
149
  log2(f'* Invalid command: {cmd}')
143
150
  log2()
144
- lines = [c.help(state) for c in cmd_list if c.help(state)]
145
- log2(lines_to_tabular(lines, separator='\t'))
151
+ tabulize([c.help(state) for c in cmd_list if c.help(state)], separator='\t', to=2)
146
152
 
147
153
  return result
148
154
 
@@ -174,6 +180,9 @@ def repl(kubeconfig: str, config: str, param: list[str], cluster:str, namespace:
174
180
  if not KubeContext.init_params(config, param):
175
181
  return
176
182
 
177
- state = ReplState(device=Config().get('repl.start-drive', 'a'), ns_sts=cluster, namespace=namespace, in_repl=True)
183
+ state = ReplState(ns_sts=cluster, namespace=namespace, in_repl=True)
178
184
  state, _ = state.apply_device_arg(extra_args)
185
+ if not state.device:
186
+ state.device=Config().get('repl.start-drive', 'a')
187
+
179
188
  enter_repl(state)
adam/repl_commands.py CHANGED
@@ -7,6 +7,7 @@ from adam.commands.app.show_app_queues import ShowAppQueues
7
7
  from adam.commands.audit.audit import Audit
8
8
  from adam.commands.cat import Cat
9
9
  from adam.commands.code import Code
10
+ from adam.commands.download_file import DownloadFile
10
11
  from adam.commands.deploy.code_start import CodeStart
11
12
  from adam.commands.deploy.code_stop import CodeStop
12
13
  from adam.commands.deploy.deploy import Deploy
@@ -22,22 +23,27 @@ from adam.commands.devices.device_auit_log import DeviceAuditLog
22
23
  from adam.commands.devices.device_cass import DeviceCass
23
24
  from adam.commands.devices.device_export import DeviceExport
24
25
  from adam.commands.devices.device_postgres import DevicePostgres
26
+ from adam.commands.export.download_export_session import DownloadExportSession
25
27
  from adam.commands.export.drop_export_database import DropExportDatabase
26
28
  from adam.commands.export.export import ExportTables
29
+ from adam.commands.export.import_files import ImportCSVFiles
27
30
  from adam.commands.export.import_session import ImportSession
28
31
  from adam.commands.export.clean_up_export_sessions import CleanUpExportSessions
29
32
  from adam.commands.export.clean_up_all_export_sessions import CleanUpAllExportSessions
30
33
  from adam.commands.export.drop_export_databases import DropExportDatabases
31
- from adam.commands.export.export_select import ExportSelect
34
+ from adam.commands.export.export_x_select import ExportXSelect
32
35
  from adam.commands.export.export_use import ExportUse
33
- from adam.commands.export.export_select_x import ExportSelectX
36
+ from adam.commands.export.export_select import ExportSelect
34
37
  from adam.commands.export.show_column_counts import ShowColumnCounts
35
38
  from adam.commands.export.show_export_databases import ShowExportDatabases
36
39
  from adam.commands.export.show_export_session import ShowExportSession
37
40
  from adam.commands.export.show_export_sessions import ShowExportSessions
41
+ from adam.commands.find_files import FindLocalFiles
42
+ from adam.commands.find_processes import FindProcesses
43
+ from adam.commands.head import Head
38
44
  from adam.commands.kubectl import Kubectl
39
45
  from adam.commands.shell import Shell
40
- from adam.commands.cp import ClipboardCopy
46
+ from adam.commands.clipboard_copy import ClipboardCopy
41
47
  from adam.commands.bash.bash import Bash
42
48
  from adam.commands.cd import Cd
43
49
  from adam.commands.check import Check
@@ -61,7 +67,7 @@ from adam.commands.param_set import SetParam
61
67
  from adam.commands.show.show import Show
62
68
  from adam.commands.show.show_cassandra_status import ShowCassandraStatus
63
69
  from adam.commands.show.show_cassandra_version import ShowCassandraVersion
64
- from adam.commands.show.show_commands import ShowKubectlCommands
70
+ from adam.commands.show.show_cli_commands import ShowKubectlCommands
65
71
  from adam.commands.show.show_host import ShowHost
66
72
  from adam.commands.show.show_login import ShowLogin
67
73
  from adam.commands.show.show_params import ShowParams
@@ -93,16 +99,17 @@ class ReplCommands:
93
99
  return deduped
94
100
 
95
101
  def navigation() -> list[Command]:
96
- return [Ls(), PreviewTable(), DeviceApp(), DevicePostgres(), DeviceCass(), DeviceAuditLog(), DeviceExport(), Cd(), Cat(), Pwd(), ClipboardCopy(),
102
+ return [Ls(), PreviewTable(), DeviceApp(), DevicePostgres(), DeviceCass(), DeviceAuditLog(), DeviceExport(),
103
+ Cd(), Cat(), Head(), DownloadFile(), FindLocalFiles(), FindProcesses(), Pwd(), ClipboardCopy(),
97
104
  GetParam(), SetParam(), ShowParams(), ShowKubectlCommands(), ShowLogin(), ShowAdam(), ShowHost()]
98
105
 
99
106
  def cassandra_ops() -> list[Command]:
100
107
  return [Cqlsh(), ShowCassandraStatus(), ShowCassandraVersion(), ShowCassandraRepairs(), ShowStorage(), ShowProcesses(),
101
108
  Check(), Issues(), NodeTool(), Report(), AlterTables(), Bash(),
102
- ExportTables(), ExportSelect(), ExportUse(), ShowExportDatabases(), ShowColumnCounts(),
109
+ ExportTables(), ExportXSelect(), ExportUse(), ShowExportDatabases(), ShowColumnCounts(),
103
110
  DropExportDatabase(), DropExportDatabases(),
104
- ShowExportSessions(), ShowExportSession(),
105
- CleanUpExportSessions(), CleanUpAllExportSessions(), ImportSession()] + \
111
+ ShowExportSessions(), ShowExportSession(), DownloadExportSession(),
112
+ CleanUpExportSessions(), CleanUpAllExportSessions(), ImportSession(), ImportCSVFiles()] + \
106
113
  Medusa().cmd_list() + [Restart(), RollOut(), Watch()] + Reaper().cmd_list() + Repair().cmd_list()
107
114
 
108
115
  def postgres_ops() -> list[Command]:
@@ -115,7 +122,7 @@ class ReplCommands:
115
122
  return [Audit()] + Audit().cmd_list()
116
123
 
117
124
  def export_ops() -> list[Command]:
118
- return [ExportSelectX(), DropExportDatabase(), DropExportDatabases(), ShowColumnCounts()]
125
+ return [ExportSelect(), DropExportDatabase(), DropExportDatabases(), ShowColumnCounts()]
119
126
 
120
127
  def tools() -> list[Command]:
121
128
  return [Shell(), CodeStart(), CodeStop(), DeployFrontend(), UndeployFrontend(), DeployPod(), UndeployPod(), Kubectl(), Code()]
adam/repl_session.py CHANGED
@@ -1,6 +1,8 @@
1
1
  from prompt_toolkit import PromptSession
2
2
  from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
3
3
 
4
+ from adam.config import Config
5
+
4
6
  class ReplSession:
5
7
  # the singleton pattern
6
8
  def __new__(cls, *args, **kwargs):
@@ -10,4 +12,9 @@ class ReplSession:
10
12
 
11
13
  def __init__(self):
12
14
  if not hasattr(self, 'prompt_session'):
13
- self.prompt_session = PromptSession(auto_suggest=AutoSuggestFromHistory())
15
+ self.prompt_session = PromptSession(auto_suggest=AutoSuggestFromHistory())
16
+
17
+ def append_history(self, entry: str):
18
+ if entry and Config().get('repl.history.push-cat-remote-log-file', True):
19
+ if self.prompt_session:
20
+ self.prompt_session.history.append_string(entry)
adam/repl_state.py CHANGED
@@ -3,7 +3,6 @@ from enum import Enum
3
3
  import re
4
4
  from typing import Callable
5
5
 
6
- from adam.commands.postgres.postgres_context import PostgresContext
7
6
  from adam.utils_k8s.app_clusters import AppClusters
8
7
  from adam.utils_k8s.app_pods import AppPods
9
8
  from adam.utils_k8s.cassandra_clusters import CassandraClusters
@@ -62,6 +61,7 @@ class ReplState:
62
61
  self.bash_session = bash_session
63
62
  self.remote_dir = remote_dir
64
63
  self.original_state: ReplState = None
64
+ self.pod_targetted = False
65
65
 
66
66
  self.export_session: str = None
67
67
 
@@ -82,11 +82,11 @@ class ReplState:
82
82
  msg = ''
83
83
  if self.device == ReplState.P:
84
84
  msg = f'{ReplState.P}:'
85
- pg: PostgresContext = PostgresContext.apply(self.namespace, self.pg_path) if self.pg_path else None
86
- if pg and pg.db:
87
- msg += pg.db
88
- elif pg and pg.host:
89
- msg += pg.host
85
+ host, database = self.pg_host_n_database()
86
+ if database:
87
+ msg += database
88
+ elif host:
89
+ msg += host
90
90
  elif self.device == ReplState.A:
91
91
  msg = f'{ReplState.A}:'
92
92
  if self.app_env:
@@ -314,8 +314,8 @@ class ReplState:
314
314
  if self.device != ReplState.P:
315
315
  return (False, None)
316
316
 
317
- pg: PostgresContext = PostgresContext.apply(self.namespace, self.pg_path)
318
- if not pg.db:
317
+ _, database = self.pg_host_n_database()
318
+ if not database:
319
319
  def error():
320
320
  if self.in_repl:
321
321
  log2('cd to a database first.')
@@ -346,7 +346,10 @@ class ReplState:
346
346
  if not self.export_session:
347
347
  def error():
348
348
  if self.in_repl:
349
- log2("Select an export database first with 'use' command.")
349
+ if self.device == ReplState.C:
350
+ log2("Select an export database first with 'use' command.")
351
+ else:
352
+ log2('cd to an export database first.')
350
353
  else:
351
354
  log2('* export database is missing.')
352
355
  log2()
@@ -390,9 +393,10 @@ class ReplState:
390
393
  self.pop()
391
394
  self.bash_session = None
392
395
 
393
- def push(self):
396
+ def push(self, pod_targetted=False):
394
397
  if not self.original_state:
395
398
  self.original_state = copy(self)
399
+ self.pod_targetted = pod_targetted
396
400
 
397
401
  def pop(self):
398
402
  if o := self.original_state:
@@ -407,6 +411,25 @@ class ReplState:
407
411
  self.namespace = o.namespace
408
412
 
409
413
  self.original_state = None
414
+ self.pod_targetted = False
415
+
416
+ def pg_host_n_database(self):
417
+ host = None
418
+ database = None
419
+
420
+ if self.pg_path:
421
+ host_n_db = self.pg_path.split('/')
422
+ host = host_n_db[0]
423
+ if len(host_n_db) > 1:
424
+ database = host_n_db[1]
425
+
426
+ return host, database
427
+
428
+ def with_no_pod(self):
429
+ state1 = copy(self)
430
+ state1.pod = None
431
+
432
+ return state1
410
433
 
411
434
  class DevicePodService:
412
435
  def __init__(self, handler: 'DeviceExecHandler'):