kaqing 2.0.28__tar.gz → 2.0.30__tar.gz

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.
Files changed (175) hide show
  1. {kaqing-2.0.28 → kaqing-2.0.30}/PKG-INFO +1 -1
  2. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/alter_tables.py +4 -20
  3. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/command.py +0 -1
  4. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/cql_utils.py +45 -1
  5. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/cqlsh.py +1 -0
  6. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/deploy/deploy_pod.py +7 -2
  7. kaqing-2.0.30/adam/commands/describe_keyspace.py +63 -0
  8. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/login.py +1 -1
  9. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/param_set.py +1 -1
  10. {kaqing-2.0.28 → kaqing-2.0.30}/adam/config.py +1 -1
  11. kaqing-2.0.30/adam/embedded_params.py +2 -0
  12. {kaqing-2.0.28 → kaqing-2.0.30}/adam/k8s_utils/cassandra_nodes.py +1 -1
  13. {kaqing-2.0.28 → kaqing-2.0.30}/adam/k8s_utils/kube_context.py +1 -1
  14. {kaqing-2.0.28 → kaqing-2.0.30}/adam/repl.py +5 -5
  15. {kaqing-2.0.28 → kaqing-2.0.30}/adam/repl_commands.py +2 -1
  16. {kaqing-2.0.28 → kaqing-2.0.30}/adam/utils.py +13 -0
  17. kaqing-2.0.30/adam/version.py +5 -0
  18. {kaqing-2.0.28 → kaqing-2.0.30}/kaqing.egg-info/PKG-INFO +1 -1
  19. {kaqing-2.0.28 → kaqing-2.0.30}/kaqing.egg-info/SOURCES.txt +1 -0
  20. {kaqing-2.0.28 → kaqing-2.0.30}/setup.py +1 -1
  21. kaqing-2.0.28/adam/embedded_params.py +0 -2
  22. kaqing-2.0.28/adam/version.py +0 -5
  23. {kaqing-2.0.28 → kaqing-2.0.30}/README +0 -0
  24. {kaqing-2.0.28 → kaqing-2.0.30}/adam/__init__.py +0 -0
  25. {kaqing-2.0.28 → kaqing-2.0.30}/adam/app_session.py +0 -0
  26. {kaqing-2.0.28 → kaqing-2.0.30}/adam/apps.py +0 -0
  27. {kaqing-2.0.28 → kaqing-2.0.30}/adam/batch.py +0 -0
  28. {kaqing-2.0.28 → kaqing-2.0.30}/adam/checks/__init__.py +0 -0
  29. {kaqing-2.0.28 → kaqing-2.0.30}/adam/checks/check.py +0 -0
  30. {kaqing-2.0.28 → kaqing-2.0.30}/adam/checks/check_context.py +0 -0
  31. {kaqing-2.0.28 → kaqing-2.0.30}/adam/checks/check_result.py +0 -0
  32. {kaqing-2.0.28 → kaqing-2.0.30}/adam/checks/check_utils.py +0 -0
  33. {kaqing-2.0.28 → kaqing-2.0.30}/adam/checks/compactionstats.py +0 -0
  34. {kaqing-2.0.28 → kaqing-2.0.30}/adam/checks/cpu.py +0 -0
  35. {kaqing-2.0.28 → kaqing-2.0.30}/adam/checks/disk.py +0 -0
  36. {kaqing-2.0.28 → kaqing-2.0.30}/adam/checks/gossip.py +0 -0
  37. {kaqing-2.0.28 → kaqing-2.0.30}/adam/checks/issue.py +0 -0
  38. {kaqing-2.0.28 → kaqing-2.0.30}/adam/checks/memory.py +0 -0
  39. {kaqing-2.0.28 → kaqing-2.0.30}/adam/checks/status.py +0 -0
  40. {kaqing-2.0.28 → kaqing-2.0.30}/adam/cli.py +0 -0
  41. {kaqing-2.0.28 → kaqing-2.0.30}/adam/cli_group.py +0 -0
  42. {kaqing-2.0.28 → kaqing-2.0.30}/adam/columns/__init__.py +0 -0
  43. {kaqing-2.0.28 → kaqing-2.0.30}/adam/columns/column.py +0 -0
  44. {kaqing-2.0.28 → kaqing-2.0.30}/adam/columns/columns.py +0 -0
  45. {kaqing-2.0.28 → kaqing-2.0.30}/adam/columns/compactions.py +0 -0
  46. {kaqing-2.0.28 → kaqing-2.0.30}/adam/columns/cpu.py +0 -0
  47. {kaqing-2.0.28 → kaqing-2.0.30}/adam/columns/dir_data.py +0 -0
  48. {kaqing-2.0.28 → kaqing-2.0.30}/adam/columns/dir_snapshots.py +0 -0
  49. {kaqing-2.0.28 → kaqing-2.0.30}/adam/columns/gossip.py +0 -0
  50. {kaqing-2.0.28 → kaqing-2.0.30}/adam/columns/host_id.py +0 -0
  51. {kaqing-2.0.28 → kaqing-2.0.30}/adam/columns/memory.py +0 -0
  52. {kaqing-2.0.28 → kaqing-2.0.30}/adam/columns/node_address.py +0 -0
  53. {kaqing-2.0.28 → kaqing-2.0.30}/adam/columns/node_load.py +0 -0
  54. {kaqing-2.0.28 → kaqing-2.0.30}/adam/columns/node_owns.py +0 -0
  55. {kaqing-2.0.28 → kaqing-2.0.30}/adam/columns/node_status.py +0 -0
  56. {kaqing-2.0.28 → kaqing-2.0.30}/adam/columns/node_tokens.py +0 -0
  57. {kaqing-2.0.28 → kaqing-2.0.30}/adam/columns/node_utils.py +0 -0
  58. {kaqing-2.0.28 → kaqing-2.0.30}/adam/columns/pod_name.py +0 -0
  59. {kaqing-2.0.28 → kaqing-2.0.30}/adam/columns/volume_cassandra.py +0 -0
  60. {kaqing-2.0.28 → kaqing-2.0.30}/adam/columns/volume_root.py +0 -0
  61. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/__init__.py +0 -0
  62. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/app.py +0 -0
  63. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/app_ping.py +0 -0
  64. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/bash.py +0 -0
  65. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/cd.py +0 -0
  66. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/check.py +0 -0
  67. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/cli_commands.py +0 -0
  68. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/command_helpers.py +0 -0
  69. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/commands_utils.py +0 -0
  70. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/cp.py +0 -0
  71. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/deploy/__init__.py +0 -0
  72. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/deploy/code_start.py +0 -0
  73. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/deploy/code_stop.py +0 -0
  74. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/deploy/code_utils.py +0 -0
  75. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/deploy/deploy.py +0 -0
  76. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/deploy/deploy_frontend.py +0 -0
  77. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/deploy/deploy_pg_agent.py +0 -0
  78. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/deploy/deploy_utils.py +0 -0
  79. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/deploy/undeploy.py +0 -0
  80. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/deploy/undeploy_frontend.py +0 -0
  81. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/deploy/undeploy_pg_agent.py +0 -0
  82. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/deploy/undeploy_pod.py +0 -0
  83. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/devices.py +0 -0
  84. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/exit.py +0 -0
  85. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/help.py +0 -0
  86. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/issues.py +0 -0
  87. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/logs.py +0 -0
  88. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/ls.py +0 -0
  89. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/medusa/__init__.py +0 -0
  90. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/medusa/medusa.py +0 -0
  91. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/medusa/medusa_backup.py +0 -0
  92. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/medusa/medusa_restore.py +0 -0
  93. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/medusa/medusa_show_backupjobs.py +0 -0
  94. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/medusa/medusa_show_restorejobs.py +0 -0
  95. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/nodetool.py +0 -0
  96. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/nodetool_commands.py +0 -0
  97. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/param_get.py +0 -0
  98. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/postgres/__init__.py +0 -0
  99. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/postgres/postgres.py +0 -0
  100. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/postgres/postgres_ls.py +0 -0
  101. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/postgres/postgres_preview.py +0 -0
  102. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/postgres/postgres_session.py +0 -0
  103. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/preview_table.py +0 -0
  104. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/pwd.py +0 -0
  105. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/reaper/__init__.py +0 -0
  106. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/reaper/reaper.py +0 -0
  107. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/reaper/reaper_forward.py +0 -0
  108. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/reaper/reaper_forward_stop.py +0 -0
  109. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/reaper/reaper_restart.py +0 -0
  110. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/reaper/reaper_run_abort.py +0 -0
  111. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/reaper/reaper_runs.py +0 -0
  112. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/reaper/reaper_runs_abort.py +0 -0
  113. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/reaper/reaper_schedule_activate.py +0 -0
  114. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/reaper/reaper_schedule_start.py +0 -0
  115. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/reaper/reaper_schedule_stop.py +0 -0
  116. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/reaper/reaper_schedules.py +0 -0
  117. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/reaper/reaper_session.py +0 -0
  118. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/reaper/reaper_status.py +0 -0
  119. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/repair/__init__.py +0 -0
  120. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/repair/repair.py +0 -0
  121. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/repair/repair_log.py +0 -0
  122. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/repair/repair_run.py +0 -0
  123. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/repair/repair_scan.py +0 -0
  124. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/repair/repair_stop.py +0 -0
  125. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/report.py +0 -0
  126. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/restart.py +0 -0
  127. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/rollout.py +0 -0
  128. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/shell.py +0 -0
  129. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/show/__init__.py +0 -0
  130. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/show/show.py +0 -0
  131. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/show/show_adam.py +0 -0
  132. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/show/show_app_actions.py +0 -0
  133. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/show/show_app_id.py +0 -0
  134. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/show/show_app_queues.py +0 -0
  135. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/show/show_cassandra_status.py +0 -0
  136. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/show/show_cassandra_version.py +0 -0
  137. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/show/show_commands.py +0 -0
  138. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/show/show_login.py +0 -0
  139. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/show/show_params.py +0 -0
  140. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/show/show_processes.py +0 -0
  141. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/show/show_repairs.py +0 -0
  142. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/show/show_storage.py +0 -0
  143. {kaqing-2.0.28 → kaqing-2.0.30}/adam/commands/watch.py +0 -0
  144. {kaqing-2.0.28 → kaqing-2.0.30}/adam/embedded_apps.py +0 -0
  145. {kaqing-2.0.28 → kaqing-2.0.30}/adam/k8s_utils/__init__.py +0 -0
  146. {kaqing-2.0.28 → kaqing-2.0.30}/adam/k8s_utils/cassandra_clusters.py +0 -0
  147. {kaqing-2.0.28 → kaqing-2.0.30}/adam/k8s_utils/config_maps.py +0 -0
  148. {kaqing-2.0.28 → kaqing-2.0.30}/adam/k8s_utils/custom_resources.py +0 -0
  149. {kaqing-2.0.28 → kaqing-2.0.30}/adam/k8s_utils/deployment.py +0 -0
  150. {kaqing-2.0.28 → kaqing-2.0.30}/adam/k8s_utils/ingresses.py +0 -0
  151. {kaqing-2.0.28 → kaqing-2.0.30}/adam/k8s_utils/jobs.py +0 -0
  152. {kaqing-2.0.28 → kaqing-2.0.30}/adam/k8s_utils/pods.py +0 -0
  153. {kaqing-2.0.28 → kaqing-2.0.30}/adam/k8s_utils/secrets.py +0 -0
  154. {kaqing-2.0.28 → kaqing-2.0.30}/adam/k8s_utils/service_accounts.py +0 -0
  155. {kaqing-2.0.28 → kaqing-2.0.30}/adam/k8s_utils/services.py +0 -0
  156. {kaqing-2.0.28 → kaqing-2.0.30}/adam/k8s_utils/statefulsets.py +0 -0
  157. {kaqing-2.0.28 → kaqing-2.0.30}/adam/k8s_utils/volumes.py +0 -0
  158. {kaqing-2.0.28 → kaqing-2.0.30}/adam/log.py +0 -0
  159. {kaqing-2.0.28 → kaqing-2.0.30}/adam/pod_exec_result.py +0 -0
  160. {kaqing-2.0.28 → kaqing-2.0.30}/adam/repl_session.py +0 -0
  161. {kaqing-2.0.28 → kaqing-2.0.30}/adam/repl_state.py +0 -0
  162. {kaqing-2.0.28 → kaqing-2.0.30}/adam/sso/__init__.py +0 -0
  163. {kaqing-2.0.28 → kaqing-2.0.30}/adam/sso/authenticator.py +0 -0
  164. {kaqing-2.0.28 → kaqing-2.0.30}/adam/sso/authn_ad.py +0 -0
  165. {kaqing-2.0.28 → kaqing-2.0.30}/adam/sso/authn_okta.py +0 -0
  166. {kaqing-2.0.28 → kaqing-2.0.30}/adam/sso/cred_cache.py +0 -0
  167. {kaqing-2.0.28 → kaqing-2.0.30}/adam/sso/id_token.py +0 -0
  168. {kaqing-2.0.28 → kaqing-2.0.30}/adam/sso/idp.py +0 -0
  169. {kaqing-2.0.28 → kaqing-2.0.30}/adam/sso/idp_login.py +0 -0
  170. {kaqing-2.0.28 → kaqing-2.0.30}/adam/sso/idp_session.py +0 -0
  171. {kaqing-2.0.28 → kaqing-2.0.30}/adam/sso/sso_config.py +0 -0
  172. {kaqing-2.0.28 → kaqing-2.0.30}/kaqing.egg-info/dependency_links.txt +0 -0
  173. {kaqing-2.0.28 → kaqing-2.0.30}/kaqing.egg-info/entry_points.txt +0 -0
  174. {kaqing-2.0.28 → kaqing-2.0.30}/kaqing.egg-info/top_level.txt +0 -0
  175. {kaqing-2.0.28 → kaqing-2.0.30}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: kaqing
