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,730 @@
|
|
|
1
|
+
"""
|
|
2
|
+
工作流运维应用层(opsbffsrv)
|
|
3
|
+
Workflow Operations Application Layer (opsbffsrv)
|
|
4
|
+
|
|
5
|
+
职责 / Responsibilities:
|
|
6
|
+
1. 调用 infrasrv API / Call infrasrv APIs
|
|
7
|
+
2. 数据转换和格式化 / Data transformation and formatting
|
|
8
|
+
3. 错误处理和日志记录 / Error handling and logging
|
|
9
|
+
"""
|
|
10
|
+
from typing import (
|
|
11
|
+
Optional,
|
|
12
|
+
List,
|
|
13
|
+
Dict,
|
|
14
|
+
Any,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
from cancan_microstack.public.error import HTTPException
|
|
18
|
+
from cancan_microstack.public.schemas.infra import workflow as wt
|
|
19
|
+
from cancan_microstack.public.api.infrasrv_client import InfraSrvApiClient
|
|
20
|
+
from cancan_microstack.public.const.workflow_consts import (
|
|
21
|
+
IMMUTABLE_END_NODE_IDS,
|
|
22
|
+
IMMUTABLE_START_NODE_IDS,
|
|
23
|
+
)
|
|
24
|
+
from linglong_web import LinglongConfig
|
|
25
|
+
from linglong_web.utils import logger
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class WorkflowOpsApp:
|
|
29
|
+
"""工作流运维应用服务 / Workflow operations application service"""
|
|
30
|
+
|
|
31
|
+
def __init__(self):
|
|
32
|
+
self.infra_client = InfraSrvApiClient(LinglongConfig.INFRASRV_HOST)
|
|
33
|
+
|
|
34
|
+
async def list_workflows(self, query: wt.WorkflowListQuery) -> wt.WorkflowListResponse:
|
|
35
|
+
"""
|
|
36
|
+
列出工作流定义(支持分页和过滤)
|
|
37
|
+
List workflow definitions (with pagination and filtering)
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
query: 查询参数 / Query parameters
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
工作流列表响应 / Workflow list response
|
|
44
|
+
"""
|
|
45
|
+
try:
|
|
46
|
+
# 调用 infrasrv 接口 / Call infrasrv API
|
|
47
|
+
response = await self.infra_client.list_workflow_definitions(
|
|
48
|
+
page=query.page,
|
|
49
|
+
page_size=query.page_size,
|
|
50
|
+
keyword=query.keyword,
|
|
51
|
+
status=query.status,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
if not response.success:
|
|
55
|
+
logger.error(f"Failed to list workflows from infrasrv: {response.error}")
|
|
56
|
+
raise HTTPException(status_code=500,
|
|
57
|
+
msg=f"Upstream error: {response.error.msg if response.error else 'Unknown error'}")
|
|
58
|
+
|
|
59
|
+
raw_payload = response.data
|
|
60
|
+
if isinstance(raw_payload, wt.WorkflowListResponse):
|
|
61
|
+
payload = raw_payload
|
|
62
|
+
else:
|
|
63
|
+
payload_dict = raw_payload or {}
|
|
64
|
+
payload = wt.WorkflowListResponse(**payload_dict) if payload_dict else wt.WorkflowListResponse(
|
|
65
|
+
list=[],
|
|
66
|
+
total=0,
|
|
67
|
+
page=query.page,
|
|
68
|
+
page_size=query.page_size,
|
|
69
|
+
)
|
|
70
|
+
workflows = payload.list
|
|
71
|
+
total = payload.total
|
|
72
|
+
filtered_workflows = workflows
|
|
73
|
+
filters_applied = False
|
|
74
|
+
|
|
75
|
+
# 过滤逻辑(infrasrv 暂不支持,opsbffsrv 层处理)
|
|
76
|
+
# Filtering logic (infrasrv doesn't support yet, handle in opsbffsrv)
|
|
77
|
+
if query.keyword:
|
|
78
|
+
filters_applied = True
|
|
79
|
+
keyword_lower = query.keyword.lower()
|
|
80
|
+
filtered_workflows = [
|
|
81
|
+
workflow for workflow in filtered_workflows
|
|
82
|
+
if self._workflow_matches_keyword(workflow, keyword_lower)
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
if query.status:
|
|
86
|
+
filters_applied = True
|
|
87
|
+
is_active = query.status == "ACTIVE"
|
|
88
|
+
filtered_workflows = [
|
|
89
|
+
workflow for workflow in filtered_workflows
|
|
90
|
+
if workflow.is_active == is_active
|
|
91
|
+
]
|
|
92
|
+
|
|
93
|
+
final_total = len(filtered_workflows) if filters_applied else total
|
|
94
|
+
|
|
95
|
+
return wt.WorkflowListResponse(
|
|
96
|
+
list=filtered_workflows,
|
|
97
|
+
total=final_total,
|
|
98
|
+
page=query.page,
|
|
99
|
+
page_size=query.page_size
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
except HTTPException:
|
|
103
|
+
raise
|
|
104
|
+
except Exception as e:
|
|
105
|
+
logger.error(f"Error listing workflows: {e}", exc_info=True)
|
|
106
|
+
raise HTTPException(status_code=500, msg="Internal server error")
|
|
107
|
+
|
|
108
|
+
async def get_workflow(self, workflow_id: str) -> wt.WorkflowDefinition:
|
|
109
|
+
"""
|
|
110
|
+
获取工作流详情
|
|
111
|
+
Get workflow details
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
workflow_id: 工作流唯一标识符 / Workflow unique identifier
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
工作流详情 / Workflow details
|
|
118
|
+
"""
|
|
119
|
+
try:
|
|
120
|
+
response = await self.infra_client.get_workflow_definition(workflow_id)
|
|
121
|
+
|
|
122
|
+
if not response.success:
|
|
123
|
+
logger.error(f"Failed to get workflow {workflow_id} from infrasrv: {response.error}")
|
|
124
|
+
upstream_code = str(response.error.code) if response.error and response.error.code else ""
|
|
125
|
+
if upstream_code == "404":
|
|
126
|
+
raise HTTPException(status_code=404, msg="Workflow not found")
|
|
127
|
+
raise HTTPException(
|
|
128
|
+
status_code=500,
|
|
129
|
+
msg=f"Upstream error: {response.error.msg if response.error else 'Unknown error'}",
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
return self._parse_workflow_definition(response.data)
|
|
133
|
+
|
|
134
|
+
except HTTPException:
|
|
135
|
+
raise
|
|
136
|
+
except Exception as e:
|
|
137
|
+
logger.error(f"Error getting workflow {workflow_id}: {e}", exc_info=True)
|
|
138
|
+
raise HTTPException(status_code=500, msg="Internal server error")
|
|
139
|
+
|
|
140
|
+
async def list_workflow_versions(self, workflow_id: str, limit: int = 50) -> wt.WorkflowVersionListResponse:
|
|
141
|
+
"""列出工作流版本历史
|
|
142
|
+
List workflow definition versions for UI consumption"""
|
|
143
|
+
|
|
144
|
+
try:
|
|
145
|
+
response = await self.infra_client.list_workflow_versions(workflow_id, limit)
|
|
146
|
+
|
|
147
|
+
if not response.success:
|
|
148
|
+
logger.error(f"Failed to list workflow versions for {workflow_id}: {response.error}")
|
|
149
|
+
raise HTTPException(status_code=500, msg="Failed to fetch workflow versions")
|
|
150
|
+
|
|
151
|
+
payload = response.data or {}
|
|
152
|
+
if isinstance(payload, wt.WorkflowVersionListResponse):
|
|
153
|
+
return payload
|
|
154
|
+
return wt.WorkflowVersionListResponse(**payload)
|
|
155
|
+
|
|
156
|
+
except HTTPException:
|
|
157
|
+
raise
|
|
158
|
+
except Exception as exc:
|
|
159
|
+
logger.error(f"Error listing workflow versions for {workflow_id}: {exc}", exc_info=True)
|
|
160
|
+
raise HTTPException(status_code=500, msg="Internal server error")
|
|
161
|
+
|
|
162
|
+
async def create_workflow(self, payload: wt.WorkflowDefinitionCreate) -> wt.WorkflowDefinition:
|
|
163
|
+
"""
|
|
164
|
+
创建工作流
|
|
165
|
+
Create workflow
|
|
166
|
+
|
|
167
|
+
Args:
|
|
168
|
+
payload: 工作流定义数据 / Workflow definition data
|
|
169
|
+
|
|
170
|
+
Returns:
|
|
171
|
+
已创建的工作流 / Created workflow
|
|
172
|
+
"""
|
|
173
|
+
try:
|
|
174
|
+
response = await self.infra_client.create_workflow_definition(payload.model_dump())
|
|
175
|
+
|
|
176
|
+
if not response.success:
|
|
177
|
+
logger.error(f"Failed to create workflow: {response.error}")
|
|
178
|
+
raise HTTPException(status_code=500,
|
|
179
|
+
msg=f"Upstream error: {response.error.msg if response.error else 'Unknown error'}")
|
|
180
|
+
|
|
181
|
+
return self._parse_workflow_definition(response.data)
|
|
182
|
+
|
|
183
|
+
except HTTPException:
|
|
184
|
+
raise
|
|
185
|
+
except Exception as e:
|
|
186
|
+
logger.error(f"Error creating workflow: {e}", exc_info=True)
|
|
187
|
+
raise HTTPException(status_code=500, msg="Internal server error")
|
|
188
|
+
|
|
189
|
+
async def update_workflow(self, workflow_id: str, payload: wt.WorkflowDefinitionUpdate) -> wt.WorkflowDefinition:
|
|
190
|
+
"""
|
|
191
|
+
更新工作流
|
|
192
|
+
Update workflow
|
|
193
|
+
|
|
194
|
+
Args:
|
|
195
|
+
workflow_id: 工作流唯一标识符 / Workflow unique identifier
|
|
196
|
+
payload: 更新数据 / Update data
|
|
197
|
+
|
|
198
|
+
Returns:
|
|
199
|
+
更新后的工作流 / Updated workflow
|
|
200
|
+
"""
|
|
201
|
+
try:
|
|
202
|
+
response = await self.infra_client.update_workflow_definition(workflow_id,
|
|
203
|
+
payload.model_dump(exclude_unset=True))
|
|
204
|
+
|
|
205
|
+
if not response.success:
|
|
206
|
+
logger.error(f"Failed to update workflow {workflow_id}: {response.error}")
|
|
207
|
+
raise HTTPException(status_code=500,
|
|
208
|
+
msg=f"Upstream error: {response.error.msg if response.error else 'Unknown error'}")
|
|
209
|
+
|
|
210
|
+
return self._parse_workflow_definition(response.data)
|
|
211
|
+
|
|
212
|
+
except HTTPException:
|
|
213
|
+
raise
|
|
214
|
+
except Exception as e:
|
|
215
|
+
logger.error(f"Error updating workflow {workflow_id}: {e}", exc_info=True)
|
|
216
|
+
raise HTTPException(status_code=500, msg="Internal server error")
|
|
217
|
+
|
|
218
|
+
async def delete_workflow(self, workflow_id: str) -> None:
|
|
219
|
+
"""
|
|
220
|
+
删除工作流
|
|
221
|
+
Delete workflow
|
|
222
|
+
|
|
223
|
+
Args:
|
|
224
|
+
workflow_id: 工作流唯一标识符 / Workflow unique identifier
|
|
225
|
+
"""
|
|
226
|
+
try:
|
|
227
|
+
response = await self.infra_client.delete_workflow_definition(workflow_id)
|
|
228
|
+
|
|
229
|
+
if not response.success:
|
|
230
|
+
logger.error(f"Failed to delete workflow {workflow_id}: {response.error}")
|
|
231
|
+
raise HTTPException(status_code=500,
|
|
232
|
+
msg=f"Upstream error: {response.error.msg if response.error else 'Unknown error'}")
|
|
233
|
+
|
|
234
|
+
except HTTPException:
|
|
235
|
+
raise
|
|
236
|
+
except Exception as e:
|
|
237
|
+
logger.error(f"Error deleting workflow {workflow_id}: {e}", exc_info=True)
|
|
238
|
+
raise HTTPException(status_code=500, msg="Internal server error")
|
|
239
|
+
|
|
240
|
+
async def toggle_workflow(self, workflow_id: str) -> wt.WorkflowDefinition:
|
|
241
|
+
"""
|
|
242
|
+
切换工作流启用状态
|
|
243
|
+
Toggle workflow active status
|
|
244
|
+
|
|
245
|
+
Args:
|
|
246
|
+
workflow_id: 工作流唯一标识符 / Workflow unique identifier
|
|
247
|
+
|
|
248
|
+
Returns:
|
|
249
|
+
更新后的工作流 / Updated workflow
|
|
250
|
+
"""
|
|
251
|
+
try:
|
|
252
|
+
# 先获取当前状态 / Get current status first
|
|
253
|
+
workflow = await self.get_workflow(workflow_id)
|
|
254
|
+
|
|
255
|
+
# 更新状态 / Update status
|
|
256
|
+
payload = wt.WorkflowDefinitionUpdate(is_active=not workflow.is_active)
|
|
257
|
+
return await self.update_workflow(workflow_id, payload)
|
|
258
|
+
|
|
259
|
+
except HTTPException:
|
|
260
|
+
raise
|
|
261
|
+
except Exception as e:
|
|
262
|
+
logger.error(f"Error toggling workflow {workflow_id}: {e}", exc_info=True)
|
|
263
|
+
raise HTTPException(status_code=500, msg="Internal server error")
|
|
264
|
+
|
|
265
|
+
async def duplicate_workflow(self, workflow_id: str, payload: wt.DuplicateWorkflowPayload) -> wt.WorkflowDefinition:
|
|
266
|
+
"""
|
|
267
|
+
复制工作流
|
|
268
|
+
Duplicate workflow
|
|
269
|
+
|
|
270
|
+
Args:
|
|
271
|
+
workflow_id: 源工作流唯一标识符 / Source workflow unique identifier
|
|
272
|
+
payload: 复制配置 / Duplication config
|
|
273
|
+
|
|
274
|
+
Returns:
|
|
275
|
+
复制后的工作流 / Duplicated workflow
|
|
276
|
+
"""
|
|
277
|
+
try:
|
|
278
|
+
# 获取源工作流 / Get source workflow
|
|
279
|
+
source = await self.get_workflow(workflow_id)
|
|
280
|
+
|
|
281
|
+
# 创建副本 / Create copy
|
|
282
|
+
create_payload = wt.WorkflowDefinitionCreate(
|
|
283
|
+
name=payload.name,
|
|
284
|
+
description=f"Copy of {source.name}",
|
|
285
|
+
schedule=source.schedule,
|
|
286
|
+
graph_data=source.graph_data,
|
|
287
|
+
nodes_config=source.nodes_config,
|
|
288
|
+
global_context=source.global_context,
|
|
289
|
+
is_active=False # 副本默认禁用 / Copy is inactive by default
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
return await self.create_workflow(create_payload)
|
|
293
|
+
|
|
294
|
+
except HTTPException:
|
|
295
|
+
raise
|
|
296
|
+
except Exception as e:
|
|
297
|
+
logger.error(f"Error duplicating workflow {workflow_id}: {e}", exc_info=True)
|
|
298
|
+
raise HTTPException(status_code=500, msg="Internal server error")
|
|
299
|
+
|
|
300
|
+
async def publish_workflow(self, workflow_id: str) -> wt.WorkflowDefinition:
|
|
301
|
+
"""
|
|
302
|
+
发布工作流(标记为生产就绪)
|
|
303
|
+
Publish workflow (mark as production-ready)
|
|
304
|
+
|
|
305
|
+
Args:
|
|
306
|
+
workflow_id: 工作流唯一标识符 / Workflow unique identifier
|
|
307
|
+
|
|
308
|
+
Returns:
|
|
309
|
+
发布后的工作流 / Published workflow
|
|
310
|
+
"""
|
|
311
|
+
try:
|
|
312
|
+
# 发布即启用 / Publish means activate
|
|
313
|
+
payload = wt.WorkflowDefinitionUpdate(is_active=True)
|
|
314
|
+
return await self.update_workflow(workflow_id, payload)
|
|
315
|
+
|
|
316
|
+
except HTTPException:
|
|
317
|
+
raise
|
|
318
|
+
except Exception as e:
|
|
319
|
+
logger.error(f"Error publishing workflow {workflow_id}: {e}", exc_info=True)
|
|
320
|
+
raise HTTPException(status_code=500, msg="Internal server error")
|
|
321
|
+
|
|
322
|
+
async def rollback_workflow(self, workflow_id: str, payload: wt.WorkflowRollbackRequest) -> wt.WorkflowDefinition:
|
|
323
|
+
"""回滚工作流定义
|
|
324
|
+
Roll back workflow definition to a target version"""
|
|
325
|
+
|
|
326
|
+
try:
|
|
327
|
+
response = await self.infra_client.rollback_workflow_definition(
|
|
328
|
+
workflow_id,
|
|
329
|
+
payload.model_dump(exclude_none=True),
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
if not response.success:
|
|
333
|
+
logger.error(f"Failed to rollback workflow {workflow_id}: {response.error}")
|
|
334
|
+
raise HTTPException(status_code=500,
|
|
335
|
+
msg=f"Upstream error: {response.error.msg if response.error else 'Unknown error'}")
|
|
336
|
+
|
|
337
|
+
return self._parse_workflow_definition(response.data)
|
|
338
|
+
|
|
339
|
+
except HTTPException:
|
|
340
|
+
raise
|
|
341
|
+
except Exception as exc:
|
|
342
|
+
logger.error(f"Error rolling back workflow {workflow_id}: {exc}", exc_info=True)
|
|
343
|
+
raise HTTPException(status_code=500, msg="Internal server error")
|
|
344
|
+
|
|
345
|
+
@staticmethod
|
|
346
|
+
def _workflow_matches_keyword(workflow: wt.WorkflowDefinition, keyword_lower: str) -> bool:
|
|
347
|
+
"""匹配关键字 / Check if workflow matches keyword"""
|
|
348
|
+
|
|
349
|
+
searchable_fields = [
|
|
350
|
+
(workflow.name or "").lower(),
|
|
351
|
+
(workflow.description or "").lower(),
|
|
352
|
+
]
|
|
353
|
+
|
|
354
|
+
global_ctx = workflow.global_context or {}
|
|
355
|
+
tags_value = global_ctx.get("tags")
|
|
356
|
+
if isinstance(tags_value, list):
|
|
357
|
+
searchable_fields.extend(str(tag).lower() for tag in tags_value)
|
|
358
|
+
|
|
359
|
+
return any(keyword_lower in field for field in searchable_fields if field)
|
|
360
|
+
|
|
361
|
+
@staticmethod
|
|
362
|
+
def _parse_workflow_definition(data: Any) -> wt.WorkflowDefinition:
|
|
363
|
+
"""
|
|
364
|
+
解析工作流定义响应,兼容字典与模型
|
|
365
|
+
Normalize workflow definition payload returned from infrasrv
|
|
366
|
+
"""
|
|
367
|
+
|
|
368
|
+
if isinstance(data, wt.WorkflowDefinition):
|
|
369
|
+
return data
|
|
370
|
+
if isinstance(data, dict):
|
|
371
|
+
return wt.WorkflowDefinition(**data)
|
|
372
|
+
raise HTTPException(status_code=500, msg="Invalid workflow payload from infrasrv")
|
|
373
|
+
|
|
374
|
+
@staticmethod
|
|
375
|
+
def _normalize_nodes_config(nodes_config: Optional[Dict[str, Any]]) -> Dict[str, Dict[str, Any]]:
|
|
376
|
+
"""统一节点配置格式,兼容 Pydantic 模型与原始字典
|
|
377
|
+
Normalize node configuration values (dict or Pydantic models) into plain dicts"""
|
|
378
|
+
|
|
379
|
+
normalized: Dict[str, Dict[str, Any]] = {}
|
|
380
|
+
if not nodes_config:
|
|
381
|
+
return normalized
|
|
382
|
+
|
|
383
|
+
for node_id, node in nodes_config.items():
|
|
384
|
+
normalized[node_id] = WorkflowOpsApp._normalize_single_node(node)
|
|
385
|
+
return normalized
|
|
386
|
+
|
|
387
|
+
@staticmethod
|
|
388
|
+
def _normalize_single_node(node: Any) -> Dict[str, Any]:
|
|
389
|
+
"""转换单个节点配置为标准 dict 格式,便于统一校验
|
|
390
|
+
Convert an individual node config into a dict for downstream validation"""
|
|
391
|
+
|
|
392
|
+
if isinstance(node, wt.NodeConfig):
|
|
393
|
+
payload = node.model_dump()
|
|
394
|
+
elif hasattr(node, "model_dump"):
|
|
395
|
+
payload = node.model_dump()
|
|
396
|
+
elif isinstance(node, dict):
|
|
397
|
+
payload = dict(node)
|
|
398
|
+
else:
|
|
399
|
+
raise HTTPException(status_code=500, msg="Invalid node configuration payload")
|
|
400
|
+
|
|
401
|
+
node_type = payload.get("type")
|
|
402
|
+
payload["type"] = str(node_type).upper() if node_type is not None else None
|
|
403
|
+
|
|
404
|
+
raw_next_ids = payload.get("next_node_ids")
|
|
405
|
+
next_ids: List[str] = []
|
|
406
|
+
if isinstance(raw_next_ids, list):
|
|
407
|
+
next_ids = [str(item) for item in raw_next_ids if item is not None]
|
|
408
|
+
|
|
409
|
+
single_next = payload.get("next_node_id")
|
|
410
|
+
if single_next:
|
|
411
|
+
candidate = str(single_next)
|
|
412
|
+
if candidate not in next_ids:
|
|
413
|
+
next_ids.append(candidate)
|
|
414
|
+
|
|
415
|
+
payload["next_node_ids"] = next_ids
|
|
416
|
+
return payload
|
|
417
|
+
|
|
418
|
+
async def validate_workflow(self, workflow_id: str) -> Dict[str, Any]:
|
|
419
|
+
"""
|
|
420
|
+
验证工作流定义
|
|
421
|
+
Validate workflow definition
|
|
422
|
+
|
|
423
|
+
Args:
|
|
424
|
+
workflow_id: 工作流唯一标识符 / Workflow unique identifier
|
|
425
|
+
|
|
426
|
+
Returns:
|
|
427
|
+
验证结果 / Validation result
|
|
428
|
+
"""
|
|
429
|
+
try:
|
|
430
|
+
workflow = await self.get_workflow(workflow_id)
|
|
431
|
+
nodes_config = self._normalize_nodes_config(workflow.nodes_config)
|
|
432
|
+
|
|
433
|
+
issues = []
|
|
434
|
+
|
|
435
|
+
# 基础验证 / Basic validation
|
|
436
|
+
if not workflow.name or not workflow.name.strip():
|
|
437
|
+
issues.append("Workflow name cannot be empty")
|
|
438
|
+
|
|
439
|
+
if not nodes_config:
|
|
440
|
+
issues.append("Workflow must have at least one node")
|
|
441
|
+
|
|
442
|
+
# 检查是否有 START 节点 / Check for START node
|
|
443
|
+
start_nodes = [node for node in nodes_config.values() if node.get("type") == "START"]
|
|
444
|
+
if not start_nodes:
|
|
445
|
+
issues.append("Workflow must have a START node")
|
|
446
|
+
elif len(start_nodes) > 1:
|
|
447
|
+
issues.append("Workflow can only contain one START node")
|
|
448
|
+
else:
|
|
449
|
+
start_id = (start_nodes[0].get("id") or start_nodes[0].get("node_id") or "").lower()
|
|
450
|
+
if start_id not in IMMUTABLE_START_NODE_IDS:
|
|
451
|
+
issues.append("START node id must remain immutable (start/start_node)")
|
|
452
|
+
if not start_nodes[0].get("next_node_ids"):
|
|
453
|
+
issues.append("START node must define downstream nodes")
|
|
454
|
+
|
|
455
|
+
# 检查是否有 END 节点 / Check for END node
|
|
456
|
+
end_nodes = [node for node in nodes_config.values() if node.get("type") == "END"]
|
|
457
|
+
if not end_nodes:
|
|
458
|
+
issues.append("Workflow must have at least one END node")
|
|
459
|
+
elif len(end_nodes) > 1:
|
|
460
|
+
issues.append("Workflow can only contain one END node")
|
|
461
|
+
else:
|
|
462
|
+
end_id = (end_nodes[0].get("id") or end_nodes[0].get("node_id") or "").lower()
|
|
463
|
+
if end_id not in IMMUTABLE_END_NODE_IDS:
|
|
464
|
+
issues.append("END node id must remain immutable (end/end_node)")
|
|
465
|
+
|
|
466
|
+
# 检查节点连接 / Check node connections
|
|
467
|
+
for node_id, node in nodes_config.items():
|
|
468
|
+
next_ids = node.get("next_node_ids", [])
|
|
469
|
+
for next_id in next_ids:
|
|
470
|
+
if next_id not in nodes_config:
|
|
471
|
+
issues.append(f"Node {node_id} references non-existent node {next_id}")
|
|
472
|
+
|
|
473
|
+
return {
|
|
474
|
+
"valid": len(issues) == 0,
|
|
475
|
+
"issues": issues
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
except HTTPException:
|
|
479
|
+
raise
|
|
480
|
+
except Exception as e:
|
|
481
|
+
logger.error(f"Error validating workflow {workflow_id}: {e}", exc_info=True)
|
|
482
|
+
raise HTTPException(status_code=500, msg="Internal server error")
|
|
483
|
+
|
|
484
|
+
async def get_workflow_stats(self) -> wt.WorkflowStats:
|
|
485
|
+
"""
|
|
486
|
+
获取工作流统计
|
|
487
|
+
Get workflow statistics
|
|
488
|
+
|
|
489
|
+
Returns:
|
|
490
|
+
统计信息 / Statistics
|
|
491
|
+
"""
|
|
492
|
+
try:
|
|
493
|
+
response = await self.infra_client.get_workflow_stats()
|
|
494
|
+
|
|
495
|
+
if not response.success:
|
|
496
|
+
logger.error(f"Failed to get workflow stats from infrasrv: {response.error}")
|
|
497
|
+
# 降级:返回空统计 / Fallback: return empty stats
|
|
498
|
+
return wt.WorkflowStats()
|
|
499
|
+
|
|
500
|
+
payload = response.data
|
|
501
|
+
if isinstance(payload, wt.WorkflowStats):
|
|
502
|
+
return payload
|
|
503
|
+
if isinstance(payload, dict):
|
|
504
|
+
return wt.WorkflowStats(**payload)
|
|
505
|
+
logger.warning("Unexpected workflow stats payload type: %s", type(payload))
|
|
506
|
+
return wt.WorkflowStats()
|
|
507
|
+
|
|
508
|
+
except Exception as e:
|
|
509
|
+
logger.error(f"Error getting workflow stats: {e}", exc_info=True)
|
|
510
|
+
# 降级:返回空统计 / Fallback: return empty stats
|
|
511
|
+
return wt.WorkflowStats()
|
|
512
|
+
|
|
513
|
+
async def trigger_workflow(
|
|
514
|
+
self,
|
|
515
|
+
workflow_id: str,
|
|
516
|
+
payload: wt.WorkflowTriggerRequest,
|
|
517
|
+
) -> wt.WorkflowTriggerResponse:
|
|
518
|
+
"""
|
|
519
|
+
触发工作流运行
|
|
520
|
+
Trigger workflow run
|
|
521
|
+
|
|
522
|
+
Args:
|
|
523
|
+
workflow_id: 工作流唯一标识符 / Workflow unique identifier
|
|
524
|
+
payload: 触发上下文数据 / Trigger context data
|
|
525
|
+
|
|
526
|
+
Returns:
|
|
527
|
+
运行实例信息 / Run instance info
|
|
528
|
+
"""
|
|
529
|
+
try:
|
|
530
|
+
response = await self.infra_client.trigger_workflow_run(workflow_id, payload.model_dump())
|
|
531
|
+
|
|
532
|
+
if not response.success:
|
|
533
|
+
logger.error(f"Failed to trigger workflow {workflow_id}: {response.error}")
|
|
534
|
+
raise HTTPException(status_code=500,
|
|
535
|
+
msg=f"Upstream error: {response.error.msg if response.error else 'Unknown error'}")
|
|
536
|
+
|
|
537
|
+
payload = response.data
|
|
538
|
+
if isinstance(payload, wt.WorkflowTriggerResponse):
|
|
539
|
+
return payload
|
|
540
|
+
if isinstance(payload, dict):
|
|
541
|
+
return wt.WorkflowTriggerResponse(**payload)
|
|
542
|
+
raise HTTPException(status_code=500, msg="Invalid trigger response payload")
|
|
543
|
+
|
|
544
|
+
except HTTPException:
|
|
545
|
+
raise
|
|
546
|
+
except Exception as e:
|
|
547
|
+
logger.error(f"Error triggering workflow {workflow_id}: {e}", exc_info=True)
|
|
548
|
+
raise HTTPException(status_code=500, msg="Internal server error")
|
|
549
|
+
|
|
550
|
+
async def list_runs(
|
|
551
|
+
self,
|
|
552
|
+
workflow_id: Optional[str],
|
|
553
|
+
reqid: Optional[str],
|
|
554
|
+
page: int,
|
|
555
|
+
page_size: int,
|
|
556
|
+
status: Optional[str] = None,
|
|
557
|
+
date_from: Optional[str] = None,
|
|
558
|
+
date_to: Optional[str] = None,
|
|
559
|
+
) -> wt.WorkflowRunListResponse:
|
|
560
|
+
"""
|
|
561
|
+
列出工作流运行实例
|
|
562
|
+
List workflow runs
|
|
563
|
+
|
|
564
|
+
Args:
|
|
565
|
+
workflow_id: 按工作流ID过滤 / Filter by workflow ID
|
|
566
|
+
reqid: 按请求追踪 ID 过滤 / Filter by request trace ID
|
|
567
|
+
page: 页码 / Page number
|
|
568
|
+
page_size: 每页大小 / Page size
|
|
569
|
+
|
|
570
|
+
Returns:
|
|
571
|
+
运行实例列表 / Run instance list
|
|
572
|
+
"""
|
|
573
|
+
try:
|
|
574
|
+
response = await self.infra_client.list_workflow_runs(
|
|
575
|
+
workflow_id=workflow_id,
|
|
576
|
+
reqid=reqid,
|
|
577
|
+
page=page,
|
|
578
|
+
page_size=page_size,
|
|
579
|
+
status=status,
|
|
580
|
+
date_from=date_from,
|
|
581
|
+
date_to=date_to,
|
|
582
|
+
)
|
|
583
|
+
|
|
584
|
+
if not response.success:
|
|
585
|
+
logger.error(f"Failed to list workflow runs from infrasrv: {response.error}")
|
|
586
|
+
raise HTTPException(status_code=500,
|
|
587
|
+
msg=f"Upstream error: {response.error.msg if response.error else 'Unknown error'}")
|
|
588
|
+
|
|
589
|
+
payload_dict = response.data or {}
|
|
590
|
+
if not payload_dict:
|
|
591
|
+
return wt.WorkflowRunListResponse(list=[], total=0, page=page, page_size=page_size)
|
|
592
|
+
return wt.WorkflowRunListResponse(**payload_dict)
|
|
593
|
+
|
|
594
|
+
except HTTPException:
|
|
595
|
+
raise
|
|
596
|
+
except Exception as e:
|
|
597
|
+
logger.error(f"Error listing workflow runs: {e}", exc_info=True)
|
|
598
|
+
raise HTTPException(status_code=500, msg="Internal server error")
|
|
599
|
+
|
|
600
|
+
async def get_run_graph_status(self, run_id: str) -> wt.RunGraphResponse:
|
|
601
|
+
"""
|
|
602
|
+
获取运行图状态
|
|
603
|
+
Get run graph status
|
|
604
|
+
|
|
605
|
+
Args:
|
|
606
|
+
run_id: 运行实例唯一标识符 / Run instance unique identifier
|
|
607
|
+
|
|
608
|
+
Returns:
|
|
609
|
+
图状态数据 / Graph status data
|
|
610
|
+
"""
|
|
611
|
+
try:
|
|
612
|
+
response = await self.infra_client.get_run_graph_status(run_id)
|
|
613
|
+
|
|
614
|
+
if not response.success:
|
|
615
|
+
logger.error(f"Failed to get run graph status for {run_id}: {response.error}")
|
|
616
|
+
error_code = str(response.error.code) if response.error else "500"
|
|
617
|
+
error_msg = response.error.msg if response.error else "Failed to fetch run graph"
|
|
618
|
+
status_code = 404 if error_code == "404" else 500
|
|
619
|
+
raise HTTPException(status_code=status_code, msg=error_msg or "Failed to fetch run graph")
|
|
620
|
+
|
|
621
|
+
return wt.RunGraphResponse(**(response.data or {}))
|
|
622
|
+
|
|
623
|
+
except HTTPException:
|
|
624
|
+
raise
|
|
625
|
+
except Exception as e:
|
|
626
|
+
logger.error(f"Error getting run graph status for {run_id}: {e}", exc_info=True)
|
|
627
|
+
raise HTTPException(status_code=500, msg="Internal server error")
|
|
628
|
+
|
|
629
|
+
async def get_node_history(self, run_id: str, node_id: str) -> wt.NodeExecutionHistoryResponse:
|
|
630
|
+
"""
|
|
631
|
+
获取节点执行历史
|
|
632
|
+
Get node execution history
|
|
633
|
+
|
|
634
|
+
Args:
|
|
635
|
+
run_id: 运行实例唯一标识符 / Run instance unique identifier
|
|
636
|
+
node_id: 节点ID / Node ID
|
|
637
|
+
|
|
638
|
+
Returns:
|
|
639
|
+
节点执行历史 / Node execution history
|
|
640
|
+
"""
|
|
641
|
+
try:
|
|
642
|
+
response = await self.infra_client.get_node_history(run_id, node_id)
|
|
643
|
+
|
|
644
|
+
if not response.success:
|
|
645
|
+
logger.error(f"Failed to get node history for {run_id}/{node_id}: {response.error}")
|
|
646
|
+
raise HTTPException(status_code=404, msg="Node history not found")
|
|
647
|
+
|
|
648
|
+
payload = response.data or {}
|
|
649
|
+
if not payload:
|
|
650
|
+
return wt.NodeExecutionHistoryResponse(histories=[])
|
|
651
|
+
return wt.NodeExecutionHistoryResponse(**payload)
|
|
652
|
+
|
|
653
|
+
except HTTPException:
|
|
654
|
+
raise
|
|
655
|
+
except Exception as e:
|
|
656
|
+
logger.error(f"Error getting node history for {run_id}/{node_id}: {e}", exc_info=True)
|
|
657
|
+
raise HTTPException(status_code=500, msg="Internal server error")
|
|
658
|
+
|
|
659
|
+
async def list_engine_alerts(self, query: wt.WorkflowEngineAlertQuery) -> wt.WorkflowEngineAlertListResponse:
|
|
660
|
+
"""列出工作流引擎告警 / List workflow engine alerts"""
|
|
661
|
+
|
|
662
|
+
try:
|
|
663
|
+
response = await self.infra_client.list_workflow_engine_alerts(
|
|
664
|
+
status=query.status.value if query.status else None,
|
|
665
|
+
severity=query.severity.value if query.severity else None,
|
|
666
|
+
run_id=query.run_id,
|
|
667
|
+
page=query.page,
|
|
668
|
+
page_size=query.page_size,
|
|
669
|
+
)
|
|
670
|
+
if not response.success:
|
|
671
|
+
logger.error(f"Failed to list workflow alerts: {response.error}")
|
|
672
|
+
raise HTTPException(status_code=500, msg="Failed to fetch workflow alerts")
|
|
673
|
+
|
|
674
|
+
payload = response.data or {}
|
|
675
|
+
if isinstance(payload, wt.WorkflowEngineAlertListResponse):
|
|
676
|
+
return payload
|
|
677
|
+
if isinstance(payload, dict):
|
|
678
|
+
return wt.WorkflowEngineAlertListResponse(**payload)
|
|
679
|
+
return wt.WorkflowEngineAlertListResponse()
|
|
680
|
+
except HTTPException:
|
|
681
|
+
raise
|
|
682
|
+
except Exception as exc:
|
|
683
|
+
logger.error(f"Error listing workflow alerts: {exc}", exc_info=True)
|
|
684
|
+
raise HTTPException(status_code=500, msg="Internal server error")
|
|
685
|
+
|
|
686
|
+
async def acknowledge_engine_alert(
|
|
687
|
+
self,
|
|
688
|
+
alert_id: str,
|
|
689
|
+
payload: wt.WorkflowEngineAlertAckRequest,
|
|
690
|
+
) -> wt.WorkflowEngineAlert:
|
|
691
|
+
"""标记告警为已知晓"""
|
|
692
|
+
|
|
693
|
+
try:
|
|
694
|
+
response = await self.infra_client.acknowledge_workflow_engine_alert(
|
|
695
|
+
alert_id,
|
|
696
|
+
payload.model_dump(exclude_none=True),
|
|
697
|
+
)
|
|
698
|
+
if not response.success:
|
|
699
|
+
logger.error(f"Failed to acknowledge workflow alert {alert_id}: {response.error}")
|
|
700
|
+
raise HTTPException(status_code=500, msg="Failed to acknowledge workflow alert")
|
|
701
|
+
data = response.data or {}
|
|
702
|
+
return wt.WorkflowEngineAlert(**data)
|
|
703
|
+
except HTTPException:
|
|
704
|
+
raise
|
|
705
|
+
except Exception as exc:
|
|
706
|
+
logger.error(f"Error acknowledging workflow alert {alert_id}: {exc}", exc_info=True)
|
|
707
|
+
raise HTTPException(status_code=500, msg="Internal server error")
|
|
708
|
+
|
|
709
|
+
async def resolve_engine_alert(
|
|
710
|
+
self,
|
|
711
|
+
alert_id: str,
|
|
712
|
+
payload: wt.WorkflowEngineAlertAckRequest,
|
|
713
|
+
) -> wt.WorkflowEngineAlert:
|
|
714
|
+
"""标记告警为已解决"""
|
|
715
|
+
|
|
716
|
+
try:
|
|
717
|
+
response = await self.infra_client.resolve_workflow_engine_alert(
|
|
718
|
+
alert_id,
|
|
719
|
+
payload.model_dump(exclude_none=True),
|
|
720
|
+
)
|
|
721
|
+
if not response.success:
|
|
722
|
+
logger.error(f"Failed to resolve workflow alert {alert_id}: {response.error}")
|
|
723
|
+
raise HTTPException(status_code=500, msg="Failed to resolve workflow alert")
|
|
724
|
+
data = response.data or {}
|
|
725
|
+
return wt.WorkflowEngineAlert(**data)
|
|
726
|
+
except HTTPException:
|
|
727
|
+
raise
|
|
728
|
+
except Exception as exc:
|
|
729
|
+
logger.error(f"Error resolving workflow alert {alert_id}: {exc}", exc_info=True)
|
|
730
|
+
raise HTTPException(status_code=500, msg="Internal server error")
|