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,689 @@
1
+ """
2
+ 服务管理应用层 / Service Management Application Layer
3
+
4
+ 职责 / Responsibilities:
5
+ 1. 统一管理所有 Docker 服务操作的生命周期 / Unified lifecycle management for all Docker service operations
6
+ 2. 创建操作记录 → 调用 controllersrv → 更新操作状态 / Create operation record → Call controllersrv → Update operation status
7
+ 3. 实现自动重试机制 / Implement automatic retry mechanism
8
+ 4. 提供操作生命周期钩子(验证、通知、指标收集)/ Provide operation lifecycle hooks (validation, notification, metrics)
9
+ """
10
+ import asyncio
11
+ from typing import (
12
+ Dict,
13
+ Any,
14
+ Optional,
15
+ Callable,
16
+ List,
17
+ )
18
+ from datetime import (
19
+ datetime,
20
+ timezone,
21
+ )
22
+
23
+ from linglong_web.utils import logger
24
+
25
+ from cancan_microstack.services.infrasrv.infrastructure.api.controllersrv_api import ControllerSrvApi
26
+ from cancan_microstack.services.infrasrv.infrastructure.db.operate.service_action_log_op import (
27
+ insert_service_action_log,
28
+ )
29
+ from cancan_microstack.services.infrasrv.infrastructure.db.operate.service_operation_op import (
30
+ create_operation,
31
+ get_operation_by_id,
32
+ update_operation,
33
+ )
34
+ from cancan_microstack.services.infrasrv.infrastructure.db.operate.service_info_op import (
35
+ update_expected_status,
36
+ )
37
+ from cancan_microstack.public.const.health_consts import ServiceRuntimeStatus
38
+ from cancan_microstack.public.schemas.infra.service_operation import (
39
+ ServiceOperationCreate,
40
+ ServiceOperation,
41
+ ServiceOperationUpdate,
42
+ )
43
+ from cancan_microstack.public.schemas.infra.service_management import (
44
+ ServiceManagementRequest,
45
+ ServiceManagementResponse,
46
+ HookResult,
47
+ ControllerSrvResult,
48
+ )
49
+ from cancan_microstack.public.const.action_consts import ActionType
50
+ from cancan_microstack.public.const.operation_consts import (
51
+ OperationType,
52
+ OperationStatus,
53
+ InitiatedBy,
54
+ InitiatedFrom,
55
+ )
56
+
57
+
58
+ class ServiceManagementHooks:
59
+ """
60
+ 服务管理操作钩子 / Service Management Operation Hooks
61
+
62
+ 提供可扩展的生命周期钩子系统 / Provides extensible lifecycle hook system
63
+ """
64
+
65
+ def __init__(self):
66
+ # 预操作钩子列表(操作前执行:验证、准备)/ Pre-operation hooks (executed before operation: validation, preparation)
67
+ self._pre_hooks: List[Callable] = []
68
+ # 后操作钩子列表(操作后执行:通知、清理)/ Post-operation hooks (executed after operation: notification, cleanup)
69
+ self._post_hooks: List[Callable] = []
70
+ # 重试钩子列表(重试前执行:日志、延迟)/ Retry hooks (executed before retry: logging, delay)
71
+ self._retry_hooks: List[Callable] = []
72
+
73
+ def register_pre_hook(self, hook: Callable):
74
+ """
75
+ 注册预操作钩子 / Register pre-operation hook
76
+
77
+ 钩子函数签名 / Hook function signature:
78
+ async def hook(request: ServiceManagementRequest) -> HookResult
79
+
80
+ 返回值 / Return value:
81
+ HookResult - 如果 allow=False,操作将被阻止 / If allow=False, operation will be blocked
82
+ """
83
+ self._pre_hooks.append(hook)
84
+ logger.info(f"Registered pre-operation hook: {hook.__name__}")
85
+
86
+ def register_post_hook(self, hook: Callable):
87
+ """
88
+ 注册后操作钩子 / Register post-operation hook
89
+
90
+ 钩子函数签名 / Hook function signature:
91
+ async def hook(request: ServiceManagementRequest, response: ServiceManagementResponse) -> None
92
+ """
93
+ self._post_hooks.append(hook)
94
+ logger.info(f"Registered post-operation hook: {hook.__name__}")
95
+
96
+ def register_retry_hook(self, hook: Callable):
97
+ """
98
+ 注册重试钩子 / Register retry hook
99
+
100
+ 钩子函数签名 / Hook function signature:
101
+ async def hook(request: ServiceManagementRequest, attempt: int, error: Exception) -> None
102
+ """
103
+ self._retry_hooks.append(hook)
104
+ logger.info(f"Registered retry hook: {hook.__name__}")
105
+
106
+ async def execute_pre_hooks(self, request: ServiceManagementRequest) -> HookResult:
107
+ """
108
+ 执行所有预操作钩子 / Execute all pre-operation hooks
109
+
110
+ Returns:
111
+ HookResult - 钩子执行结果 / Hook execution result
112
+ """
113
+ for hook in self._pre_hooks:
114
+ try:
115
+ result = await hook(request)
116
+ if not result.allow:
117
+ logger.warning(f"Pre-operation hook {hook.__name__} rejected operation: {result.reason}")
118
+ return result
119
+ except Exception as e:
120
+ logger.error(f"Pre-operation hook {hook.__name__} failed: {e}", exc_info=True)
121
+ # 钩子失败不应阻止操作 / Hook failure should not block operation
122
+ return HookResult(allow=True, reason="")
123
+
124
+ async def execute_post_hooks(self, request: ServiceManagementRequest, response: ServiceManagementResponse):
125
+ """执行所有后操作钩子 / Execute all post-operation hooks"""
126
+ for hook in self._post_hooks:
127
+ try:
128
+ await hook(request, response)
129
+ except Exception as e:
130
+ logger.error(f"Post-operation hook {hook.__name__} failed: {e}", exc_info=True)
131
+
132
+ async def execute_retry_hooks(self, request: ServiceManagementRequest, attempt: int, error: Exception):
133
+ """执行所有重试钩子 / Execute all retry hooks"""
134
+ for hook in self._retry_hooks:
135
+ try:
136
+ await hook(request, attempt, error)
137
+ except Exception as e:
138
+ logger.error(f"Retry hook {hook.__name__} failed: {e}", exc_info=True)
139
+
140
+
141
+ class ServiceManagementApp:
142
+ """
143
+ 服务管理应用层 / Service Management Application Layer
144
+
145
+ 统一处理所有服务管理操作,作为 infrasrv 的核心控制平面 / Unified handling of all service management operations as infrasrv's core control plane
146
+ """
147
+
148
+ # 重试配置 / Retry Configuration
149
+ MAX_RETRIES = 3 # 最大重试次数 / Maximum retry attempts
150
+ RETRY_DELAY_SECONDS = 5 # 重试延迟(秒)/ Retry delay (seconds)
151
+ RETRY_BACKOFF_MULTIPLIER = 2 # 退避倍数 / Backoff multiplier
152
+ EXPECTED_STATUS_SYNC_TIMEOUT_SECONDS = 1.5
153
+ EXPECTED_STATUS_SYNC_RETRIES = 3
154
+
155
+ _OPERATION_EXPECTED_STATUS_MAP = {
156
+ OperationType.START: ServiceRuntimeStatus.RUNNING.value,
157
+ OperationType.RESTART: ServiceRuntimeStatus.RUNNING.value,
158
+ OperationType.STOP: ServiceRuntimeStatus.STOPPED.value,
159
+ }
160
+
161
+ def __init__(self):
162
+ self.controllersrv_api = ControllerSrvApi()
163
+ self.hooks = ServiceManagementHooks()
164
+ # 保存后台任务的强引用,防止 fire-and-forget 任务在运行期间被 GC 回收。
165
+ # Hold strong references to background tasks so fire-and-forget tasks are not GC'd while running.
166
+ self._bg: set = set()
167
+ self._register_builtin_hooks()
168
+
169
+ def _register_builtin_hooks(self):
170
+ """注册内置钩子 / Register built-in hooks"""
171
+
172
+ # 内置预操作钩子:参数验证 / Built-in pre-operation hook: parameter validation
173
+ async def validate_request_hook(request: ServiceManagementRequest) -> HookResult:
174
+ """验证请求参数 / Validate request parameters"""
175
+ if not request.service_name:
176
+ return HookResult(allow=False, reason="Service name is required")
177
+ if not request.operation_id:
178
+ return HookResult(allow=False, reason="Operation ID is required")
179
+ return HookResult(allow=True, reason="")
180
+
181
+ # 内置后操作钩子:指标收集 / Built-in post-operation hook: metrics collection
182
+ async def metrics_collection_hook(request: ServiceManagementRequest, response: ServiceManagementResponse):
183
+ """收集操作指标 / Collect operation metrics"""
184
+ duration = None
185
+ if response.started_at and response.completed_at:
186
+ duration = (response.completed_at - response.started_at).total_seconds()
187
+
188
+ logger.info(
189
+ f"[Metrics] Operation completed: "
190
+ f"type={request.operation_type}, "
191
+ f"service={request.service_name}, "
192
+ f"status={response.status}, "
193
+ f"duration={duration}s"
194
+ )
195
+
196
+ # 内置重试钩子:日志记录 / Built-in retry hook: logging
197
+ async def retry_logging_hook(request: ServiceManagementRequest, attempt: int, error: Exception):
198
+ """记录重试信息 / Log retry information"""
199
+ logger.warning(
200
+ f"[Retry] Attempt {attempt}/{self.MAX_RETRIES} failed for operation {request.operation_id}: {error}"
201
+ )
202
+
203
+ self.hooks.register_pre_hook(validate_request_hook)
204
+ self.hooks.register_post_hook(metrics_collection_hook)
205
+ self.hooks.register_retry_hook(retry_logging_hook)
206
+
207
+ async def execute_service_management(self, request: ServiceManagementRequest) -> ServiceManagementResponse:
208
+ """
209
+ 执行服务管理操作(统一入口)/ Execute service management operation (unified entry point)
210
+
211
+ 流程 / Flow:
212
+ 1. 执行预操作钩子 / Execute pre-operation hooks
213
+ 2. 创建操作记录 / Create operation record
214
+ 3. 调用 controllersrv(带重试)/ Call controllersrv (with retry)
215
+ 4. 更新操作状态 / Update operation status
216
+ 5. 执行后操作钩子 / Execute post-operation hooks
217
+
218
+ Args:
219
+ request: 服务管理请求 / Service management request
220
+
221
+ Returns:
222
+ 服务管理响应 / Service management response
223
+ """
224
+ logger.info(
225
+ f"[ServiceManagementApp] Starting operation: "
226
+ f"operation_id={request.operation_id}, "
227
+ f"type={request.operation_type}, "
228
+ f"service={request.service_name}"
229
+ )
230
+
231
+ # 步骤 1: 执行预操作钩子 / Step 1: Execute pre-operation hooks
232
+ hook_result = await self.hooks.execute_pre_hooks(request)
233
+ if not hook_result.allow:
234
+ logger.warning(f"Operation {request.operation_id} rejected by pre-hooks: {hook_result.reason}")
235
+ await self._record_action_log(
236
+ request=request,
237
+ action_status=OperationStatus.FAILED,
238
+ stage="rejected_by_pre_hooks",
239
+ error_message=hook_result.reason,
240
+ )
241
+ return ServiceManagementResponse(
242
+ operation_id=request.operation_id,
243
+ status=OperationStatus.FAILED,
244
+ service_name=request.service_name,
245
+ message=f"Operation rejected: {hook_result.reason}",
246
+ error_message=hook_result.reason
247
+ )
248
+
249
+ # 步骤 2: 处理重复请求并创建操作记录 / Step 2: Handle duplicates and create operation record
250
+ existing_operation = await get_operation_by_id(request.operation_id)
251
+ if existing_operation:
252
+ existing_status = self._coerce_operation_status(existing_operation.status)
253
+ if existing_status != OperationStatus.PENDING or existing_operation.started_at:
254
+ response = self._build_response_from_operation(
255
+ existing_operation,
256
+ default_message="Operation already exists",
257
+ )
258
+ await self._record_action_log(
259
+ request=request,
260
+ action_status=existing_status,
261
+ stage="duplicate_request",
262
+ error_message=response.error_message,
263
+ )
264
+ return response
265
+
266
+ logger.info(
267
+ "Operation record already exists and is pending: operation_id=%s",
268
+ request.operation_id,
269
+ )
270
+
271
+ try:
272
+ if not existing_operation:
273
+ await self._create_operation_record(request)
274
+ await self._record_action_log(
275
+ request=request,
276
+ action_status=OperationStatus.PENDING,
277
+ stage="operation_record_created",
278
+ )
279
+ except Exception as e:
280
+ logger.error(f"Failed to create operation record for {request.operation_id}: {e}", exc_info=True)
281
+ await self._record_action_log(
282
+ request=request,
283
+ action_status=OperationStatus.FAILED,
284
+ stage="operation_record_failed",
285
+ error_message=str(e),
286
+ )
287
+ return ServiceManagementResponse(
288
+ operation_id=request.operation_id,
289
+ status=OperationStatus.FAILED,
290
+ service_name=request.service_name,
291
+ message=f"Failed to create operation record: {str(e)}",
292
+ error_message=str(e)
293
+ )
294
+
295
+ # 步骤 3: 调用 controllersrv(带自动重试)/ Step 3: Call controllersrv (with automatic retry)
296
+ started_at = datetime.now(timezone.utc)
297
+ controller_result = await self._call_controllersrv_with_retry(request)
298
+ controller_completed_at = datetime.now(timezone.utc)
299
+
300
+ # 步骤 4: 更新操作状态 / Step 4: Update operation status
301
+ if controller_result.success:
302
+ status = OperationStatus.RUNNING
303
+ error_message = None
304
+ completed_at: Optional[datetime] = None
305
+ else:
306
+ status = OperationStatus.FAILED
307
+ error_message = controller_result.error or "Unknown error from controllersrv"
308
+ completed_at = controller_completed_at
309
+
310
+ try:
311
+ await self._update_operation_status(
312
+ operation_id=request.operation_id,
313
+ status=status,
314
+ started_at=started_at,
315
+ completed_at=completed_at,
316
+ result=controller_result.model_dump(),
317
+ error_message=error_message
318
+ )
319
+ except Exception as e:
320
+ logger.error(f"Failed to update operation status for {request.operation_id}: {e}", exc_info=True)
321
+
322
+ if controller_result.success:
323
+ await self._sync_service_expected_status_with_timeout(request)
324
+
325
+ # 构造响应 / Build response
326
+ response = ServiceManagementResponse(
327
+ operation_id=request.operation_id,
328
+ status=status,
329
+ service_name=request.service_name,
330
+ message=controller_result.message or (
331
+ "controllersrv accepted operation" if status == OperationStatus.RUNNING else "Operation failed"
332
+ ),
333
+ result=controller_result.model_dump(),
334
+ error_message=error_message,
335
+ started_at=started_at,
336
+ completed_at=completed_at
337
+ )
338
+
339
+ await self._record_action_log(
340
+ request=request,
341
+ action_status=status,
342
+ stage="operation_dispatched" if status == OperationStatus.RUNNING else "operation_failed",
343
+ result=controller_result,
344
+ error_message=error_message,
345
+ )
346
+
347
+ # 步骤 5: 执行后操作钩子 / Step 5: Execute post-operation hooks
348
+ await self.hooks.execute_post_hooks(request, response)
349
+
350
+ end_at = completed_at or controller_completed_at
351
+ duration_seconds = None
352
+ if started_at and end_at:
353
+ duration_seconds = (end_at - started_at).total_seconds()
354
+
355
+ duration_text = f"{duration_seconds:.2f}s" if duration_seconds is not None else "unknown"
356
+ logger.info(
357
+ f"[ServiceManagementApp] Operation completed: "
358
+ f"operation_id={request.operation_id}, "
359
+ f"status={status}, "
360
+ f"duration={duration_text}"
361
+ )
362
+
363
+ return response
364
+
365
+ async def _create_operation_record(self, request: ServiceManagementRequest) -> ServiceOperation:
366
+ """创建操作记录 / Create operation record"""
367
+ operation_data = ServiceOperationCreate(
368
+ operation_id=request.operation_id,
369
+ operation_type=request.operation_type,
370
+ service_name=request.service_name,
371
+ operation_params=request.operation_params,
372
+ status=OperationStatus.PENDING,
373
+ initiated_by=request.initiated_by,
374
+ initiated_from=request.initiated_from,
375
+ )
376
+ operation = await create_operation(operation_data)
377
+ logger.debug(f"Operation record created: {request.operation_id}")
378
+ return operation
379
+
380
+ @staticmethod
381
+ def _coerce_operation_status(value: str) -> OperationStatus:
382
+ """安全解析操作状态 / Safely parse operation status"""
383
+ try:
384
+ return OperationStatus(value)
385
+ except ValueError:
386
+ return OperationStatus.PENDING
387
+
388
+ def _build_response_from_operation(
389
+ self,
390
+ operation: ServiceOperation,
391
+ default_message: str,
392
+ ) -> ServiceManagementResponse:
393
+ """基于操作记录构造响应 / Build response from operation record"""
394
+ status = self._coerce_operation_status(operation.status)
395
+ message = default_message
396
+ if isinstance(operation.result, dict):
397
+ message = operation.result.get("message") or default_message
398
+
399
+ return ServiceManagementResponse(
400
+ operation_id=operation.operation_id,
401
+ status=status,
402
+ service_name=operation.service_name,
403
+ message=message,
404
+ result=operation.result or None,
405
+ error_message=operation.error_message,
406
+ started_at=operation.started_at,
407
+ completed_at=operation.completed_at,
408
+ )
409
+
410
+ async def _update_operation_status(
411
+ self,
412
+ operation_id: str,
413
+ status: OperationStatus,
414
+ started_at: Optional[datetime] = None,
415
+ completed_at: Optional[datetime] = None,
416
+ result: Optional[Dict[str, Any]] = None,
417
+ error_message: Optional[str] = None
418
+ ):
419
+ """更新操作状态 / Update operation status"""
420
+ update_data = ServiceOperationUpdate(
421
+ status=status,
422
+ started_at=started_at,
423
+ completed_at=completed_at,
424
+ result=result,
425
+ error_message=error_message
426
+ )
427
+ await update_operation(operation_id, update_data)
428
+ logger.debug(f"Operation status updated: {operation_id} -> {status}")
429
+
430
+ async def _call_controllersrv_with_retry(self, request: ServiceManagementRequest) -> ControllerSrvResult:
431
+ """
432
+ 调用 controllersrv 执行操作(带自动重试)/ Call controllersrv to execute operation (with automatic retry)
433
+
434
+ 实现指数退避重试策略 / Implements exponential backoff retry strategy
435
+
436
+ Args:
437
+ request: 服务管理请求 / Service management request
438
+
439
+ Returns:
440
+ ControllerSrvResult - 操作结果 / Operation result
441
+ """
442
+ last_error = None
443
+ delay = self.RETRY_DELAY_SECONDS
444
+
445
+ for attempt in range(1, self.MAX_RETRIES + 1):
446
+ try:
447
+ logger.info(
448
+ f"[Retry Attempt {attempt}/{self.MAX_RETRIES}] Calling controllersrv for {request.operation_id}")
449
+ result = await self._call_controllersrv(request)
450
+
451
+ # 检查 controllersrv 是否成功接受任务 / Check if controllersrv successfully accepted the task
452
+ if result.success:
453
+ logger.info(f"[Retry Success] Operation {request.operation_id} succeeded on attempt {attempt}")
454
+ return result
455
+ else:
456
+ # controllersrv 拒绝任务(业务错误,不重试)/ controllersrv rejected task (business error, no retry)
457
+ logger.warning(f"[No Retry] Controllersrv rejected task {request.operation_id}: {result.error}")
458
+ return result # 直接返回失败结果 / Return failure result directly
459
+
460
+ except Exception as e:
461
+ last_error = e
462
+ logger.warning(f"[Retry Attempt {attempt}] Failed to call controllersrv: {e}")
463
+
464
+ # 如果不是最后一次尝试,执行重试钩子并等待 / If not the last attempt, execute retry hooks and wait
465
+ if attempt < self.MAX_RETRIES:
466
+ await self.hooks.execute_retry_hooks(request, attempt, last_error)
467
+ logger.info(f"[Retry] Waiting {delay}s before next attempt...")
468
+ await asyncio.sleep(delay)
469
+ delay *= self.RETRY_BACKOFF_MULTIPLIER # 指数退避 / Exponential backoff
470
+
471
+ # 所有重试失败 / All retries failed
472
+ logger.error(f"[Retry Exhausted] All {self.MAX_RETRIES} attempts failed for {request.operation_id}")
473
+ return ControllerSrvResult(
474
+ success=False,
475
+ error=f"All retry attempts exhausted. Last error: {str(last_error)}",
476
+ retry_count=self.MAX_RETRIES
477
+ )
478
+
479
+ async def _sync_service_expected_status_with_timeout(self, request: ServiceManagementRequest) -> None:
480
+ """
481
+ 以受控超时执行期望状态同步,避免阻塞主请求
482
+ Sync expected_status with bounded timeout to avoid blocking API request
483
+ """
484
+ try:
485
+ synced = await asyncio.wait_for(
486
+ self._sync_service_expected_status(request),
487
+ timeout=self.EXPECTED_STATUS_SYNC_TIMEOUT_SECONDS,
488
+ )
489
+ if not synced:
490
+ retry_task = asyncio.create_task(self._sync_service_expected_status_retry(request))
491
+ self._bg.add(retry_task)
492
+ retry_task.add_done_callback(self._bg.discard)
493
+ except asyncio.TimeoutError:
494
+ logger.warning(
495
+ "Expected_status sync timed out, scheduling async retry: service=%s, operation_id=%s",
496
+ request.service_name,
497
+ request.operation_id,
498
+ )
499
+ retry_task = asyncio.create_task(self._sync_service_expected_status_retry(request))
500
+ self._bg.add(retry_task)
501
+ retry_task.add_done_callback(self._bg.discard)
502
+
503
+ async def _sync_service_expected_status_retry(self, request: ServiceManagementRequest) -> None:
504
+ """
505
+ 后台重试同步期望状态
506
+ Retry expected_status sync in background
507
+ """
508
+ for attempt in range(1, self.EXPECTED_STATUS_SYNC_RETRIES + 1):
509
+ try:
510
+ synced = await self._sync_service_expected_status(request)
511
+ if synced:
512
+ return
513
+ except Exception as exc:
514
+ logger.warning(
515
+ "Async expected_status sync retry failed: service=%s, operation_id=%s, attempt=%s, error=%s",
516
+ request.service_name,
517
+ request.operation_id,
518
+ attempt,
519
+ exc,
520
+ )
521
+
522
+ if attempt < self.EXPECTED_STATUS_SYNC_RETRIES:
523
+ await asyncio.sleep(float(attempt))
524
+
525
+ async def _sync_service_expected_status(self, request: ServiceManagementRequest) -> bool:
526
+ """
527
+ 根据操作类型同步服务期望状态
528
+ Sync service expected_status based on accepted operation type
529
+ """
530
+ expected_status = self._OPERATION_EXPECTED_STATUS_MAP.get(request.operation_type)
531
+ if not expected_status:
532
+ return
533
+
534
+ candidates = self._build_service_name_candidates(request.service_name)
535
+
536
+ try:
537
+ updated = None
538
+ updated_service_name = None
539
+ for candidate in candidates:
540
+ updated = await update_expected_status(candidate, expected_status)
541
+ if updated is not None:
542
+ updated_service_name = candidate
543
+ break
544
+
545
+ if updated is None:
546
+ logger.warning(
547
+ "Skip expected_status sync because service_info not found: service=%s, candidates=%s, expected_status=%s",
548
+ request.service_name,
549
+ candidates,
550
+ expected_status,
551
+ )
552
+ return False
553
+ else:
554
+ logger.info(
555
+ "Synced service expected_status: service=%s, matched_service=%s, expected_status=%s, operation_id=%s",
556
+ request.service_name,
557
+ updated_service_name,
558
+ expected_status,
559
+ request.operation_id,
560
+ )
561
+ return True
562
+ except Exception as exc:
563
+ logger.error(
564
+ "Failed to sync expected_status: service=%s, operation_id=%s, error=%s",
565
+ request.service_name,
566
+ request.operation_id,
567
+ exc,
568
+ exc_info=True,
569
+ )
570
+ return False
571
+
572
+ @staticmethod
573
+ def _build_service_name_candidates(service_name: str) -> List[str]:
574
+ """
575
+ 生成可能命中的服务名候选
576
+ Build service name candidates for service_info lookup
577
+ """
578
+ base_name = service_name or ""
579
+ candidates: List[str] = [base_name]
580
+
581
+ if base_name.endswith(".service"):
582
+ plain_name = base_name[:-len(".service")]
583
+ if plain_name:
584
+ candidates.append(plain_name)
585
+ else:
586
+ candidates.append(f"{base_name}.service")
587
+
588
+ deduped: List[str] = []
589
+ for candidate in candidates:
590
+ if candidate and candidate not in deduped:
591
+ deduped.append(candidate)
592
+ return deduped
593
+
594
+ async def _call_controllersrv(self, request: ServiceManagementRequest) -> ControllerSrvResult:
595
+ """
596
+ 调用 controllersrv 执行具体操作 / Call controllersrv to execute specific operation
597
+
598
+ 根据操作类型分派到不同的 API / Dispatch to different APIs based on operation type
599
+
600
+ Args:
601
+ request: 服务管理请求 / Service management request
602
+
603
+ Returns:
604
+ ControllerSrvResult - 操作结果 / Operation result
605
+ """
606
+ service_names = [request.service_name]
607
+ operation_id = request.operation_id
608
+
609
+ try:
610
+ if request.operation_type == OperationType.START:
611
+ return await self.controllersrv_api.start_services(service_names, operation_id)
612
+
613
+ elif request.operation_type == OperationType.STOP:
614
+ return await self.controllersrv_api.stop_services(service_names, operation_id)
615
+
616
+ elif request.operation_type == OperationType.RESTART:
617
+ return await self.controllersrv_api.restart_services(service_names, operation_id)
618
+ else:
619
+ raise ValueError(f"Unsupported operation type: {request.operation_type}")
620
+
621
+ except Exception as e:
622
+ logger.error(f"Exception when calling controllersrv for {operation_id}: {e}", exc_info=True)
623
+ raise
624
+
625
+ def _map_operation_type_to_action_type(self, operation_type: OperationType) -> ActionType:
626
+ """根据操作类型映射日志行为类型 / Map operation type to action log type"""
627
+ mapping = {
628
+ OperationType.START: ActionType.START,
629
+ OperationType.STOP: ActionType.STOP,
630
+ OperationType.RESTART: ActionType.RESTART,
631
+ }
632
+ return mapping.get(operation_type, ActionType.RESTART)
633
+
634
+ @staticmethod
635
+ def _normalize_initiated_by(initiated_by: InitiatedBy) -> str:
636
+ """规范化操作发起者字段 / Normalize initiated_by value"""
637
+ if isinstance(initiated_by, InitiatedBy):
638
+ return initiated_by
639
+ return str(initiated_by)
640
+
641
+ @staticmethod
642
+ def _normalize_initiated_from(initiated_from: InitiatedFrom) -> str:
643
+ """规范化操作来源字段 / Normalize initiated_from value"""
644
+ if isinstance(initiated_from, InitiatedFrom):
645
+ return initiated_from
646
+ return str(initiated_from)
647
+
648
+ async def _record_action_log(
649
+ self,
650
+ *,
651
+ request: ServiceManagementRequest,
652
+ action_status: OperationStatus,
653
+ stage: str,
654
+ result: Optional[ControllerSrvResult] = None,
655
+ error_message: Optional[str] = None,
656
+ ):
657
+ """
658
+ 写入服务行为日志,确保所有管理操作可追踪
659
+ Record service action logs so every management operation is traceable
660
+ """
661
+ action_type = self._map_operation_type_to_action_type(request.operation_type)
662
+ metadata: Dict[str, Any] = {
663
+ "operation_id": request.operation_id,
664
+ "operation_stage": stage,
665
+ "operation_params": request.operation_params,
666
+ "initiated_from": self._normalize_initiated_from(request.initiated_from),
667
+ }
668
+
669
+ if result:
670
+ metadata["controllersrv_result"] = result.model_dump()
671
+
672
+ try:
673
+ await insert_service_action_log(
674
+ service_name=request.service_name,
675
+ action_type=action_type,
676
+ action_status=action_status,
677
+ triggered_by=self._normalize_initiated_by(request.initiated_by),
678
+ action_detail=result.model_dump() if result else None,
679
+ error_message=error_message,
680
+ action_metadata=metadata,
681
+ )
682
+ except Exception as exc:
683
+ logger.error(
684
+ "Failed to record action log for %s (stage=%s): %s",
685
+ request.operation_id,
686
+ stage,
687
+ exc,
688
+ exc_info=True,
689
+ )