3
- Version: 2.0.28
3
+ Version: 2.0.30
4
4
  Summary: UNKNOWN
5
5
  Home-page: UNKNOWN
6
6
  License: UNKNOWN
@@ -54,7 +54,7 @@ class AlterTables(Command):
54
54
 
55
55
  excludes = [e.strip(' \r\n') for e in Config().get(
56
56
  'cql.alter-tables.excludes',
57
- 'system_auth,system_traces,system_distributed,system_views,system,system_schema,system_virtual_schema').split(',')]
57
+ 'system_auth,system_traces,reaper_db,system_distributed,system_views,system,system_schema,system_virtual_schema').split(',')]
58
58
  batching = Config().get('cql.alter-tables.batching', True)
59
59
  tables = parse_cql_desc_tables(r[0].stdout)
60
60
  for k, v in tables.items():
@@ -63,7 +63,7 @@ class AlterTables(Command):
63
63
  # alter table <table_name> with GC_GRACE_SECONDS = <timeout>;
64
64
  cql = ';\n'.join([f'alter table {k}.{t} with {arg_str}' for t in v])
65
65
  try:
66
- run_cql(state, cql, [], show_out=Config().get('debug.show-out', False), on_any=True)
66
+ run_cql(state, cql, [], show_out=Config().is_debug(), on_any=True)
67
67
  except Exception as e:
