cancan-microstack 0.0.1__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.
Files changed (440) hide show
  1. cancan_microstack/__init__.py +14 -0
  2. cancan_microstack/__version__.py +10 -0
  3. cancan_microstack/assets/__init__.py +6 -0
  4. cancan_microstack/assets/builds/caddy/Caddyfile +187 -0
  5. cancan_microstack/assets/builds/caddy/DEPLOYMENT.md +303 -0
  6. cancan_microstack/assets/builds/caddy/Dockerfile +46 -0
  7. cancan_microstack/assets/builds/caddy/README.md +343 -0
  8. cancan_microstack/assets/builds/caddy/geoip/README.md +5 -0
  9. cancan_microstack/assets/builds/caddy/start.sh +78 -0
  10. cancan_microstack/assets/builds/caddy/waf/coraza.conf +179 -0
  11. cancan_microstack/assets/builds/service/Dockerfile +59 -0
  12. cancan_microstack/assets/builds/service/README.md +13 -0
  13. cancan_microstack/assets/ddl/create_db.sql +22 -0
  14. cancan_microstack/assets/ddl/infra/execution_log_tbl.sql +46 -0
  15. cancan_microstack/assets/ddl/infra/node_instance_tbl.sql +56 -0
  16. cancan_microstack/assets/ddl/infra/service_action_log_tbl.sql +36 -0
  17. cancan_microstack/assets/ddl/infra/service_config_tbl.sql +26 -0
  18. cancan_microstack/assets/ddl/infra/service_info_tbl.sql +45 -0
  19. cancan_microstack/assets/ddl/infra/service_instance_tbl.sql +54 -0
  20. cancan_microstack/assets/ddl/infra/service_operation_tbl.sql +47 -0
  21. cancan_microstack/assets/ddl/infra/workflow_definition_tbl.sql +60 -0
  22. cancan_microstack/assets/ddl/infra/workflow_definition_version_tbl.sql +35 -0
  23. cancan_microstack/assets/ddl/infra/workflow_engine_alert_tbl.sql +34 -0
  24. cancan_microstack/assets/ddl/infra/workflow_run_tbl.sql +52 -0
  25. cancan_microstack/assets/ddl/ops/admin_user_tbl.sql +34 -0
  26. cancan_microstack/assets/ddl/ops/caddy_access_log_tbl.sql +91 -0
  27. cancan_microstack/assets/ddl/ops/caddy_certificate_tbl.sql +59 -0
  28. cancan_microstack/assets/ddl/ops/caddy_rate_limit_tbl.sql +64 -0
  29. cancan_microstack/assets/ddl/ops/caddy_route_tbl.sql +63 -0
  30. cancan_microstack/assets/ddl/ops/caddy_stats_tbl.sql +77 -0
  31. cancan_microstack/assets/ddl/trigger.sql +21 -0
  32. cancan_microstack/assets/docker/docker-compose.infra.yml +401 -0
  33. cancan_microstack/assets/scripts/README.md +195 -0
  34. cancan_microstack/assets/scripts/docker/build_images.sh +44 -0
  35. cancan_microstack/assets/scripts/docker/force_rebuild_images.sh +38 -0
  36. cancan_microstack/assets/scripts/docker/rebuild_all.sh +34 -0
  37. cancan_microstack/assets/scripts/docker/rebuild_compose.sh +61 -0
  38. cancan_microstack/assets/scripts/docker/restart.sh +35 -0
  39. cancan_microstack/assets/scripts/docker/restart_compose.sh +35 -0
  40. cancan_microstack/assets/scripts/docker/start.sh +78 -0
  41. cancan_microstack/assets/scripts/docker/start_all.sh +46 -0
  42. cancan_microstack/assets/scripts/docker/start_compose.sh +66 -0
  43. cancan_microstack/assets/scripts/docker/stop.sh +67 -0
  44. cancan_microstack/assets/scripts/docker/stop_all.sh +38 -0
  45. cancan_microstack/assets/scripts/docker/stop_compose.sh +38 -0
  46. cancan_microstack/assets/scripts/podman/build_images_podman.sh +59 -0
  47. cancan_microstack/assets/scripts/podman/cleanup_podman.sh +25 -0
  48. cancan_microstack/assets/scripts/podman/force_rebuild_images_podman.sh +56 -0
  49. cancan_microstack/assets/scripts/podman/rebuild_all_podman.sh +37 -0
  50. cancan_microstack/assets/scripts/podman/rebuild_compose_podman.sh +60 -0
  51. cancan_microstack/assets/scripts/podman/restart_compose_podman.sh +73 -0
  52. cancan_microstack/assets/scripts/podman/start_all_podman.sh +66 -0
  53. cancan_microstack/assets/scripts/podman/start_compose_podman.sh +80 -0
  54. cancan_microstack/assets/scripts/podman/start_podman.sh +91 -0
  55. cancan_microstack/assets/scripts/podman/stop.sh +73 -0
  56. cancan_microstack/assets/scripts/podman/stop_all_podman.sh +34 -0
  57. cancan_microstack/assets/scripts/podman/stop_compose_podman.sh +58 -0
  58. cancan_microstack/assets/scripts/start_controllersrv.sh +9 -0
  59. cancan_microstack/assets/scripts/utils/check_all_db_tables.sh +104 -0
  60. cancan_microstack/assets/scripts/utils/check_env.sh +177 -0
  61. cancan_microstack/assets/scripts/utils/check_service_management_deployment.sh +225 -0
  62. cancan_microstack/assets/scripts/utils/deploy_service_management.sh +176 -0
  63. cancan_microstack/assets/scripts/utils/force_reload_infrasrv.sh +52 -0
  64. cancan_microstack/assets/scripts/utils/monitor_service_management.sh +187 -0
  65. cancan_microstack/assets/scripts/utils/reset_postgres_volume.sh +68 -0
  66. cancan_microstack/assets/scripts/utils/test_async_operations.sh +141 -0
  67. cancan_microstack/assets/scripts/utils/verify_real_operations.sh +76 -0
  68. cancan_microstack/assets/service/Dockerfile +65 -0
  69. cancan_microstack/assets/www/adminops/assets/AppEmpty.vue_vue_type_script_setup_true_lang-BOKUurnM.js +1 -0
  70. cancan_microstack/assets/www/adminops/assets/ConfigManage-DKV5YOUz.js +1 -0
  71. cancan_microstack/assets/www/adminops/assets/ConfigManage-Y5bhy7wG.css +1 -0
  72. cancan_microstack/assets/www/adminops/assets/ConsoleManage-8ljYvCW2.js +1 -0
  73. cancan_microstack/assets/www/adminops/assets/ConsoleManage-BWpyqbuQ.css +1 -0
  74. cancan_microstack/assets/www/adminops/assets/DashboardNew-B9Nf1OPl.js +1 -0
  75. cancan_microstack/assets/www/adminops/assets/DashboardNew-DYWZKQ1V.css +1 -0
  76. cancan_microstack/assets/www/adminops/assets/LogSearch-CA0Jhe78.js +1 -0
  77. cancan_microstack/assets/www/adminops/assets/LogSearch-CCZfTNPF.css +1 -0
  78. cancan_microstack/assets/www/adminops/assets/LoginView-BId3kP3M.css +1 -0
  79. cancan_microstack/assets/www/adminops/assets/LoginView-BQZTV_Qy.js +1 -0
  80. cancan_microstack/assets/www/adminops/assets/OperationProgressDialog-BdEYwqFq.js +1 -0
  81. cancan_microstack/assets/www/adminops/assets/OperationProgressDialog-D-pASR8G.css +1 -0
  82. cancan_microstack/assets/www/adminops/assets/PageContainer-Byss-yUC.js +1 -0
  83. cancan_microstack/assets/www/adminops/assets/PageContainer-C3nSZwM7.css +1 -0
  84. cancan_microstack/assets/www/adminops/assets/RateLimitManage-BDI8jLpC.css +1 -0
  85. cancan_microstack/assets/www/adminops/assets/RateLimitManage-DJY4NiF-.js +1 -0
  86. cancan_microstack/assets/www/adminops/assets/RouteManage-DaUQ4QLw.css +1 -0
  87. cancan_microstack/assets/www/adminops/assets/RouteManage-w9XCU0UA.js +1 -0
  88. cancan_microstack/assets/www/adminops/assets/ServiceCard-BFzHe6Tw.css +1 -0
  89. cancan_microstack/assets/www/adminops/assets/ServiceCard-BJUhWnA-.js +1 -0
  90. cancan_microstack/assets/www/adminops/assets/ServiceDetail-Cw24WuKp.js +1 -0
  91. cancan_microstack/assets/www/adminops/assets/ServiceDetail-Yum47zdB.css +1 -0
  92. cancan_microstack/assets/www/adminops/assets/ServiceList-C7ryvbhE.js +1 -0
  93. cancan_microstack/assets/www/adminops/assets/ServiceList-Cgd01fUx.css +1 -0
  94. cancan_microstack/assets/www/adminops/assets/ServiceLogs-COpG9H0h.js +1 -0
  95. cancan_microstack/assets/www/adminops/assets/ServiceLogs-H_Alq0cf.css +1 -0
  96. cancan_microstack/assets/www/adminops/assets/StatsOverview-D0TwMQkA.js +39 -0
  97. cancan_microstack/assets/www/adminops/assets/StatsOverview-lqAN6pqM.css +1 -0
  98. cancan_microstack/assets/www/adminops/assets/TotpBindView-CWlAmzFt.js +1 -0
  99. cancan_microstack/assets/www/adminops/assets/TotpBindView-HoQC1lhx.css +1 -0
  100. cancan_microstack/assets/www/adminops/assets/TotpVerifyView-BHN1VtX1.css +1 -0
  101. cancan_microstack/assets/www/adminops/assets/TotpVerifyView-D3w_lZk8.js +1 -0
  102. cancan_microstack/assets/www/adminops/assets/WorkflowCenter-DU_mpIA0.css +1 -0
  103. cancan_microstack/assets/www/adminops/assets/WorkflowCenter-i50rZyxN.js +1 -0
  104. cancan_microstack/assets/www/adminops/assets/WorkflowDesigner-CnHokPL9.js +1 -0
  105. cancan_microstack/assets/www/adminops/assets/WorkflowDesigner-DaZaZpLd.css +1 -0
  106. cancan_microstack/assets/www/adminops/assets/WorkflowRuns-B09hK48c.js +1 -0
  107. cancan_microstack/assets/www/adminops/assets/WorkflowRuns-wGutKIIU.css +1 -0
  108. cancan_microstack/assets/www/adminops/assets/caddy-nnCKf8fG.js +1 -0
  109. cancan_microstack/assets/www/adminops/assets/format-Cuzxgna9.js +1 -0
  110. cancan_microstack/assets/www/adminops/assets/index-CiFlm8oc.js +64 -0
  111. cancan_microstack/assets/www/adminops/assets/index-UW0T1Dkc.css +1 -0
  112. cancan_microstack/assets/www/adminops/assets/service-BYlgGPs_.js +1 -0
  113. cancan_microstack/assets/www/adminops/assets/service-operation-6GzLw2Z1.js +1 -0
  114. cancan_microstack/assets/www/adminops/assets/style-CcIXnQ5y.css +1 -0
  115. cancan_microstack/assets/www/adminops/assets/style-lRnStdGu.js +39 -0
  116. cancan_microstack/assets/www/adminops/assets/useDebounce-BRlqfXqf.js +1 -0
  117. cancan_microstack/assets/www/adminops/assets/workflow-CUXs39Ac.js +1 -0
  118. cancan_microstack/assets/www/adminops/index.html +16 -0
  119. cancan_microstack/assets/www/adminops/vite.svg +1 -0
  120. cancan_microstack/cli/__init__.py +14 -0
  121. cancan_microstack/cli/__main__.py +9 -0
  122. cancan_microstack/cli/main.py +552 -0
  123. cancan_microstack/cmd/__init__.py +54 -0
  124. cancan_microstack/cmd/cancan/__init__.py +12 -0
  125. cancan_microstack/cmd/cancan/run.py +395 -0
  126. cancan_microstack/cmd/controllersrv/__init__.py +0 -0
  127. cancan_microstack/cmd/controllersrv/run.py +131 -0
  128. cancan_microstack/cmd/infrasrv/__init__.py +5 -0
  129. cancan_microstack/cmd/infrasrv/run.py +100 -0
  130. cancan_microstack/cmd/opsbffsrv/__init__.py +5 -0
  131. cancan_microstack/cmd/opsbffsrv/run.py +96 -0
  132. cancan_microstack/core/__init__.py +5 -0
  133. cancan_microstack/core/assets.py +123 -0
  134. cancan_microstack/core/compose_builder.py +102 -0
  135. cancan_microstack/core/doctor.py +152 -0
  136. cancan_microstack/core/microstack.py +71 -0
  137. cancan_microstack/core/runner.py +56 -0
  138. cancan_microstack/core/stack_manager.py +186 -0
  139. cancan_microstack/public/__init__.py +7 -0
  140. cancan_microstack/public/api/__init__.py +1 -0
  141. cancan_microstack/public/api/controllersrv_client.py +277 -0
  142. cancan_microstack/public/api/infrasrv_client.py +404 -0
  143. cancan_microstack/public/const/__init__.py +1 -0
  144. cancan_microstack/public/const/action_consts.py +18 -0
  145. cancan_microstack/public/const/app_consts.py +42 -0
  146. cancan_microstack/public/const/caddy_consts.py +22 -0
  147. cancan_microstack/public/const/controllersrv_consts.py +163 -0
  148. cancan_microstack/public/const/docker_consts.py +15 -0
  149. cancan_microstack/public/const/error.py +56 -0
  150. cancan_microstack/public/const/health_consts.py +52 -0
  151. cancan_microstack/public/const/hook_enums.py +56 -0
  152. cancan_microstack/public/const/logging_enums.py +13 -0
  153. cancan_microstack/public/const/metrics_enums.py +36 -0
  154. cancan_microstack/public/const/monitor_enums.py +26 -0
  155. cancan_microstack/public/const/operation_consts.py +53 -0
  156. cancan_microstack/public/const/opsbffsrv_error.py +92 -0
  157. cancan_microstack/public/const/overrides_consts.py +13 -0
  158. cancan_microstack/public/const/redis.py +17 -0
  159. cancan_microstack/public/const/service_consts.py +15 -0
  160. cancan_microstack/public/const/workflow_consts.py +65 -0
  161. cancan_microstack/public/error.py +41 -0
  162. cancan_microstack/public/logging/__init__.py +0 -0
  163. cancan_microstack/public/logging/initializer.py +109 -0
  164. cancan_microstack/public/logging/mq_handler.py +279 -0
  165. cancan_microstack/public/schemas/__init__.py +1 -0
  166. cancan_microstack/public/schemas/caddy/__init__.py +381 -0
  167. cancan_microstack/public/schemas/caddy/analysis.py +90 -0
  168. cancan_microstack/public/schemas/caddy/route.py +18 -0
  169. cancan_microstack/public/schemas/common.py +79 -0
  170. cancan_microstack/public/schemas/controllersrv/__init__.py +3 -0
  171. cancan_microstack/public/schemas/controllersrv/async_requests.py +30 -0
  172. cancan_microstack/public/schemas/controllersrv/compose_models.py +47 -0
  173. cancan_microstack/public/schemas/controllersrv/const.py +24 -0
  174. cancan_microstack/public/schemas/controllersrv/docker_models.py +45 -0
  175. cancan_microstack/public/schemas/controllersrv/docker_responses.py +104 -0
  176. cancan_microstack/public/schemas/controllersrv/requests.py +54 -0
  177. cancan_microstack/public/schemas/controllersrv/responses.py +124 -0
  178. cancan_microstack/public/schemas/controllersrv/task_models.py +102 -0
  179. cancan_microstack/public/schemas/controllersrv/validation.py +23 -0
  180. cancan_microstack/public/schemas/hook_metrics.py +124 -0
  181. cancan_microstack/public/schemas/hooks.py +39 -0
  182. cancan_microstack/public/schemas/infra/__init__.py +0 -0
  183. cancan_microstack/public/schemas/infra/cleanup.py +25 -0
  184. cancan_microstack/public/schemas/infra/container.py +74 -0
  185. cancan_microstack/public/schemas/infra/enums.py +135 -0
  186. cancan_microstack/public/schemas/infra/health_check.py +42 -0
  187. cancan_microstack/public/schemas/infra/hook_log.py +42 -0
  188. cancan_microstack/public/schemas/infra/operation.py +90 -0
  189. cancan_microstack/public/schemas/infra/overview.py +25 -0
  190. cancan_microstack/public/schemas/infra/push.py +33 -0
  191. cancan_microstack/public/schemas/infra/service_action_log.py +47 -0
  192. cancan_microstack/public/schemas/infra/service_config.py +10 -0
  193. cancan_microstack/public/schemas/infra/service_info.py +69 -0
  194. cancan_microstack/public/schemas/infra/service_instance.py +93 -0
  195. cancan_microstack/public/schemas/infra/service_management.py +152 -0
  196. cancan_microstack/public/schemas/infra/service_operation.py +79 -0
  197. cancan_microstack/public/schemas/infra/service_registry.py +158 -0
  198. cancan_microstack/public/schemas/infra/status_types.py +19 -0
  199. cancan_microstack/public/schemas/infra/workflow.py +566 -0
  200. cancan_microstack/public/schemas/logging/__init__.py +1 -0
  201. cancan_microstack/public/schemas/logging/log_event.py +121 -0
  202. cancan_microstack/public/schemas/opsbffsrv/__init__.py +1 -0
  203. cancan_microstack/public/schemas/opsbffsrv/async_ops.py +17 -0
  204. cancan_microstack/public/schemas/opsbffsrv/db_admin.py +147 -0
  205. cancan_microstack/public/schemas/opsbffsrv/db_init.py +48 -0
  206. cancan_microstack/public/schemas/opsbffsrv/service_config.py +89 -0
  207. cancan_microstack/public/schemas/opsbffsrv/service_logs.py +54 -0
  208. cancan_microstack/public/schemas/service_operation.py +24 -0
  209. cancan_microstack/public/schemas/service_registry.py +40 -0
  210. cancan_microstack/public/types/__init__.py +7 -0
  211. cancan_microstack/public/web/__init__.py +0 -0
  212. cancan_microstack/public/web/config_value.py +105 -0
  213. cancan_microstack/public/web/server.py +385 -0
  214. cancan_microstack/py.typed +0 -0
  215. cancan_microstack/runtime/__init__.py +0 -0
  216. cancan_microstack/runtime/compose_cmd.py +228 -0
  217. cancan_microstack/runtime/host_daemon.py +318 -0
  218. cancan_microstack/runtime/overrides.py +103 -0
  219. cancan_microstack/runtime/resources.py +25 -0
  220. cancan_microstack/runtime/workspace.py +94 -0
  221. cancan_microstack/services/__init__.py +0 -0
  222. cancan_microstack/services/controllersrv/__init__.py +8 -0
  223. cancan_microstack/services/controllersrv/application/__init__.py +0 -0
  224. cancan_microstack/services/controllersrv/application/docker_compose_app.py +427 -0
  225. cancan_microstack/services/controllersrv/conf/__init__.py +0 -0
  226. cancan_microstack/services/controllersrv/conf/config.py +76 -0
  227. cancan_microstack/services/controllersrv/conf/settings.py +54 -0
  228. cancan_microstack/services/controllersrv/domain/__init__.py +0 -0
  229. cancan_microstack/services/controllersrv/domain/docker_compose/__init__.py +0 -0
  230. cancan_microstack/services/controllersrv/domain/docker_compose/docker_compose_domain.py +278 -0
  231. cancan_microstack/services/controllersrv/domain/service_validator.py +327 -0
  232. cancan_microstack/services/controllersrv/domain/task/__init__.py +17 -0
  233. cancan_microstack/services/controllersrv/domain/task/task_queue.py +286 -0
  234. cancan_microstack/services/controllersrv/domain/task/task_worker.py +495 -0
  235. cancan_microstack/services/controllersrv/infrastructure/__init__.py +0 -0
  236. cancan_microstack/services/controllersrv/interface/__init__.py +0 -0
  237. cancan_microstack/services/controllersrv/interface/api/__init__.py +0 -0
  238. cancan_microstack/services/controllersrv/interface/api/docker_control_api.py +470 -0
  239. cancan_microstack/services/controllersrv/router.py +132 -0
  240. cancan_microstack/services/infrasrv/__init__.py +4 -0
  241. cancan_microstack/services/infrasrv/application/__init__.py +0 -0
  242. cancan_microstack/services/infrasrv/application/health_check_app.py +24 -0
  243. cancan_microstack/services/infrasrv/application/logging/__init__.py +1 -0
  244. cancan_microstack/services/infrasrv/application/logging/log_ingestion_service.py +183 -0
  245. cancan_microstack/services/infrasrv/application/service_config.py +22 -0
  246. cancan_microstack/services/infrasrv/application/service_logs_app.py +53 -0
  247. cancan_microstack/services/infrasrv/application/service_management_app.py +689 -0
  248. cancan_microstack/services/infrasrv/application/service_operation_tracker.py +251 -0
  249. cancan_microstack/services/infrasrv/application/service_registry.py +53 -0
  250. cancan_microstack/services/infrasrv/application/workflow/__init__.py +0 -0
  251. cancan_microstack/services/infrasrv/application/workflow/workflow_app.py +991 -0
  252. cancan_microstack/services/infrasrv/application/workflow/workflow_queue.py +302 -0
  253. cancan_microstack/services/infrasrv/application/workflow/workflow_tasks.py +46 -0
  254. cancan_microstack/services/infrasrv/application/workflow/workflow_worker_runtime.py +122 -0
  255. cancan_microstack/services/infrasrv/conf/__init__.py +0 -0
  256. cancan_microstack/services/infrasrv/conf/config.py +98 -0
  257. cancan_microstack/services/infrasrv/domain/__init__.py +0 -0
  258. cancan_microstack/services/infrasrv/domain/health_check/__init__.py +3 -0
  259. cancan_microstack/services/infrasrv/domain/health_check/health_check_domain.py +576 -0
  260. cancan_microstack/services/infrasrv/domain/hooks/__init__.py +19 -0
  261. cancan_microstack/services/infrasrv/domain/hooks/builtin_hooks.py +308 -0
  262. cancan_microstack/services/infrasrv/domain/hooks/hook_registry.py +43 -0
  263. cancan_microstack/services/infrasrv/domain/hooks/hooks_log_utils.py +275 -0
  264. cancan_microstack/services/infrasrv/domain/hooks/init.py +17 -0
  265. cancan_microstack/services/infrasrv/domain/hooks/metrics.py +205 -0
  266. cancan_microstack/services/infrasrv/domain/hooks/pre_registration_hooks.py +490 -0
  267. cancan_microstack/services/infrasrv/domain/registry/__init__.py +0 -0
  268. cancan_microstack/services/infrasrv/domain/registry/service_registry.py +509 -0
  269. cancan_microstack/services/infrasrv/domain/service_config/__init__.py +0 -0
  270. cancan_microstack/services/infrasrv/domain/service_config/service_config.py +50 -0
  271. cancan_microstack/services/infrasrv/domain/service_logs/__init__.py +0 -0
  272. cancan_microstack/services/infrasrv/domain/service_logs/service_logs_domain.py +51 -0
  273. cancan_microstack/services/infrasrv/domain/workflow/__init__.py +4 -0
  274. cancan_microstack/services/infrasrv/domain/workflow/engine.py +159 -0
  275. cancan_microstack/services/infrasrv/domain/workflow/node_handlers.py +509 -0
  276. cancan_microstack/services/infrasrv/domain/workflow/workflow_domain.py +164 -0
  277. cancan_microstack/services/infrasrv/infrastructure/__init__.py +0 -0
  278. cancan_microstack/services/infrasrv/infrastructure/api/__init__.py +0 -0
  279. cancan_microstack/services/infrasrv/infrastructure/api/controllersrv_api.py +165 -0
  280. cancan_microstack/services/infrasrv/infrastructure/cache/__init__.py +0 -0
  281. cancan_microstack/services/infrasrv/infrastructure/cache/service_registry_cache.py +174 -0
  282. cancan_microstack/services/infrasrv/infrastructure/db/__init__.py +0 -0
  283. cancan_microstack/services/infrasrv/infrastructure/db/model/__init__.py +0 -0
  284. cancan_microstack/services/infrasrv/infrastructure/db/model/execution_log_tbl.py +53 -0
  285. cancan_microstack/services/infrasrv/infrastructure/db/model/node_instance_tbl.py +55 -0
  286. cancan_microstack/services/infrasrv/infrastructure/db/model/service_action_log_tbl.py +44 -0
  287. cancan_microstack/services/infrasrv/infrastructure/db/model/service_config_tbl.py +30 -0
  288. cancan_microstack/services/infrasrv/infrastructure/db/model/service_info_tbl.py +59 -0
  289. cancan_microstack/services/infrasrv/infrastructure/db/model/service_instance_tbl.py +88 -0
  290. cancan_microstack/services/infrasrv/infrastructure/db/model/service_operation_tbl.py +73 -0
  291. cancan_microstack/services/infrasrv/infrastructure/db/model/workflow_definition_tbl.py +55 -0
  292. cancan_microstack/services/infrasrv/infrastructure/db/model/workflow_definition_version_tbl.py +43 -0
  293. cancan_microstack/services/infrasrv/infrastructure/db/model/workflow_engine_alert_tbl.py +57 -0
  294. cancan_microstack/services/infrasrv/infrastructure/db/model/workflow_run_tbl.py +56 -0
  295. cancan_microstack/services/infrasrv/infrastructure/db/operate/__init__.py +0 -0
  296. cancan_microstack/services/infrasrv/infrastructure/db/operate/service_action_log_op.py +239 -0
  297. cancan_microstack/services/infrasrv/infrastructure/db/operate/service_config.py +80 -0
  298. cancan_microstack/services/infrasrv/infrastructure/db/operate/service_config_manager.py +198 -0
  299. cancan_microstack/services/infrasrv/infrastructure/db/operate/service_info_op.py +297 -0
  300. cancan_microstack/services/infrasrv/infrastructure/db/operate/service_instance_op.py +688 -0
  301. cancan_microstack/services/infrasrv/infrastructure/db/operate/service_operation_op.py +387 -0
  302. cancan_microstack/services/infrasrv/infrastructure/db/operate/service_registry.py +124 -0
  303. cancan_microstack/services/infrasrv/infrastructure/db/operate/workflow_op.py +804 -0
  304. cancan_microstack/services/infrasrv/infrastructure/ddl_manager.py +31 -0
  305. cancan_microstack/services/infrasrv/infrastructure/mongo/__init__.py +1 -0
  306. cancan_microstack/services/infrasrv/infrastructure/mongo/log_repository.py +129 -0
  307. cancan_microstack/services/infrasrv/interface/__init__.py +0 -0
  308. cancan_microstack/services/infrasrv/interface/api/__init__.py +0 -0
  309. cancan_microstack/services/infrasrv/interface/api/health_check_api.py +29 -0
  310. cancan_microstack/services/infrasrv/interface/api/hooks.py +284 -0
  311. cancan_microstack/services/infrasrv/interface/api/internal.py +49 -0
  312. cancan_microstack/services/infrasrv/interface/api/internal_instance_api.py +265 -0
  313. cancan_microstack/services/infrasrv/interface/api/internal_operation_api.py +206 -0
  314. cancan_microstack/services/infrasrv/interface/api/service_config.py +50 -0
  315. cancan_microstack/services/infrasrv/interface/api/service_logs_api.py +49 -0
  316. cancan_microstack/services/infrasrv/interface/api/service_management_api.py +113 -0
  317. cancan_microstack/services/infrasrv/interface/api/service_registry.py +117 -0
  318. cancan_microstack/services/infrasrv/interface/api/workflow_api.py +303 -0
  319. cancan_microstack/services/infrasrv/interface/schedule/__init__.py +0 -0
  320. cancan_microstack/services/infrasrv/interface/schedule/cleanup.py +13 -0
  321. cancan_microstack/services/infrasrv/interface/schedule/health_check.py +27 -0
  322. cancan_microstack/services/infrasrv/interface/schedule/log_cleanup.py +26 -0
  323. cancan_microstack/services/infrasrv/interface/schedule/operation_tracker.py +25 -0
  324. cancan_microstack/services/infrasrv/interface/schedule/scheduler.py +39 -0
  325. cancan_microstack/services/infrasrv/interface/schedule/workflow_scheduler.py +115 -0
  326. cancan_microstack/services/infrasrv/router.py +341 -0
  327. cancan_microstack/services/opsbffsrv/__init__.py +4 -0
  328. cancan_microstack/services/opsbffsrv/application/__init__.py +0 -0
  329. cancan_microstack/services/opsbffsrv/application/async_operation_app.py +150 -0
  330. cancan_microstack/services/opsbffsrv/application/auth_app.py +285 -0
  331. cancan_microstack/services/opsbffsrv/application/caddy/__init__.py +0 -0
  332. cancan_microstack/services/opsbffsrv/application/caddy/access_log_analysis_app.py +344 -0
  333. cancan_microstack/services/opsbffsrv/application/caddy/access_log_ingestion_service.py +169 -0
  334. cancan_microstack/services/opsbffsrv/application/caddy/certificate_management_app.py +355 -0
  335. cancan_microstack/services/opsbffsrv/application/caddy/rate_limit_management_app.py +496 -0
  336. cancan_microstack/services/opsbffsrv/application/caddy/route_management_app.py +401 -0
  337. cancan_microstack/services/opsbffsrv/application/caddy/stats_aggregation_app.py +364 -0
  338. cancan_microstack/services/opsbffsrv/application/db_admin_app.py +103 -0
  339. cancan_microstack/services/opsbffsrv/application/db_init_app.py +283 -0
  340. cancan_microstack/services/opsbffsrv/application/logging/__init__.py +1 -0
  341. cancan_microstack/services/opsbffsrv/application/logging/log_query_app.py +28 -0
  342. cancan_microstack/services/opsbffsrv/application/service_config.py +158 -0
  343. cancan_microstack/services/opsbffsrv/application/service_logs_app.py +74 -0
  344. cancan_microstack/services/opsbffsrv/application/service_registry.py +36 -0
  345. cancan_microstack/services/opsbffsrv/application/workflow_ops_app.py +730 -0
  346. cancan_microstack/services/opsbffsrv/conf/__init__.py +0 -0
  347. cancan_microstack/services/opsbffsrv/conf/config.py +224 -0
  348. cancan_microstack/services/opsbffsrv/domain/__init__.py +0 -0
  349. cancan_microstack/services/opsbffsrv/domain/auth/__init__.py +0 -0
  350. cancan_microstack/services/opsbffsrv/domain/auth/admin_init.py +38 -0
  351. cancan_microstack/services/opsbffsrv/domain/auth/auth_domain.py +108 -0
  352. cancan_microstack/services/opsbffsrv/domain/caddy/__init__.py +0 -0
  353. cancan_microstack/services/opsbffsrv/domain/caddy/access_log_analysis.py +358 -0
  354. cancan_microstack/services/opsbffsrv/domain/caddy/certificate_management.py +325 -0
  355. cancan_microstack/services/opsbffsrv/domain/caddy/default_routes.py +53 -0
  356. cancan_microstack/services/opsbffsrv/domain/caddy/rate_limit_management.py +308 -0
  357. cancan_microstack/services/opsbffsrv/domain/caddy/route_management.py +279 -0
  358. cancan_microstack/services/opsbffsrv/domain/caddy/stats_aggregation.py +654 -0
  359. cancan_microstack/services/opsbffsrv/domain/db_admin/__init__.py +0 -0
  360. cancan_microstack/services/opsbffsrv/domain/db_admin/db_admin_domain.py +118 -0
  361. cancan_microstack/services/opsbffsrv/domain/db_init/__init__.py +3 -0
  362. cancan_microstack/services/opsbffsrv/domain/db_init/db_init_domain.py +358 -0
  363. cancan_microstack/services/opsbffsrv/domain/logging/__init__.py +1 -0
  364. cancan_microstack/services/opsbffsrv/domain/logging/log_query_domain.py +99 -0
  365. cancan_microstack/services/opsbffsrv/domain/service_config/__init__.py +0 -0
  366. cancan_microstack/services/opsbffsrv/domain/service_config/service_config.py +81 -0
  367. cancan_microstack/services/opsbffsrv/domain/service_registry/__init__.py +0 -0
  368. cancan_microstack/services/opsbffsrv/domain/service_registry/service_registry.py +292 -0
  369. cancan_microstack/services/opsbffsrv/infrastructure/__init__.py +0 -0
  370. cancan_microstack/services/opsbffsrv/infrastructure/api/__init__.py +0 -0
  371. cancan_microstack/services/opsbffsrv/infrastructure/api/infrasrv_api.py +242 -0
  372. cancan_microstack/services/opsbffsrv/infrastructure/auth/__init__.py +0 -0
  373. cancan_microstack/services/opsbffsrv/infrastructure/auth/captcha_service.py +67 -0
  374. cancan_microstack/services/opsbffsrv/infrastructure/auth/password_service.py +12 -0
  375. cancan_microstack/services/opsbffsrv/infrastructure/auth/redis_store.py +131 -0
  376. cancan_microstack/services/opsbffsrv/infrastructure/auth/totp_service.py +59 -0
  377. cancan_microstack/services/opsbffsrv/infrastructure/caddy/__init__.py +0 -0
  378. cancan_microstack/services/opsbffsrv/infrastructure/caddy/access_log_parser.py +307 -0
  379. cancan_microstack/services/opsbffsrv/infrastructure/caddy/admin_api_client.py +678 -0
  380. cancan_microstack/services/opsbffsrv/infrastructure/caddy/ip_geo_locator.py +176 -0
  381. cancan_microstack/services/opsbffsrv/infrastructure/db/__init__.py +0 -0
  382. cancan_microstack/services/opsbffsrv/infrastructure/db/model/__init__.py +0 -0
  383. cancan_microstack/services/opsbffsrv/infrastructure/db/model/admin_user_tbl.py +33 -0
  384. cancan_microstack/services/opsbffsrv/infrastructure/db/model/caddy_access_log_tbl.py +90 -0
  385. cancan_microstack/services/opsbffsrv/infrastructure/db/model/caddy_certificate_tbl.py +65 -0
  386. cancan_microstack/services/opsbffsrv/infrastructure/db/model/caddy_rate_limit_tbl.py +69 -0
  387. cancan_microstack/services/opsbffsrv/infrastructure/db/model/caddy_route_tbl.py +66 -0
  388. cancan_microstack/services/opsbffsrv/infrastructure/db/model/caddy_stats_tbl.py +78 -0
  389. cancan_microstack/services/opsbffsrv/infrastructure/db/model/service_action_log_tbl.py +44 -0
  390. cancan_microstack/services/opsbffsrv/infrastructure/db/model/service_config_tbl.py +30 -0
  391. cancan_microstack/services/opsbffsrv/infrastructure/db/model/service_info_tbl.py +51 -0
  392. cancan_microstack/services/opsbffsrv/infrastructure/db/model/service_instance_tbl.py +68 -0
  393. cancan_microstack/services/opsbffsrv/infrastructure/db/operate/__init__.py +0 -0
  394. cancan_microstack/services/opsbffsrv/infrastructure/db/operate/admin_user_operate.py +59 -0
  395. cancan_microstack/services/opsbffsrv/infrastructure/db/operate/caddy_access_log.py +531 -0
  396. cancan_microstack/services/opsbffsrv/infrastructure/db/operate/caddy_certificate.py +451 -0
  397. cancan_microstack/services/opsbffsrv/infrastructure/db/operate/caddy_rate_limit.py +360 -0
  398. cancan_microstack/services/opsbffsrv/infrastructure/db/operate/caddy_route.py +271 -0
  399. cancan_microstack/services/opsbffsrv/infrastructure/db/operate/caddy_stats.py +343 -0
  400. cancan_microstack/services/opsbffsrv/infrastructure/db/operate/service_action_log_op.py +57 -0
  401. cancan_microstack/services/opsbffsrv/infrastructure/db/operate/service_config.py +86 -0
  402. cancan_microstack/services/opsbffsrv/infrastructure/db/operate/service_info_op.py +79 -0
  403. cancan_microstack/services/opsbffsrv/infrastructure/db/operate/service_instance.py +58 -0
  404. cancan_microstack/services/opsbffsrv/infrastructure/db/operate/service_registry.py +138 -0
  405. cancan_microstack/services/opsbffsrv/infrastructure/ddl_manager.py +31 -0
  406. cancan_microstack/services/opsbffsrv/infrastructure/mongo/__init__.py +1 -0
  407. cancan_microstack/services/opsbffsrv/infrastructure/mongo/log_query_repository.py +87 -0
  408. cancan_microstack/services/opsbffsrv/interface/__init__.py +0 -0
  409. cancan_microstack/services/opsbffsrv/interface/api/__init__.py +0 -0
  410. cancan_microstack/services/opsbffsrv/interface/api/async_operation_api.py +137 -0
  411. cancan_microstack/services/opsbffsrv/interface/api/auth_api.py +113 -0
  412. cancan_microstack/services/opsbffsrv/interface/api/caddy/__init__.py +3 -0
  413. cancan_microstack/services/opsbffsrv/interface/api/caddy/access_log_api.py +174 -0
  414. cancan_microstack/services/opsbffsrv/interface/api/caddy/certificate_api.py +235 -0
  415. cancan_microstack/services/opsbffsrv/interface/api/caddy/rate_limit_api.py +302 -0
  416. cancan_microstack/services/opsbffsrv/interface/api/caddy/route_api.py +250 -0
  417. cancan_microstack/services/opsbffsrv/interface/api/caddy/stats_api.py +243 -0
  418. cancan_microstack/services/opsbffsrv/interface/api/db_admin_api.py +62 -0
  419. cancan_microstack/services/opsbffsrv/interface/api/db_init_api.py +109 -0
  420. cancan_microstack/services/opsbffsrv/interface/api/instance_management_api.py +165 -0
  421. cancan_microstack/services/opsbffsrv/interface/api/log_query_api.py +41 -0
  422. cancan_microstack/services/opsbffsrv/interface/api/mongo_express_proxy_api.py +181 -0
  423. cancan_microstack/services/opsbffsrv/interface/api/pgweb_proxy_api.py +154 -0
  424. cancan_microstack/services/opsbffsrv/interface/api/rabbitmq_mgmt_proxy_api.py +518 -0
  425. cancan_microstack/services/opsbffsrv/interface/api/redis_commander_proxy_api.py +133 -0
  426. cancan_microstack/services/opsbffsrv/interface/api/service_config.py +146 -0
  427. cancan_microstack/services/opsbffsrv/interface/api/service_logs_api.py +81 -0
  428. cancan_microstack/services/opsbffsrv/interface/api/service_registry.py +66 -0
  429. cancan_microstack/services/opsbffsrv/interface/api/workflow_ops_api.py +413 -0
  430. cancan_microstack/services/opsbffsrv/interface/middleware/__init__.py +0 -0
  431. cancan_microstack/services/opsbffsrv/interface/middleware/auth_middleware.py +52 -0
  432. cancan_microstack/services/opsbffsrv/router.py +901 -0
  433. cancan_microstack/utils/__init__.py +1 -0
  434. cancan_microstack/utils/container_env.py +218 -0
  435. cancan_microstack-0.0.1.dist-info/METADATA +155 -0
  436. cancan_microstack-0.0.1.dist-info/RECORD +440 -0
  437. cancan_microstack-0.0.1.dist-info/WHEEL +5 -0
  438. cancan_microstack-0.0.1.dist-info/entry_points.txt +2 -0
  439. cancan_microstack-0.0.1.dist-info/licenses/LICENSE +21 -0
  440. cancan_microstack-0.0.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,165 @@
