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,292 @@
1
+ """
2
+ 服务注册查询领域层
3
+ 负责为ops前端提供服务实例的查询功能
4
+ 不包含服务注册/注销/心跳等写操作(由infrasrv负责)
5
+ 说明:本服务直接从数据库读取由 infrasrv 维护的服务状态,不执行任何独立的健康检查或陈旧实例过滤。
6
+ """
7
+ from typing import (
8
+ List,
9
+ Dict,
10
+ )
11
+ from datetime import (
12
+ datetime,
13
+ timezone,
14
+ )
15
+
16
+ from cancan_microstack.public.const.health_consts import (
17
+ HealthOverallStatus,
18
+ InstanceHealthStatus,
19
+ ServiceExpectedStatusAlias,
20
+ ServiceRuntimeStatus,
21
+ )
22
+ from cancan_microstack.public.schemas.infra.enums import ServiceType
23
+ from cancan_microstack.public.schemas.infra.overview import ServiceOverview
24
+ from cancan_microstack.public.schemas.infra.service_registry import ServiceInstance
25
+ from cancan_microstack.services.opsbffsrv.infrastructure.db.operate.service_info_op import get_all_service_info
26
+ from cancan_microstack.services.opsbffsrv.infrastructure.db.operate.service_registry import (
27
+ get_all_service_names,
28
+ get_all_services,
29
+ get_service_by_instance,
30
+ get_service_instances as db_get_service_instances,
31
+ )
32
+ from linglong_web import LinglongConfig
33
+ from linglong_web.utils import logger
34
+
35
+
36
+ class ServiceRegistryDomain:
37
+ """
38
+ 服务注册查询域
39
+ Service Registry Query Domain
40
+
41
+ 职责:直接查询并返回由 infrasrv 清理和维护的服务注册数据。
42
+ Responsibility: Directly query and return service registry data maintained and cleaned by infrasrv.
43
+ """
44
+
45
+ @staticmethod
46
+ def _normalize_service_name(service_name: str) -> str:
47
+ """规范化服务名(兼容 .service 后缀)
48
+ Normalize service name (compatible with .service suffix)
49
+ """
50
+ value = (service_name or "").strip()
51
+ if value.endswith(".service"):
52
+ return value[:-len(".service")]
53
+ return value
54
+
55
+ @staticmethod
56
+ def _normalize_expected_status(expected_status: str) -> ServiceRuntimeStatus:
57
+ """规范化期望状态
58
+ Normalize expected status string
59
+ """
60
+ value = (expected_status or ServiceRuntimeStatus.RUNNING.value).strip().lower()
61
+ if value in {
62
+ ServiceExpectedStatusAlias.STOP.value,
63
+ ServiceExpectedStatusAlias.STOPPED.value,
64
+ ServiceExpectedStatusAlias.DOWN.value,
65
+ }:
66
+ return ServiceRuntimeStatus.STOPPED
67
+ return ServiceRuntimeStatus.RUNNING
68
+
69
+ @staticmethod
70
+ def _extract_instance_timestamp(instance: ServiceInstance) -> datetime | None:
71
+ """提取实例最近活动时间
72
+ Extract last seen timestamp for an instance
73
+ """
74
+ for field_name in ("last_heartbeat", "update_time", "created_time"):
75
+ timestamp = getattr(instance, field_name, None)
76
+ if timestamp is not None:
77
+ if timestamp.tzinfo is None:
78
+ return timestamp.replace(tzinfo=timezone.utc)
79
+ return timestamp
80
+ return None
81
+
82
+ def _is_stale_instance(self, instance: ServiceInstance, now: datetime) -> bool:
83
+ """判断实例是否超时陈旧
84
+ Determine whether an instance is stale by heartbeat/update timestamp
85
+ """
86
+ stale_seconds = int(getattr(LinglongConfig, "SERVICE_INSTANCE_STALE_SECONDS", 180) or 180)
87
+ if stale_seconds <= 0:
88
+ return False
89
+
90
+ last_seen = self._extract_instance_timestamp(instance)
91
+ if last_seen is None:
92
+ return False
93
+
94
+ return (now - last_seen).total_seconds() > stale_seconds
95
+
96
+ def _build_instance_dedupe_key(self, instance: ServiceInstance) -> str:
97
+ """构建实例去重键
98
+ Build dedupe key for instance consolidation
99
+ """
100
+ normalized_service_name = self._normalize_service_name(instance.service_name)
101
+
102
+ if instance.container_name:
103
+ return f"{normalized_service_name}|container:{instance.container_name}"
104
+
105
+ return (
106
+ f"{normalized_service_name}|endpoint:{instance.host}:{instance.port}:{instance.internal_port}"
107
+ )
108
+
109
+ async def _load_expected_status_map(self) -> Dict[str, ServiceRuntimeStatus]:
110
+ """加载服务期望状态映射
111
+ Load expected status map from service info table
112
+ """
113
+ service_info_list = await get_all_service_info()
114
+ status_map: Dict[str, ServiceRuntimeStatus] = {}
115
+ for service_info in service_info_list:
116
+ normalized_service_name = self._normalize_service_name(service_info.service_name)
117
+ status_map[normalized_service_name] = self._normalize_expected_status(service_info.expected_status)
118
+ return status_map
119
+
120
+ def _filter_and_dedupe_instances(
121
+ self,
122
+ instances: List[ServiceInstance],
123
+ expected_status_map: Dict[str, ServiceRuntimeStatus],
124
+ ) -> List[ServiceInstance]:
125
+ """过滤陈旧实例并做同容器去重
126
+ Filter stale instances and dedupe duplicated container rows
127
+ """
128
+ now = datetime.now(timezone.utc)
129
+ deduped_instances: Dict[str, ServiceInstance] = {}
130
+
131
+ for instance in instances:
132
+ normalized_service_name = self._normalize_service_name(instance.service_name)
133
+ expected_status = expected_status_map.get(normalized_service_name)
134
+ if expected_status == ServiceRuntimeStatus.STOPPED:
135
+ continue
136
+
137
+ if self._is_stale_instance(instance, now):
138
+ continue
139
+
140
+ dedupe_key = self._build_instance_dedupe_key(instance)
141
+ existing = deduped_instances.get(dedupe_key)
142
+ if existing is None:
143
+ deduped_instances[dedupe_key] = instance
144
+ continue
145
+
146
+ existing_ts = self._extract_instance_timestamp(existing)
147
+ current_ts = self._extract_instance_timestamp(instance)
148
+ if existing_ts is None and current_ts is not None:
149
+ deduped_instances[dedupe_key] = instance
150
+ elif existing_ts is not None and current_ts is not None and current_ts >= existing_ts:
151
+ deduped_instances[dedupe_key] = instance
152
+
153
+ return list(deduped_instances.values())
154
+
155
+ @staticmethod
156
+ def _derive_actual_status(total_instances: int, healthy_instances: int) -> ServiceRuntimeStatus:
157
+ """根据实例统计推导实际状态
158
+ Derive actual status from instance counters
159
+ """
160
+ if total_instances <= 0:
161
+ return ServiceRuntimeStatus.STOPPED
162
+ if healthy_instances > 0:
163
+ return ServiceRuntimeStatus.RUNNING
164
+ return ServiceRuntimeStatus.DEGRADED
165
+
166
+ def _to_models(self, instances: List[ServiceInstance]) -> List[ServiceInstance]:
167
+ """将数据库模型转换为 Pydantic 模型 / Convert DB models to Pydantic models."""
168
+ return [ServiceInstance.model_validate(inst, from_attributes=True) for inst in instances]
169
+
170
+ async def get_service_instances(self, service_name: str | None = None, only_healthy: bool = True) -> List[ServiceInstance]:
171
+ """
172
+ 获取服务实例列表
173
+ Get the list of instances for a service.
174
+
175
+ Args:
176
+ service_name: 服务名称 / Service name
177
+ only_healthy: 是否只返回健康实例 / Whether to return only healthy instances
178
+ """
179
+ logger.debug(f"Querying instances for service: {service_name}, only_healthy: {only_healthy}")
180
+
181
+ normalized_service_name = self._normalize_service_name(service_name or "")
182
+ health_status_filter = InstanceHealthStatus.HEALTHY if only_healthy else None
183
+
184
+ if normalized_service_name:
185
+ instances = await db_get_service_instances(
186
+ normalized_service_name,
187
+ health_status=health_status_filter,
188
+ )
189
+ else:
190
+ instances = await get_all_services()
191
+ if health_status_filter:
192
+ instances = [instance for instance in instances if instance.health_status == health_status_filter]
193
+
194
+ expected_status_map = await self._load_expected_status_map()
195
+ cleaned_instances = self._filter_and_dedupe_instances(instances, expected_status_map)
196
+ logger.info(
197
+ "Found %s cleaned instances for service=%s (only_healthy=%s)",
198
+ len(cleaned_instances),
199
+ normalized_service_name or "ALL",
200
+ only_healthy,
201
+ )
202
+ return self._to_models(cleaned_instances)
203
+
204
+ async def get_all_instances(self) -> List[ServiceInstance]:
205
+ """
206
+ 获取所有服务实例
207
+ Get all service instances.
208
+ """
209
+ logger.debug("Querying all service instances.")
210
+ instances = await get_all_services()
211
+ expected_status_map = await self._load_expected_status_map()
212
+ cleaned_instances = self._filter_and_dedupe_instances(instances, expected_status_map)
213
+ return self._to_models(cleaned_instances)
214
+
215
+ async def get_instance(self, service_name: str, instance_id: str) -> ServiceInstance | None:
216
+ """
217
+ 获取指定服务实例
218
+ Get a specific service instance.
219
+ """
220
+ instance = await get_service_by_instance(service_name, instance_id)
221
+ return ServiceInstance.model_validate(instance, from_attributes=True) if instance else None
222
+
223
+ async def get_all_service_names(self) -> List[str]:
224
+ """
225
+ 获取所有服务名称
226
+ Get all service names.
227
+ """
228
+ return await get_all_service_names()
229
+
230
+ async def get_services_overview(self) -> List[ServiceOverview]:
231
+ """
232
+ 获取所有服务的概览信息(服务名、状态统计)
233
+ 基于 service_info_tbl 的元数据配合实例信息完成统计
234
+ 包含没有实例运行的服务
235
+ Get an overview of all services (name, status statistics).
236
+ This is based on metadata from service_info_tbl combined with instance information.
237
+ Includes services that have no running instances.
238
+ """
239
+ all_service_info = await get_all_service_info()
240
+ all_instances = await get_all_services()
241
+ service_map: Dict[str, ServiceOverview] = {}
242
+ expected_status_map = await self._load_expected_status_map()
243
+ cleaned_instances = self._filter_and_dedupe_instances(all_instances, expected_status_map)
244
+
245
+ for service_info in all_service_info:
246
+ service_name = service_info.service_name
247
+ expected_status = self._normalize_expected_status(service_info.expected_status)
248
+ service_map[service_name] = ServiceOverview(
249
+ service_name=service_name,
250
+ description=service_info.description or "",
251
+ service_type=service_info.service_type or ServiceType.BUSINESS,
252
+ expected_status=expected_status,
253
+ desired_replicas=int(service_info.desired_replicas or 1),
254
+ actual_replicas=int(service_info.actual_replicas or 0),
255
+ )
256
+
257
+ for instance in cleaned_instances:
258
+ service_name = self._normalize_service_name(instance.service_name)
259
+ if service_name not in service_map:
260
+ service_map[service_name] = ServiceOverview(
261
+ service_name=service_name,
262
+ service_type=ServiceType.BUSINESS,
263
+ expected_status=ServiceRuntimeStatus.RUNNING,
264
+ )
265
+
266
+ service_map[service_name].total_instances += 1
267
+ if instance.status == HealthOverallStatus.UP or instance.status == InstanceHealthStatus.HEALTHY:
268
+ service_map[service_name].healthy_instances += 1
269
+ else:
270
+ service_map[service_name].unhealthy_instances += 1
271
+
272
+ for info in service_map.values():
273
+ info.actual_replicas = info.total_instances
274
+ info.actual_status = self._derive_actual_status(info.total_instances, info.healthy_instances)
275
+ info.status_matches_expected = info.expected_status == info.actual_status
276
+
277
+ if info.expected_status == ServiceRuntimeStatus.STOPPED:
278
+ if info.actual_status == ServiceRuntimeStatus.STOPPED:
279
+ info.overall_status = HealthOverallStatus.UP
280
+ else:
281
+ info.overall_status = HealthOverallStatus.PARTIAL
282
+ elif info.total_instances == 0:
283
+ info.overall_status = HealthOverallStatus.DOWN
284
+ elif info.healthy_instances == 0:
285
+ info.overall_status = HealthOverallStatus.DOWN
286
+ elif info.unhealthy_instances > 0:
287
+ info.overall_status = HealthOverallStatus.PARTIAL
288
+ else:
289
+ info.overall_status = HealthOverallStatus.UP
290
+
291
+ logger.info(f"Retrieved overview for {len(service_map)} services")
292
+ return list(service_map.values())
@@ -0,0 +1,242 @@
1
+ """
2
+ InfraSrv API 客户端 / InfraSrv API Client
3
+
4
+ 用于调用 infrasrv 的内部接口和服务管理接口 / For calling infrasrv internal and service management interfaces
5
+ """
6
+ from typing import (
7
+ Optional,
8
+ )
9
+ import os
10
+ import http
11
+
12
+ from linglong_web.utils import logger
13
+ from linglong_web import LinglongConfig
14
+ from linglong_web import (
15
+ HTTPClientConfig,
16
+ http_client,
17
+ )
18
+ from cancan_microstack.public.api.infrasrv_client import InfraSrvApiClient
19
+ from cancan_microstack.public.error import HTTPException
20
+ from cancan_microstack.public.const.error import ErrorCode
21
+ from cancan_microstack.public.schemas.infra.service_management import (
22
+ ServiceManagementRequest,
23
+ ServiceManagementAPIResponse,
24
+ )
25
+ from cancan_microstack.public.schemas.infra.operation import (
26
+ OperationCreateRequest,
27
+ OperationUpdateRequest,
28
+ )
29
+
30
+
31
+ class InfraSrvApi(InfraSrvApiClient):
32
+ """
33
+ 用于与 InfraSrv 通信的 API 客户端 / API client for communicating with InfraSrv
34
+ 继承自 InfraSrvApiClient,提供配置注入 / Inherits from InfraSrvApiClient with configuration injection
35
+
36
+ 继承的方法 / Inherited methods:
37
+ - create_operation(request: OperationCreateRequest) -> Dict[str, Any]
38
+ - update_operation(request: OperationUpdateRequest) -> Dict[str, Any]
39
+ - get_operation(operation_id: str) -> Dict[str, Any]
40
+ - list_operations(service_name, status, limit, offset) -> Dict[str, Any]
41
+
42
+ 新增方法(服务管理)/ New methods (service management):
43
+ - start_service(request: ServiceManagementRequest) -> Dict[str, Any]
44
+ - stop_service(request: ServiceManagementRequest) -> Dict[str, Any]
45
+ - restart_service(request: ServiceManagementRequest) -> Dict[str, Any]
46
+ """
47
+
48
+ def __init__(self):
49
+ # 注意:该类可能会在 LinglongConfig 初始化前被 import。
50
+ # Note: This class may be imported before LinglongConfig is initialized.
51
+ config_host = getattr(LinglongConfig, "INFRASRV_HOST", None)
52
+ infrasrv_host = os.getenv(
53
+ "INFRASRV_HOST",
54
+ config_host or "http://infrasrv.service:8080",
55
+ )
56
+
57
+ base_url = f"{infrasrv_host}"
58
+ super().__init__(base_url)
59
+ self._internal_base_url = f"{infrasrv_host}/v1/infrasrv/internal"
60
+ self.service_mgmt_base_url = f"{infrasrv_host}/v1/infrasrv/service"
61
+ logger.info(f"InfraSrvApi initialized (opsbffsrv) with base_url: {base_url}")
62
+ logger.info(f"Service management base URL: {self.service_mgmt_base_url}")
63
+ logger.info(f"Internal base URL: {self._internal_base_url}")
64
+
65
+ async def create_operation(self, request: OperationCreateRequest):
66
+ """创建操作记录(内部接口)/ Create operation via internal API."""
67
+ json_data = request.model_dump(mode="json")
68
+ return await self._make_request(
69
+ http.HTTPMethod.POST,
70
+ "/v1/infrasrv/internal/operation/create",
71
+ json_data=json_data,
72
+ response_models=self.OPERATION_RESPONSE_MODELS,
73
+ )
74
+
75
+ async def update_operation(self, request: OperationUpdateRequest):
76
+ """更新操作记录(内部接口)/ Update operation via internal API."""
77
+ json_data = request.model_dump(mode="json", exclude_none=True)
78
+ if request.started_at:
79
+ json_data["started_at"] = request.started_at.isoformat()
80
+ if request.completed_at:
81
+ json_data["completed_at"] = request.completed_at.isoformat()
82
+ return await self._make_request(
83
+ http.HTTPMethod.POST,
84
+ "/v1/infrasrv/internal/operation/update",
85
+ json_data=json_data,
86
+ response_models=self.OPERATION_RESPONSE_MODELS,
87
+ )
88
+
89
+ async def get_operation(self, operation_id: str):
90
+ """获取操作记录(内部接口)/ Get operation via internal API."""
91
+ return await self._make_request(
92
+ http.HTTPMethod.GET,
93
+ "/v1/infrasrv/internal/operation/get",
94
+ params={"operation_id": operation_id},
95
+ response_models=self.OPERATION_RESPONSE_MODELS,
96
+ )
97
+
98
+ async def list_operations(
99
+ self,
100
+ service_name: Optional[str] = None,
101
+ status: Optional[str] = None,
102
+ limit: int = 50,
103
+ offset: int = 0,
104
+ ):
105
+ """列出操作记录(内部接口)/ List operations via internal API."""
106
+ params: dict[str, object] = {"limit": limit, "offset": offset}
107
+ if service_name:
108
+ params["service_name"] = service_name
109
+ if status:
110
+ params["status"] = status
111
+ return await self._make_request(
112
+ http.HTTPMethod.GET,
113
+ "/v1/infrasrv/internal/operation/list",
114
+ params=params,
115
+ response_models=self.OPERATION_LIST_MODELS,
116
+ )
117
+
118
+ async def _make_service_management_request(
119
+ self,
120
+ endpoint: str,
121
+ request: ServiceManagementRequest
122
+ ) -> ServiceManagementAPIResponse:
123
+ """
124
+ 调用 infrasrv 服务管理接口的通用方法 / Generic method for calling infrasrv service management interfaces
125
+
126
+ Args:
127
+ endpoint: API 端点(如 /start, /stop)/ API endpoint (e.g., /start, /stop)
128
+ request: 服务管理请求 / Service management request
129
+
130
+ Returns:
131
+ ServiceManagementAPIResponse
132
+
133
+ Raises:
134
+ HTTPException: 调用失败时抛出异常 / Raise exception on call failure
135
+ """
136
+ url = f"{self.service_mgmt_base_url}{endpoint}"
137
+ json_data = request.model_dump(mode='json')
138
+
139
+ try:
140
+ resp = await http_client.post(
141
+ url=url,
142
+ json=json_data,
143
+ timeout=HTTPClientConfig.INTERNAL_SERVICE_TIMEOUT
144
+ )
145
+
146
+ if resp and resp.status == 200:
147
+ response_json = await resp.json()
148
+ logger.debug(f"Successfully called infrasrv service management API [{endpoint}]")
149
+
150
+ # 处理 infrasrv 的标准响应格式 / Handle infrasrv's standard response format
151
+ if isinstance(response_json, dict) and "success" in response_json:
152
+ if response_json.get("success"):
153
+ data = response_json.get("data", {})
154
+ # 将 dict 转换为 model / Convert dict to model
155
+ try:
156
+ return ServiceManagementAPIResponse(**data)
157
+ except Exception as e:
158
+ logger.error(f"Failed to parse response as ServiceManagementAPIResponse: {e}")
159
+ raise HTTPException(
160
+ status_code=http.HTTPStatus.INTERNAL_SERVER_ERROR.value,
161
+ error_code=ErrorCode.SYSTEM_ERROR,
162
+ msg=f"Failed to parse response from infrasrv: {str(e)}"
163
+ )
164
+ else:
165
+ error_info = response_json.get("error", {})
166
+ error_msg = error_info.get("msg", "Unknown error") if isinstance(error_info, dict) else str(
167
+ error_info)
168
+ error_code = error_info.get("code", ErrorCode.SYSTEM_ERROR) if isinstance(error_info,
169
+ dict) else ErrorCode.SYSTEM_ERROR
170
+ logger.error(f"infrasrv returned error: {error_msg}")
171
+ raise HTTPException(
172
+ status_code=http.HTTPStatus.INTERNAL_SERVER_ERROR.value,
173
+ error_code=error_code,
174
+ msg=f"Infrasrv error: {error_msg}"
175
+ )
176
+ else:
177
+ logger.error(f"Unexpected response format from infrasrv: {response_json}")
178
+ raise HTTPException(
179
+ status_code=http.HTTPStatus.INTERNAL_SERVER_ERROR.value,
180
+ error_code=ErrorCode.SYSTEM_ERROR,
181
+ msg=f"Unexpected response format from infrasrv"
182
+ )
183
+ else:
184
+ status_code = resp.status if resp else 500
185
+ error_msg = f"HTTP error: {status_code}"
186
+ logger.error(f"Failed to call infrasrv service management API [{endpoint}]: {error_msg}")
187
+ raise HTTPException(
188
+ status_code=status_code,
189
+ error_code=ErrorCode.NETWORK_ERROR,
190
+ msg=f"Failed to call infrasrv: {error_msg}"
191
+ )
192
+ except HTTPException:
193
+ raise
194
+ except Exception as e:
195
+ logger.error(f"Error calling infrasrv service management API [{endpoint}]: {e}", exc_info=True)
196
+ raise HTTPException(
197
+ status_code=http.HTTPStatus.INTERNAL_SERVER_ERROR.value,
198
+ error_code=ErrorCode.SYSTEM_ERROR,
199
+ msg=f"Error calling infrasrv: {str(e)}"
200
+ )
201
+
202
+ async def start_service(self, request: ServiceManagementRequest) -> ServiceManagementAPIResponse:
203
+ """
204
+ 调用 infrasrv 启动服务 / Call infrasrv to start service
205
+
206
+ Args:
207
+ request: 服务管理请求 / Service management request
208
+
209
+ Returns:
210
+ ServiceManagementAPIResponse 或 None / ServiceManagementAPIResponse or None
211
+ """
212
+ logger.info(
213
+ f"[opsbffsrv → infrasrv] Starting service: {request.service_name}, operation_id: {request.operation_id}")
214
+ return await self._make_service_management_request("/start", request)
215
+
216
+ async def stop_service(self, request: ServiceManagementRequest) -> ServiceManagementAPIResponse:
217
+ """
218
+ 调用 infrasrv 停止服务 / Call infrasrv to stop service
219
+
220
+ Args:
221
+ request: 服务管理请求 / Service management request
222
+
223
+ Returns:
224
+ 操作结果 / Operation result
225
+ """
226
+ logger.info(
227
+ f"[opsbffsrv → infrasrv] Stopping service: {request.service_name}, operation_id: {request.operation_id}")
228
+ return await self._make_service_management_request("/stop", request)
229
+
230
+ async def restart_service(self, request: ServiceManagementRequest) -> ServiceManagementAPIResponse:
231
+ """
232
+ 调用 infrasrv 重启服务 / Call infrasrv to restart service
233
+
234
+ Args:
235
+ request: 服务管理请求 / Service management request
236
+
237
+ Returns:
238
+ ServiceManagementAPIResponse 或 None / ServiceManagementAPIResponse or None
239
+ """
240
+ logger.info(
241
+ f"[opsbffsrv → infrasrv] Restarting service: {request.service_name}, operation_id: {request.operation_id}")
242
+ return await self._make_service_management_request("/restart", request)
@@ -0,0 +1,67 @@
1
+ """图形验证码生成 / Captcha image generation using Pillow."""
2
+ import base64
3
+ import io
4
+ import random
5
+ import secrets
6
+ import string
7
+
8
+ from nanoid import generate as nanoid_generate
9
+ from PIL import Image, ImageDraw, ImageFont
10
+
11
+ # 排除易混淆字符 0/O/I/1
12
+ _CHARS = "".join(c for c in string.ascii_uppercase + string.digits if c not in "OI01")
13
+ _CAPTCHA_LENGTH = 6
14
+ _IMG_WIDTH = 200
15
+ _IMG_HEIGHT = 60
16
+
17
+
18
+ def generate_captcha() -> tuple[str, str, str]:
19
+ """生成图形验证码 / Generate a captcha: (captcha_id, answer, image_base64).
20
+
21
+ Returns:
22
+ captcha_id: 唯一标识符
23
+ answer: 验证码答案(大写)
24
+ image_base64: data URI 格式的 PNG 图片
25
+ """
26
+ captcha_id = nanoid_generate(size=16)
27
+ # 验证码答案必须用 CSPRNG(不可预测),避免被预测/暴力绕过。
28
+ # Captcha answer must use a CSPRNG so it cannot be predicted.
29
+ # (The visual noise/jitter below stays on `random` — not security-relevant.)
30
+ answer = "".join(secrets.choice(_CHARS) for _ in range(_CAPTCHA_LENGTH))
31
+
32
+ image = Image.new("RGB", (_IMG_WIDTH, _IMG_HEIGHT), color=(255, 255, 255))
33
+ draw = ImageDraw.Draw(image)
34
+
35
+ # 尝试使用系统字体,不可用时使用默认字体
36
+ try:
37
+ font = ImageFont.truetype("Arial", 32)
38
+ except (OSError, IOError):
39
+ font = ImageFont.load_default()
40
+
41
+ # 绘制字符(带随机偏移和颜色)
42
+ x_offset = 15
43
+ for ch in answer:
44
+ color = (random.randint(0, 150), random.randint(0, 150), random.randint(0, 150))
45
+ y_offset = random.randint(5, 15)
46
+ draw.text((x_offset, y_offset), ch, fill=color, font=font)
47
+ x_offset += 28
48
+
49
+ # 绘制干扰线
50
+ for _ in range(5):
51
+ x1, y1 = random.randint(0, _IMG_WIDTH), random.randint(0, _IMG_HEIGHT)
52
+ x2, y2 = random.randint(0, _IMG_WIDTH), random.randint(0, _IMG_HEIGHT)
53
+ color = (random.randint(100, 200), random.randint(100, 200), random.randint(100, 200))
54
+ draw.line([(x1, y1), (x2, y2)], fill=color, width=1)
55
+
56
+ # 绘制噪点
57
+ for _ in range(100):
58
+ x, y = random.randint(0, _IMG_WIDTH - 1), random.randint(0, _IMG_HEIGHT - 1)
59
+ color = (random.randint(100, 200), random.randint(100, 200), random.randint(100, 200))
60
+ draw.point((x, y), fill=color)
61
+
62
+ buf = io.BytesIO()
63
+ image.save(buf, format="PNG")
64
+ b64 = base64.b64encode(buf.getvalue()).decode("utf-8")
65
+ image_base64 = f"data:image/png;base64,{b64}"
66
+
67
+ return captcha_id, answer, image_base64
@@ -0,0 +1,12 @@
1
+ """bcrypt 密码哈希与验证 / Password hashing and verification with bcrypt."""
2
+ import bcrypt
3
+
4
+
5
+ def hash_password(plain: str) -> str:
6
+ """生成 bcrypt 密码哈希 / Generate bcrypt hash for a plaintext password."""
7
+ return bcrypt.hashpw(plain.encode("utf-8"), bcrypt.gensalt()).decode("utf-8")
8
+
9
+
10
+ def verify_password(plain: str, hashed: str) -> bool:
11
+ """校验明文密码与 bcrypt 哈希 / Verify plaintext password against bcrypt hash."""
12
+ return bcrypt.checkpw(plain.encode("utf-8"), hashed.encode("utf-8"))