68
68
  log2(e)
69
69
  continue
@@ -72,7 +72,7 @@ class AlterTables(Command):
72
72
  try:
73
73
  # alter table <table_name> with GC_GRACE_SECONDS = <timeout>;
74
74
  cql = f'alter table {k}.{t} with {arg_str}'
75
- run_cql(state, cql, [], show_out=Config().get('debug.show-out', False), on_any=True)
75
+ run_cql(state, cql, [], show_out=Config().is_debug(), on_any=True)
76
76
  except Exception as e:
77
77
  log2(e)
78
78
  continue
@@ -92,20 +92,4 @@ class AlterTables(Command):
92
92
  return {}
93
93
 
94
94
  def help(self, _: ReplState) -> str:
95
- return f'[{AlterTables.COMMAND}] <param = value> [--include-reaper] \t alter on all tables'
96
-
97
- class CqlCommandHelper(click.Command):
98
- def get_help(self, ctx: click.Context):
99
- log(super().get_help(ctx))
100
- log()
101
- log(' e.g. qing cql <cluster or pod> select host_id from system.local')
102
- log()
103
- log('Advanced Usages:')
104
- log(' 1. Use -- to specify what arguments are passed to the cqlsh.')
105
- log(' 2. Use "" to avoid expansion on shell variables.')
106
- log(' 3. Use ; to use multiple CQL statements')
107
- log()
108
- log(' e.g. qing cql <cluster or pod> -- "consistency quorum; select * from system.local" --request-timeout=3600')
109
- log()
110
-
111
- ClusterOrPodCommandHelper.cluter_or_pod_help()
95
+ return f'{AlterTables.COMMAND} <param = value> [--include-reaper] \t alter on all tables'
@@ -22,7 +22,6 @@ class Command:
22
22
  # Do not do child of child!!!