1
+ """
2
+ 实例管理 API(Phase 4)
3
+
4
+ 为前端提供实例管理接口:
5
+ 1. 查询服务的所有实例
6
+ 2. 查询单个实例详情
7
+ 3. 查询实例统计信息
8
+ """
9
+ from typing import Optional
10
+ import http
11
+
12
+ from linglong_web.utils import logger
13
+ from cancan_microstack.public.schemas.common import APIResponse
14
+ from linglong_web import build_success_response
15
+ from linglong_web import (
16
+ HTTPClientConfig,
17
+ http_client,
18
+ )
19
+ from linglong_web import LinglongConfig
20
+ from cancan_microstack.public.error import HTTPException
21
+ from cancan_microstack.public.const.error import ErrorCode
22
+
23
+
24
+ async def list_service_instances_handler(
25
+ service_name: Optional[str] = None,
26
+ status: Optional[str] = None,
27
+ ) -> APIResponse[dict | None]:
28
+ """
29
+ 列出服务实例
30
+
31
+ Args:
32
+ service_name: 服务名称过滤(可选)
33
+ status: 状态过滤(可选,如 running, stopped, starting)
34
+
35
+ Returns:
36
+ 实例列表
37
+ """
38
+ logger.debug(f"List instances: service={service_name}, status={status}")
39
+
40
+ # 调用 infrasrv 内部实例列表 API
41
+ url = f"{LinglongConfig.INFRASRV_HOST}/v1/infrasrv/internal/instance/list"
42
+
43
+ params = {}
44
+ if service_name:
45
+ params["service_name"] = service_name
46
+ if status:
47
+ params["status"] = status
48
+
49
+ resp = await http_client.get(
50
+ url,
51
+ params=params,
52
+ timeout=HTTPClientConfig.INTERNAL_SERVICE_TIMEOUT
53
+ )
54
+
55
+ if resp and resp.status == 200:
56
+ data = await resp.json()
57
+ return build_success_response(data=data.get("data"))
58
+
59
+ error_msg = f"Failed to list instances: HTTP {resp.status if resp else 'None'}"
60
+ logger.error(error_msg)
61
+ raise HTTPException(
62
+ status_code=http.HTTPStatus.INTERNAL_SERVER_ERROR.value,
63
+ error_code=ErrorCode.SYSTEM_ERROR,
64
+ msg=error_msg
65
+ )
66
+
67
+
68
+ async def get_instance_detail_handler(instance_id: str) -> APIResponse[dict | None]:
69
+ """
70
+ 获取实例详情
71
+
72
+ Args:
73
+ instance_id: 实例ID
74
+
75
+ Returns:
76
+ 实例详细信息
77
+ """
78
+ logger.debug(f"Get instance detail: {instance_id}")
79
+
80
+ # 调用 infrasrv 内部实例查询 API
81
+ url = f"{LinglongConfig.INFRASRV_HOST}/v1/infrasrv/internal/instance/get"
82
+
83
+ resp = await http_client.get(
84
+ url,
85
+ params={"instance_id": instance_id},
86
+ timeout=HTTPClientConfig.INTERNAL_SERVICE_TIMEOUT
87
+ )
88
+
89
+ if resp and resp.status == 200:
90
+ data = await resp.json()
91
+ return build_success_response(data=data.get("data"))
92
+
93
+ error_msg = f"Failed to get instance detail: HTTP {resp.status if resp else 'None'}"
94
+ logger.error(error_msg)
95
+ raise HTTPException(
96
+ status_code=http.HTTPStatus.INTERNAL_SERVER_ERROR.value,
97
+ error_code=ErrorCode.SYSTEM_ERROR,
98
+ msg=error_msg
99
+ )
100
+
101
+
102
+ async def get_service_instance_stats_handler(service_name: str) -> APIResponse[dict]:
103
+ """
104
+ 获取服务的实例统计信息
105
+
106
+ Args:
107
+ service_name: 服务名称
108
+
109
+ Returns:
110
+ 实例统计信息(总数、运行中、停止、健康状态等)
111
+ """
112
+ logger.debug(f"Get instance stats: {service_name}")
113
+
114
+ # 调用 infrasrv 内部实例列表 API 获取所有实例
115
+ url = f"{LinglongConfig.INFRASRV_HOST}/v1/infrasrv/internal/instance/list"
116
+
117
+ resp = await http_client.get(
118
+ url,
119
+ params={"service_name": service_name},
120
+ timeout=HTTPClientConfig.INTERNAL_SERVICE_TIMEOUT
121
+ )
122
+
123
+ if resp and resp.status == 200:
124
+ data = await resp.json()
125
+ instances = data.get("data", {}).get("instances", [])
126
+
127
+ # 统计信息
128
+ stats = {
129
+ "service_name": service_name,
130
+ "total": len(instances),
131
+ "by_status": {},
132
+ "by_health": {},
133
+ "instances": instances
134
+ }
135
+
136
+ # 按状态统计(支持 dict 或 Pydantic model)
137
+ for instance in instances:
138
+ if hasattr(instance, "get"):
139
+ status = instance.get("status", "unknown")
140
+ health_status = instance.get("health_status", "unknown")
141
+ else:
142
+ # 可能是 Pydantic model 或对象
143
+ status = getattr(instance, "status", "unknown")
144
+ # health_status 可能是枚举实例,要转为字符串
145
+ hs_val = getattr(instance, "health_status", None)
146
+ if hs_val is None:
147
+ health_status = "unknown"
148
+ else:
149
+ try:
150
+ health_status = hs_val.value
151
+ except Exception:
152
+ health_status = str(hs_val)
153
+
154
+ stats["by_status"][status] = stats["by_status"].get(status, 0) + 1
155
+ stats["by_health"][health_status] = stats["by_health"].get(health_status, 0) + 1
156
+
157
+ return build_success_response(data=stats)
158
+
159
+ error_msg = f"Failed to get instance stats: HTTP {resp.status if resp else 'None'}"
160
+ logger.error(error_msg)
161
+ raise HTTPException(
162
+ status_code=http.HTTPStatus.INTERNAL_SERVER_ERROR.value,
163
+ error_code=ErrorCode.SYSTEM_ERROR,
164
+ msg=error_msg
165
+ )
@@ -0,0 +1,41 @@
1
+ """业务日志查询 API / Business log search API."""
2
+ import http
3
+
4
+ from linglong_web.utils import logger
5
+ from cancan_microstack.public.const.opsbffsrv_error import OpsbffsrvServiceLogsErrorCode
6
+ from cancan_microstack.public.error import HTTPException
7
+ from cancan_microstack.public.schemas.common import APIResponse
8
+ from cancan_microstack.public.schemas.logging.log_event import (
9
+ LogQueryRequest,
10
+ LogQueryResponse,
11
+ )
12
+ from linglong_web import build_success_response
13
+
14
+ from cancan_microstack.services.opsbffsrv.application.logging.log_query_app import log_query_app
15
+
16
+
17
+ async def search_business_logs_handler(payload: LogQueryRequest) -> APIResponse[LogQueryResponse]:
18
+ """查询业务日志 / Search business log documents."""
19
+ logger.info(
20
+ "Search business logs: services=%s range=%s -> %s",
21
+ payload.service_names,
22
+ payload.start_time,
23
+ payload.end_time,
24
+ )
25
+ try:
26
+ result = await log_query_app.search_logs(payload)
27
+ except ValueError as exc:
28
+ logger.warning("Log search validation error: %s", exc)
29
+ raise HTTPException(
30
+ status_code=http.HTTPStatus.BAD_REQUEST.value,
31
+ error_code=OpsbffsrvServiceLogsErrorCode.INVALID_INPUT,
32
+ msg=str(exc),
33
+ )
34
+ except Exception as exc: # noqa: BLE001
35
+ logger.error("Log search failed: %s", exc, exc_info=True)
36
+ raise HTTPException(
37
+ status_code=http.HTTPStatus.INTERNAL_SERVER_ERROR.value,
38
+ error_code=OpsbffsrvServiceLogsErrorCode.INTERNAL_ERROR,
39
+ msg="Failed to query business logs",
40
+ )
41
+ return build_success_response(data=result)
@@ -0,0 +1,181 @@
1
+ """
2
+ mongo-express 代理 API / Mongo-express proxy API
3
+ 将前端对 /v1/opsbffsrv/mongo_express/* 的请求转发到 mongo-express.internal:8081
4
+ Forward every /v1/opsbffsrv/mongo_express/* request to mongo-express.internal:8081
5
+ """
6
+ import base64
7
+ import http
8
+ from typing import Optional
9
+
10
+ from starlette.requests import Request
11
+ from starlette.responses import RedirectResponse
12
+ from starlette.responses import Response
13
+
14
+ from linglong_web.utils import logger
15
+ from cancan_microstack.public.const.error import ErrorCode
16
+ from cancan_microstack.public.error import HTTPException
17
+ from linglong_web import http_client
18
+ from linglong_web import LinglongConfig
19
+
20
+
21
+ def _build_proxy_aware_redirect(request: Request) -> Optional[RedirectResponse]:
22
+ """构造考虑代理头的 308 重定向 / Build a proxy-aware 308 redirect"""
23
+ forwarded_uri = request.headers.get("x-original-uri") or request.headers.get("x-forwarded-uri")
24
+ corrected_path: Optional[str] = None
25
+
26
+ if forwarded_uri:
27
+ corrected_path = forwarded_uri if forwarded_uri.endswith('/') else f"{forwarded_uri}/"
28
+ else:
29
+ forwarded_prefix = request.headers.get("x-forwarded-prefix")
30
+ if forwarded_prefix:
31
+ trimmed = forwarded_prefix.rstrip('/')
32
+ corrected_path = f"{trimmed}/"
33
+
34
+ if not corrected_path:
35
+ return None
36
+
37
+ scheme = request.headers.get("x-forwarded-proto") or request.url.scheme
38
+ host = request.headers.get("x-forwarded-host") or request.headers.get("host") or request.url.hostname
39
+ port = request.headers.get("x-forwarded-port")
40
+
41
+ if not host:
42
+ return None
43
+
44
+ netloc = host
45
+ if port and ':' not in host:
46
+ netloc = f"{host}:{port}"
47
+
48
+ redirect_target = f"{scheme}://{netloc}{corrected_path}"
49
+ if request.url.query:
50
+ redirect_target = f"{redirect_target}?{request.url.query}"
51
+
52
+ logger.debug("Redirecting mongo-express request to %s", redirect_target)
53
+ return RedirectResponse(url=redirect_target, status_code=http.HTTPStatus.PERMANENT_REDIRECT.value)
54
+
55
+
56
+ def _ensure_basic_auth(headers: dict[str, str]) -> None:
57
+ """缺省时注入 Basic Auth / Inject Basic auth header when missing."""
58
+ username = LinglongConfig.MONGO_EXPRESS_USERNAME
59
+ password = LinglongConfig.MONGO_EXPRESS_PASSWORD
60
+ if not username or not password:
61
+ return
62
+
63
+ token = base64.b64encode(f"{username}:{password}".encode("utf-8")).decode("ascii")
64
+ headers["Authorization"] = f"Basic {token}"
65
+
66
+
67
+ async def mongo_express_proxy_handler(request: Request) -> Response:
68
+ """mongo-express 代理处理器 / Proxy handler for mongo-express"""
69
+ original_path = request.url.path
70
+ if original_path.endswith("/mongo_express") and not original_path.endswith("/mongo_express/"):
71
+ redirect_response = _build_proxy_aware_redirect(request)
72
+ if redirect_response:
73
+ return redirect_response
74
+
75
+ html_content = (
76
+ "<!DOCTYPE html><html lang=\"zh-CN\"><head>"
77
+ "<meta charset=\"utf-8\" />"
78
+ "<title>Redirecting</title>"
79
+ "<script>(function(){var url=new URL(window.location.href);"
80
+ "if(!url.pathname.endsWith('/')){url.pathname=url.pathname+'/';}"
81
+ "window.location.replace(url.toString());})();</script>"
82
+ "</head><body></body></html>"
83
+ )
84
+ return Response(content=html_content, status_code=http.HTTPStatus.OK.value, media_type="text/html")
85
+
86
+ # Mongo Express with ME_CONFIG_SITE_BASEURL expects requests at that path
87
+ # Do NOT strip the prefix - send original path to upstream
88
+ proxy_path = original_path or "/"
89
+ base_url = (LinglongConfig.MONGO_EXPRESS_BASE_URL or "").rstrip("/")
90
+ target_url = f"{base_url}{proxy_path}"
91
+ if request.url.query:
92
+ target_url = f"{target_url}?{request.url.query}"
93
+
94
+ logger.debug("Proxying %s %s -> %s", request.method, original_path, target_url)
95
+
96
+ headers = dict(request.headers)
97
+ headers.pop('host', None)
98
+
99
+ # 强制覆盖 Authorization 头,防止用户的 Token 传递给上游导致 401
100
+ # Force overwrite Authorization header to prevent client tokens from causing upstream 401s
101
+ headers.pop('authorization', None)
102
+ headers.pop('Authorization', None)
103
+ _ensure_basic_auth(headers)
104
+
105
+ logger.debug("Proxying to MongoExpress with headers: %s (Auth present: %s)",
106
+ {k: v for k, v in headers.items() if k.lower() != 'authorization'},
107
+ 'Authorization' in headers)
108
+
109
+ body = None
110
+ if request.method in {"POST", "PUT", "PATCH"}:
111
+ body = await request.body()
112
+
113
+ try:
114
+ resp = await http_client.fetch(
115
+ method=request.method,
116
+ url=target_url,
117
+ format_type='raw',
118
+ headers=headers,
119
+ data=body,
120
+ timeout=30.0,
121
+ passthrough_errors=True,
122
+ )
123
+
124
+ if not resp:
125
+ logger.error("Failed to proxy request to mongo-express: %s", target_url)
126
+ raise HTTPException(
127
+ status_code=http.HTTPStatus.BAD_GATEWAY.value,
128
+ error_code=ErrorCode.NETWORK_ERROR,
129
+ msg="Failed to connect to mongo-express",
130
+ )
131
+
132
+ content = await resp.read()
133
+ content = await resp.read()
134
+
135
+ # 处理响应头:移除 hop-by-hop 头
136
+ response_headers = {}
137
+ content_type = ""
138
+ for k, v in resp.headers.items():
139
+ k_lower = k.lower()
140
+ if k_lower == 'content-type':
141
+ content_type = v
142
+ if k_lower in ('transfer-encoding', 'content-encoding', 'connection', 'keep-alive', 'content-length'):
143
+ continue
144
+ response_headers[k] = v
145
+
146
+ # 针对 HTML 响应进行路径重写 / Rewrite paths in HTML responses
147
+ # Mongo Express 默认使用绝对路径 /public/xxx,需要改写为 /v1/opsbffsrv/mongo_express/public/xxx
148
+ if "text/html" in content_type:
149
+ html_str = content.decode("utf-8", errors="replace")
150
+ # 替换 public 资源路径
151
+ html_str = html_str.replace('href="/public/', 'href="/v1/opsbffsrv/mongo_express/public/')
152
+ html_str = html_str.replace('src="/public/', 'src="/v1/opsbffsrv/mongo_express/public/')
153
+ html_str = html_str.replace('href="public/', 'href="/v1/opsbffsrv/mongo_express/public/')
154
+ html_str = html_str.replace('src="public/', 'src="/v1/opsbffsrv/mongo_express/public/')
155
+
156
+ # 替换 base href (如果存在) 或注入新的
157
+ if '<base href="' in html_str:
158
+ html_str = html_str.replace('<base href="/"', '<base href="/v1/opsbffsrv/mongo_express/"')
159
+ else:
160
+ # 在 <head> 后插入 base 标签
161
+ html_str = html_str.replace('<head>', '<head><base href="/v1/opsbffsrv/mongo_express/">', 1)
162
+
163
+ content = html_str.encode("utf-8")
164
+ # 更新 Content-Length (虽然 starlette Response 会自动处理,但如果是流式传输可能需要注意,这里是一次性读取)
165
+ response_headers.pop("Content-Length", None)
166
+
167
+ logger.debug("Proxied mongo-express response: %s %s bytes", resp.status, len(content))
168
+
169
+ return Response(content=content, status_code=resp.status, headers=response_headers)
170
+
171
+ except Exception as e:
172
+ logger.error("Error proxying to mongo-express: %s", e, exc_info=True)
173
+ # 如果是已知 HTTP 异常直接抛出
174
+ if isinstance(e, HTTPException):
175
+ raise e
176
+ # 其他异常转换为 502 Bad Gateway
177
+ raise HTTPException(
178
+ status_code=http.HTTPStatus.BAD_GATEWAY.value,
179
+ error_code=ErrorCode.NETWORK_ERROR,
180
+ msg=f"Upstream error: {str(e)}",
181
+ )
@@ -0,0 +1,154 @@
1
+ """
2
+ pgweb 代理 API
3
+ 将前端对 /v1/opsbffsrv/pgweb/* 的请求转发到 pgweb.internal:8081
4
+ """
5
+ import http
6
+ from typing import Optional
7
+
8
+ from starlette.requests import Request
9
+ from starlette.responses import (
10
+ RedirectResponse,
11
+ Response,
12
+ )
13
+ from linglong_web.utils import logger
14
+ from linglong_web import http_client
15
+ from linglong_web import LinglongConfig
16
+
17
+ from cancan_microstack.public.error import HTTPException
18
+ from cancan_microstack.public.const.error import ErrorCode
19
+
20
+
21
+ async def pgweb_proxy_handler(request: Request) -> Response:
22
+ """
23
+ pgweb 代理处理器
24
+
25
+ 将所有 /v1/opsbffsrv/pgweb/* 请求转发到 pgweb.internal:8081/*
26
+ 保持请求方法、查询参数、请求头和请求体不变
27
+
28
+ Examples:
29
+ GET /v1/opsbffsrv/pgweb/ -> GET http://pgweb.internal:8081/
30
+ GET /v1/opsbffsrv/pgweb/api/info -> GET http://pgweb.internal:8081/api/info
31
+ POST /v1/opsbffsrv/pgweb/api/sql -> POST http://pgweb.internal:8081/api/sql
32
+ """
33
+ # 提取原始路径,缺少尾部 / 时优先重定向
34
+ # Extract original path and normalize trailing slash before proxying
35
+ original_path = request.url.path
36
+ if original_path.endswith("/pgweb") and not original_path.endswith("/pgweb/"):
37
+ redirect_response = _build_proxy_aware_redirect(request)
38
+ if redirect_response:
39
+ return redirect_response
40
+
41
+ # 回退为在前端执行跳转,确保任何代理路径都能正确追加 /
42
+ # Fallback: client-side redirect to preserve upstream proxy prefixes
43
+ html_content = (
44
+ "<!DOCTYPE html><html lang=\"zh-CN\"><head>"
45
+ "<meta charset=\"utf-8\" />"
46
+ "<title>Redirecting</title>"
47
+ "<script>(function(){var url=new URL(window.location.href);"
48
+ "if(!url.pathname.endsWith('/')){url.pathname=url.pathname+'/';}"
49
+ "window.location.replace(url.toString());})();</script>"
50
+ "</head><body></body></html>"
51
+ )
52
+ return Response(
53
+ content=html_content,
54
+ status_code=http.HTTPStatus.OK.value,
55
+ media_type="text/html",
56
+ )
57
+
58
+ pgweb_path = original_path.replace("/v1/opsbffsrv/pgweb", "", 1)
59
+
60
+ # 如果路径为空,默认为根路径
61
+ if not pgweb_path:
62
+ pgweb_path = "/"
63
+
64
+ # 构建目标 URL
65
+ base_url = (LinglongConfig.PGWEB_BASE_URL or "").rstrip("/")
66
+ target_url = f"{base_url}{pgweb_path}"
67
+
68
+ # 保留查询参数
69
+ if request.url.query:
70
+ target_url = f"{target_url}?{request.url.query}"
71
+
72
+ logger.debug(f"Proxying {request.method} {original_path} -> {target_url}")
73
+
74
+ # 准备转发的请求头(移除 Host 头)
75
+ headers = dict(request.headers)
76
+ headers.pop('host', None)
77
+
78
+ # 读取请求体(如果有)
79
+ body = None
80
+ if request.method in ("POST", "PUT", "PATCH"):
81
+ body = await request.body()
82
+
83
+ # 转发请求到 pgweb
84
+ resp = await http_client.fetch(
85
+ method=request.method,
86
+ url=target_url,
87
+ format_type='raw', # 禁止文本解析以便透传二进制资源 / disable text decode for binary passthrough
88
+ headers=headers,
89
+ data=body,
90
+ timeout=30.0, # pgweb 查询可能较慢
91
+ )
92
+
93
+ if not resp:
94
+ logger.error(f"Failed to proxy request to pgweb: {target_url}")
95
+ raise HTTPException(
96
+ status_code=http.HTTPStatus.BAD_GATEWAY.value,
97
+ error_code=ErrorCode.NETWORK_ERROR,
98
+ msg="Failed to connect to pgweb"
99
+ )
100
+
101
+ # 读取响应内容
102
+ content = await resp.read()
103
+
104
+ # 准备返回的响应头(移除某些不应该转发的头)
105
+ response_headers = dict(resp.headers)
106
+ response_headers.pop('transfer-encoding', None)
107
+ response_headers.pop('content-encoding', None)
108
+
109
+ logger.debug(f"Proxied response: {resp.status} {len(content)} bytes")
110
+
111
+ # 返回代理响应
112
+ return Response(
113
+ content=content,
114
+ status_code=resp.status,
115
+ headers=response_headers,
116
+ )
117
+
118
+
119
+ def _build_proxy_aware_redirect(request: Request) -> Optional[RedirectResponse]:
120
+ """构造考虑代理头的 308 重定向 / Build a proxy-aware 308 redirect"""
121
+ forwarded_uri = request.headers.get("x-original-uri") or request.headers.get("x-forwarded-uri")
122
+ corrected_path: Optional[str] = None
123
+
124
+ if forwarded_uri:
125
+ corrected_path = forwarded_uri if forwarded_uri.endswith("/") else f"{forwarded_uri}/"
126
+ else:
127
+ forwarded_prefix = request.headers.get("x-forwarded-prefix")
128
+ if forwarded_prefix:
129
+ trimmed = forwarded_prefix.rstrip("/")
130
+ corrected_path = f"{trimmed}/"
131
+
132
+ if not corrected_path:
133
+ return None
134
+
135
+ scheme = request.headers.get("x-forwarded-proto") or request.url.scheme
136
+ host = request.headers.get("x-forwarded-host") or request.headers.get("host") or request.url.hostname
137
+ port = request.headers.get("x-forwarded-port")
138
+
139
+ if not host:
140
+ return None
141
+
142
+ netloc = host
143
+ if port and ":" not in host:
144
+ netloc = f"{host}:{port}"
145
+
146
+ redirect_target = f"{scheme}://{netloc}{corrected_path}"
147
+ if request.url.query:
148
+ redirect_target = f"{redirect_target}?{request.url.query}"
149
+
150
+ logger.debug(f"Redirecting to {redirect_target} with proxy-aware headers")
151
+ return RedirectResponse(
152
+ url=redirect_target,
153
+ status_code=http.HTTPStatus.PERMANENT_REDIRECT.value,
154
+ )