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,688 @@
1
+ """
2
+ 服务实例表数据库操作函数
3
+ """
4
+ from typing import (
5
+ List,
6
+ Optional,
7
+ )
8
+ from datetime import datetime, timezone
9
+ from sqlalchemy import select, update, delete, and_, or_, func
10
+ from sqlalchemy.dialects.postgresql import insert
11
+
12
+ from linglong_web import Rmanager
13
+ from cancan_microstack.public.schemas.infra.service_instance import (
14
+ ServiceInstance,
15
+ ServiceInstanceCreate,
16
+ ServiceInstanceUpdate,
17
+ ServiceInstanceQuery,
18
+ )
19
+ from cancan_microstack.services.infrasrv.infrastructure.db.model.service_instance_tbl import ServiceInstanceTbl
20
+
21
+
22
+ async def get_instance_by_id(instance_id: str) -> Optional[ServiceInstance]:
23
+ """
24
+ 根据实例ID查询实例信息
25
+
26
+ Args:
27
+ instance_id: 实例ID
28
+
29
+ Returns:
30
+ 实例信息,不存在则返回 None
31
+ """
32
+ async with Rmanager.pg_session() as session:
33
+ async with session.begin():
34
+ stmt = select(ServiceInstanceTbl).where(
35
+ and_(
36
+ ServiceInstanceTbl.instance_id == instance_id,
37
+ ServiceInstanceTbl.flag == 0
38
+ )
39
+ )
40
+ row = (await session.execute(stmt)).scalar_one_or_none()
41
+ return ServiceInstance.model_validate(row, from_attributes=True) if row else None
42
+
43
+
44
+ async def get_instance_by_container_name(container_name: str) -> Optional[ServiceInstance]:
45
+ """
46
+ 根据容器名查询实例信息
47
+
48
+ Args:
49
+ container_name: 容器名称
50
+
51
+ Returns:
52
+ 实例信息,不存在则返回 None
53
+ """
54
+ async with Rmanager.pg_session() as session:
55
+ async with session.begin():
56
+ stmt = select(ServiceInstanceTbl).where(
57
+ and_(
58
+ ServiceInstanceTbl.container_name == container_name,
59
+ ServiceInstanceTbl.flag == 0
60
+ )
61
+ )
62
+ row = (await session.execute(stmt)).scalar_one_or_none()
63
+ return ServiceInstance.model_validate(row, from_attributes=True) if row else None
64
+
65
+
66
+ async def insert_instance(data: ServiceInstanceCreate) -> ServiceInstance:
67
+ """
68
+ 创建服务实例记录(插入实例)
69
+
70
+ Args:
71
+ data: 实例数据
72
+
73
+ Returns:
74
+ 创建的实例记录
75
+ """
76
+ async with Rmanager.pg_session() as session:
77
+ async with session.begin():
78
+ stmt = insert(ServiceInstanceTbl).values(data.model_dump()).returning(ServiceInstanceTbl)
79
+ row = (await session.execute(stmt)).scalar_one()
80
+ return ServiceInstance.model_validate(row, from_attributes=True)
81
+
82
+
83
+ async def create_instance(data: ServiceInstanceCreate) -> ServiceInstance:
84
+ """
85
+ Alias of `insert_instance`.
86
+ Delegates to `insert_instance` which implements the actual insertion logic.
87
+ """
88
+ return await insert_instance(data)
89
+
90
+
91
+ async def upsert_instance(data: ServiceInstanceCreate) -> ServiceInstance:
92
+ """插入或更新服务实例,保持实例唯一 / Upsert a service instance row."""
93
+
94
+ payload = data.model_dump()
95
+ now_utc = datetime.now(timezone.utc)
96
+ payload.setdefault("status", "UP")
97
+ payload.setdefault("expected_status", "UP")
98
+ payload.setdefault("health_status", data.health_status or "unknown")
99
+ payload.setdefault("last_heartbeat", now_utc)
100
+
101
+ async with Rmanager.pg_session() as session:
102
+ async with session.begin():
103
+ stmt = (
104
+ insert(ServiceInstanceTbl)
105
+ .values(**payload)
106
+ .returning(ServiceInstanceTbl)
107
+ )
108
+ stmt = stmt.on_conflict_do_update(
109
+ index_elements=[ServiceInstanceTbl.instance_id],
110
+ set_={
111
+ "service_name": stmt.excluded.service_name,
112
+ "container_name": stmt.excluded.container_name,
113
+ "compose_service_name": stmt.excluded.compose_service_name,
114
+ "host": stmt.excluded.host,
115
+ "port": stmt.excluded.port,
116
+ "internal_port": stmt.excluded.internal_port,
117
+ "status": "UP",
118
+ "expected_status": stmt.excluded.expected_status,
119
+ "health_check_url": stmt.excluded.health_check_url,
120
+ "health_status": stmt.excluded.health_status,
121
+ "instance_metadata": stmt.excluded.instance_metadata,
122
+ "last_heartbeat": now_utc,
123
+ "flag": 0,
124
+ }
125
+ )
126
+ row = (await session.execute(stmt)).scalar_one()
127
+ return ServiceInstance.model_validate(row, from_attributes=True)
128
+
129
+
130
+ async def update_instance(instance_id: str, data: ServiceInstanceUpdate) -> Optional[ServiceInstance]:
131
+ """
132
+ 更新服务实例记录
133
+
134
+ Args:
135
+ instance_id: 实例ID
136
+ data: 更新数据
137
+
138
+ Returns:
139
+ 更新后的实例记录,不存在则返回 None
140
+ """
141
+ async with Rmanager.pg_session() as session:
142
+ async with session.begin():
143
+ # 构建更新字典,只包含非 None 的字段
144
+ update_dict = {k: v for k, v in data.model_dump().items() if v is not None}
145
+
146
+ if not update_dict:
147
+ return await get_instance_by_id(instance_id)
148
+
149
+ stmt = (
150
+ update(ServiceInstanceTbl)
151
+ .where(
152
+ and_(
153
+ ServiceInstanceTbl.instance_id == instance_id,
154
+ ServiceInstanceTbl.flag == 0
155
+ )
156
+ )
157
+ .values(**update_dict)
158
+ .returning(ServiceInstanceTbl)
159
+ )
160
+
161
+ result = await session.execute(stmt)
162
+ row = result.scalar_one_or_none()
163
+
164
+ return ServiceInstance.model_validate(row, from_attributes=True) if row else None
165
+
166
+
167
+ async def query_instances(query: ServiceInstanceQuery) -> List[ServiceInstance]:
168
+ """
169
+ 查询服务实例列表
170
+
171
+ Args:
172
+ query: 查询条件
173
+
174
+ Returns:
175
+ 实例列表
176
+ """
177
+ async with Rmanager.pg_session() as session:
178
+ async with session.begin():
179
+ stmt = select(ServiceInstanceTbl).where(ServiceInstanceTbl.flag == 0)
180
+
181
+ # 动态添加查询条件
182
+ if query.service_name:
183
+ stmt = stmt.where(ServiceInstanceTbl.service_name == query.service_name)
184
+ if query.instance_id:
185
+ stmt = stmt.where(ServiceInstanceTbl.instance_id == query.instance_id)
186
+ if query.status:
187
+ stmt = stmt.where(ServiceInstanceTbl.status == query.status)
188
+ if query.expected_status:
189
+ stmt = stmt.where(ServiceInstanceTbl.expected_status == query.expected_status)
190
+ if query.health_status:
191
+ stmt = stmt.where(ServiceInstanceTbl.health_status == query.health_status)
192
+
193
+ # 排序:按创建时间升序(实例0在前)
194
+ stmt = stmt.order_by(ServiceInstanceTbl.instance_id.asc())
195
+
196
+ # 分页
197
+ stmt = stmt.limit(query.limit).offset(query.offset)
198
+
199
+ rows = list((await session.execute(stmt)).scalars().all())
200
+ return [ServiceInstance.model_validate(r, from_attributes=True) for r in rows] if rows else []
201
+
202
+
203
+ async def list_instances_by_service(service_name: str) -> List[ServiceInstance]:
204
+ """
205
+ 获取服务的所有实例(列出实例)
206
+
207
+ Args:
208
+ service_name: 服务名称
209
+
210
+ Returns:
211
+ 实例列表
212
+ """
213
+ query = ServiceInstanceQuery(service_name=service_name, limit=1000)
214
+ return await query_instances(query)
215
+
216
+
217
+ async def get_all_instances() -> List[ServiceInstance]:
218
+ """列出所有有效实例 / List every active instance."""
219
+
220
+ async with Rmanager.pg_session() as session:
221
+ async with session.begin():
222
+ stmt = select(ServiceInstanceTbl).where(ServiceInstanceTbl.flag == 0)
223
+ rows = list((await session.execute(stmt)).scalars().all())
224
+ return [ServiceInstance.model_validate(r, from_attributes=True) for r in rows]
225
+
226
+
227
+ async def get_healthy_instances(service_name: str) -> List[ServiceInstance]:
228
+ """
229
+ 获取服务的所有健康实例
230
+
231
+ Args:
232
+ service_name: 服务名称
233
+
234
+ Returns:
235
+ 健康实例列表
236
+ """
237
+ async with Rmanager.pg_session() as session:
238
+ async with session.begin():
239
+ stmt = (
240
+ select(ServiceInstanceTbl)
241
+ .where(
242
+ and_(
243
+ ServiceInstanceTbl.service_name == service_name,
244
+ ServiceInstanceTbl.status == "UP",
245
+ ServiceInstanceTbl.health_status == 'healthy',
246
+ ServiceInstanceTbl.flag == 0
247
+ )
248
+ )
249
+ .order_by(ServiceInstanceTbl.instance_id.asc())
250
+ )
251
+
252
+ rows = list((await session.execute(stmt)).scalars().all())
253
+ return [ServiceInstance.model_validate(r, from_attributes=True) for r in rows] if rows else []
254
+
255
+
256
+ async def get_unhealthy_instances(
257
+ consecutive_failures_threshold: int = 3
258
+ ) -> List[ServiceInstance]:
259
+ """
260
+ 获取所有不健康的实例(连续失败次数达到阈值)
261
+
262
+ Args:
263
+ consecutive_failures_threshold: 连续失败次数阈值
264
+
265
+ Returns:
266
+ 不健康实例列表
267
+ """
268
+ async with Rmanager.pg_session() as session:
269
+ async with session.begin():
270
+ stmt = (
271
+ select(ServiceInstanceTbl)
272
+ .where(
273
+ and_(
274
+ ServiceInstanceTbl.expected_status == "UP",
275
+ ServiceInstanceTbl.consecutive_failures >= consecutive_failures_threshold,
276
+ ServiceInstanceTbl.flag == 0
277
+ )
278
+ )
279
+ .order_by(ServiceInstanceTbl.consecutive_failures.desc())
280
+ )
281
+
282
+ rows = list((await session.execute(stmt)).scalars().all())
283
+ return [ServiceInstance.model_validate(r, from_attributes=True) for r in rows] if rows else []
284
+
285
+
286
+ async def increment_failure_count(instance_id: str, error_message: Optional[str] = None) -> Optional[ServiceInstance]:
287
+ """
288
+ 增加实例的连续失败次数
289
+
290
+ Args:
291
+ instance_id: 实例ID
292
+ error_message: 错误信息
293
+
294
+ Returns:
295
+ 更新后的实例记录
296
+ """
297
+ async with Rmanager.pg_session() as session:
298
+ async with session.begin():
299
+ update_values = {
300
+ 'consecutive_failures': ServiceInstanceTbl.consecutive_failures + 1,
301
+ 'health_status': 'unhealthy',
302
+ 'last_health_check': datetime.now(timezone.utc),
303
+ }
304
+
305
+ if error_message:
306
+ update_values['last_health_error'] = error_message
307
+
308
+ stmt = (
309
+ update(ServiceInstanceTbl)
310
+ .where(
311
+ and_(
312
+ ServiceInstanceTbl.instance_id == instance_id,
313
+ ServiceInstanceTbl.flag == 0
314
+ )
315
+ )
316
+ .values(**update_values)
317
+ .returning(ServiceInstanceTbl)
318
+ )
319
+
320
+ result = await session.execute(stmt)
321
+ row = result.scalar_one_or_none()
322
+
323
+ return ServiceInstance.model_validate(row, from_attributes=True) if row else None
324
+
325
+
326
+ async def mark_instance_status(service_name: str, instance_id: str, status: str) -> None:
327
+ """更新实例状态(含软删除逻辑) / Update instance status marker."""
328
+
329
+ async with Rmanager.pg_session() as session:
330
+ async with session.begin():
331
+ stmt = (
332
+ update(ServiceInstanceTbl)
333
+ .where(
334
+ and_(
335
+ ServiceInstanceTbl.service_name == service_name,
336
+ ServiceInstanceTbl.instance_id == instance_id,
337
+ )
338
+ )
339
+ .values(status=status)
340
+ )
341
+ await session.execute(stmt)
342
+
343
+
344
+ async def soft_delete_instance(service_name: str, instance_id: str) -> None:
345
+ """通过 flag 标记实例为删除状态 / Soft delete instance via flag."""
346
+
347
+ async with Rmanager.pg_session() as session:
348
+ async with session.begin():
349
+ stmt = (
350
+ update(ServiceInstanceTbl)
351
+ .where(
352
+ and_(
353
+ ServiceInstanceTbl.service_name == service_name,
354
+ ServiceInstanceTbl.instance_id == instance_id,
355
+ )
356
+ )
357
+ .values(flag=1, status='DOWN')
358
+ )
359
+ await session.execute(stmt)
360
+
361
+
362
+ async def touch_instance_heartbeat(service_name: str, instance_id: str, status: Optional[str] = None) -> None:
363
+ """更新实例心跳和可选状态 / Update heartbeat timestamp and optionally status."""
364
+
365
+ update_fields = {
366
+ 'last_heartbeat': datetime.now(timezone.utc),
367
+ }
368
+ if status:
369
+ update_fields['status'] = status
370
+
371
+ async with Rmanager.pg_session() as session:
372
+ async with session.begin():
373
+ stmt = (
374
+ update(ServiceInstanceTbl)
375
+ .where(
376
+ and_(
377
+ ServiceInstanceTbl.service_name == service_name,
378
+ ServiceInstanceTbl.instance_id == instance_id,
379
+ ServiceInstanceTbl.flag == 0,
380
+ )
381
+ )
382
+ .values(**update_fields)
383
+ )
384
+ await session.execute(stmt)
385
+
386
+
387
+ async def reset_failure_count(instance_id: str) -> Optional[ServiceInstance]:
388
+ """
389
+ 重置实例的连续失败次数(健康检查成功时调用)
390
+
391
+ Args:
392
+ instance_id: 实例ID
393
+
394
+ Returns:
395
+ 更新后的实例记录
396
+ """
397
+ async with Rmanager.pg_session() as session:
398
+ async with session.begin():
399
+ stmt = (
400
+ update(ServiceInstanceTbl)
401
+ .where(
402
+ and_(
403
+ ServiceInstanceTbl.instance_id == instance_id,
404
+ ServiceInstanceTbl.flag == 0
405
+ )
406
+ )
407
+ .values(
408
+ consecutive_failures=0,
409
+ health_status='healthy',
410
+ last_health_check=datetime.now(timezone.utc),
411
+ last_health_error=None
412
+ )
413
+ .returning(ServiceInstanceTbl)
414
+ )
415
+
416
+ result = await session.execute(stmt)
417
+ row = result.scalar_one_or_none()
418
+
419
+ return ServiceInstance.model_validate(row, from_attributes=True) if row else None
420
+
421
+
422
+ async def increment_restart_count(instance_id: str) -> Optional[ServiceInstance]:
423
+ """
424
+ 增加实例的重启次数
425
+
426
+ Args:
427
+ instance_id: 实例ID
428
+
429
+ Returns:
430
+ 更新后的实例记录
431
+ """
432
+ async with Rmanager.pg_session() as session:
433
+ async with session.begin():
434
+ stmt = (
435
+ update(ServiceInstanceTbl)
436
+ .where(
437
+ and_(
438
+ ServiceInstanceTbl.instance_id == instance_id,
439
+ ServiceInstanceTbl.flag == 0
440
+ )
441
+ )
442
+ .values(restart_count=ServiceInstanceTbl.restart_count + 1)
443
+ .returning(ServiceInstanceTbl)
444
+ )
445
+
446
+ result = await session.execute(stmt)
447
+ row = result.scalar_one_or_none()
448
+
449
+ return ServiceInstance.model_validate(row, from_attributes=True) if row else None
450
+
451
+
452
+ async def get_next_available_port(service_name: str, base_port: int = 18000, max_instances: int = 100) -> Optional[int]:
453
+ """
454
+ 获取服务的下一个可用端口
455
+
456
+ Args:
457
+ service_name: 服务名称
458
+ base_port: 基础端口号
459
+ max_instances: 最大实例数
460
+
461
+ Returns:
462
+ 可用端口号,如果没有可用端口则返回 None
463
+ """
464
+ async with Rmanager.pg_session() as session:
465
+ async with session.begin():
466
+ # 查询该服务已使用的端口
467
+ stmt = (
468
+ select(ServiceInstanceTbl.port)
469
+ .where(
470
+ and_(
471
+ ServiceInstanceTbl.service_name == service_name,
472
+ ServiceInstanceTbl.flag == 0
473
+ )
474
+ )
475
+ .order_by(ServiceInstanceTbl.port.asc())
476
+ )
477
+
478
+ rows = (await session.execute(stmt)).scalars().all()
479
+ used_ports = set(rows)
480
+
481
+ # 查找第一个未使用的端口
482
+ for i in range(max_instances):
483
+ port = base_port + i
484
+ if port not in used_ports:
485
+ return port
486
+
487
+ return None
488
+
489
+
490
+ async def count_instances_by_service(service_name: str, status: Optional[str] = None) -> int:
491
+ """
492
+ 统计服务的实例数量
493
+
494
+ Args:
495
+ service_name: 服务名称
496
+ status: 状态过滤,None 表示不过滤
497
+
498
+ Returns:
499
+ 实例数量
500
+ """
501
+ async with Rmanager.pg_session() as session:
502
+ async with session.begin():
503
+ stmt = select(func.count()).select_from(ServiceInstanceTbl).where(
504
+ and_(
505
+ ServiceInstanceTbl.service_name == service_name,
506
+ ServiceInstanceTbl.flag == 0
507
+ )
508
+ )
509
+
510
+ if status:
511
+ stmt = stmt.where(ServiceInstanceTbl.status == status)
512
+
513
+ result = await session.execute(stmt)
514
+ return result.scalar_one_or_none() or 0
515
+
516
+
517
+ async def delete_instance_by_id(instance_id: str) -> bool:
518
+ """
519
+ 根据ID删除服务实例(软删除)
520
+
521
+ Args:
522
+ instance_id: 实例ID
523
+
524
+ Returns:
525
+ 是否成功删除
526
+ """
527
+ async with Rmanager.pg_session() as session:
528
+ async with session.begin():
529
+ stmt = (
530
+ update(ServiceInstanceTbl)
531
+ .where(
532
+ and_(
533
+ ServiceInstanceTbl.instance_id == instance_id,
534
+ ServiceInstanceTbl.flag == 0
535
+ )
536
+ )
537
+ .values(flag=1)
538
+ )
539
+
540
+ result = await session.execute(stmt)
541
+ return result.rowcount > 0
542
+
543
+
544
+ async def get_instances_by_status(status: str) -> List[ServiceInstance]:
545
+ """
546
+ 根据状态查询实例列表
547
+
548
+ Args:
549
+ status: 实例状态 (running, stopped, starting, stopping等)
550
+
551
+ Returns:
552
+ 实例列表
553
+ """
554
+ async with Rmanager.pg_session() as session:
555
+ async with session.begin():
556
+ stmt = select(ServiceInstanceTbl).where(
557
+ and_(
558
+ ServiceInstanceTbl.status == status,
559
+ ServiceInstanceTbl.flag == 0
560
+ )
561
+ )
562
+ rows = list((await session.execute(stmt)).scalars().all())
563
+ return [ServiceInstance.model_validate(r, from_attributes=True) for r in rows] if rows else []
564
+
565
+
566
+ async def update_instance_health_status(
567
+ instance_id: str,
568
+ health_status: str,
569
+ last_health_check: Optional[datetime] = None,
570
+ last_health_error: Optional[str] = None,
571
+ last_heartbeat: Optional[datetime] = None,
572
+ ) -> Optional[ServiceInstance]:
573
+ """
574
+ 更新实例健康状态
575
+
576
+ Args:
577
+ instance_id: 实例ID
578
+ health_status: 健康状态 (healthy, degraded, unhealthy)
579
+ last_health_check: 最后健康检查时间
580
+ last_health_error: 最后健康检查错误信息
581
+
582
+ Returns:
583
+ 更新后的实例信息
584
+ """
585
+ async with Rmanager.pg_session() as session:
586
+ async with session.begin():
587
+ update_data = {"health_status": health_status}
588
+ if last_health_check:
589
+ update_data["last_health_check"] = last_health_check
590
+ if last_health_error is not None: # 允许设置为 None 清空错误
591
+ update_data["last_health_error"] = last_health_error
592
+ if last_heartbeat:
593
+ update_data["last_heartbeat"] = last_heartbeat
594
+
595
+ stmt = (
596
+ update(ServiceInstanceTbl)
597
+ .where(
598
+ and_(
599
+ ServiceInstanceTbl.instance_id == instance_id,
600
+ ServiceInstanceTbl.flag == 0
601
+ )
602
+ )
603
+ .values(**update_data)
604
+ .returning(ServiceInstanceTbl)
605
+ )
606
+
607
+ row = (await session.execute(stmt)).scalar_one_or_none()
608
+ return ServiceInstance.model_validate(row, from_attributes=True) if row else None
609
+
610
+
611
+ async def increment_instance_consecutive_failures(instance_id: str) -> Optional[int]:
612
+ """
613
+ 递增实例连续失败次数
614
+
615
+ Args:
616
+ instance_id: 实例ID
617
+
618
+ Returns:
619
+ 更新后的连续失败次数。如果实例不存在,返回 None
620
+ """
621
+ async with Rmanager.pg_session() as session:
622
+ async with session.begin():
623
+ stmt = (
624
+ update(ServiceInstanceTbl)
625
+ .where(
626
+ and_(
627
+ ServiceInstanceTbl.instance_id == instance_id,
628
+ ServiceInstanceTbl.flag == 0
629
+ )
630
+ )
631
+ .values(consecutive_failures=ServiceInstanceTbl.consecutive_failures + 1)
632
+ .returning(ServiceInstanceTbl.consecutive_failures)
633
+ )
634
+
635
+ result = await session.execute(stmt)
636
+ return result.scalar_one_or_none()
637
+
638
+
639
+ async def reset_instance_consecutive_failures(instance_id: str) -> Optional[ServiceInstance]:
640
+ """
641
+ 重置实例连续失败次数
642
+
643
+ Args:
644
+ instance_id: 实例ID
645
+
646
+ Returns:
647
+ 更新后的实例信息
648
+ """
649
+ async with Rmanager.pg_session() as session:
650
+ async with session.begin():
651
+ stmt = (
652
+ update(ServiceInstanceTbl)
653
+ .where(
654
+ and_(
655
+ ServiceInstanceTbl.instance_id == instance_id,
656
+ ServiceInstanceTbl.flag == 0
657
+ )
658
+ )
659
+ .values(consecutive_failures=0)
660
+ .returning(ServiceInstanceTbl)
661
+ )
662
+
663
+ row = (await session.execute(stmt)).scalar_one_or_none()
664
+ return ServiceInstance.model_validate(row, from_attributes=True) if row else None
665
+
666
+
667
+ async def hard_delete_instances_by_ids(instance_ids: List[str]) -> int:
668
+ """
669
+ 根据实例ID列表物理删除实例记录
670
+ Hard delete instance records by a list of instance IDs.
671
+
672
+ Args:
673
+ instance_ids: 要删除的实例ID列表
674
+
675
+ Returns:
676
+ 被删除的记录数量
677
+ """
678
+ if not instance_ids:
679
+ return 0
680
+
681
+ async with Rmanager.pg_session() as session:
682
+ async with session.begin():
683
+ stmt = (
684
+ delete(ServiceInstanceTbl)
685
+ .where(ServiceInstanceTbl.instance_id.in_(instance_ids))
686
+ )
687
+ result = await session.execute(stmt)
688
+ return result.rowcount