23
23
  @abstractmethod
24
24
  def run(self, cmd: str, state: ReplState):
25
- Config().debug(cmd)
26
25
  if self._successor:
27
26
  return self._successor.run(cmd, state)
28
27
 
@@ -1,9 +1,24 @@
1
+ import functools
1
2
  import re
2
3
 
3
4
  from adam.k8s_utils.cassandra_clusters import CassandraClusters
4
5
  from adam.k8s_utils.cassandra_nodes import CassandraNodes
5
6
  from adam.k8s_utils.secrets import Secrets
7
+ from adam.pod_exec_result import PodExecResult
6
8
  from adam.repl_state import ReplState
9
+ from adam.utils import log2
10
+
11
+ @functools.lru_cache()
12
+ def keyspaces(sts: str, namespace: str):
13
+ user, pw = Secrets.get_user_pass(sts, namespace, secret_path='cql.secret')
14
+ command = f'cqlsh -u {user} -p {pw} -e "describe keyspaces"'
15
+
16
+ r: list[PodExecResult] = CassandraClusters.exec(sts, namespace, command, show_out=False, action='cql', on_any=True)
17
+ if not r:
18
+ log2('No pod is available')
19
+ return []
20
+
21
+ return parse_cql_desc_keyspaces(r[0].stdout)
7
22
 
