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,285 @@
1
+ """认证用例编排 / Authentication application service (use case orchestration)."""
2
+ import http
3
+ from dataclasses import dataclass
4
+ from typing import Optional
5
+
6
+ from pydantic import BaseModel
7
+
8
+ from linglong_web import LinglongConfig
9
+ from linglong_web.utils import logger
10
+
11
+ from cancan_microstack.public.const.opsbffsrv_error import OpsbffsrvAuthErrorCode
12
+ from cancan_microstack.public.error import HTTPException
13
+ from cancan_microstack.services.opsbffsrv.domain.auth import auth_domain
14
+ from cancan_microstack.services.opsbffsrv.infrastructure.auth import (
15
+ captcha_service,
16
+ redis_store,
17
+ totp_service,
18
+ )
19
+ from cancan_microstack.services.opsbffsrv.infrastructure.db.operate.admin_user_operate import (
20
+ get_admin_user_by_id,
21
+ mark_totp_bound,
22
+ update_totp_secret,
23
+ )
24
+
25
+
26
+ # ── Request / Response schemas ───────────────────────────────────────────────
27
+
28
+ class LoginRequest(BaseModel):
29
+ username: str
30
+ password: str
31
+ captcha_id: str
32
+ captcha_answer: str
33
+
34
+
35
+ class LoginResponse(BaseModel):
36
+ next_step: str # "totp_bind" | "totp_verify"
37
+ temp_token: str
38
+
39
+
40
+ class CaptchaResponse(BaseModel):
41
+ captcha_id: str
42
+ image_base64: str
43
+
44
+
45
+ class TotpSetupResponse(BaseModel):
46
+ otpauth_uri: str
47
+ qr_code_base64: str
48
+
49
+
50
+ class TempTokenRequest(BaseModel):
51
+ temp_token: str
52
+
53
+
54
+ class TotpCodeRequest(BaseModel):
55
+ temp_token: str
56
+ totp_code: str
57
+
58
+
59
+ class SessionResponse(BaseModel):
60
+ authenticated: bool
61
+ username: str
62
+
63
+
64
+ # ── Application methods ──────────────────────────────────────────────────────
65
+
66
+ async def _enforce_totp_attempt_limit(temp_token: str) -> None:
67
+ """TOTP 暴力破解防护:超过上限则失效 temp_token 并拒绝。
68
+
69
+ Guard against TOTP brute force: once the per-temp_token failure count
70
+ reaches the configured cap, invalidate the temp_token and reject the request.
71
+ Call this BEFORE verifying the TOTP code on each attempt.
72
+ """
73
+ max_failures = int(getattr(LinglongConfig, "AUTH_TOTP_MAX_FAILURES", 5))
74
+ fail_count = await redis_store.get_totp_fail_count(temp_token)
75
+ if fail_count >= max_failures:
76
+ # 失效 token,强制用户重新走密码登录流程
77
+ await redis_store.delete_temp_token(temp_token)
78
+ await redis_store.reset_totp_fail(temp_token)
79
+ raise HTTPException(
80
+ status_code=http.HTTPStatus.UNAUTHORIZED.value,
81
+ error_code=OpsbffsrvAuthErrorCode.TEMP_TOKEN_INVALID,
82
+ msg="Too many invalid TOTP attempts; please log in again",
83
+ )
84
+
85
+
86
+ async def _record_totp_failure(temp_token: str) -> None:
87
+ """记录一次 TOTP 失败 / Record one TOTP failure for a temp token."""
88
+ temp_ttl = int(getattr(LinglongConfig, "AUTH_TEMP_TOKEN_TTL", 300))
89
+ await redis_store.increment_totp_fail(temp_token, ttl=temp_ttl)
90
+
91
+
92
+ async def get_captcha() -> CaptchaResponse:
93
+ """生成并存储验证码 / Generate captcha and save to Redis."""
94
+ captcha_id, answer, image_base64 = captcha_service.generate_captcha()
95
+ captcha_ttl = int(LinglongConfig.get("AUTH_CAPTCHA_TTL", 60))
96
+ await redis_store.save_captcha(captcha_id, answer, ttl=captcha_ttl)
97
+ return CaptchaResponse(captcha_id=captcha_id, image_base64=image_base64)
98
+
99
+
100
+ async def login(req: LoginRequest, client_ip: str) -> LoginResponse:
101
+ """登录入口 / Login: validate captcha → authenticate → return next step."""
102
+ # 1. 校验验证码
103
+ if not await auth_domain.validate_captcha(req.captcha_id, req.captcha_answer):
104
+ raise HTTPException(
105
+ status_code=http.HTTPStatus.BAD_REQUEST.value,
106
+ error_code=OpsbffsrvAuthErrorCode.CAPTCHA_INVALID,
107
+ msg="Invalid captcha",
108
+ )
109
+
110
+ # 2. 认证
111
+ result = await auth_domain.authenticate(req.username, req.password, client_ip)
112
+ if not result.success:
113
+ status = (
114
+ http.HTTPStatus.FORBIDDEN.value
115
+ if result.error_code == "AUTH_IP_LOCKED"
116
+ else http.HTTPStatus.UNAUTHORIZED.value
117
+ )
118
+ code = {
119
+ "AUTH_IP_LOCKED": OpsbffsrvAuthErrorCode.IP_LOCKED,
120
+ "AUTH_CREDENTIALS_INVALID": OpsbffsrvAuthErrorCode.CREDENTIALS_INVALID,
121
+ }.get(result.error_code, OpsbffsrvAuthErrorCode.INTERNAL_ERROR)
122
+ raise HTTPException(status_code=status, error_code=code, msg=result.error_msg)
123
+
124
+ # 3. 返回下一步
125
+ next_step = "totp_bind" if not result.totp_bound else "totp_verify"
126
+ return LoginResponse(next_step=next_step, temp_token=result.temp_token)
127
+
128
+
129
+ async def totp_setup(temp_token: str) -> TotpSetupResponse:
130
+ """获取 TOTP 绑定信息 / Get TOTP provisioning URI and QR code."""
131
+ user_id = await redis_store.get_temp_token(temp_token)
132
+ if user_id is None:
133
+ raise HTTPException(
134
+ status_code=http.HTTPStatus.UNAUTHORIZED.value,
135
+ error_code=OpsbffsrvAuthErrorCode.TEMP_TOKEN_INVALID,
136
+ msg="Temp token invalid or expired",
137
+ )
138
+
139
+ user = await get_admin_user_by_id(user_id)
140
+ if user is None:
141
+ raise HTTPException(
142
+ status_code=http.HTTPStatus.UNAUTHORIZED.value,
143
+ error_code=OpsbffsrvAuthErrorCode.TEMP_TOKEN_INVALID,
144
+ msg="User not found",
145
+ )
146
+
147
+ # 如果已有加密 secret 则解密复用,否则生成新的
148
+ if user.totp_secret_encrypted:
149
+ secret = totp_service.decrypt_secret(user.totp_secret_encrypted)
150
+ else:
151
+ secret = totp_service.generate_secret()
152
+ encrypted = totp_service.encrypt_secret(secret)
153
+ await update_totp_secret(user.id, encrypted)
154
+
155
+ uri = totp_service.get_provisioning_uri(secret, user.username)
156
+ qr_base64 = totp_service.generate_qr_base64(uri)
157
+
158
+ return TotpSetupResponse(otpauth_uri=uri, qr_code_base64=qr_base64)
159
+
160
+
161
+ async def totp_bind(temp_token: str, totp_code: str) -> Optional[str]:
162
+ """完成 TOTP 绑定 / Bind TOTP: verify code → mark bound → create session.
163
+
164
+ Returns:
165
+ session token string on success.
166
+ """
167
+ user_id = await redis_store.get_temp_token(temp_token)
168
+ if user_id is None:
169
+ raise HTTPException(
170
+ status_code=http.HTTPStatus.UNAUTHORIZED.value,
171
+ error_code=OpsbffsrvAuthErrorCode.TEMP_TOKEN_INVALID,
172
+ msg="Temp token invalid or expired",
173
+ )
174
+
175
+ # 暴力破解防护:超过上限直接失效 token
176
+ await _enforce_totp_attempt_limit(temp_token)
177
+
178
+ user = await get_admin_user_by_id(user_id)
179
+ if user is None:
180
+ raise HTTPException(
181
+ status_code=http.HTTPStatus.UNAUTHORIZED.value,
182
+ error_code=OpsbffsrvAuthErrorCode.TEMP_TOKEN_INVALID,
183
+ msg="User not found",
184
+ )
185
+
186
+ if user.totp_bound:
187
+ raise HTTPException(
188
+ status_code=http.HTTPStatus.BAD_REQUEST.value,
189
+ error_code=OpsbffsrvAuthErrorCode.TOTP_ALREADY_BOUND,
190
+ msg="TOTP already bound",
191
+ )
192
+
193
+ if not user.totp_secret_encrypted:
194
+ raise HTTPException(
195
+ status_code=http.HTTPStatus.BAD_REQUEST.value,
196
+ error_code=OpsbffsrvAuthErrorCode.TOTP_INVALID,
197
+ msg="TOTP has not been set up",
198
+ )
199
+
200
+ secret = totp_service.decrypt_secret(user.totp_secret_encrypted)
201
+ if not totp_service.verify_totp(secret, totp_code):
202
+ await _record_totp_failure(temp_token)
203
+ raise HTTPException(
204
+ status_code=http.HTTPStatus.BAD_REQUEST.value,
205
+ error_code=OpsbffsrvAuthErrorCode.TOTP_INVALID,
206
+ msg="Invalid TOTP code",
207
+ )
208
+
209
+ # 绑定成功
210
+ await mark_totp_bound(user.id)
211
+ await redis_store.delete_temp_token(temp_token)
212
+ await redis_store.reset_totp_fail(temp_token)
213
+ session_token = await auth_domain.create_session_token(user.id)
214
+ return session_token
215
+
216
+
217
+ async def totp_verify(temp_token: str, totp_code: str) -> Optional[str]:
218
+ """常规 TOTP 验证 / Verify TOTP for regular login.
219
+
220
+ Returns:
221
+ session token string on success.
222
+ """
223
+ user_id = await redis_store.get_temp_token(temp_token)
224
+ if user_id is None:
225
+ raise HTTPException(
226
+ status_code=http.HTTPStatus.UNAUTHORIZED.value,
227
+ error_code=OpsbffsrvAuthErrorCode.TEMP_TOKEN_INVALID,
228
+ msg="Temp token invalid or expired",
229
+ )
230
+
231
+ # 暴力破解防护:超过上限直接失效 token
232
+ await _enforce_totp_attempt_limit(temp_token)
233
+
234
+ user = await get_admin_user_by_id(user_id)
235
+ if user is None:
236
+ raise HTTPException(
237
+ status_code=http.HTTPStatus.UNAUTHORIZED.value,
238
+ error_code=OpsbffsrvAuthErrorCode.TEMP_TOKEN_INVALID,
239
+ msg="User not found",
240
+ )
241
+
242
+ if not user.totp_secret_encrypted:
243
+ raise HTTPException(
244
+ status_code=http.HTTPStatus.BAD_REQUEST.value,
245
+ error_code=OpsbffsrvAuthErrorCode.TOTP_INVALID,
246
+ msg="TOTP not configured",
247
+ )
248
+
249
+ secret = totp_service.decrypt_secret(user.totp_secret_encrypted)
250
+ if not totp_service.verify_totp(secret, totp_code):
251
+ await _record_totp_failure(temp_token)
252
+ raise HTTPException(
253
+ status_code=http.HTTPStatus.BAD_REQUEST.value,
254
+ error_code=OpsbffsrvAuthErrorCode.TOTP_INVALID,
255
+ msg="Invalid TOTP code",
256
+ )
257
+
258
+ # 验证成功
259
+ await redis_store.delete_temp_token(temp_token)
260
+ await redis_store.reset_totp_fail(temp_token)
261
+ session_token = await auth_domain.create_session_token(user.id)
262
+ return session_token
263
+
264
+
265
+ async def logout(token: Optional[str]) -> None:
266
+ """登出 / Logout: revoke the session token in Redis (idempotent)."""
267
+ if token:
268
+ await auth_domain.revoke_session(token)
269
+
270
+
271
+ async def check_session(token: str) -> Optional[SessionResponse]:
272
+ """检查 session 有效性 / Check if session token is valid.
273
+
274
+ Returns:
275
+ SessionResponse if valid, None if invalid.
276
+ """
277
+ user_id = await auth_domain.verify_session(token)
278
+ if user_id is None:
279
+ return None
280
+
281
+ user = await get_admin_user_by_id(user_id)
282
+ if user is None:
283
+ return None
284
+
285
+ return SessionResponse(authenticated=True, username=user.username)
@@ -0,0 +1,344 @@
1
+ """
2
+ Caddy 访问日志应用服务
3
+ 协调访问日志接收、查询和分析的业务流程
4
+ """
5
+ from typing import (
6
+ Any,
7
+ Dict,
8
+ List,
9
+ Optional,
10
+ )
11
+ from datetime import datetime
12
+ from linglong_web.utils import logger
13
+ from cancan_microstack.public.schemas.caddy import CaddyAccessLog, AccessLogQuery
14
+ from cancan_microstack.services.opsbffsrv.domain.caddy.access_log_analysis import AccessLogAnalysisDomain
15
+
16
+
17
+ class AccessLogAnalysisApp:
18
+ """访问日志应用服务"""
19
+
20
+ def __init__(self):
21
+ self.domain = AccessLogAnalysisDomain()
22
+
23
+ async def ingest_single_log(self, log_data: Dict[str, Any]) -> Dict[str, Any]:
24
+ """
25
+ 接收单条访问日志
26
+
27
+ Args:
28
+ log_data: 日志数据字典
29
+
30
+ Returns:
31
+ 结果字典
32
+ """
33
+ logger.debug("Ingesting single access log")
34
+
35
+ try:
36
+ log_entry = await self.domain.ingest_log_entry(log_data)
37
+
38
+ return {
39
+ "status": "success",
40
+ "log": log_entry
41
+ }
42
+ except ValueError as e:
43
+ logger.warning(f"Log ingestion failed: {e}")
44
+ return {
45
+ "status": "error",
46
+ "error": str(e)
47
+ }
48
+ except Exception as e:
49
+ logger.error(f"Error ingesting log: {e}", exc_info=True)
50
+ return {
51
+ "status": "error",
52
+ "error": "Internal server error"
53
+ }
54
+
55
+ async def ingest_batch_logs(self, log_lines: List[str]) -> Dict[str, Any]:
56
+ """
57
+ 批量接收访问日志
58
+
59
+ Args:
60
+ log_lines: JSON 格式的日志行列表
61
+
62
+ Returns:
63
+ 结果字典
64
+ """
65
+ logger.info(f"Ingesting batch of {len(log_lines)} logs")
66
+
67
+ try:
68
+ ingested_count = await self.domain.ingest_log_batch(log_lines)
69
+
70
+ return {
71
+ "status": "success",
72
+ "message": f"Successfully ingested {ingested_count} logs",
73
+ "count": ingested_count
74
+ }
75
+ except Exception as e:
76
+ logger.error(f"Error ingesting batch logs: {e}", exc_info=True)
77
+ return {
78
+ "status": "error",
79
+ "error": str(e)
80
+ }
81
+
82
+ async def search_logs(self, query: AccessLogQuery) -> List[CaddyAccessLog]:
83
+ """
84
+ 搜索访问日志
85
+
86
+ Args:
87
+ query: 查询参数
88
+
89
+ Returns:
90
+ 访问日志列表
91
+ """
92
+ logger.info("Searching access logs")
93
+
94
+ try:
95
+ return await self.domain.search_logs(query)
96
+ except ValueError as e:
97
+ logger.warning(f"Invalid query parameters: {e}")
98
+ return []
99
+ except Exception as e:
100
+ logger.error(f"Error searching logs: {e}", exc_info=True)
101
+ return []
102
+
103
+ async def get_log_details(self, log_id: int) -> Optional[CaddyAccessLog]:
104
+ """
105
+ 获取访问日志详情
106
+
107
+ Args:
108
+ log_id: 日志 ID
109
+
110
+ Returns:
111
+ 访问日志对象或 None
112
+ """
113
+ return await self.domain.get_log_details(log_id)
114
+
115
+ async def get_log_by_request_id(self, request_id: str) -> Optional[CaddyAccessLog]:
116
+ """
117
+ 根据请求 ID 获取访问日志
118
+
119
+ Args:
120
+ request_id: 请求 ID
121
+
122
+ Returns:
123
+ 访问日志对象或 None
124
+ """
125
+ return await self.domain.get_log_by_request_id(request_id)
126
+
127
+ async def get_logs_for_ip(self, client_ip: str, limit: int = 100) -> List[CaddyAccessLog]:
128
+ """
129
+ 获取指定 IP 的访问日志
130
+
131
+ Args:
132
+ client_ip: 客户端 IP
133
+ limit: 返回数量限制
134
+
135
+ Returns:
136
+ 访问日志列表
137
+ """
138
+ return await self.domain.get_logs_for_ip(client_ip, limit)
139
+
140
+ async def get_logs_for_service(self, service: str, limit: int = 100) -> List[CaddyAccessLog]:
141
+ """
142
+ 获取指定服务的访问日志
143
+
144
+ Args:
145
+ service: 服务名称
146
+ limit: 返回数量限制
147
+
148
+ Returns:
149
+ 访问日志列表
150
+ """
151
+ return await self.domain.get_logs_for_service(service, limit)
152
+
153
+ async def get_security_events(self, event_type: str = 'waf_blocked', limit: int = 100) -> Dict[str, Any]:
154
+ """
155
+ 获取安全事件日志
156
+
157
+ Args:
158
+ event_type: 事件类型(waf_blocked/rate_limited)
159
+ limit: 返回数量限制
160
+
161
+ Returns:
162
+ 安全事件数据
163
+ """
164
+ logger.info(f"Fetching security events: {event_type}")
165
+
166
+ try:
167
+ events = await self.domain.get_security_events(event_type, limit)
168
+
169
+ return {
170
+ "status": "success",
171
+ "event_type": event_type,
172
+ "count": len(events),
173
+ "data": events
174
+ }
175
+ except ValueError as e:
176
+ return {
177
+ "status": "error",
178
+ "error": str(e)
179
+ }
180
+ except Exception as e:
181
+ logger.error(f"Error fetching security events: {e}", exc_info=True)
182
+ return {
183
+ "status": "error",
184
+ "error": str(e)
185
+ }
186
+
187
+ async def analyze_geographic_distribution(
188
+ self,
189
+ start_time: Optional[datetime] = None,
190
+ end_time: Optional[datetime] = None
191
+ ) -> Dict[str, Any]:
192
+ """
193
+ 分析访问的地理分布
194
+
195
+ Args:
196
+ start_time: 开始时间
197
+ end_time: 结束时间
198
+
199
+ Returns:
200
+ 地理分布数据
201
+ """
202
+ logger.info("Analyzing geographic distribution")
203
+
204
+ try:
205
+ distribution = await self.domain.analyze_geographic_distribution(start_time, end_time)
206
+
207
+ return {
208
+ "status": "success",
209
+ "data": distribution
210
+ }
211
+ except Exception as e:
212
+ logger.error(f"Error analyzing geographic distribution: {e}", exc_info=True)
213
+ return {
214
+ "status": "error",
215
+ "error": str(e)
216
+ }
217
+
218
+ async def analyze_status_code_distribution(
219
+ self,
220
+ start_time: Optional[datetime] = None,
221
+ end_time: Optional[datetime] = None
222
+ ) -> Dict[str, Any]:
223
+ """
224
+ 分析 HTTP 状态码分布
225
+
226
+ Args:
227
+ start_time: 开始时间
228
+ end_time: 结束时间
229
+
230
+ Returns:
231
+ 状态码分布数据
232
+ """
233
+ logger.info("Analyzing status code distribution")
234
+
235
+ try:
236
+ distribution = await self.domain.analyze_status_code_distribution(start_time, end_time)
237
+
238
+ return {
239
+ "status": "success",
240
+ "data": distribution
241
+ }
242
+ except Exception as e:
243
+ logger.error(f"Error analyzing status code distribution: {e}", exc_info=True)
244
+ return {
245
+ "status": "error",
246
+ "error": str(e)
247
+ }
248
+
249
+ async def detect_suspicious_ips(
250
+ self,
251
+ time_window: int = 60,
252
+ request_threshold: int = 1000
253
+ ) -> Dict[str, Any]:
254
+ """
255
+ 检测可疑 IP(高频访问)
256
+
257
+ Args:
258
+ time_window: 时间窗口(分钟)
259
+ request_threshold: 请求数阈值
260
+
261
+ Returns:
262
+ 可疑 IP 数据
263
+ """
264
+ logger.info(f"Detecting suspicious IPs: window={time_window}min, threshold={request_threshold}")
265
+
266
+ try:
267
+ suspicious_ips = await self.domain.detect_suspicious_ips(time_window, request_threshold)
268
+
269
+ return {
270
+ "status": "success",
271
+ "count": len(suspicious_ips),
272
+ "data": suspicious_ips
273
+ }
274
+ except Exception as e:
275
+ logger.error(f"Error detecting suspicious IPs: {e}", exc_info=True)
276
+ return {
277
+ "status": "error",
278
+ "error": str(e)
279
+ }
280
+
281
+ async def analyze_error_patterns(self, hours: int = 24) -> Dict[str, Any]:
282
+ """
283
+ 分析错误模式
284
+
285
+ Args:
286
+ hours: 过去多少小时
287
+
288
+ Returns:
289
+ 错误分析结果
290
+ """
291
+ logger.info(f"Analyzing error patterns for the past {hours} hours")
292
+
293
+ try:
294
+ error_analysis = await self.domain.analyze_error_patterns(hours)
295
+
296
+ # domain 返回 ErrorPatternAnalysis (pydantic),需先 model_dump 才能展开
297
+ return {
298
+ "status": "success",
299
+ **error_analysis.model_dump()
300
+ }
301
+ except Exception as e:
302
+ logger.error(f"Error analyzing error patterns: {e}", exc_info=True)
303
+ return {
304
+ "status": "error",
305
+ "error": str(e)
306
+ }
307
+
308
+ async def cleanup_old_logs(self, days: int = 30) -> Dict[str, Any]:
309
+ """
310
+ 清理旧的访问日志
311
+
312
+ Args:
313
+ days: 保留天数
314
+
315
+ Returns:
316
+ 清理结果
317
+ """
318
+ logger.info(f"Cleaning up logs older than {days} days")
319
+
320
+ try:
321
+ deleted_count = await self.domain.cleanup_old_logs(days)
322
+
323
+ return {
324
+ "status": "success",
325
+ "message": f"Deleted {deleted_count} old access log records"
326
+ }
327
+ except Exception as e:
328
+ logger.error(f"Error cleaning up logs: {e}", exc_info=True)
329
+ return {
330
+ "status": "error",
331
+ "error": str(e)
332
+ }
333
+
334
+ async def get_log_count(self, filters: Optional[Dict[str, Any]] = None) -> int:
335
+ """
336
+ 获取日志数量
337
+
338
+ Args:
339
+ filters: 过滤条件
340
+
341
+ Returns:
342
+ 日志数量
343
+ """
344
+ return await self.domain.get_log_count(filters)