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,318 @@
1
+ """Host-side daemon helpers for services like controllersrv.
2
+
3
+ 用于在宿主机后台启动/停止 controllersrv,并使用 pidfile 进行管理。
4
+ Start/stop host-side services (e.g. controllersrv) in background using a pidfile.
5
+
6
+ Design goals / 设计目标:
7
+ - 标准库实现,避免引入额外依赖
8
+ Stdio-only to avoid extra dependencies.
9
+ - 默认不覆盖用户已有进程/日志
10
+ Do not overwrite user's existing processes/logs by default.
11
+ """
12
+ import json
13
+ import logging
14
+ import os
15
+ import signal
16
+ import subprocess
17
+ import time
18
+ from dataclasses import dataclass
19
+ from pathlib import Path
20
+ from typing import Callable
21
+
22
+ log = logging.getLogger(__name__)
23
+
24
+
25
+ @dataclass(frozen=True)
26
+ class DaemonPaths:
27
+ """pid/log 路径约定 / pid/log path convention."""
28
+
29
+ pid_file: Path
30
+ log_file: Path
31
+
32
+
33
+ def _proc_identity(pid: int) -> dict | None:
34
+ """读取进程身份信息(启动时间 / 命令行),用于防止 PID 复用误杀。
35
+
36
+ Read process identity (start time / cmdline) to guard against PID-reuse mis-kill.
37
+
38
+ 仅依赖标准库,尽力而为;任何一项拿不到就置 None(向后兼容、降级)。
39
+ Stdlib-only and best-effort; any missing field is set to None (backward-compatible degradation).
40
+
41
+ Returns:
42
+ 身份字典;若进程不存在则返回 None / identity dict, or None if the process does not exist.
43
+ """
44
+
45
+ try:
46
+ # ps 在 macOS / Linux 上都可用,输出进程启动时间与命令行。
47
+ # ps is available on both macOS and Linux; emits process start time and command line.
48
+ out = subprocess.run(
49
+ ["ps", "-o", "lstart=", "-o", "command=", "-p", str(pid)],
50
+ capture_output=True,
51
+ text=True,
52
+ timeout=2.0,
53
+ )
54
+ except Exception as exc: # noqa: BLE001
55
+ log.warning("Failed to read process identity for pid=%s: %s", pid, exc)
56
+ return None
57
+
58
+ if out.returncode != 0:
59
+ # 进程不存在 / process not found.
60
+ return None
61
+
62
+ line = out.stdout.strip()
63
+ if not line:
64
+ return None
65
+
66
+ # lstart 是固定 5 字段格式(如 "Mon Jun 14 10:00:00 2026"),其后是 command。
67
+ # lstart is a fixed 5-field format (e.g. "Mon Jun 14 10:00:00 2026"), followed by command.
68
+ parts = line.split(maxsplit=5)
69
+ if len(parts) >= 5:
70
+ lstart = " ".join(parts[:5])
71
+ cmdline = parts[5] if len(parts) == 6 else ""
72
+ return {"lstart": lstart, "cmdline": cmdline}
73
+
74
+ return {"lstart": line, "cmdline": ""}
75
+
76
+
77
+ def default_daemon_paths(workspace: Path, *, name: str) -> DaemonPaths:
78
+ """计算默认 pid/log 路径 / Compute default pid/log paths."""
79
+
80
+ pid_dir = workspace / "server_log_data" / "pids"
81
+ pid_file = pid_dir / f"{name}.pid"
82
+ log_file = workspace / "server_log_data" / f"{name}.out.log"
83
+ return DaemonPaths(pid_file=pid_file, log_file=log_file)
84
+
85
+
86
+ def _pid_alive(pid: int) -> bool:
87
+ try:
88
+ os.kill(pid, 0)
89
+ except OSError:
90
+ return False
91
+ return True
92
+
93
+
94
+ def _pid_alive_as_recorded(pid: int, recorded_identity: dict | None) -> bool:
95
+ """判断 pid 是否仍是当初记录的那个进程,避免 PID 复用误杀。
96
+
97
+ Decide whether pid is still the originally-recorded process, to avoid PID-reuse mis-kill.
98
+
99
+ 向后兼容:旧 pidfile 无身份信息(recorded_identity is None)时降级为仅 os.kill(pid, 0)。
100
+ Backward-compatible: when the old pidfile carries no identity info (recorded_identity is None),
101
+ degrade to the legacy os.kill(pid, 0) behavior.
102
+ """
103
+
104
+ if not _pid_alive(pid):
105
+ return False
106
+
107
+ # 旧 pidfile:无身份信息,降级为旧行为。
108
+ # Old pidfile: no identity info, degrade to legacy behavior.
109
+ if not recorded_identity:
110
+ return True
111
+
112
+ actual = _proc_identity(pid)
113
+ if actual is None:
114
+ # 拿不到当前身份(进程刚退出或 ps 不可用):保守按"非同一进程"处理,避免误杀。
115
+ # Cannot read current identity (process just exited or ps unavailable):
116
+ # conservatively treat as "not the same process" to avoid mis-kill.
117
+ return False
118
+
119
+ same = (
120
+ actual.get("lstart") == recorded_identity.get("lstart")
121
+ and actual.get("cmdline") == recorded_identity.get("cmdline")
122
+ )
123
+ if not same:
124
+ log.warning(
125
+ "PID %s reused by a different process (recorded=%s, actual=%s); not treating as alive",
126
+ pid,
127
+ recorded_identity,
128
+ actual,
129
+ )
130
+ return same
131
+
132
+
133
+ def read_pid_record(pid_file: Path) -> tuple[int, dict | None] | None:
134
+ """读取 pidfile 的完整记录(pid + 身份信息)。
135
+
136
+ Read the full pidfile record (pid + identity info).
137
+
138
+ 支持两种格式 / Supports two formats:
139
+ - 新格式 / new: JSON {"pid": int, "lstart": str, "cmdline": str}
140
+ - 旧格式 / legacy: 纯整数文本(身份信息返回 None,降级为旧行为)
141
+ plain integer text (identity returned as None, degrades to legacy behavior)
142
+
143
+ Returns:
144
+ (pid, identity_or_None);无法读取时返回 None / (pid, identity_or_None), or None if unreadable.
145
+ """
146
+
147
+ try:
148
+ raw = pid_file.read_text(encoding="utf-8").strip()
149
+ except FileNotFoundError:
150
+ return None
151
+ except OSError:
152
+ return None
153
+
154
+ if not raw:
155
+ return None
156
+
157
+ # 先尝试新格式(JSON)。/ Try the new (JSON) format first.
158
+ try:
159
+ data = json.loads(raw)
160
+ if isinstance(data, dict) and "pid" in data:
161
+ pid = int(data["pid"])
162
+ identity = {
163
+ "lstart": data.get("lstart"),
164
+ "cmdline": data.get("cmdline"),
165
+ }
166
+ # 身份字段都缺失则视为无身份信息(降级)。
167
+ # If all identity fields are missing, treat as no identity info (degrade).
168
+ if identity["lstart"] is None and identity["cmdline"] is None:
169
+ identity = None
170
+ return pid, identity
171
+ except (ValueError, TypeError):
172
+ pass
173
+
174
+ # 回退到旧格式:纯整数。/ Fall back to legacy format: plain integer.
175
+ try:
176
+ return int(raw), None
177
+ except ValueError:
178
+ return None
179
+
180
+
181
+ def read_pid(pid_file: Path) -> int | None:
182
+ """读取 pidfile 中的 pid(兼容新旧格式)/ Read the pid from the pidfile (both formats)."""
183
+
184
+ record = read_pid_record(pid_file)
185
+ if record is None:
186
+ return None
187
+ return record[0]
188
+
189
+
190
+ def start_daemon(
191
+ *,
192
+ argv: list[str],
193
+ workspace: Path,
194
+ paths: DaemonPaths,
195
+ env: dict[str, str] | None = None,
196
+ popen: Callable[..., subprocess.Popen] = subprocess.Popen,
197
+ ) -> int:
198
+ """后台启动进程并写 pidfile。
199
+
200
+ Start process in background and write pidfile.
201
+
202
+ Returns:
203
+ pid
204
+ """
205
+
206
+ # 用身份校验判断已有进程是否真的还活着,避免 PID 复用把无关进程当作存活而拒绝启动。
207
+ # Use identity-aware liveness so a reused PID (an unrelated process) is not mistaken as alive.
208
+ existing_record = read_pid_record(paths.pid_file)
209
+ if existing_record is not None:
210
+ existing_pid, existing_identity = existing_record
211
+ if existing_pid and _pid_alive_as_recorded(existing_pid, existing_identity):
212
+ return existing_pid
213
+
214
+ paths.pid_file.parent.mkdir(parents=True, exist_ok=True)
215
+ paths.log_file.parent.mkdir(parents=True, exist_ok=True)
216
+
217
+ merged_env = os.environ.copy()
218
+ if env:
219
+ merged_env.update(env)
220
+
221
+ # Append to log file, do not truncate.
222
+ # 追加日志,避免覆盖。
223
+ log_fp = open(paths.log_file, "a", encoding="utf-8")
224
+ try:
225
+ proc = popen(
226
+ argv,
227
+ cwd=str(workspace),
228
+ stdout=log_fp,
229
+ stderr=log_fp,
230
+ start_new_session=True,
231
+ env=merged_env,
232
+ text=True,
233
+ )
234
+ finally:
235
+ # child keeps the fd; safe to close in parent.
236
+ # 子进程会继承 fd;父进程关闭即可。
237
+ log_fp.close()
238
+
239
+ # Give it a brief moment to fail fast.
240
+ # 短暂等待以便“快速失败”。
241
+ time.sleep(0.2)
242
+ if proc.poll() is not None:
243
+ raise RuntimeError(f"Failed to start daemon: exited with code {proc.returncode}")
244
+
245
+ # 不仅靠"没退出"判成功:再确认该 pid 当前确实是一个存活进程,并抓取其身份信息写入 pidfile。
246
+ # Don't rely only on "didn't exit": confirm the pid is a live process now and capture its
247
+ # identity to persist into the pidfile.
248
+ if not _pid_alive(proc.pid):
249
+ raise RuntimeError(f"Failed to start daemon: pid {proc.pid} not alive after launch")
250
+
251
+ identity = _proc_identity(proc.pid)
252
+ record: dict = {"pid": proc.pid}
253
+ if identity:
254
+ record.update(identity)
255
+ else:
256
+ # 拿不到身份信息(如 ps 不可用):写入纯 pid,仍然向后兼容(判活时降级为旧行为)。
257
+ # No identity available (e.g. ps unavailable): write plain pid, still backward-compatible
258
+ # (liveness check degrades to legacy behavior).
259
+ log.warning("Could not capture process identity for pid=%s; pidfile will use legacy format", proc.pid)
260
+
261
+ paths.pid_file.write_text(json.dumps(record), encoding="utf-8")
262
+ return proc.pid
263
+
264
+
265
+ def stop_daemon(
266
+ *,
267
+ paths: DaemonPaths,
268
+ timeout_seconds: float = 5.0,
269
+ remover: Callable[[Path], None] | None = None,
270
+ ) -> bool:
271
+ """停止后台进程(SIGTERM -> SIGKILL)。
272
+
273
+ Stop daemon process (SIGTERM then SIGKILL).
274
+
275
+ Returns:
276
+ True if a process was stopped, False if pidfile missing/dead.
277
+ """
278
+
279
+ record = read_pid_record(paths.pid_file)
280
+ if record is None:
281
+ return False
282
+
283
+ pid, identity = record
284
+ if not pid:
285
+ return False
286
+
287
+ # 身份校验:若该 pid 已被复用为其它进程(或已死),不要向它发信号,避免误杀无关进程。
288
+ # Identity check: if the pid has been reused by another process (or is dead), do not signal
289
+ # it, to avoid killing an unrelated process.
290
+ if not _pid_alive_as_recorded(pid, identity):
291
+ try:
292
+ paths.pid_file.unlink(missing_ok=True)
293
+ except Exception as exc: # noqa: BLE001
294
+ log.warning("Failed to remove stale pidfile %s: %s", paths.pid_file, exc)
295
+ return False
296
+
297
+ os.kill(pid, signal.SIGTERM)
298
+ deadline = time.time() + timeout_seconds
299
+ while time.time() < deadline:
300
+ if not _pid_alive(pid):
301
+ break
302
+ time.sleep(0.1)
303
+
304
+ if _pid_alive(pid):
305
+ os.kill(pid, signal.SIGKILL)
306
+
307
+ try:
308
+ paths.pid_file.unlink(missing_ok=True)
309
+ except Exception as exc: # noqa: BLE001
310
+ log.warning("Failed to remove pidfile %s after stop: %s", paths.pid_file, exc)
311
+
312
+ if remover:
313
+ try:
314
+ remover(paths.pid_file)
315
+ except Exception as exc: # noqa: BLE001
316
+ log.warning("pidfile remover callback failed for %s: %s", paths.pid_file, exc)
317
+
318
+ return True
@@ -0,0 +1,103 @@
1
+ """Optional override support for Cancan-managed services.
2
+
3
+ 允许业务仓库通过 ``cancan_overrides`` 目录注入 controllersrv / infrasrv /
4
+ opsbffsrv 的自定义配置,而无需 fork 主库。
5
+ Optional overrides so downstream workspaces can inject custom files without forking.
6
+ """
7
+ import os
8
+ import pkgutil
9
+ from pathlib import Path
10
+ from typing import (
11
+ Iterable,
12
+ List,
13
+ Optional,
14
+ )
15
+
16
+ from cancan_microstack.public.const.overrides_consts import (
17
+ OVERRIDE_DIR_NAME,
18
+ OVERRIDE_ENV,
19
+ )
20
+
21
+ from .workspace import configure_workspace, get_workspace_root
22
+
23
+ _override_root: Optional[Path] = None
24
+
25
+
26
+ def configure_overrides(root: Path | str | None = None) -> Optional[Path]:
27
+ """显式设置 overrides 根目录(None 时自动探测)。
28
+
29
+ Explicitly set override root; auto-discover when None.
30
+ """
31
+
32
+ global _override_root
33
+ if isinstance(root, str):
34
+ override_path = Path(root)
35
+ elif root is None:
36
+ override_path = discover_override_root()
37
+ else:
38
+ override_path = root
39
+
40
+ if not override_path:
41
+ _override_root = None
42
+ return None
43
+
44
+ resolved = override_path.resolve()
45
+ if not resolved.exists():
46
+ return None
47
+ _override_root = resolved
48
+ os.environ[OVERRIDE_ENV] = str(resolved)
49
+ return resolved
50
+
51
+
52
+ def discover_override_root(start: Path | None = None) -> Optional[Path]:
53
+ """从 workspace 起向上寻找 ``cancan_overrides`` 目录 / Search upward for overrides folder."""
54
+
55
+ env_value = os.environ.get(OVERRIDE_ENV)
56
+ if env_value:
57
+ candidate = Path(env_value).expanduser().resolve()
58
+ if candidate.exists():
59
+ return candidate
60
+
61
+ workspace = start or get_workspace_root()
62
+ for candidate in [workspace, *workspace.parents]:
63
+ override_dir = candidate / OVERRIDE_DIR_NAME
64
+ if override_dir.exists():
65
+ return override_dir
66
+ return None
67
+
68
+
69
+ def get_override_root() -> Optional[Path]:
70
+ """返回当前 overrides 根目录(若存在)/ Return current override root when configured."""
71
+
72
+ if _override_root is not None:
73
+ return _override_root
74
+ return configure_overrides(os.environ.get(OVERRIDE_ENV))
75
+
76
+
77
+ def extend_service_package(service_name: str, package_name: str, package_path: Iterable[str]) -> List[str]:
78
+ """扩展 cancan_microstack.services 的搜索路径以支持 overrides。
79
+
80
+ If ``cancan_overrides/<service_name>`` exists, prepend it to module search path
81
+ so workspace files override packaged ones.
82
+ """
83
+
84
+ override_root = get_override_root()
85
+ if not override_root:
86
+ return list(package_path)
87
+
88
+ service_override = override_root / service_name
89
+ if not service_override.exists():
90
+ return list(package_path)
91
+
92
+ combined_paths = [str(service_override), *package_path]
93
+ return list(pkgutil.extend_path(combined_paths, package_name))
94
+
95
+
96
+ def bootstrap_from_workspace(workspace: Path | None) -> None:
97
+ """在启动前同时配置 workspace 与 overrides。
98
+
99
+ Ensure workspace and overrides are configured together before startup.
100
+ """
101
+
102
+ effective_root = configure_workspace(workspace)
103
+ configure_overrides(discover_override_root(effective_root))
@@ -0,0 +1,25 @@
1
+ """Helpers for resolving workspace overrides vs packaged assets.
2
+
3
+ 工作区文件优先,包内资产兜底。
4
+ Prefer workspace files; fall back to packaged assets when missing.
5
+ """
6
+ from pathlib import Path
7
+
8
+ from cancan_microstack.core.assets import AssetManager
9
+
10
+ from .workspace import get_workspace_root
11
+
12
+ _asset_manager = AssetManager()
13
+
14
+
15
+ def resolve_workspace_or_asset(relative_path: str, asset_logical: str) -> Path:
16
+ """工作区路径优先,缺失时使用包资产。
17
+
18
+ Prefer workspace-relative path; fall back to packaged asset when missing.
19
+ """
20
+
21
+ workspace_root = get_workspace_root()
22
+ candidate = workspace_root / relative_path
23
+ if candidate.exists():
24
+ return candidate
25
+ return _asset_manager.resolve_path(asset_logical)
@@ -0,0 +1,94 @@
1
+ """Workspace detection helpers for Cancan Microstack.
2
+
3
+ 用于在宿主项目中自动定位工作目录,并提供 server_log_data 等通用路径。
4
+ Detect workspace roots in host projects and provision common paths like server_log_data.
5
+ """
6
+ import os
7
+ from pathlib import Path
8
+ from typing import Optional
9
+
10
+ _WORKSPACE_ENV = "CANCAN_WORKSPACE_ROOT"
11
+ _LOG_DIR_NAME = "server_log_data"
12
+ _MARKERS: tuple[str, ...] = (
13
+ "server_log_data",
14
+ "cmd",
15
+ "docker-compose.infra.yml",
16
+ "docker-compose.services.yml",
17
+ "pyproject.toml",
18
+ "requirements.txt",
19
+ )
20
+
21
+ _workspace_root: Optional[Path] = None
22
+
23
+
24
+ def configure_workspace(root: Path | str | None = None) -> Path:
25
+ """配置或重新配置当前 workspace 根。
26
+
27
+ 设置当前 Cancan 工作目录,可显式传入路径,也可依赖自动探测。
28
+ Configure the current Cancan workspace root (explicit or auto-detected).
29
+ """
30
+
31
+ global _workspace_root
32
+ if isinstance(root, str):
33
+ root_path = Path(root)
34
+ elif root is None:
35
+ root_path = detect_workspace_root()
36
+ else:
37
+ root_path = root
38
+
39
+ _workspace_root = root_path.resolve()
40
+ os.environ[_WORKSPACE_ENV] = str(_workspace_root)
41
+ return _workspace_root
42
+
43
+
44
+ def get_workspace_root() -> Path:
45
+ """返回已配置的 workspace 根;若未配置则懒加载探测。
46
+
47
+ Return configured workspace root, lazily detecting when absent.
48
+ """
49
+
50
+ if _workspace_root is not None:
51
+ return _workspace_root
52
+ return configure_workspace(os.environ.get(_WORKSPACE_ENV))
53
+
54
+
55
+ def detect_workspace_root(start: Path | str | None = None) -> Path:
56
+ """探测 workspace 根(环境变量优先,其次向上遍历寻找标记)。
57
+
58
+ Detect workspace root using env var or upward marker walk.
59
+ """
60
+
61
+ env_value = os.environ.get(_WORKSPACE_ENV)
62
+ if env_value:
63
+ return Path(env_value).expanduser().resolve()
64
+
65
+ start_path = Path(start or Path.cwd()).resolve()
66
+ for candidate in [start_path, *start_path.parents]:
67
+ if _has_markers(candidate):
68
+ return candidate
69
+ return start_path
70
+
71
+
72
+ def ensure_server_log_dir() -> Path:
73
+ """确保标准日志目录存在 / Ensure canonical ``server_log_data`` exists."""
74
+
75
+ root = get_workspace_root()
76
+ log_dir = root / _LOG_DIR_NAME
77
+ log_dir.mkdir(parents=True, exist_ok=True)
78
+ return log_dir
79
+
80
+
81
+ def ensure_subdir(relative_path: str) -> Path:
82
+ """确保 workspace 下子目录存在并返回路径 / Ensure subdir exists under workspace."""
83
+
84
+ root = get_workspace_root()
85
+ target = root / relative_path
86
+ target.mkdir(parents=True, exist_ok=True)
87
+ return target
88
+
89
+
90
+ def _has_markers(candidate: Path) -> bool:
91
+ for marker in _MARKERS:
92
+ if (candidate / marker).exists():
93
+ return True
94
+ return False
File without changes
@@ -0,0 +1,8 @@
1
+ """controllersrv - Docker Compose 控制器服务。
2
+
3
+ 这是一个特殊的服务,运行在宿主机上,负责管理 Docker Compose 集群,
4
+ 不需要进行服务注册、配置拉取等常规微服务操作。
5
+ """
6
+ from cancan_microstack.runtime.overrides import extend_service_package
7
+
8
+ __path__ = extend_service_package("controllersrv", __name__, __path__) # type: ignore[name-defined]