8
23
  def run_cql(state: ReplState, cql: str, opts: list = [], show_out = False, use_single_quotes = False, on_any = False):
9
24
  user, pw = Secrets.get_user_pass(state.sts if state.sts else state.pod, state.namespace, secret_path='cql.secret')
@@ -50,4 +65,33 @@ def parse_cql_desc_tables(out: str):
50
65
  tables_by_keyspace[keyspace] = []
51
66
  tables_by_keyspace[keyspace].append(t)
52
67
 
53
- return tables_by_keyspace
68
+ return tables_by_keyspace
69
+
70
+ def parse_cql_desc_keyspaces(out: str) -> list[str]:
71
+ #
72
+ # Warning: Cannot create directory at `/home/cassandra/.cassandra`. Command history will not be saved. Please check what was the environment property CQL_HISTORY set to.
73
+ #
74
+ #
75
+ # Warning: Using a password on the command line interface can be insecure.
76
+ # Recommendation: use the credentials file to securely provide the password.
77
+ #
78
+ #
79
+ # azops88_db system_auth system_traces
80
+ # reaper_db system_distributed system_views
81
+ # system system_schema system_virtual_schema
82
+ #
83
+ kses = []
84
+ for line in out.split('\n'):
85
+ line = line.strip(' \r')
86
+ if not line:
87
+ continue
88
+ if line.startswith('Warning:'):
89
+ continue
90
+ if line.startswith('Recommendation:'):
91
+ continue
92
+
93
+ for ks in line.split(' '):
94
+ if s := ks.strip(' \r\t'):
95
+ kses.append(s)
96
+
97
+ return kses
@@ -59,6 +59,7 @@ class Cqlsh(Command):
59
59
  'insert': {'into': None},
60
60
  'select': None,
61
61
  'update': None,
62
+ 'describe': {'keyspaces': None},
62
63
  }
63
64
 
64
65
  return {}
@@ -3,6 +3,7 @@ import yaml
3
3
 
