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.
- cancan_microstack/__init__.py +14 -0
- cancan_microstack/__version__.py +10 -0
- cancan_microstack/assets/__init__.py +6 -0
- cancan_microstack/assets/builds/caddy/Caddyfile +187 -0
- cancan_microstack/assets/builds/caddy/DEPLOYMENT.md +303 -0
- cancan_microstack/assets/builds/caddy/Dockerfile +46 -0
- cancan_microstack/assets/builds/caddy/README.md +343 -0
- cancan_microstack/assets/builds/caddy/geoip/README.md +5 -0
- cancan_microstack/assets/builds/caddy/start.sh +78 -0
- cancan_microstack/assets/builds/caddy/waf/coraza.conf +179 -0
- cancan_microstack/assets/builds/service/Dockerfile +59 -0
- cancan_microstack/assets/builds/service/README.md +13 -0
- cancan_microstack/assets/ddl/create_db.sql +22 -0
- cancan_microstack/assets/ddl/infra/execution_log_tbl.sql +46 -0
- cancan_microstack/assets/ddl/infra/node_instance_tbl.sql +56 -0
- cancan_microstack/assets/ddl/infra/service_action_log_tbl.sql +36 -0
- cancan_microstack/assets/ddl/infra/service_config_tbl.sql +26 -0
- cancan_microstack/assets/ddl/infra/service_info_tbl.sql +45 -0
- cancan_microstack/assets/ddl/infra/service_instance_tbl.sql +54 -0
- cancan_microstack/assets/ddl/infra/service_operation_tbl.sql +47 -0
- cancan_microstack/assets/ddl/infra/workflow_definition_tbl.sql +60 -0
- cancan_microstack/assets/ddl/infra/workflow_definition_version_tbl.sql +35 -0
- cancan_microstack/assets/ddl/infra/workflow_engine_alert_tbl.sql +34 -0
- cancan_microstack/assets/ddl/infra/workflow_run_tbl.sql +52 -0
- cancan_microstack/assets/ddl/ops/admin_user_tbl.sql +34 -0
- cancan_microstack/assets/ddl/ops/caddy_access_log_tbl.sql +91 -0
- cancan_microstack/assets/ddl/ops/caddy_certificate_tbl.sql +59 -0
- cancan_microstack/assets/ddl/ops/caddy_rate_limit_tbl.sql +64 -0
- cancan_microstack/assets/ddl/ops/caddy_route_tbl.sql +63 -0
- cancan_microstack/assets/ddl/ops/caddy_stats_tbl.sql +77 -0
- cancan_microstack/assets/ddl/trigger.sql +21 -0
- cancan_microstack/assets/docker/docker-compose.infra.yml +401 -0
- cancan_microstack/assets/scripts/README.md +195 -0
- cancan_microstack/assets/scripts/docker/build_images.sh +44 -0
- cancan_microstack/assets/scripts/docker/force_rebuild_images.sh +38 -0
- cancan_microstack/assets/scripts/docker/rebuild_all.sh +34 -0
- cancan_microstack/assets/scripts/docker/rebuild_compose.sh +61 -0
- cancan_microstack/assets/scripts/docker/restart.sh +35 -0
- cancan_microstack/assets/scripts/docker/restart_compose.sh +35 -0
- cancan_microstack/assets/scripts/docker/start.sh +78 -0
- cancan_microstack/assets/scripts/docker/start_all.sh +46 -0
- cancan_microstack/assets/scripts/docker/start_compose.sh +66 -0
- cancan_microstack/assets/scripts/docker/stop.sh +67 -0
- cancan_microstack/assets/scripts/docker/stop_all.sh +38 -0
- cancan_microstack/assets/scripts/docker/stop_compose.sh +38 -0
- cancan_microstack/assets/scripts/podman/build_images_podman.sh +59 -0
- cancan_microstack/assets/scripts/podman/cleanup_podman.sh +25 -0
- cancan_microstack/assets/scripts/podman/force_rebuild_images_podman.sh +56 -0
- cancan_microstack/assets/scripts/podman/rebuild_all_podman.sh +37 -0
- cancan_microstack/assets/scripts/podman/rebuild_compose_podman.sh +60 -0
- cancan_microstack/assets/scripts/podman/restart_compose_podman.sh +73 -0
- cancan_microstack/assets/scripts/podman/start_all_podman.sh +66 -0
- cancan_microstack/assets/scripts/podman/start_compose_podman.sh +80 -0
- cancan_microstack/assets/scripts/podman/start_podman.sh +91 -0
- cancan_microstack/assets/scripts/podman/stop.sh +73 -0
- cancan_microstack/assets/scripts/podman/stop_all_podman.sh +34 -0
- cancan_microstack/assets/scripts/podman/stop_compose_podman.sh +58 -0
- cancan_microstack/assets/scripts/start_controllersrv.sh +9 -0
- cancan_microstack/assets/scripts/utils/check_all_db_tables.sh +104 -0
- cancan_microstack/assets/scripts/utils/check_env.sh +177 -0
- cancan_microstack/assets/scripts/utils/check_service_management_deployment.sh +225 -0
- cancan_microstack/assets/scripts/utils/deploy_service_management.sh +176 -0
- cancan_microstack/assets/scripts/utils/force_reload_infrasrv.sh +52 -0
- cancan_microstack/assets/scripts/utils/monitor_service_management.sh +187 -0
- cancan_microstack/assets/scripts/utils/reset_postgres_volume.sh +68 -0
- cancan_microstack/assets/scripts/utils/test_async_operations.sh +141 -0
- cancan_microstack/assets/scripts/utils/verify_real_operations.sh +76 -0
- cancan_microstack/assets/service/Dockerfile +65 -0
- cancan_microstack/assets/www/adminops/assets/AppEmpty.vue_vue_type_script_setup_true_lang-BOKUurnM.js +1 -0
- cancan_microstack/assets/www/adminops/assets/ConfigManage-DKV5YOUz.js +1 -0
- cancan_microstack/assets/www/adminops/assets/ConfigManage-Y5bhy7wG.css +1 -0
- cancan_microstack/assets/www/adminops/assets/ConsoleManage-8ljYvCW2.js +1 -0
- cancan_microstack/assets/www/adminops/assets/ConsoleManage-BWpyqbuQ.css +1 -0
- cancan_microstack/assets/www/adminops/assets/DashboardNew-B9Nf1OPl.js +1 -0
- cancan_microstack/assets/www/adminops/assets/DashboardNew-DYWZKQ1V.css +1 -0
- cancan_microstack/assets/www/adminops/assets/LogSearch-CA0Jhe78.js +1 -0
- cancan_microstack/assets/www/adminops/assets/LogSearch-CCZfTNPF.css +1 -0
- cancan_microstack/assets/www/adminops/assets/LoginView-BId3kP3M.css +1 -0
- cancan_microstack/assets/www/adminops/assets/LoginView-BQZTV_Qy.js +1 -0
- cancan_microstack/assets/www/adminops/assets/OperationProgressDialog-BdEYwqFq.js +1 -0
- cancan_microstack/assets/www/adminops/assets/OperationProgressDialog-D-pASR8G.css +1 -0
- cancan_microstack/assets/www/adminops/assets/PageContainer-Byss-yUC.js +1 -0
- cancan_microstack/assets/www/adminops/assets/PageContainer-C3nSZwM7.css +1 -0
- cancan_microstack/assets/www/adminops/assets/RateLimitManage-BDI8jLpC.css +1 -0
- cancan_microstack/assets/www/adminops/assets/RateLimitManage-DJY4NiF-.js +1 -0
- cancan_microstack/assets/www/adminops/assets/RouteManage-DaUQ4QLw.css +1 -0
- cancan_microstack/assets/www/adminops/assets/RouteManage-w9XCU0UA.js +1 -0
- cancan_microstack/assets/www/adminops/assets/ServiceCard-BFzHe6Tw.css +1 -0
- cancan_microstack/assets/www/adminops/assets/ServiceCard-BJUhWnA-.js +1 -0
- cancan_microstack/assets/www/adminops/assets/ServiceDetail-Cw24WuKp.js +1 -0
- cancan_microstack/assets/www/adminops/assets/ServiceDetail-Yum47zdB.css +1 -0
- cancan_microstack/assets/www/adminops/assets/ServiceList-C7ryvbhE.js +1 -0
- cancan_microstack/assets/www/adminops/assets/ServiceList-Cgd01fUx.css +1 -0
- cancan_microstack/assets/www/adminops/assets/ServiceLogs-COpG9H0h.js +1 -0
- cancan_microstack/assets/www/adminops/assets/ServiceLogs-H_Alq0cf.css +1 -0
- cancan_microstack/assets/www/adminops/assets/StatsOverview-D0TwMQkA.js +39 -0
- cancan_microstack/assets/www/adminops/assets/StatsOverview-lqAN6pqM.css +1 -0
- cancan_microstack/assets/www/adminops/assets/TotpBindView-CWlAmzFt.js +1 -0
- cancan_microstack/assets/www/adminops/assets/TotpBindView-HoQC1lhx.css +1 -0
- cancan_microstack/assets/www/adminops/assets/TotpVerifyView-BHN1VtX1.css +1 -0
- cancan_microstack/assets/www/adminops/assets/TotpVerifyView-D3w_lZk8.js +1 -0
- cancan_microstack/assets/www/adminops/assets/WorkflowCenter-DU_mpIA0.css +1 -0
- cancan_microstack/assets/www/adminops/assets/WorkflowCenter-i50rZyxN.js +1 -0
- cancan_microstack/assets/www/adminops/assets/WorkflowDesigner-CnHokPL9.js +1 -0
- cancan_microstack/assets/www/adminops/assets/WorkflowDesigner-DaZaZpLd.css +1 -0
- cancan_microstack/assets/www/adminops/assets/WorkflowRuns-B09hK48c.js +1 -0
- cancan_microstack/assets/www/adminops/assets/WorkflowRuns-wGutKIIU.css +1 -0
- cancan_microstack/assets/www/adminops/assets/caddy-nnCKf8fG.js +1 -0
- cancan_microstack/assets/www/adminops/assets/format-Cuzxgna9.js +1 -0
- cancan_microstack/assets/www/adminops/assets/index-CiFlm8oc.js +64 -0
- cancan_microstack/assets/www/adminops/assets/index-UW0T1Dkc.css +1 -0
- cancan_microstack/assets/www/adminops/assets/service-BYlgGPs_.js +1 -0
- cancan_microstack/assets/www/adminops/assets/service-operation-6GzLw2Z1.js +1 -0
- cancan_microstack/assets/www/adminops/assets/style-CcIXnQ5y.css +1 -0
- cancan_microstack/assets/www/adminops/assets/style-lRnStdGu.js +39 -0
- cancan_microstack/assets/www/adminops/assets/useDebounce-BRlqfXqf.js +1 -0
- cancan_microstack/assets/www/adminops/assets/workflow-CUXs39Ac.js +1 -0
- cancan_microstack/assets/www/adminops/index.html +16 -0
- cancan_microstack/assets/www/adminops/vite.svg +1 -0
- cancan_microstack/cli/__init__.py +14 -0
- cancan_microstack/cli/__main__.py +9 -0
- cancan_microstack/cli/main.py +552 -0
- cancan_microstack/cmd/__init__.py +54 -0
- cancan_microstack/cmd/cancan/__init__.py +12 -0
- cancan_microstack/cmd/cancan/run.py +395 -0
- cancan_microstack/cmd/controllersrv/__init__.py +0 -0
- cancan_microstack/cmd/controllersrv/run.py +131 -0
- cancan_microstack/cmd/infrasrv/__init__.py +5 -0
- cancan_microstack/cmd/infrasrv/run.py +100 -0
- cancan_microstack/cmd/opsbffsrv/__init__.py +5 -0
- cancan_microstack/cmd/opsbffsrv/run.py +96 -0
- cancan_microstack/core/__init__.py +5 -0
- cancan_microstack/core/assets.py +123 -0
- cancan_microstack/core/compose_builder.py +102 -0
- cancan_microstack/core/doctor.py +152 -0
- cancan_microstack/core/microstack.py +71 -0
- cancan_microstack/core/runner.py +56 -0
- cancan_microstack/core/stack_manager.py +186 -0
- cancan_microstack/public/__init__.py +7 -0
- cancan_microstack/public/api/__init__.py +1 -0
- cancan_microstack/public/api/controllersrv_client.py +277 -0
- cancan_microstack/public/api/infrasrv_client.py +404 -0
- cancan_microstack/public/const/__init__.py +1 -0
- cancan_microstack/public/const/action_consts.py +18 -0
- cancan_microstack/public/const/app_consts.py +42 -0
- cancan_microstack/public/const/caddy_consts.py +22 -0
- cancan_microstack/public/const/controllersrv_consts.py +163 -0
- cancan_microstack/public/const/docker_consts.py +15 -0
- cancan_microstack/public/const/error.py +56 -0
- cancan_microstack/public/const/health_consts.py +52 -0
- cancan_microstack/public/const/hook_enums.py +56 -0
- cancan_microstack/public/const/logging_enums.py +13 -0
- cancan_microstack/public/const/metrics_enums.py +36 -0
- cancan_microstack/public/const/monitor_enums.py +26 -0
- cancan_microstack/public/const/operation_consts.py +53 -0
- cancan_microstack/public/const/opsbffsrv_error.py +92 -0
- cancan_microstack/public/const/overrides_consts.py +13 -0
- cancan_microstack/public/const/redis.py +17 -0
- cancan_microstack/public/const/service_consts.py +15 -0
- cancan_microstack/public/const/workflow_consts.py +65 -0
- cancan_microstack/public/error.py +41 -0
- cancan_microstack/public/logging/__init__.py +0 -0
- cancan_microstack/public/logging/initializer.py +109 -0
- cancan_microstack/public/logging/mq_handler.py +279 -0
- cancan_microstack/public/schemas/__init__.py +1 -0
- cancan_microstack/public/schemas/caddy/__init__.py +381 -0
- cancan_microstack/public/schemas/caddy/analysis.py +90 -0
- cancan_microstack/public/schemas/caddy/route.py +18 -0
- cancan_microstack/public/schemas/common.py +79 -0
- cancan_microstack/public/schemas/controllersrv/__init__.py +3 -0
- cancan_microstack/public/schemas/controllersrv/async_requests.py +30 -0
- cancan_microstack/public/schemas/controllersrv/compose_models.py +47 -0
- cancan_microstack/public/schemas/controllersrv/const.py +24 -0
- cancan_microstack/public/schemas/controllersrv/docker_models.py +45 -0
- cancan_microstack/public/schemas/controllersrv/docker_responses.py +104 -0
- cancan_microstack/public/schemas/controllersrv/requests.py +54 -0
- cancan_microstack/public/schemas/controllersrv/responses.py +124 -0
- cancan_microstack/public/schemas/controllersrv/task_models.py +102 -0
- cancan_microstack/public/schemas/controllersrv/validation.py +23 -0
- cancan_microstack/public/schemas/hook_metrics.py +124 -0
- cancan_microstack/public/schemas/hooks.py +39 -0
- cancan_microstack/public/schemas/infra/__init__.py +0 -0
- cancan_microstack/public/schemas/infra/cleanup.py +25 -0
- cancan_microstack/public/schemas/infra/container.py +74 -0
- cancan_microstack/public/schemas/infra/enums.py +135 -0
- cancan_microstack/public/schemas/infra/health_check.py +42 -0
- cancan_microstack/public/schemas/infra/hook_log.py +42 -0
- cancan_microstack/public/schemas/infra/operation.py +90 -0
- cancan_microstack/public/schemas/infra/overview.py +25 -0
- cancan_microstack/public/schemas/infra/push.py +33 -0
- cancan_microstack/public/schemas/infra/service_action_log.py +47 -0
- cancan_microstack/public/schemas/infra/service_config.py +10 -0
- cancan_microstack/public/schemas/infra/service_info.py +69 -0
- cancan_microstack/public/schemas/infra/service_instance.py +93 -0
- cancan_microstack/public/schemas/infra/service_management.py +152 -0
- cancan_microstack/public/schemas/infra/service_operation.py +79 -0
- cancan_microstack/public/schemas/infra/service_registry.py +158 -0
- cancan_microstack/public/schemas/infra/status_types.py +19 -0
- cancan_microstack/public/schemas/infra/workflow.py +566 -0
- cancan_microstack/public/schemas/logging/__init__.py +1 -0
- cancan_microstack/public/schemas/logging/log_event.py +121 -0
- cancan_microstack/public/schemas/opsbffsrv/__init__.py +1 -0
- cancan_microstack/public/schemas/opsbffsrv/async_ops.py +17 -0
- cancan_microstack/public/schemas/opsbffsrv/db_admin.py +147 -0
- cancan_microstack/public/schemas/opsbffsrv/db_init.py +48 -0
- cancan_microstack/public/schemas/opsbffsrv/service_config.py +89 -0
- cancan_microstack/public/schemas/opsbffsrv/service_logs.py +54 -0
- cancan_microstack/public/schemas/service_operation.py +24 -0
- cancan_microstack/public/schemas/service_registry.py +40 -0
- cancan_microstack/public/types/__init__.py +7 -0
- cancan_microstack/public/web/__init__.py +0 -0
- cancan_microstack/public/web/config_value.py +105 -0
- cancan_microstack/public/web/server.py +385 -0
- cancan_microstack/py.typed +0 -0
- cancan_microstack/runtime/__init__.py +0 -0
- cancan_microstack/runtime/compose_cmd.py +228 -0
- cancan_microstack/runtime/host_daemon.py +318 -0
- cancan_microstack/runtime/overrides.py +103 -0
- cancan_microstack/runtime/resources.py +25 -0
- cancan_microstack/runtime/workspace.py +94 -0
- cancan_microstack/services/__init__.py +0 -0
- cancan_microstack/services/controllersrv/__init__.py +8 -0
- cancan_microstack/services/controllersrv/application/__init__.py +0 -0
- cancan_microstack/services/controllersrv/application/docker_compose_app.py +427 -0
- cancan_microstack/services/controllersrv/conf/__init__.py +0 -0
- cancan_microstack/services/controllersrv/conf/config.py +76 -0
- cancan_microstack/services/controllersrv/conf/settings.py +54 -0
- cancan_microstack/services/controllersrv/domain/__init__.py +0 -0
- cancan_microstack/services/controllersrv/domain/docker_compose/__init__.py +0 -0
- cancan_microstack/services/controllersrv/domain/docker_compose/docker_compose_domain.py +278 -0
- cancan_microstack/services/controllersrv/domain/service_validator.py +327 -0
- cancan_microstack/services/controllersrv/domain/task/__init__.py +17 -0
- cancan_microstack/services/controllersrv/domain/task/task_queue.py +286 -0
- cancan_microstack/services/controllersrv/domain/task/task_worker.py +495 -0
- cancan_microstack/services/controllersrv/infrastructure/__init__.py +0 -0
- cancan_microstack/services/controllersrv/interface/__init__.py +0 -0
- cancan_microstack/services/controllersrv/interface/api/__init__.py +0 -0
- cancan_microstack/services/controllersrv/interface/api/docker_control_api.py +470 -0
- cancan_microstack/services/controllersrv/router.py +132 -0
- cancan_microstack/services/infrasrv/__init__.py +4 -0
- cancan_microstack/services/infrasrv/application/__init__.py +0 -0
- cancan_microstack/services/infrasrv/application/health_check_app.py +24 -0
- cancan_microstack/services/infrasrv/application/logging/__init__.py +1 -0
- cancan_microstack/services/infrasrv/application/logging/log_ingestion_service.py +183 -0
- cancan_microstack/services/infrasrv/application/service_config.py +22 -0
- cancan_microstack/services/infrasrv/application/service_logs_app.py +53 -0
- cancan_microstack/services/infrasrv/application/service_management_app.py +689 -0
- cancan_microstack/services/infrasrv/application/service_operation_tracker.py +251 -0
- cancan_microstack/services/infrasrv/application/service_registry.py +53 -0
- cancan_microstack/services/infrasrv/application/workflow/__init__.py +0 -0
- cancan_microstack/services/infrasrv/application/workflow/workflow_app.py +991 -0
- cancan_microstack/services/infrasrv/application/workflow/workflow_queue.py +302 -0
- cancan_microstack/services/infrasrv/application/workflow/workflow_tasks.py +46 -0
- cancan_microstack/services/infrasrv/application/workflow/workflow_worker_runtime.py +122 -0
- cancan_microstack/services/infrasrv/conf/__init__.py +0 -0
- cancan_microstack/services/infrasrv/conf/config.py +98 -0
- cancan_microstack/services/infrasrv/domain/__init__.py +0 -0
- cancan_microstack/services/infrasrv/domain/health_check/__init__.py +3 -0
- cancan_microstack/services/infrasrv/domain/health_check/health_check_domain.py +576 -0
- cancan_microstack/services/infrasrv/domain/hooks/__init__.py +19 -0
- cancan_microstack/services/infrasrv/domain/hooks/builtin_hooks.py +308 -0
- cancan_microstack/services/infrasrv/domain/hooks/hook_registry.py +43 -0
- cancan_microstack/services/infrasrv/domain/hooks/hooks_log_utils.py +275 -0
- cancan_microstack/services/infrasrv/domain/hooks/init.py +17 -0
- cancan_microstack/services/infrasrv/domain/hooks/metrics.py +205 -0
- cancan_microstack/services/infrasrv/domain/hooks/pre_registration_hooks.py +490 -0
- cancan_microstack/services/infrasrv/domain/registry/__init__.py +0 -0
- cancan_microstack/services/infrasrv/domain/registry/service_registry.py +509 -0
- cancan_microstack/services/infrasrv/domain/service_config/__init__.py +0 -0
- cancan_microstack/services/infrasrv/domain/service_config/service_config.py +50 -0
- cancan_microstack/services/infrasrv/domain/service_logs/__init__.py +0 -0
- cancan_microstack/services/infrasrv/domain/service_logs/service_logs_domain.py +51 -0
- cancan_microstack/services/infrasrv/domain/workflow/__init__.py +4 -0
- cancan_microstack/services/infrasrv/domain/workflow/engine.py +159 -0
- cancan_microstack/services/infrasrv/domain/workflow/node_handlers.py +509 -0
- cancan_microstack/services/infrasrv/domain/workflow/workflow_domain.py +164 -0
- cancan_microstack/services/infrasrv/infrastructure/__init__.py +0 -0
- cancan_microstack/services/infrasrv/infrastructure/api/__init__.py +0 -0
- cancan_microstack/services/infrasrv/infrastructure/api/controllersrv_api.py +165 -0
- cancan_microstack/services/infrasrv/infrastructure/cache/__init__.py +0 -0
- cancan_microstack/services/infrasrv/infrastructure/cache/service_registry_cache.py +174 -0
- cancan_microstack/services/infrasrv/infrastructure/db/__init__.py +0 -0
- cancan_microstack/services/infrasrv/infrastructure/db/model/__init__.py +0 -0
- cancan_microstack/services/infrasrv/infrastructure/db/model/execution_log_tbl.py +53 -0
- cancan_microstack/services/infrasrv/infrastructure/db/model/node_instance_tbl.py +55 -0
- cancan_microstack/services/infrasrv/infrastructure/db/model/service_action_log_tbl.py +44 -0
- cancan_microstack/services/infrasrv/infrastructure/db/model/service_config_tbl.py +30 -0
- cancan_microstack/services/infrasrv/infrastructure/db/model/service_info_tbl.py +59 -0
- cancan_microstack/services/infrasrv/infrastructure/db/model/service_instance_tbl.py +88 -0
- cancan_microstack/services/infrasrv/infrastructure/db/model/service_operation_tbl.py +73 -0
- cancan_microstack/services/infrasrv/infrastructure/db/model/workflow_definition_tbl.py +55 -0
- cancan_microstack/services/infrasrv/infrastructure/db/model/workflow_definition_version_tbl.py +43 -0
- cancan_microstack/services/infrasrv/infrastructure/db/model/workflow_engine_alert_tbl.py +57 -0
- cancan_microstack/services/infrasrv/infrastructure/db/model/workflow_run_tbl.py +56 -0
- cancan_microstack/services/infrasrv/infrastructure/db/operate/__init__.py +0 -0
- cancan_microstack/services/infrasrv/infrastructure/db/operate/service_action_log_op.py +239 -0
- cancan_microstack/services/infrasrv/infrastructure/db/operate/service_config.py +80 -0
- cancan_microstack/services/infrasrv/infrastructure/db/operate/service_config_manager.py +198 -0
- cancan_microstack/services/infrasrv/infrastructure/db/operate/service_info_op.py +297 -0
- cancan_microstack/services/infrasrv/infrastructure/db/operate/service_instance_op.py +688 -0
- cancan_microstack/services/infrasrv/infrastructure/db/operate/service_operation_op.py +387 -0
- cancan_microstack/services/infrasrv/infrastructure/db/operate/service_registry.py +124 -0
- cancan_microstack/services/infrasrv/infrastructure/db/operate/workflow_op.py +804 -0
- cancan_microstack/services/infrasrv/infrastructure/ddl_manager.py +31 -0
- cancan_microstack/services/infrasrv/infrastructure/mongo/__init__.py +1 -0
- cancan_microstack/services/infrasrv/infrastructure/mongo/log_repository.py +129 -0
- cancan_microstack/services/infrasrv/interface/__init__.py +0 -0
- cancan_microstack/services/infrasrv/interface/api/__init__.py +0 -0
- cancan_microstack/services/infrasrv/interface/api/health_check_api.py +29 -0
- cancan_microstack/services/infrasrv/interface/api/hooks.py +284 -0
- cancan_microstack/services/infrasrv/interface/api/internal.py +49 -0
- cancan_microstack/services/infrasrv/interface/api/internal_instance_api.py +265 -0
- cancan_microstack/services/infrasrv/interface/api/internal_operation_api.py +206 -0
- cancan_microstack/services/infrasrv/interface/api/service_config.py +50 -0
- cancan_microstack/services/infrasrv/interface/api/service_logs_api.py +49 -0
- cancan_microstack/services/infrasrv/interface/api/service_management_api.py +113 -0
- cancan_microstack/services/infrasrv/interface/api/service_registry.py +117 -0
- cancan_microstack/services/infrasrv/interface/api/workflow_api.py +303 -0
- cancan_microstack/services/infrasrv/interface/schedule/__init__.py +0 -0
- cancan_microstack/services/infrasrv/interface/schedule/cleanup.py +13 -0
- cancan_microstack/services/infrasrv/interface/schedule/health_check.py +27 -0
- cancan_microstack/services/infrasrv/interface/schedule/log_cleanup.py +26 -0
- cancan_microstack/services/infrasrv/interface/schedule/operation_tracker.py +25 -0
- cancan_microstack/services/infrasrv/interface/schedule/scheduler.py +39 -0
- cancan_microstack/services/infrasrv/interface/schedule/workflow_scheduler.py +115 -0
- cancan_microstack/services/infrasrv/router.py +341 -0
- cancan_microstack/services/opsbffsrv/__init__.py +4 -0
- cancan_microstack/services/opsbffsrv/application/__init__.py +0 -0
- cancan_microstack/services/opsbffsrv/application/async_operation_app.py +150 -0
- cancan_microstack/services/opsbffsrv/application/auth_app.py +285 -0
- cancan_microstack/services/opsbffsrv/application/caddy/__init__.py +0 -0
- cancan_microstack/services/opsbffsrv/application/caddy/access_log_analysis_app.py +344 -0
- cancan_microstack/services/opsbffsrv/application/caddy/access_log_ingestion_service.py +169 -0
- cancan_microstack/services/opsbffsrv/application/caddy/certificate_management_app.py +355 -0
- cancan_microstack/services/opsbffsrv/application/caddy/rate_limit_management_app.py +496 -0
- cancan_microstack/services/opsbffsrv/application/caddy/route_management_app.py +401 -0
- cancan_microstack/services/opsbffsrv/application/caddy/stats_aggregation_app.py +364 -0
- cancan_microstack/services/opsbffsrv/application/db_admin_app.py +103 -0
- cancan_microstack/services/opsbffsrv/application/db_init_app.py +283 -0
- cancan_microstack/services/opsbffsrv/application/logging/__init__.py +1 -0
- cancan_microstack/services/opsbffsrv/application/logging/log_query_app.py +28 -0
- cancan_microstack/services/opsbffsrv/application/service_config.py +158 -0
- cancan_microstack/services/opsbffsrv/application/service_logs_app.py +74 -0
- cancan_microstack/services/opsbffsrv/application/service_registry.py +36 -0
- cancan_microstack/services/opsbffsrv/application/workflow_ops_app.py +730 -0
- cancan_microstack/services/opsbffsrv/conf/__init__.py +0 -0
- cancan_microstack/services/opsbffsrv/conf/config.py +224 -0
- cancan_microstack/services/opsbffsrv/domain/__init__.py +0 -0
- cancan_microstack/services/opsbffsrv/domain/auth/__init__.py +0 -0
- cancan_microstack/services/opsbffsrv/domain/auth/admin_init.py +38 -0
- cancan_microstack/services/opsbffsrv/domain/auth/auth_domain.py +108 -0
- cancan_microstack/services/opsbffsrv/domain/caddy/__init__.py +0 -0
- cancan_microstack/services/opsbffsrv/domain/caddy/access_log_analysis.py +358 -0
- cancan_microstack/services/opsbffsrv/domain/caddy/certificate_management.py +325 -0
- cancan_microstack/services/opsbffsrv/domain/caddy/default_routes.py +53 -0
- cancan_microstack/services/opsbffsrv/domain/caddy/rate_limit_management.py +308 -0
- cancan_microstack/services/opsbffsrv/domain/caddy/route_management.py +279 -0
- cancan_microstack/services/opsbffsrv/domain/caddy/stats_aggregation.py +654 -0
- cancan_microstack/services/opsbffsrv/domain/db_admin/__init__.py +0 -0
- cancan_microstack/services/opsbffsrv/domain/db_admin/db_admin_domain.py +118 -0
- cancan_microstack/services/opsbffsrv/domain/db_init/__init__.py +3 -0
- cancan_microstack/services/opsbffsrv/domain/db_init/db_init_domain.py +358 -0
- cancan_microstack/services/opsbffsrv/domain/logging/__init__.py +1 -0
- cancan_microstack/services/opsbffsrv/domain/logging/log_query_domain.py +99 -0
- cancan_microstack/services/opsbffsrv/domain/service_config/__init__.py +0 -0
- cancan_microstack/services/opsbffsrv/domain/service_config/service_config.py +81 -0
- cancan_microstack/services/opsbffsrv/domain/service_registry/__init__.py +0 -0
- cancan_microstack/services/opsbffsrv/domain/service_registry/service_registry.py +292 -0
- cancan_microstack/services/opsbffsrv/infrastructure/__init__.py +0 -0
- cancan_microstack/services/opsbffsrv/infrastructure/api/__init__.py +0 -0
- cancan_microstack/services/opsbffsrv/infrastructure/api/infrasrv_api.py +242 -0
- cancan_microstack/services/opsbffsrv/infrastructure/auth/__init__.py +0 -0
- cancan_microstack/services/opsbffsrv/infrastructure/auth/captcha_service.py +67 -0
- cancan_microstack/services/opsbffsrv/infrastructure/auth/password_service.py +12 -0
- cancan_microstack/services/opsbffsrv/infrastructure/auth/redis_store.py +131 -0
- cancan_microstack/services/opsbffsrv/infrastructure/auth/totp_service.py +59 -0
- cancan_microstack/services/opsbffsrv/infrastructure/caddy/__init__.py +0 -0
- cancan_microstack/services/opsbffsrv/infrastructure/caddy/access_log_parser.py +307 -0
- cancan_microstack/services/opsbffsrv/infrastructure/caddy/admin_api_client.py +678 -0
- cancan_microstack/services/opsbffsrv/infrastructure/caddy/ip_geo_locator.py +176 -0
- cancan_microstack/services/opsbffsrv/infrastructure/db/__init__.py +0 -0
- cancan_microstack/services/opsbffsrv/infrastructure/db/model/__init__.py +0 -0
- cancan_microstack/services/opsbffsrv/infrastructure/db/model/admin_user_tbl.py +33 -0
- cancan_microstack/services/opsbffsrv/infrastructure/db/model/caddy_access_log_tbl.py +90 -0
- cancan_microstack/services/opsbffsrv/infrastructure/db/model/caddy_certificate_tbl.py +65 -0
- cancan_microstack/services/opsbffsrv/infrastructure/db/model/caddy_rate_limit_tbl.py +69 -0
- cancan_microstack/services/opsbffsrv/infrastructure/db/model/caddy_route_tbl.py +66 -0
- cancan_microstack/services/opsbffsrv/infrastructure/db/model/caddy_stats_tbl.py +78 -0
- cancan_microstack/services/opsbffsrv/infrastructure/db/model/service_action_log_tbl.py +44 -0
- cancan_microstack/services/opsbffsrv/infrastructure/db/model/service_config_tbl.py +30 -0
- cancan_microstack/services/opsbffsrv/infrastructure/db/model/service_info_tbl.py +51 -0
- cancan_microstack/services/opsbffsrv/infrastructure/db/model/service_instance_tbl.py +68 -0
- cancan_microstack/services/opsbffsrv/infrastructure/db/operate/__init__.py +0 -0
- cancan_microstack/services/opsbffsrv/infrastructure/db/operate/admin_user_operate.py +59 -0
- cancan_microstack/services/opsbffsrv/infrastructure/db/operate/caddy_access_log.py +531 -0
- cancan_microstack/services/opsbffsrv/infrastructure/db/operate/caddy_certificate.py +451 -0
- cancan_microstack/services/opsbffsrv/infrastructure/db/operate/caddy_rate_limit.py +360 -0
- cancan_microstack/services/opsbffsrv/infrastructure/db/operate/caddy_route.py +271 -0
- cancan_microstack/services/opsbffsrv/infrastructure/db/operate/caddy_stats.py +343 -0
- cancan_microstack/services/opsbffsrv/infrastructure/db/operate/service_action_log_op.py +57 -0
- cancan_microstack/services/opsbffsrv/infrastructure/db/operate/service_config.py +86 -0
- cancan_microstack/services/opsbffsrv/infrastructure/db/operate/service_info_op.py +79 -0
- cancan_microstack/services/opsbffsrv/infrastructure/db/operate/service_instance.py +58 -0
- cancan_microstack/services/opsbffsrv/infrastructure/db/operate/service_registry.py +138 -0
- cancan_microstack/services/opsbffsrv/infrastructure/ddl_manager.py +31 -0
- cancan_microstack/services/opsbffsrv/infrastructure/mongo/__init__.py +1 -0
- cancan_microstack/services/opsbffsrv/infrastructure/mongo/log_query_repository.py +87 -0
- cancan_microstack/services/opsbffsrv/interface/__init__.py +0 -0
- cancan_microstack/services/opsbffsrv/interface/api/__init__.py +0 -0
- cancan_microstack/services/opsbffsrv/interface/api/async_operation_api.py +137 -0
- cancan_microstack/services/opsbffsrv/interface/api/auth_api.py +113 -0
- cancan_microstack/services/opsbffsrv/interface/api/caddy/__init__.py +3 -0
- cancan_microstack/services/opsbffsrv/interface/api/caddy/access_log_api.py +174 -0
- cancan_microstack/services/opsbffsrv/interface/api/caddy/certificate_api.py +235 -0
- cancan_microstack/services/opsbffsrv/interface/api/caddy/rate_limit_api.py +302 -0
- cancan_microstack/services/opsbffsrv/interface/api/caddy/route_api.py +250 -0
- cancan_microstack/services/opsbffsrv/interface/api/caddy/stats_api.py +243 -0
- cancan_microstack/services/opsbffsrv/interface/api/db_admin_api.py +62 -0
- cancan_microstack/services/opsbffsrv/interface/api/db_init_api.py +109 -0
- cancan_microstack/services/opsbffsrv/interface/api/instance_management_api.py +165 -0
- cancan_microstack/services/opsbffsrv/interface/api/log_query_api.py +41 -0
- cancan_microstack/services/opsbffsrv/interface/api/mongo_express_proxy_api.py +181 -0
- cancan_microstack/services/opsbffsrv/interface/api/pgweb_proxy_api.py +154 -0
- cancan_microstack/services/opsbffsrv/interface/api/rabbitmq_mgmt_proxy_api.py +518 -0
- cancan_microstack/services/opsbffsrv/interface/api/redis_commander_proxy_api.py +133 -0
- cancan_microstack/services/opsbffsrv/interface/api/service_config.py +146 -0
- cancan_microstack/services/opsbffsrv/interface/api/service_logs_api.py +81 -0
- cancan_microstack/services/opsbffsrv/interface/api/service_registry.py +66 -0
- cancan_microstack/services/opsbffsrv/interface/api/workflow_ops_api.py +413 -0
- cancan_microstack/services/opsbffsrv/interface/middleware/__init__.py +0 -0
- cancan_microstack/services/opsbffsrv/interface/middleware/auth_middleware.py +52 -0
- cancan_microstack/services/opsbffsrv/router.py +901 -0
- cancan_microstack/utils/__init__.py +1 -0
- cancan_microstack/utils/container_env.py +218 -0
- cancan_microstack-0.0.1.dist-info/METADATA +155 -0
- cancan_microstack-0.0.1.dist-info/RECORD +440 -0
- cancan_microstack-0.0.1.dist-info/WHEEL +5 -0
- cancan_microstack-0.0.1.dist-info/entry_points.txt +2 -0
- cancan_microstack-0.0.1.dist-info/licenses/LICENSE +21 -0
- cancan_microstack-0.0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,689 @@
|
|
|
1
|
+
"""
|
|
2
|
+
服务管理应用层 / Service Management Application Layer
|
|
3
|
+
|
|
4
|
+
职责 / Responsibilities:
|
|
5
|
+
1. 统一管理所有 Docker 服务操作的生命周期 / Unified lifecycle management for all Docker service operations
|
|
6
|
+
2. 创建操作记录 → 调用 controllersrv → 更新操作状态 / Create operation record → Call controllersrv → Update operation status
|
|
7
|
+
3. 实现自动重试机制 / Implement automatic retry mechanism
|
|
8
|
+
4. 提供操作生命周期钩子(验证、通知、指标收集)/ Provide operation lifecycle hooks (validation, notification, metrics)
|
|
9
|
+
"""
|
|
10
|
+
import asyncio
|
|
11
|
+
from typing import (
|
|
12
|
+
Dict,
|
|
13
|
+
Any,
|
|
14
|
+
Optional,
|
|
15
|
+
Callable,
|
|
16
|
+
List,
|
|
17
|
+
)
|
|
18
|
+
from datetime import (
|
|
19
|
+
datetime,
|
|
20
|
+
timezone,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
from linglong_web.utils import logger
|
|
24
|
+
|
|
25
|
+
from cancan_microstack.services.infrasrv.infrastructure.api.controllersrv_api import ControllerSrvApi
|
|
26
|
+
from cancan_microstack.services.infrasrv.infrastructure.db.operate.service_action_log_op import (
|
|
27
|
+
insert_service_action_log,
|
|
28
|
+
)
|
|
29
|
+
from cancan_microstack.services.infrasrv.infrastructure.db.operate.service_operation_op import (
|
|
30
|
+
create_operation,
|
|
31
|
+
get_operation_by_id,
|
|
32
|
+
update_operation,
|
|
33
|
+
)
|
|
34
|
+
from cancan_microstack.services.infrasrv.infrastructure.db.operate.service_info_op import (
|
|
35
|
+
update_expected_status,
|
|
36
|
+
)
|
|
37
|
+
from cancan_microstack.public.const.health_consts import ServiceRuntimeStatus
|
|
38
|
+
from cancan_microstack.public.schemas.infra.service_operation import (
|
|
39
|
+
ServiceOperationCreate,
|
|
40
|
+
ServiceOperation,
|
|
41
|
+
ServiceOperationUpdate,
|
|
42
|
+
)
|
|
43
|
+
from cancan_microstack.public.schemas.infra.service_management import (
|
|
44
|
+
ServiceManagementRequest,
|
|
45
|
+
ServiceManagementResponse,
|
|
46
|
+
HookResult,
|
|
47
|
+
ControllerSrvResult,
|
|
48
|
+
)
|
|
49
|
+
from cancan_microstack.public.const.action_consts import ActionType
|
|
50
|
+
from cancan_microstack.public.const.operation_consts import (
|
|
51
|
+
OperationType,
|
|
52
|
+
OperationStatus,
|
|
53
|
+
InitiatedBy,
|
|
54
|
+
InitiatedFrom,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class ServiceManagementHooks:
|
|
59
|
+
"""
|
|
60
|
+
服务管理操作钩子 / Service Management Operation Hooks
|
|
61
|
+
|
|
62
|
+
提供可扩展的生命周期钩子系统 / Provides extensible lifecycle hook system
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
def __init__(self):
|
|
66
|
+
# 预操作钩子列表(操作前执行:验证、准备)/ Pre-operation hooks (executed before operation: validation, preparation)
|
|
67
|
+
self._pre_hooks: List[Callable] = []
|
|
68
|
+
# 后操作钩子列表(操作后执行:通知、清理)/ Post-operation hooks (executed after operation: notification, cleanup)
|
|
69
|
+
self._post_hooks: List[Callable] = []
|
|
70
|
+
# 重试钩子列表(重试前执行:日志、延迟)/ Retry hooks (executed before retry: logging, delay)
|
|
71
|
+
self._retry_hooks: List[Callable] = []
|
|
72
|
+
|
|
73
|
+
def register_pre_hook(self, hook: Callable):
|
|
74
|
+
"""
|
|
75
|
+
注册预操作钩子 / Register pre-operation hook
|
|
76
|
+
|
|
77
|
+
钩子函数签名 / Hook function signature:
|
|
78
|
+
async def hook(request: ServiceManagementRequest) -> HookResult
|
|
79
|
+
|
|
80
|
+
返回值 / Return value:
|
|
81
|
+
HookResult - 如果 allow=False,操作将被阻止 / If allow=False, operation will be blocked
|
|
82
|
+
"""
|
|
83
|
+
self._pre_hooks.append(hook)
|
|
84
|
+
logger.info(f"Registered pre-operation hook: {hook.__name__}")
|
|
85
|
+
|
|
86
|
+
def register_post_hook(self, hook: Callable):
|
|
87
|
+
"""
|
|
88
|
+
注册后操作钩子 / Register post-operation hook
|
|
89
|
+
|
|
90
|
+
钩子函数签名 / Hook function signature:
|
|
91
|
+
async def hook(request: ServiceManagementRequest, response: ServiceManagementResponse) -> None
|
|
92
|
+
"""
|
|
93
|
+
self._post_hooks.append(hook)
|
|
94
|
+
logger.info(f"Registered post-operation hook: {hook.__name__}")
|
|
95
|
+
|
|
96
|
+
def register_retry_hook(self, hook: Callable):
|
|
97
|
+
"""
|
|
98
|
+
注册重试钩子 / Register retry hook
|
|
99
|
+
|
|
100
|
+
钩子函数签名 / Hook function signature:
|
|
101
|
+
async def hook(request: ServiceManagementRequest, attempt: int, error: Exception) -> None
|
|
102
|
+
"""
|
|
103
|
+
self._retry_hooks.append(hook)
|
|
104
|
+
logger.info(f"Registered retry hook: {hook.__name__}")
|
|
105
|
+
|
|
106
|
+
async def execute_pre_hooks(self, request: ServiceManagementRequest) -> HookResult:
|
|
107
|
+
"""
|
|
108
|
+
执行所有预操作钩子 / Execute all pre-operation hooks
|
|
109
|
+
|
|
110
|
+
Returns:
|
|
111
|
+
HookResult - 钩子执行结果 / Hook execution result
|
|
112
|
+
"""
|
|
113
|
+
for hook in self._pre_hooks:
|
|
114
|
+
try:
|
|
115
|
+
result = await hook(request)
|
|
116
|
+
if not result.allow:
|
|
117
|
+
logger.warning(f"Pre-operation hook {hook.__name__} rejected operation: {result.reason}")
|
|
118
|
+
return result
|
|
119
|
+
except Exception as e:
|
|
120
|
+
logger.error(f"Pre-operation hook {hook.__name__} failed: {e}", exc_info=True)
|
|
121
|
+
# 钩子失败不应阻止操作 / Hook failure should not block operation
|
|
122
|
+
return HookResult(allow=True, reason="")
|
|
123
|
+
|
|
124
|
+
async def execute_post_hooks(self, request: ServiceManagementRequest, response: ServiceManagementResponse):
|
|
125
|
+
"""执行所有后操作钩子 / Execute all post-operation hooks"""
|
|
126
|
+
for hook in self._post_hooks:
|
|
127
|
+
try:
|
|
128
|
+
await hook(request, response)
|
|
129
|
+
except Exception as e:
|
|
130
|
+
logger.error(f"Post-operation hook {hook.__name__} failed: {e}", exc_info=True)
|
|
131
|
+
|
|
132
|
+
async def execute_retry_hooks(self, request: ServiceManagementRequest, attempt: int, error: Exception):
|
|
133
|
+
"""执行所有重试钩子 / Execute all retry hooks"""
|
|
134
|
+
for hook in self._retry_hooks:
|
|
135
|
+
try:
|
|
136
|
+
await hook(request, attempt, error)
|
|
137
|
+
except Exception as e:
|
|
138
|
+
logger.error(f"Retry hook {hook.__name__} failed: {e}", exc_info=True)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class ServiceManagementApp:
|
|
142
|
+
"""
|
|
143
|
+
服务管理应用层 / Service Management Application Layer
|
|
144
|
+
|
|
145
|
+
统一处理所有服务管理操作,作为 infrasrv 的核心控制平面 / Unified handling of all service management operations as infrasrv's core control plane
|
|
146
|
+
"""
|
|
147
|
+
|
|
148
|
+
# 重试配置 / Retry Configuration
|
|
149
|
+
MAX_RETRIES = 3 # 最大重试次数 / Maximum retry attempts
|
|
150
|
+
RETRY_DELAY_SECONDS = 5 # 重试延迟(秒)/ Retry delay (seconds)
|
|
151
|
+
RETRY_BACKOFF_MULTIPLIER = 2 # 退避倍数 / Backoff multiplier
|
|
152
|
+
EXPECTED_STATUS_SYNC_TIMEOUT_SECONDS = 1.5
|
|
153
|
+
EXPECTED_STATUS_SYNC_RETRIES = 3
|
|
154
|
+
|
|
155
|
+
_OPERATION_EXPECTED_STATUS_MAP = {
|
|
156
|
+
OperationType.START: ServiceRuntimeStatus.RUNNING.value,
|
|
157
|
+
OperationType.RESTART: ServiceRuntimeStatus.RUNNING.value,
|
|
158
|
+
OperationType.STOP: ServiceRuntimeStatus.STOPPED.value,
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
def __init__(self):
|
|
162
|
+
self.controllersrv_api = ControllerSrvApi()
|
|
163
|
+
self.hooks = ServiceManagementHooks()
|
|
164
|
+
# 保存后台任务的强引用,防止 fire-and-forget 任务在运行期间被 GC 回收。
|
|
165
|
+
# Hold strong references to background tasks so fire-and-forget tasks are not GC'd while running.
|
|
166
|
+
self._bg: set = set()
|
|
167
|
+
self._register_builtin_hooks()
|
|
168
|
+
|
|
169
|
+
def _register_builtin_hooks(self):
|
|
170
|
+
"""注册内置钩子 / Register built-in hooks"""
|
|
171
|
+
|
|
172
|
+
# 内置预操作钩子:参数验证 / Built-in pre-operation hook: parameter validation
|
|
173
|
+
async def validate_request_hook(request: ServiceManagementRequest) -> HookResult:
|
|
174
|
+
"""验证请求参数 / Validate request parameters"""
|
|
175
|
+
if not request.service_name:
|
|
176
|
+
return HookResult(allow=False, reason="Service name is required")
|
|
177
|
+
if not request.operation_id:
|
|
178
|
+
return HookResult(allow=False, reason="Operation ID is required")
|
|
179
|
+
return HookResult(allow=True, reason="")
|
|
180
|
+
|
|
181
|
+
# 内置后操作钩子:指标收集 / Built-in post-operation hook: metrics collection
|
|
182
|
+
async def metrics_collection_hook(request: ServiceManagementRequest, response: ServiceManagementResponse):
|
|
183
|
+
"""收集操作指标 / Collect operation metrics"""
|
|
184
|
+
duration = None
|
|
185
|
+
if response.started_at and response.completed_at:
|
|
186
|
+
duration = (response.completed_at - response.started_at).total_seconds()
|
|
187
|
+
|
|
188
|
+
logger.info(
|
|
189
|
+
f"[Metrics] Operation completed: "
|
|
190
|
+
f"type={request.operation_type}, "
|
|
191
|
+
f"service={request.service_name}, "
|
|
192
|
+
f"status={response.status}, "
|
|
193
|
+
f"duration={duration}s"
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
# 内置重试钩子:日志记录 / Built-in retry hook: logging
|
|
197
|
+
async def retry_logging_hook(request: ServiceManagementRequest, attempt: int, error: Exception):
|
|
198
|
+
"""记录重试信息 / Log retry information"""
|
|
199
|
+
logger.warning(
|
|
200
|
+
f"[Retry] Attempt {attempt}/{self.MAX_RETRIES} failed for operation {request.operation_id}: {error}"
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
self.hooks.register_pre_hook(validate_request_hook)
|
|
204
|
+
self.hooks.register_post_hook(metrics_collection_hook)
|
|
205
|
+
self.hooks.register_retry_hook(retry_logging_hook)
|
|
206
|
+
|
|
207
|
+
async def execute_service_management(self, request: ServiceManagementRequest) -> ServiceManagementResponse:
|
|
208
|
+
"""
|
|
209
|
+
执行服务管理操作(统一入口)/ Execute service management operation (unified entry point)
|
|
210
|
+
|
|
211
|
+
流程 / Flow:
|
|
212
|
+
1. 执行预操作钩子 / Execute pre-operation hooks
|
|
213
|
+
2. 创建操作记录 / Create operation record
|
|
214
|
+
3. 调用 controllersrv(带重试)/ Call controllersrv (with retry)
|
|
215
|
+
4. 更新操作状态 / Update operation status
|
|
216
|
+
5. 执行后操作钩子 / Execute post-operation hooks
|
|
217
|
+
|
|
218
|
+
Args:
|
|
219
|
+
request: 服务管理请求 / Service management request
|
|
220
|
+
|
|
221
|
+
Returns:
|
|
222
|
+
服务管理响应 / Service management response
|
|
223
|
+
"""
|
|
224
|
+
logger.info(
|
|
225
|
+
f"[ServiceManagementApp] Starting operation: "
|
|
226
|
+
f"operation_id={request.operation_id}, "
|
|
227
|
+
f"type={request.operation_type}, "
|
|
228
|
+
f"service={request.service_name}"
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
# 步骤 1: 执行预操作钩子 / Step 1: Execute pre-operation hooks
|
|
232
|
+
hook_result = await self.hooks.execute_pre_hooks(request)
|
|
233
|
+
if not hook_result.allow:
|
|
234
|
+
logger.warning(f"Operation {request.operation_id} rejected by pre-hooks: {hook_result.reason}")
|
|
235
|
+
await self._record_action_log(
|
|
236
|
+
request=request,
|
|
237
|
+
action_status=OperationStatus.FAILED,
|
|
238
|
+
stage="rejected_by_pre_hooks",
|
|
239
|
+
error_message=hook_result.reason,
|
|
240
|
+
)
|
|
241
|
+
return ServiceManagementResponse(
|
|
242
|
+
operation_id=request.operation_id,
|
|
243
|
+
status=OperationStatus.FAILED,
|
|
244
|
+
service_name=request.service_name,
|
|
245
|
+
message=f"Operation rejected: {hook_result.reason}",
|
|
246
|
+
error_message=hook_result.reason
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
# 步骤 2: 处理重复请求并创建操作记录 / Step 2: Handle duplicates and create operation record
|
|
250
|
+
existing_operation = await get_operation_by_id(request.operation_id)
|
|
251
|
+
if existing_operation:
|
|
252
|
+
existing_status = self._coerce_operation_status(existing_operation.status)
|
|
253
|
+
if existing_status != OperationStatus.PENDING or existing_operation.started_at:
|
|
254
|
+
response = self._build_response_from_operation(
|
|
255
|
+
existing_operation,
|
|
256
|
+
default_message="Operation already exists",
|
|
257
|
+
)
|
|
258
|
+
await self._record_action_log(
|
|
259
|
+
request=request,
|
|
260
|
+
action_status=existing_status,
|
|
261
|
+
stage="duplicate_request",
|
|
262
|
+
error_message=response.error_message,
|
|
263
|
+
)
|
|
264
|
+
return response
|
|
265
|
+
|
|
266
|
+
logger.info(
|
|
267
|
+
"Operation record already exists and is pending: operation_id=%s",
|
|
268
|
+
request.operation_id,
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
try:
|
|
272
|
+
if not existing_operation:
|
|
273
|
+
await self._create_operation_record(request)
|
|
274
|
+
await self._record_action_log(
|
|
275
|
+
request=request,
|
|
276
|
+
action_status=OperationStatus.PENDING,
|
|
277
|
+
stage="operation_record_created",
|
|
278
|
+
)
|
|
279
|
+
except Exception as e:
|
|
280
|
+
logger.error(f"Failed to create operation record for {request.operation_id}: {e}", exc_info=True)
|
|
281
|
+
await self._record_action_log(
|
|
282
|
+
request=request,
|
|
283
|
+
action_status=OperationStatus.FAILED,
|
|
284
|
+
stage="operation_record_failed",
|
|
285
|
+
error_message=str(e),
|
|
286
|
+
)
|
|
287
|
+
return ServiceManagementResponse(
|
|
288
|
+
operation_id=request.operation_id,
|
|
289
|
+
status=OperationStatus.FAILED,
|
|
290
|
+
service_name=request.service_name,
|
|
291
|
+
message=f"Failed to create operation record: {str(e)}",
|
|
292
|
+
error_message=str(e)
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
# 步骤 3: 调用 controllersrv(带自动重试)/ Step 3: Call controllersrv (with automatic retry)
|
|
296
|
+
started_at = datetime.now(timezone.utc)
|
|
297
|
+
controller_result = await self._call_controllersrv_with_retry(request)
|
|
298
|
+
controller_completed_at = datetime.now(timezone.utc)
|
|
299
|
+
|
|
300
|
+
# 步骤 4: 更新操作状态 / Step 4: Update operation status
|
|
301
|
+
if controller_result.success:
|
|
302
|
+
status = OperationStatus.RUNNING
|
|
303
|
+
error_message = None
|
|
304
|
+
completed_at: Optional[datetime] = None
|
|
305
|
+
else:
|
|
306
|
+
status = OperationStatus.FAILED
|
|
307
|
+
error_message = controller_result.error or "Unknown error from controllersrv"
|
|
308
|
+
completed_at = controller_completed_at
|
|
309
|
+
|
|
310
|
+
try:
|
|
311
|
+
await self._update_operation_status(
|
|
312
|
+
operation_id=request.operation_id,
|
|
313
|
+
status=status,
|
|
314
|
+
started_at=started_at,
|
|
315
|
+
completed_at=completed_at,
|
|
316
|
+
result=controller_result.model_dump(),
|
|
317
|
+
error_message=error_message
|
|
318
|
+
)
|
|
319
|
+
except Exception as e:
|
|
320
|
+
logger.error(f"Failed to update operation status for {request.operation_id}: {e}", exc_info=True)
|
|
321
|
+
|
|
322
|
+
if controller_result.success:
|
|
323
|
+
await self._sync_service_expected_status_with_timeout(request)
|
|
324
|
+
|
|
325
|
+
# 构造响应 / Build response
|
|
326
|
+
response = ServiceManagementResponse(
|
|
327
|
+
operation_id=request.operation_id,
|
|
328
|
+
status=status,
|
|
329
|
+
service_name=request.service_name,
|
|
330
|
+
message=controller_result.message or (
|
|
331
|
+
"controllersrv accepted operation" if status == OperationStatus.RUNNING else "Operation failed"
|
|
332
|
+
),
|
|
333
|
+
result=controller_result.model_dump(),
|
|
334
|
+
error_message=error_message,
|
|
335
|
+
started_at=started_at,
|
|
336
|
+
completed_at=completed_at
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
await self._record_action_log(
|
|
340
|
+
request=request,
|
|
341
|
+
action_status=status,
|
|
342
|
+
stage="operation_dispatched" if status == OperationStatus.RUNNING else "operation_failed",
|
|
343
|
+
result=controller_result,
|
|
344
|
+
error_message=error_message,
|
|
345
|
+
)
|
|
346
|
+
|
|
347
|
+
# 步骤 5: 执行后操作钩子 / Step 5: Execute post-operation hooks
|
|
348
|
+
await self.hooks.execute_post_hooks(request, response)
|
|
349
|
+
|
|
350
|
+
end_at = completed_at or controller_completed_at
|
|
351
|
+
duration_seconds = None
|
|
352
|
+
if started_at and end_at:
|
|
353
|
+
duration_seconds = (end_at - started_at).total_seconds()
|
|
354
|
+
|
|
355
|
+
duration_text = f"{duration_seconds:.2f}s" if duration_seconds is not None else "unknown"
|
|
356
|
+
logger.info(
|
|
357
|
+
f"[ServiceManagementApp] Operation completed: "
|
|
358
|
+
f"operation_id={request.operation_id}, "
|
|
359
|
+
f"status={status}, "
|
|
360
|
+
f"duration={duration_text}"
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
return response
|
|
364
|
+
|
|
365
|
+
async def _create_operation_record(self, request: ServiceManagementRequest) -> ServiceOperation:
|
|
366
|
+
"""创建操作记录 / Create operation record"""
|
|
367
|
+
operation_data = ServiceOperationCreate(
|
|
368
|
+
operation_id=request.operation_id,
|
|
369
|
+
operation_type=request.operation_type,
|
|
370
|
+
service_name=request.service_name,
|
|
371
|
+
operation_params=request.operation_params,
|
|
372
|
+
status=OperationStatus.PENDING,
|
|
373
|
+
initiated_by=request.initiated_by,
|
|
374
|
+
initiated_from=request.initiated_from,
|
|
375
|
+
)
|
|
376
|
+
operation = await create_operation(operation_data)
|
|
377
|
+
logger.debug(f"Operation record created: {request.operation_id}")
|
|
378
|
+
return operation
|
|
379
|
+
|
|
380
|
+
@staticmethod
|
|
381
|
+
def _coerce_operation_status(value: str) -> OperationStatus:
|
|
382
|
+
"""安全解析操作状态 / Safely parse operation status"""
|
|
383
|
+
try:
|
|
384
|
+
return OperationStatus(value)
|
|
385
|
+
except ValueError:
|
|
386
|
+
return OperationStatus.PENDING
|
|
387
|
+
|
|
388
|
+
def _build_response_from_operation(
|
|
389
|
+
self,
|
|
390
|
+
operation: ServiceOperation,
|
|
391
|
+
default_message: str,
|
|
392
|
+
) -> ServiceManagementResponse:
|
|
393
|
+
"""基于操作记录构造响应 / Build response from operation record"""
|
|
394
|
+
status = self._coerce_operation_status(operation.status)
|
|
395
|
+
message = default_message
|
|
396
|
+
if isinstance(operation.result, dict):
|
|
397
|
+
message = operation.result.get("message") or default_message
|
|
398
|
+
|
|
399
|
+
return ServiceManagementResponse(
|
|
400
|
+
operation_id=operation.operation_id,
|
|
401
|
+
status=status,
|
|
402
|
+
service_name=operation.service_name,
|
|
403
|
+
message=message,
|
|
404
|
+
result=operation.result or None,
|
|
405
|
+
error_message=operation.error_message,
|
|
406
|
+
started_at=operation.started_at,
|
|
407
|
+
completed_at=operation.completed_at,
|
|
408
|
+
)
|
|
409
|
+
|
|
410
|
+
async def _update_operation_status(
|
|
411
|
+
self,
|
|
412
|
+
operation_id: str,
|
|
413
|
+
status: OperationStatus,
|
|
414
|
+
started_at: Optional[datetime] = None,
|
|
415
|
+
completed_at: Optional[datetime] = None,
|
|
416
|
+
result: Optional[Dict[str, Any]] = None,
|
|
417
|
+
error_message: Optional[str] = None
|
|
418
|
+
):
|
|
419
|
+
"""更新操作状态 / Update operation status"""
|
|
420
|
+
update_data = ServiceOperationUpdate(
|
|
421
|
+
status=status,
|
|
422
|
+
started_at=started_at,
|
|
423
|
+
completed_at=completed_at,
|
|
424
|
+
result=result,
|
|
425
|
+
error_message=error_message
|
|
426
|
+
)
|
|
427
|
+
await update_operation(operation_id, update_data)
|
|
428
|
+
logger.debug(f"Operation status updated: {operation_id} -> {status}")
|
|
429
|
+
|
|
430
|
+
async def _call_controllersrv_with_retry(self, request: ServiceManagementRequest) -> ControllerSrvResult:
|
|
431
|
+
"""
|
|
432
|
+
调用 controllersrv 执行操作(带自动重试)/ Call controllersrv to execute operation (with automatic retry)
|
|
433
|
+
|
|
434
|
+
实现指数退避重试策略 / Implements exponential backoff retry strategy
|
|
435
|
+
|
|
436
|
+
Args:
|
|
437
|
+
request: 服务管理请求 / Service management request
|
|
438
|
+
|
|
439
|
+
Returns:
|
|
440
|
+
ControllerSrvResult - 操作结果 / Operation result
|
|
441
|
+
"""
|
|
442
|
+
last_error = None
|
|
443
|
+
delay = self.RETRY_DELAY_SECONDS
|
|
444
|
+
|
|
445
|
+
for attempt in range(1, self.MAX_RETRIES + 1):
|
|
446
|
+
try:
|
|
447
|
+
logger.info(
|
|
448
|
+
f"[Retry Attempt {attempt}/{self.MAX_RETRIES}] Calling controllersrv for {request.operation_id}")
|
|
449
|
+
result = await self._call_controllersrv(request)
|
|
450
|
+
|
|
451
|
+
# 检查 controllersrv 是否成功接受任务 / Check if controllersrv successfully accepted the task
|
|
452
|
+
if result.success:
|
|
453
|
+
logger.info(f"[Retry Success] Operation {request.operation_id} succeeded on attempt {attempt}")
|
|
454
|
+
return result
|
|
455
|
+
else:
|
|
456
|
+
# controllersrv 拒绝任务(业务错误,不重试)/ controllersrv rejected task (business error, no retry)
|
|
457
|
+
logger.warning(f"[No Retry] Controllersrv rejected task {request.operation_id}: {result.error}")
|
|
458
|
+
return result # 直接返回失败结果 / Return failure result directly
|
|
459
|
+
|
|
460
|
+
except Exception as e:
|
|
461
|
+
last_error = e
|
|
462
|
+
logger.warning(f"[Retry Attempt {attempt}] Failed to call controllersrv: {e}")
|
|
463
|
+
|
|
464
|
+
# 如果不是最后一次尝试,执行重试钩子并等待 / If not the last attempt, execute retry hooks and wait
|
|
465
|
+
if attempt < self.MAX_RETRIES:
|
|
466
|
+
await self.hooks.execute_retry_hooks(request, attempt, last_error)
|
|
467
|
+
logger.info(f"[Retry] Waiting {delay}s before next attempt...")
|
|
468
|
+
await asyncio.sleep(delay)
|
|
469
|
+
delay *= self.RETRY_BACKOFF_MULTIPLIER # 指数退避 / Exponential backoff
|
|
470
|
+
|
|
471
|
+
# 所有重试失败 / All retries failed
|
|
472
|
+
logger.error(f"[Retry Exhausted] All {self.MAX_RETRIES} attempts failed for {request.operation_id}")
|
|
473
|
+
return ControllerSrvResult(
|
|
474
|
+
success=False,
|
|
475
|
+
error=f"All retry attempts exhausted. Last error: {str(last_error)}",
|
|
476
|
+
retry_count=self.MAX_RETRIES
|
|
477
|
+
)
|
|
478
|
+
|
|
479
|
+
async def _sync_service_expected_status_with_timeout(self, request: ServiceManagementRequest) -> None:
|
|
480
|
+
"""
|
|
481
|
+
以受控超时执行期望状态同步,避免阻塞主请求
|
|
482
|
+
Sync expected_status with bounded timeout to avoid blocking API request
|
|
483
|
+
"""
|
|
484
|
+
try:
|
|
485
|
+
synced = await asyncio.wait_for(
|
|
486
|
+
self._sync_service_expected_status(request),
|
|
487
|
+
timeout=self.EXPECTED_STATUS_SYNC_TIMEOUT_SECONDS,
|
|
488
|
+
)
|
|
489
|
+
if not synced:
|
|
490
|
+
retry_task = asyncio.create_task(self._sync_service_expected_status_retry(request))
|
|
491
|
+
self._bg.add(retry_task)
|
|
492
|
+
retry_task.add_done_callback(self._bg.discard)
|
|
493
|
+
except asyncio.TimeoutError:
|
|
494
|
+
logger.warning(
|
|
495
|
+
"Expected_status sync timed out, scheduling async retry: service=%s, operation_id=%s",
|
|
496
|
+
request.service_name,
|
|
497
|
+
request.operation_id,
|
|
498
|
+
)
|
|
499
|
+
retry_task = asyncio.create_task(self._sync_service_expected_status_retry(request))
|
|
500
|
+
self._bg.add(retry_task)
|
|
501
|
+
retry_task.add_done_callback(self._bg.discard)
|
|
502
|
+
|
|
503
|
+
async def _sync_service_expected_status_retry(self, request: ServiceManagementRequest) -> None:
|
|
504
|
+
"""
|
|
505
|
+
后台重试同步期望状态
|
|
506
|
+
Retry expected_status sync in background
|
|
507
|
+
"""
|
|
508
|
+
for attempt in range(1, self.EXPECTED_STATUS_SYNC_RETRIES + 1):
|
|
509
|
+
try:
|
|
510
|
+
synced = await self._sync_service_expected_status(request)
|
|
511
|
+
if synced:
|
|
512
|
+
return
|
|
513
|
+
except Exception as exc:
|
|
514
|
+
logger.warning(
|
|
515
|
+
"Async expected_status sync retry failed: service=%s, operation_id=%s, attempt=%s, error=%s",
|
|
516
|
+
request.service_name,
|
|
517
|
+
request.operation_id,
|
|
518
|
+
attempt,
|
|
519
|
+
exc,
|
|
520
|
+
)
|
|
521
|
+
|
|
522
|
+
if attempt < self.EXPECTED_STATUS_SYNC_RETRIES:
|
|
523
|
+
await asyncio.sleep(float(attempt))
|
|
524
|
+
|
|
525
|
+
async def _sync_service_expected_status(self, request: ServiceManagementRequest) -> bool:
|
|
526
|
+
"""
|
|
527
|
+
根据操作类型同步服务期望状态
|
|
528
|
+
Sync service expected_status based on accepted operation type
|
|
529
|
+
"""
|
|
530
|
+
expected_status = self._OPERATION_EXPECTED_STATUS_MAP.get(request.operation_type)
|
|
531
|
+
if not expected_status:
|
|
532
|
+
return
|
|
533
|
+
|
|
534
|
+
candidates = self._build_service_name_candidates(request.service_name)
|
|
535
|
+
|
|
536
|
+
try:
|
|
537
|
+
updated = None
|
|
538
|
+
updated_service_name = None
|
|
539
|
+
for candidate in candidates:
|
|
540
|
+
updated = await update_expected_status(candidate, expected_status)
|
|
541
|
+
if updated is not None:
|
|
542
|
+
updated_service_name = candidate
|
|
543
|
+
break
|
|
544
|
+
|
|
545
|
+
if updated is None:
|
|
546
|
+
logger.warning(
|
|
547
|
+
"Skip expected_status sync because service_info not found: service=%s, candidates=%s, expected_status=%s",
|
|
548
|
+
request.service_name,
|
|
549
|
+
candidates,
|
|
550
|
+
expected_status,
|
|
551
|
+
)
|
|
552
|
+
return False
|
|
553
|
+
else:
|
|
554
|
+
logger.info(
|
|
555
|
+
"Synced service expected_status: service=%s, matched_service=%s, expected_status=%s, operation_id=%s",
|
|
556
|
+
request.service_name,
|
|
557
|
+
updated_service_name,
|
|
558
|
+
expected_status,
|
|
559
|
+
request.operation_id,
|
|
560
|
+
)
|
|
561
|
+
return True
|
|
562
|
+
except Exception as exc:
|
|
563
|
+
logger.error(
|
|
564
|
+
"Failed to sync expected_status: service=%s, operation_id=%s, error=%s",
|
|
565
|
+
request.service_name,
|
|
566
|
+
request.operation_id,
|
|
567
|
+
exc,
|
|
568
|
+
exc_info=True,
|
|
569
|
+
)
|
|
570
|
+
return False
|
|
571
|
+
|
|
572
|
+
@staticmethod
|
|
573
|
+
def _build_service_name_candidates(service_name: str) -> List[str]:
|
|
574
|
+
"""
|
|
575
|
+
生成可能命中的服务名候选
|
|
576
|
+
Build service name candidates for service_info lookup
|
|
577
|
+
"""
|
|
578
|
+
base_name = service_name or ""
|
|
579
|
+
candidates: List[str] = [base_name]
|
|
580
|
+
|
|
581
|
+
if base_name.endswith(".service"):
|
|
582
|
+
plain_name = base_name[:-len(".service")]
|
|
583
|
+
if plain_name:
|
|
584
|
+
candidates.append(plain_name)
|
|
585
|
+
else:
|
|
586
|
+
candidates.append(f"{base_name}.service")
|
|
587
|
+
|
|
588
|
+
deduped: List[str] = []
|
|
589
|
+
for candidate in candidates:
|
|
590
|
+
if candidate and candidate not in deduped:
|
|
591
|
+
deduped.append(candidate)
|
|
592
|
+
return deduped
|
|
593
|
+
|
|
594
|
+
async def _call_controllersrv(self, request: ServiceManagementRequest) -> ControllerSrvResult:
|
|
595
|
+
"""
|
|
596
|
+
调用 controllersrv 执行具体操作 / Call controllersrv to execute specific operation
|
|
597
|
+
|
|
598
|
+
根据操作类型分派到不同的 API / Dispatch to different APIs based on operation type
|
|
599
|
+
|
|
600
|
+
Args:
|
|
601
|
+
request: 服务管理请求 / Service management request
|
|
602
|
+
|
|
603
|
+
Returns:
|
|
604
|
+
ControllerSrvResult - 操作结果 / Operation result
|
|
605
|
+
"""
|
|
606
|
+
service_names = [request.service_name]
|
|
607
|
+
operation_id = request.operation_id
|
|
608
|
+
|
|
609
|
+
try:
|
|
610
|
+
if request.operation_type == OperationType.START:
|
|
611
|
+
return await self.controllersrv_api.start_services(service_names, operation_id)
|
|
612
|
+
|
|
613
|
+
elif request.operation_type == OperationType.STOP:
|
|
614
|
+
return await self.controllersrv_api.stop_services(service_names, operation_id)
|
|
615
|
+
|
|
616
|
+
elif request.operation_type == OperationType.RESTART:
|
|
617
|
+
return await self.controllersrv_api.restart_services(service_names, operation_id)
|
|
618
|
+
else:
|
|
619
|
+
raise ValueError(f"Unsupported operation type: {request.operation_type}")
|
|
620
|
+
|
|
621
|
+
except Exception as e:
|
|
622
|
+
logger.error(f"Exception when calling controllersrv for {operation_id}: {e}", exc_info=True)
|
|
623
|
+
raise
|
|
624
|
+
|
|
625
|
+
def _map_operation_type_to_action_type(self, operation_type: OperationType) -> ActionType:
|
|
626
|
+
"""根据操作类型映射日志行为类型 / Map operation type to action log type"""
|
|
627
|
+
mapping = {
|
|
628
|
+
OperationType.START: ActionType.START,
|
|
629
|
+
OperationType.STOP: ActionType.STOP,
|
|
630
|
+
OperationType.RESTART: ActionType.RESTART,
|
|
631
|
+
}
|
|
632
|
+
return mapping.get(operation_type, ActionType.RESTART)
|
|
633
|
+
|
|
634
|
+
@staticmethod
|
|
635
|
+
def _normalize_initiated_by(initiated_by: InitiatedBy) -> str:
|
|
636
|
+
"""规范化操作发起者字段 / Normalize initiated_by value"""
|
|
637
|
+
if isinstance(initiated_by, InitiatedBy):
|
|
638
|
+
return initiated_by
|
|
639
|
+
return str(initiated_by)
|
|
640
|
+
|
|
641
|
+
@staticmethod
|
|
642
|
+
def _normalize_initiated_from(initiated_from: InitiatedFrom) -> str:
|
|
643
|
+
"""规范化操作来源字段 / Normalize initiated_from value"""
|
|
644
|
+
if isinstance(initiated_from, InitiatedFrom):
|
|
645
|
+
return initiated_from
|
|
646
|
+
return str(initiated_from)
|
|
647
|
+
|
|
648
|
+
async def _record_action_log(
|
|
649
|
+
self,
|
|
650
|
+
*,
|
|
651
|
+
request: ServiceManagementRequest,
|
|
652
|
+
action_status: OperationStatus,
|
|
653
|
+
stage: str,
|
|
654
|
+
result: Optional[ControllerSrvResult] = None,
|
|
655
|
+
error_message: Optional[str] = None,
|
|
656
|
+
):
|
|
657
|
+
"""
|
|
658
|
+
写入服务行为日志,确保所有管理操作可追踪
|
|
659
|
+
Record service action logs so every management operation is traceable
|
|
660
|
+
"""
|
|
661
|
+
action_type = self._map_operation_type_to_action_type(request.operation_type)
|
|
662
|
+
metadata: Dict[str, Any] = {
|
|
663
|
+
"operation_id": request.operation_id,
|
|
664
|
+
"operation_stage": stage,
|
|
665
|
+
"operation_params": request.operation_params,
|
|
666
|
+
"initiated_from": self._normalize_initiated_from(request.initiated_from),
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
if result:
|
|
670
|
+
metadata["controllersrv_result"] = result.model_dump()
|
|
671
|
+
|
|
672
|
+
try:
|
|
673
|
+
await insert_service_action_log(
|
|
674
|
+
service_name=request.service_name,
|
|
675
|
+
action_type=action_type,
|
|
676
|
+
action_status=action_status,
|
|
677
|
+
triggered_by=self._normalize_initiated_by(request.initiated_by),
|
|
678
|
+
action_detail=result.model_dump() if result else None,
|
|
679
|
+
error_message=error_message,
|
|
680
|
+
action_metadata=metadata,
|
|
681
|
+
)
|
|
682
|
+
except Exception as exc:
|
|
683
|
+
logger.error(
|
|
684
|
+
"Failed to record action log for %s (stage=%s): %s",
|
|
685
|
+
request.operation_id,
|
|
686
|
+
stage,
|
|
687
|
+
exc,
|
|
688
|
+
exc_info=True,
|
|
689
|
+
)
|