4
4
  from adam.commands.command import Command
5
5
  from adam.commands.deploy.deploy_utils import creating, deploy_frontend, gen_labels
6
+ from adam.commands.deploy.undeploy_pod import UndeployPod
6
7
  from adam.config import Config
7
8
  from adam.k8s_utils.config_maps import ConfigMaps
8
9
  from adam.k8s_utils.deployment import Deployments
@@ -39,6 +40,10 @@ class DeployPod(Command):
39
40
  if not self.validate_state(state):
40
41
  return state
41
42
 
43
+ args, forced = Command.extract_options(args, '--force')
44
+ if forced:
45
+ UndeployPod().run(UndeployPod.COMMAND, state)
46
+
42
47
  if KubeContext.in_cluster():
43
48
  log2('This is doable only from outside of the Kubernetes cluster.')
44
49
  return state
@@ -103,7 +108,7 @@ class DeployPod(Command):
103
108
  return state
104
109
 
105
110
  def completion(self, state: ReplState):
106
- return super().completion(state)
111
+ return super().completion(state, {'--force': None})
107
112
 
108
113
  def help(self, _: ReplState):
109
- return f'{DeployPod.COMMAND}\t deploy Ops pod'
114
+ return f'{DeployPod.COMMAND} [--force]\t deploy Ops pod, --force to undeploy first'
@@ -0,0 +1,63 @@
1
+ import click
2
+
3
+ from adam.commands.command import Command
4
+ from adam.commands.command_helpers import ClusterOrPodCommandHelper
5
+ from adam.commands.cql_utils import keyspaces, parse_cql_desc_tables, run_cql
6
+ from adam.config import Config
7
+ from adam.pod_exec_result import PodExecResult
8
+ from adam.repl_state import ReplState, RequiredState
9
+ from adam.utils import log, log2
10
+
11
+ class DescribeKeyspace(Command):
12
+ COMMAND = 'describe keyspace'
13
+
14
+ # the singleton pattern
15
+ def __new__(cls, *args, **kwargs):
16
+ if not hasattr(cls, 'instance'): cls.instance = super(DescribeKeyspace, cls).__new__(cls)
17
+
18
+ return cls.instance
19
+
20
+ def __init__(self, successor: Command=None):
21
+ super().__init__(successor)
22
+
23
+ def required(self):
24
+ return RequiredState.CLUSTER
25
+
26
+ def command(self):
27
+ return DescribeKeyspace.COMMAND
28
+
29
+ def run(self, cmd: str, state: ReplState):
30
+ if not(args := self.args(cmd)):
31
+ return super().run(cmd, state)
32
+
33
+ state, args = self.apply_state(args, state)
34
+ if not self.validate_state(state):
35
+ return state
36
+
37
+ if not args:
38
+ if state.in_repl:
39
+ log2('Please enter keyspace name')
40
+ else:
41
+ log2('* keyspace name is missing.')
42
+ log2()
43
+ Command.display_help()
44
+
45
+ return 'missing-keyspace'
46
+
47
+ r: list[PodExecResult] = run_cql(state, f'describe keyspace {args[0]}', show_out=True, on_any=True)
48
+ if not r:
49
+ log2('No pod is available')
50
+ return 'no-pod'
51
+
52
+ # do not continue to cql route
53
+ return state
54
+
55
+ def completion(self, state: ReplState) -> dict[str, any]:
56
+ if state.sts:
57
+ state.wait_log("Inspecting Cassandra Keyspaces...")
58
+ return super().completion(state, {ks: None for ks in keyspaces(state.sts, state.namespace)})
59
+
60
+ return {}
61
+
62
+ def help(self, _: ReplState) -> str:
63
+ return f'{DescribeKeyspace.COMMAND} <keyspace-name>\t describe Cassandra keyspace'
@@ -38,7 +38,7 @@ class Login(Command):
38
38
  state, args = self.apply_state(args, state)
39
39
  args, debug = Command.extract_options(args, ['d'])
40
40
  if debug:
41
- Config().set('debug.show-out', True)
41
+ Config().set('debug', True)
42
42
 
43
43
  username: str = os.getenv('USERNAME')
44
44
  if len(args) > 0:
@@ -38,7 +38,7 @@ class SetParam(Command):
38
38
  return value
39
39
 
40
40
  def completion(self, _: ReplState):
41
- return {SetParam.COMMAND: {key: None for key in Config().keys()}}
41
+ return {SetParam.COMMAND: {key: ({'true': None, 'false': None} if Config().get(key, None) in [True, False] else None) for key in Config().keys()}}
42
42
 
43
43
  def help(self, _: ReplState):
44
44
  return f"{SetParam.COMMAND} <key> <value>\t sets a Kaqing parameter to a different value"
@@ -37,7 +37,7 @@ class Config:
37
37
  return get_deep_keys(self.params)
38
38
 
39
39
  def is_debug(self):
40
- return Config().get('debug.show-out', False)
40
+ return Config().get('debug', False)
41
41
 
42
42
  def debug(self, s: None):
43
43
  if self.is_debug():
@@ -0,0 +1,2 @@
1
+ def config():
2
+ return {'app': {'console-endpoint': 'https://{host}/{env}/{app}/static/console/index.html', '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'}, '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/{}"}, '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'}, '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,mem', 'header': 'POD_NAME,CPU,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': 'a', 'auto-enter-app': 'c3/c3', 'auto-enter-only-cluster': 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}}
@@ -12,7 +12,7 @@ class CassandraNodes:
12
12
  try:
13
13
  user, pw = Secrets.get_user_pass(pod_name, ns)
14
14
  command = f'echo "SELECT host_id FROM system.local; exit" | cqlsh --no-color -u {user} -p {pw}'
15
- result: PodExecResult = CassandraNodes.exec(pod_name, ns, command, show_out=Config().get('debug.trace', False))
15
+ result: PodExecResult = CassandraNodes.exec(pod_name, ns, command, show_out=Config().is_debug())
16
16
  next = False
17
17
  for line in result.stdout.splitlines():
18
18
  if next:
@@ -105,4 +105,4 @@ class KubeContext:
105
105
  return s or Config().is_debug()
106
106
 
107
107
  def show_parallelism():
108
- return Config().get('debug.show-parallelism', False)
108
+ return Config().get('debugs.show-parallelism', False)
@@ -18,7 +18,7 @@ from adam.log import Log
18
18
  from adam.repl_commands import ReplCommands
19
19
  from adam.repl_session import ReplSession
20
20
  from adam.repl_state import ReplState
21
- from adam.utils import deep_merge_dicts, lines_to_tabular, log2
21
+ from adam.utils import deep_merge_dicts, deep_sort_dict, lines_to_tabular, log2
22
22
  from adam.apps import Apps
23
23
  from . import __version__
24
24
 
@@ -102,9 +102,9 @@ def enter_repl(state: ReplState):
102
102
  for cmd in sorted_cmds:
103
103
  s1 = time.time()
104
104
  try:
105
- completions = deep_merge_dicts(completions, cmd.completion(state))
105
+ completions = deep_sort_dict(deep_merge_dicts(completions, cmd.completion(state)))
106
106
  finally:
107
- if Config().get('debug.timings', False):
107
+ if Config().get('debugs.timings', False):
108
108
  Config().debug('Timing completion calc', cmd.command(), f'{time.time() - s1:.2f}')
109
109
 
110
110
  completer = NestedCompleter.from_nested_dict(completions)
@@ -145,14 +145,14 @@ def enter_repl(state: ReplState):
145
145
  except EOFError: # Handle Ctrl+D (EOF) for graceful exit
146
146
  break
147
147
  except Exception as e:
148
- if Config().get('debug.exit-on-error', False):
148
+ if Config().get('debugs.exit-on-error', False):
149
149
  raise e
150
150
  else:
151
151
  log2(e)
152
152
  Config().debug(traceback.format_exc())
153
153
  finally:
154
154
  state.clear_wait_log_flag()
155
- if Config().get('debug.timings', False) and 'cmd' in locals() and 's0' in locals():
155
+ if Config().get('debugs.timings', False) and 'cmd' in locals() and 's0' in locals():
156
156
  print('Timing command', cmd, f'{time.time() - s0:.2f}')
157
157
 
158
158
  @cli.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), cls=ClusterCommandHelper, help="Enter interactive shell.")
@@ -11,6 +11,7 @@ from adam.commands.deploy.undeploy import Undeploy
11
11
  from adam.commands.deploy.undeploy_frontend import UndeployFrontend
12
12
  from adam.commands.deploy.undeploy_pg_agent import UndeployPgAgent
13
13
  from adam.commands.deploy.undeploy_pod import UndeployPod
14
+ from adam.commands.describe_keyspace import DescribeKeyspace
14
15
  from adam.commands.shell import Shell
15
16
  from adam.commands.show.show_app_queues import ShowAppQueues
16
17
  from adam.commands.cp import ClipboardCopy
@@ -75,7 +76,7 @@ class ReplCommands:
75
76
  GetParam(), SetParam(), ShowParams(), ShowKubectlCommands(), ShowLogin(), ShowAdam()]
76
77
 
77
78
  def cassandra_check() -> list[Command]:
78
- return [ShowCassandraStatus(), ShowCassandraVersion(), ShowRepairs(), ShowStorage(), ShowProcesses(), Check(), Issues(), NodeTool(), Report()]
79
+ return [DescribeKeyspace(), ShowCassandraStatus(), ShowCassandraVersion(), ShowRepairs(), ShowStorage(), ShowProcesses(), Check(), Issues(), NodeTool(), Report()]
79
80
 
80
81
  def cassandra_ops() -> list[Command]:
81
82
  # return Medusa.cmd_list() + [Restart(), RollOut(), Watch()] + Reaper.cmd_list() + Repair.cmd_list()
@@ -125,6 +125,19 @@ def deep_merge_dicts(dict1, dict2):
125
125
  merged_dict[key] = value
126
126
  return merged_dict
127
127
 
128
+ def deep_sort_dict(d):
129
+ """
130
+ Recursively sorts a dictionary by its keys, and any nested lists by their elements.
131
+ """
132
+ if not isinstance(d, (dict, list)):
133
+ return d
134
+
135
+ if isinstance(d, dict):
136
+ return {k: deep_sort_dict(d[k]) for k in sorted(d)}
137
+
138
+ if isinstance(d, list):
139
+ return sorted([deep_sort_dict(item) for item in d])
140
+
128
141
  def get_deep_keys(d, current_path=""):
129
142
  """
130
143
  Recursively collects all combined keys (paths) from a deep dictionary.
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ __version__ = "2.0.30" #: the working version
5
+ __release__ = "1.0.0" #: the release version
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: kaqing
3
- Version: 2.0.28
3
+ Version: 2.0.30
4
4
  Summary: UNKNOWN
5
5
  Home-page: UNKNOWN
6
6
  License: UNKNOWN
@@ -62,6 +62,7 @@ adam/commands/commands_utils.py
62
62
  adam/commands/cp.py
63
63
  adam/commands/cql_utils.py
64
64
  adam/commands/cqlsh.py
65
+ adam/commands/describe_keyspace.py
65
66
  adam/commands/devices.py
66
67
  adam/commands/exit.py
67
68
  adam/commands/help.py
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name='kaqing',
5
- version='2.0.28',
5
+ version='2.0.30',
6
6
  packages=find_packages(),
7
7
  entry_points={
8
8
  'console_scripts': [
@@ -1,2 +0,0 @@
1
- def config():
2
- return {'app': {'console-endpoint': 'https://{host}/{env}/{app}/static/console/index.html', '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'}, '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,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/{}"}, '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'}, '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,mem', 'header': 'POD_NAME,CPU,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': 'a', 'auto-enter-app': 'c3/c3', 'auto-enter-only-cluster': 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': {'timings': False, 'exit-on-error': False, 'show-parallelism': False, 'show-out': False}}
@@ -1,5 +0,0 @@
1
- #!/usr/bin/env python
2
- # -*- coding: utf-8 -*-
3
-
4
- __version__ = "2.0.28" #: the working version
5
- __release__ = "1.0.0" #: the release version
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes