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,358 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Caddy 访问日志分析领域服务
|
|
3
|
+
包含访问日志查询和分析的核心业务逻辑
|
|
4
|
+
"""
|
|
5
|
+
from typing import (
|
|
6
|
+
List,
|
|
7
|
+
Optional,
|
|
8
|
+
Dict,
|
|
9
|
+
Any,
|
|
10
|
+
)
|
|
11
|
+
from datetime import (
|
|
12
|
+
datetime,
|
|
13
|
+
timedelta,
|
|
14
|
+
timezone,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
from cancan_microstack.public.const.caddy_consts import SecurityEventType
|
|
18
|
+
from cancan_microstack.public.schemas.caddy import CaddyAccessLog, AccessLogQuery
|
|
19
|
+
from cancan_microstack.public.schemas.caddy.analysis import SuspiciousIP, ErrorPatternAnalysis
|
|
20
|
+
from cancan_microstack.services.opsbffsrv.infrastructure.db.operate.caddy_access_log import (
|
|
21
|
+
get_access_log_by_id,
|
|
22
|
+
get_access_log_by_request_id,
|
|
23
|
+
query_access_logs,
|
|
24
|
+
get_logs_by_ip,
|
|
25
|
+
get_logs_by_service,
|
|
26
|
+
get_waf_blocked_logs,
|
|
27
|
+
get_rate_limited_logs,
|
|
28
|
+
get_country_distribution,
|
|
29
|
+
get_status_code_distribution,
|
|
30
|
+
create_access_log,
|
|
31
|
+
batch_create_access_logs,
|
|
32
|
+
delete_old_logs,
|
|
33
|
+
count_access_logs,
|
|
34
|
+
)
|
|
35
|
+
from cancan_microstack.services.opsbffsrv.infrastructure.caddy.access_log_parser import access_log_parser
|
|
36
|
+
from linglong_web.utils import logger
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class AccessLogAnalysisDomain:
|
|
40
|
+
"""访问日志分析领域服务"""
|
|
41
|
+
|
|
42
|
+
async def ingest_log_entry(self, log_data: Dict[str, Any]) -> CaddyAccessLog:
|
|
43
|
+
"""
|
|
44
|
+
接收并处理单条访问日志
|
|
45
|
+
|
|
46
|
+
业务流程:
|
|
47
|
+
1. 解析日志数据
|
|
48
|
+
2. 提取 IP 地理位置信息
|
|
49
|
+
3. 存储到数据库
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
log_data: 日志数据字典
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
访问日志对象
|
|
56
|
+
"""
|
|
57
|
+
logger.debug("Ingesting access log entry")
|
|
58
|
+
|
|
59
|
+
# 解析日志数据
|
|
60
|
+
log_entry = access_log_parser.parse_dict_log(log_data)
|
|
61
|
+
if not log_entry:
|
|
62
|
+
raise ValueError("Failed to parse access log data")
|
|
63
|
+
|
|
64
|
+
# 存储到数据库
|
|
65
|
+
db_log = await create_access_log(log_entry)
|
|
66
|
+
logger.debug(f"Access log entry stored: {db_log.id}")
|
|
67
|
+
|
|
68
|
+
return db_log
|
|
69
|
+
|
|
70
|
+
async def ingest_log_batch(self, log_lines: List[str]) -> int:
|
|
71
|
+
"""
|
|
72
|
+
批量接收并处理访问日志
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
log_lines: JSON 格式的日志行列表
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
成功处理的日志数量
|
|
79
|
+
"""
|
|
80
|
+
logger.info(f"Ingesting batch of {len(log_lines)} access log entries")
|
|
81
|
+
|
|
82
|
+
# 解析所有日志行
|
|
83
|
+
log_entries = []
|
|
84
|
+
for line in log_lines:
|
|
85
|
+
try:
|
|
86
|
+
log_entry = access_log_parser.parse_json_log(line)
|
|
87
|
+
if log_entry:
|
|
88
|
+
log_entries.append(log_entry)
|
|
89
|
+
except Exception as e:
|
|
90
|
+
logger.warning(f"Failed to parse log line: {e}")
|
|
91
|
+
continue
|
|
92
|
+
|
|
93
|
+
if not log_entries:
|
|
94
|
+
logger.warning("No valid log entries to ingest")
|
|
95
|
+
return 0
|
|
96
|
+
|
|
97
|
+
# 批量存储到数据库
|
|
98
|
+
await batch_create_access_logs(log_entries)
|
|
99
|
+
logger.info(f"Successfully ingested {len(log_entries)} access log entries")
|
|
100
|
+
|
|
101
|
+
return len(log_entries)
|
|
102
|
+
|
|
103
|
+
async def search_logs(self, query: AccessLogQuery) -> List[CaddyAccessLog]:
|
|
104
|
+
"""
|
|
105
|
+
搜索访问日志
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
query: 查询参数对象
|
|
109
|
+
|
|
110
|
+
Returns:
|
|
111
|
+
访问日志列表
|
|
112
|
+
"""
|
|
113
|
+
logger.info(f"Searching access logs with filters: {query.model_dump()}")
|
|
114
|
+
|
|
115
|
+
# 验证查询参数
|
|
116
|
+
self._validate_query_params(query)
|
|
117
|
+
|
|
118
|
+
return await query_access_logs(query)
|
|
119
|
+
|
|
120
|
+
async def get_log_details(self, log_id: int) -> Optional[CaddyAccessLog]:
|
|
121
|
+
"""
|
|
122
|
+
获取访问日志详情
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
log_id: 日志 ID
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
访问日志对象或 None
|
|
129
|
+
"""
|
|
130
|
+
return await get_access_log_by_id(log_id)
|
|
131
|
+
|
|
132
|
+
async def get_log_by_request_id(self, request_id: str) -> Optional[CaddyAccessLog]:
|
|
133
|
+
"""
|
|
134
|
+
根据请求 ID 获取访问日志
|
|
135
|
+
|
|
136
|
+
Args:
|
|
137
|
+
request_id: 请求 ID
|
|
138
|
+
|
|
139
|
+
Returns:
|
|
140
|
+
访问日志对象或 None
|
|
141
|
+
"""
|
|
142
|
+
return await get_access_log_by_request_id(request_id)
|
|
143
|
+
|
|
144
|
+
async def get_logs_for_ip(self, client_ip: str, limit: int = 100) -> List[CaddyAccessLog]:
|
|
145
|
+
"""
|
|
146
|
+
获取指定 IP 的访问日志
|
|
147
|
+
|
|
148
|
+
Args:
|
|
149
|
+
client_ip: 客户端 IP
|
|
150
|
+
limit: 返回数量限制
|
|
151
|
+
|
|
152
|
+
Returns:
|
|
153
|
+
访问日志列表
|
|
154
|
+
"""
|
|
155
|
+
logger.info(f"Fetching logs for IP: {client_ip}")
|
|
156
|
+
return await get_logs_by_ip(client_ip, limit)
|
|
157
|
+
|
|
158
|
+
async def get_logs_for_service(self, service: str, limit: int = 100) -> List[CaddyAccessLog]:
|
|
159
|
+
"""
|
|
160
|
+
获取指定服务的访问日志
|
|
161
|
+
|
|
162
|
+
Args:
|
|
163
|
+
service: 服务名称
|
|
164
|
+
limit: 返回数量限制
|
|
165
|
+
|
|
166
|
+
Returns:
|
|
167
|
+
访问日志列表
|
|
168
|
+
"""
|
|
169
|
+
logger.info(f"Fetching logs for service: {service}")
|
|
170
|
+
return await get_logs_by_service(service, limit)
|
|
171
|
+
|
|
172
|
+
async def get_security_events(self, event_type: SecurityEventType, limit: int = 100) -> List[CaddyAccessLog]:
|
|
173
|
+
"""
|
|
174
|
+
获取安全事件日志
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
event_type: 事件类型
|
|
178
|
+
limit: 返回数量限制
|
|
179
|
+
|
|
180
|
+
Returns:
|
|
181
|
+
访问日志列表
|
|
182
|
+
"""
|
|
183
|
+
logger.info(f"Fetching security events: {event_type}")
|
|
184
|
+
|
|
185
|
+
if event_type == SecurityEventType.WAF_BLOCKED:
|
|
186
|
+
return await get_waf_blocked_logs(limit)
|
|
187
|
+
if event_type == SecurityEventType.RATE_LIMITED:
|
|
188
|
+
return await get_rate_limited_logs(limit)
|
|
189
|
+
|
|
190
|
+
raise ValueError(f"Invalid event type: {event_type}")
|
|
191
|
+
|
|
192
|
+
async def analyze_geographic_distribution(
|
|
193
|
+
self, start_time: Optional[datetime] = None, end_time: Optional[datetime] = None
|
|
194
|
+
) -> List[Dict[str, Any]]:
|
|
195
|
+
"""
|
|
196
|
+
分析访问的地理分布
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
start_time: 开始时间
|
|
200
|
+
end_time: 结束时间
|
|
201
|
+
|
|
202
|
+
Returns:
|
|
203
|
+
国家分布列表
|
|
204
|
+
"""
|
|
205
|
+
logger.info("Analyzing geographic distribution")
|
|
206
|
+
return await get_country_distribution(start_time, end_time)
|
|
207
|
+
|
|
208
|
+
async def analyze_status_code_distribution(
|
|
209
|
+
self, start_time: Optional[datetime] = None, end_time: Optional[datetime] = None
|
|
210
|
+
) -> List[Dict[str, Any]]:
|
|
211
|
+
"""
|
|
212
|
+
分析 HTTP 状态码分布
|
|
213
|
+
|
|
214
|
+
Args:
|
|
215
|
+
start_time: 开始时间
|
|
216
|
+
end_time: 结束时间
|
|
217
|
+
|
|
218
|
+
Returns:
|
|
219
|
+
状态码分布列表
|
|
220
|
+
"""
|
|
221
|
+
logger.info("Analyzing status code distribution")
|
|
222
|
+
return await get_status_code_distribution(start_time, end_time)
|
|
223
|
+
|
|
224
|
+
async def detect_suspicious_ips(
|
|
225
|
+
self, time_window: int = 60, request_threshold: int = 1000
|
|
226
|
+
) -> List[SuspiciousIP]:
|
|
227
|
+
"""
|
|
228
|
+
检测可疑 IP(高频访问)
|
|
229
|
+
|
|
230
|
+
业务规则:在指定时间窗口内,请求数超过阈值的 IP 被标记为可疑
|
|
231
|
+
|
|
232
|
+
Args:
|
|
233
|
+
time_window: 时间窗口(分钟)
|
|
234
|
+
request_threshold: 请求数阈值
|
|
235
|
+
|
|
236
|
+
Returns:
|
|
237
|
+
可疑 IP 列表
|
|
238
|
+
"""
|
|
239
|
+
logger.info(f"Detecting suspicious IPs (window={time_window}min, threshold={request_threshold})")
|
|
240
|
+
|
|
241
|
+
end_time = datetime.now(timezone.utc)
|
|
242
|
+
start_time = end_time - timedelta(minutes=time_window)
|
|
243
|
+
|
|
244
|
+
# 查询指定时间窗口内的所有日志
|
|
245
|
+
query = AccessLogQuery(start_time=start_time, end_time=end_time, limit=10000, offset=0)
|
|
246
|
+
logs = await query_access_logs(query)
|
|
247
|
+
|
|
248
|
+
# 统计每个 IP 的请求数
|
|
249
|
+
ip_counts: Dict[str, int] = {}
|
|
250
|
+
for log in logs:
|
|
251
|
+
ip_counts[log.client_ip] = ip_counts.get(log.client_ip, 0) + 1
|
|
252
|
+
|
|
253
|
+
# 筛选超过阈值的 IP
|
|
254
|
+
suspicious_ips = [
|
|
255
|
+
SuspiciousIP(ip=ip, count=count)
|
|
256
|
+
for ip, count in ip_counts.items()
|
|
257
|
+
if count > request_threshold
|
|
258
|
+
]
|
|
259
|
+
|
|
260
|
+
# 按请求数降序排序
|
|
261
|
+
suspicious_ips.sort(key=lambda x: x.count, reverse=True)
|
|
262
|
+
|
|
263
|
+
logger.info(f"Found {len(suspicious_ips)} suspicious IPs")
|
|
264
|
+
return suspicious_ips
|
|
265
|
+
|
|
266
|
+
async def analyze_error_patterns(self, hours: int = 24) -> ErrorPatternAnalysis:
|
|
267
|
+
"""
|
|
268
|
+
分析错误模式
|
|
269
|
+
|
|
270
|
+
Args:
|
|
271
|
+
hours: 过去多少小时
|
|
272
|
+
|
|
273
|
+
Returns:
|
|
274
|
+
错误分析结果
|
|
275
|
+
"""
|
|
276
|
+
logger.info(f"Analyzing error patterns for the past {hours} hours")
|
|
277
|
+
|
|
278
|
+
end_time = datetime.now(timezone.utc)
|
|
279
|
+
start_time = end_time - timedelta(hours=hours)
|
|
280
|
+
|
|
281
|
+
# 查询错误日志(4xx 和 5xx)
|
|
282
|
+
query = AccessLogQuery(start_time=start_time, end_time=end_time, limit=5000, offset=0)
|
|
283
|
+
all_logs = await query_access_logs(query)
|
|
284
|
+
|
|
285
|
+
# 筛选错误日志
|
|
286
|
+
error_logs = [log for log in all_logs if log.status_code >= 400]
|
|
287
|
+
|
|
288
|
+
# 按路径统计错误
|
|
289
|
+
error_by_path: Dict[str, int] = {}
|
|
290
|
+
for log in error_logs:
|
|
291
|
+
error_by_path[log.path] = error_by_path.get(log.path, 0) + 1
|
|
292
|
+
|
|
293
|
+
# 按状态码统计错误
|
|
294
|
+
error_by_status: Dict[int, int] = {}
|
|
295
|
+
for log in error_logs:
|
|
296
|
+
error_by_status[log.status_code] = error_by_status.get(log.status_code, 0) + 1
|
|
297
|
+
|
|
298
|
+
return ErrorPatternAnalysis(
|
|
299
|
+
total_errors=len(error_logs),
|
|
300
|
+
error_rate=len(error_logs) / len(all_logs) if all_logs else 0,
|
|
301
|
+
top_error_paths=sorted(error_by_path.items(), key=lambda x: x[1], reverse=True)[:10],
|
|
302
|
+
error_by_status=error_by_status,
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
async def cleanup_old_logs(self, days: int = 30) -> int:
|
|
306
|
+
"""
|
|
307
|
+
清理旧的访问日志
|
|
308
|
+
|
|
309
|
+
业务规则:保留最近 N 天的日志
|
|
310
|
+
|
|
311
|
+
Args:
|
|
312
|
+
days: 保留天数
|
|
313
|
+
|
|
314
|
+
Returns:
|
|
315
|
+
删除的记录数
|
|
316
|
+
"""
|
|
317
|
+
logger.info(f"Cleaning up access logs older than {days} days")
|
|
318
|
+
|
|
319
|
+
before_time = datetime.now(timezone.utc) - timedelta(days=days)
|
|
320
|
+
deleted_count = await delete_old_logs(before_time)
|
|
321
|
+
|
|
322
|
+
logger.info(f"Cleaned up {deleted_count} old access log records")
|
|
323
|
+
return deleted_count
|
|
324
|
+
|
|
325
|
+
async def get_log_count(self, filters: Optional[Dict[str, Any]] = None) -> int:
|
|
326
|
+
"""
|
|
327
|
+
获取日志数量
|
|
328
|
+
|
|
329
|
+
Args:
|
|
330
|
+
filters: 过滤条件
|
|
331
|
+
|
|
332
|
+
Returns:
|
|
333
|
+
日志数量
|
|
334
|
+
"""
|
|
335
|
+
return await count_access_logs(filters)
|
|
336
|
+
|
|
337
|
+
def _validate_query_params(self, query: AccessLogQuery):
|
|
338
|
+
"""
|
|
339
|
+
验证查询参数
|
|
340
|
+
|
|
341
|
+
Args:
|
|
342
|
+
query: 查询参数对象
|
|
343
|
+
|
|
344
|
+
Raises:
|
|
345
|
+
ValueError: 参数无效
|
|
346
|
+
"""
|
|
347
|
+
# 验证时间范围
|
|
348
|
+
if query.start_time and query.end_time and query.start_time > query.end_time:
|
|
349
|
+
raise ValueError("Start time must be before end time")
|
|
350
|
+
|
|
351
|
+
# 验证 limit
|
|
352
|
+
if query.limit > 1000:
|
|
353
|
+
raise ValueError("Limit cannot exceed 1000")
|
|
354
|
+
|
|
355
|
+
# 验证响应时间范围
|
|
356
|
+
if query.min_response_time and query.max_response_time:
|
|
357
|
+
if query.min_response_time > query.max_response_time:
|
|
358
|
+
raise ValueError("Min response time must be less than max response time")
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Caddy HTTPS 证书管理领域服务
|
|
3
|
+
包含证书生命周期管理的核心业务逻辑
|
|
4
|
+
"""
|
|
5
|
+
from typing import (
|
|
6
|
+
List,
|
|
7
|
+
Optional,
|
|
8
|
+
Dict,
|
|
9
|
+
Any,
|
|
10
|
+
)
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
|
|
13
|
+
from linglong_web.utils import logger
|
|
14
|
+
from cancan_microstack.public.schemas.caddy import CaddyCertificate
|
|
15
|
+
from cancan_microstack.services.opsbffsrv.infrastructure.db.operate.caddy_certificate import (
|
|
16
|
+
get_certificate_by_id,
|
|
17
|
+
get_certificate_by_domain,
|
|
18
|
+
get_all_certificates,
|
|
19
|
+
get_active_certificates,
|
|
20
|
+
get_expiring_certificates,
|
|
21
|
+
get_expired_certificates,
|
|
22
|
+
get_auto_renew_certificates,
|
|
23
|
+
upsert_certificate,
|
|
24
|
+
update_certificate,
|
|
25
|
+
record_renew_attempt,
|
|
26
|
+
mark_certificate_expired,
|
|
27
|
+
enable_auto_renew,
|
|
28
|
+
disable_auto_renew,
|
|
29
|
+
delete_certificate,
|
|
30
|
+
get_certificate_statistics,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class CertificateManagementDomain:
|
|
35
|
+
"""证书管理领域服务"""
|
|
36
|
+
|
|
37
|
+
async def register_new_certificate(self, cert: CaddyCertificate) -> CaddyCertificate:
|
|
38
|
+
"""
|
|
39
|
+
注册新证书
|
|
40
|
+
|
|
41
|
+
业务规则:
|
|
42
|
+
1. 域名必须唯一(或使用 upsert 更新)
|
|
43
|
+
2. 过期时间必须晚于当前时间
|
|
44
|
+
3. 续期提前天数合理(7-90 天)
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
cert: 证书对象
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
创建后的证书对象
|
|
51
|
+
"""
|
|
52
|
+
logger.info(f"Registering new certificate for domain: {cert.domain}")
|
|
53
|
+
|
|
54
|
+
# 业务规则验证
|
|
55
|
+
await self._validate_certificate_create(cert)
|
|
56
|
+
|
|
57
|
+
# 使用 upsert 避免域名冲突
|
|
58
|
+
db_cert = await upsert_certificate(cert)
|
|
59
|
+
logger.info(f"Certificate registered for domain: {db_cert.domain}")
|
|
60
|
+
|
|
61
|
+
return db_cert
|
|
62
|
+
|
|
63
|
+
async def renew_certificate(self, cert_id: int) -> Optional[CaddyCertificate]:
|
|
64
|
+
"""
|
|
65
|
+
续期证书
|
|
66
|
+
|
|
67
|
+
这是业务流程的核心方法,实际的证书申请由应用层调用 ACME 客户端完成
|
|
68
|
+
领域层只负责记录续期尝试和更新状态
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
cert_id: 证书 ID
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
更新后的证书对象或 None
|
|
75
|
+
"""
|
|
76
|
+
logger.info(f"Initiating certificate renewal for ID: {cert_id}")
|
|
77
|
+
|
|
78
|
+
# 验证证书存在
|
|
79
|
+
existing_cert = await get_certificate_by_id(cert_id)
|
|
80
|
+
if not existing_cert:
|
|
81
|
+
logger.warning(f"Certificate not found: {cert_id}")
|
|
82
|
+
return None
|
|
83
|
+
|
|
84
|
+
# 记录续期尝试(应用层会调用此方法记录结果)
|
|
85
|
+
return existing_cert
|
|
86
|
+
|
|
87
|
+
async def check_and_mark_expired_certificates(self) -> int:
|
|
88
|
+
"""
|
|
89
|
+
检查并标记过期证书
|
|
90
|
+
|
|
91
|
+
业务规则:扫描所有证书,将已过期但状态不是 'expired' 的证书标记为过期
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
标记为过期的证书数量
|
|
95
|
+
"""
|
|
96
|
+
logger.info("Checking for expired certificates")
|
|
97
|
+
|
|
98
|
+
expired_certs = await get_expired_certificates()
|
|
99
|
+
count = 0
|
|
100
|
+
|
|
101
|
+
for cert in expired_certs:
|
|
102
|
+
await mark_certificate_expired(cert.id)
|
|
103
|
+
logger.info(f"Marked certificate as expired: {cert.domain}")
|
|
104
|
+
count += 1
|
|
105
|
+
|
|
106
|
+
logger.info(f"Marked {count} certificates as expired")
|
|
107
|
+
return count
|
|
108
|
+
|
|
109
|
+
async def get_certificates_needing_renewal(self) -> List[CaddyCertificate]:
|
|
110
|
+
"""
|
|
111
|
+
获取需要续期的证书列表
|
|
112
|
+
|
|
113
|
+
业务规则:
|
|
114
|
+
1. auto_renew = True
|
|
115
|
+
2. status = 'active'
|
|
116
|
+
3. 距离过期时间 <= renew_before_days
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
需要续期的证书列表
|
|
120
|
+
"""
|
|
121
|
+
logger.info("Fetching certificates needing renewal")
|
|
122
|
+
return await get_auto_renew_certificates()
|
|
123
|
+
|
|
124
|
+
async def update_certificate_info(self, cert_id: int, data: Dict[str, Any]) -> Optional[CaddyCertificate]:
|
|
125
|
+
"""
|
|
126
|
+
更新证书信息
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
cert_id: 证书 ID
|
|
130
|
+
data: 更新数据
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
更新后的证书对象或 None
|
|
134
|
+
"""
|
|
135
|
+
logger.info(f"Updating certificate: {cert_id}")
|
|
136
|
+
|
|
137
|
+
# 验证证书存在
|
|
138
|
+
existing_cert = await get_certificate_by_id(cert_id)
|
|
139
|
+
if not existing_cert:
|
|
140
|
+
logger.warning(f"Certificate not found: {cert_id}")
|
|
141
|
+
return None
|
|
142
|
+
|
|
143
|
+
# 更新数据库记录
|
|
144
|
+
updated_cert = await update_certificate(cert_id, data)
|
|
145
|
+
|
|
146
|
+
if updated_cert:
|
|
147
|
+
logger.info(f"Certificate updated: {cert_id}")
|
|
148
|
+
|
|
149
|
+
return updated_cert
|
|
150
|
+
|
|
151
|
+
async def toggle_auto_renew(self, cert_id: int, enabled: bool) -> Optional[CaddyCertificate]:
|
|
152
|
+
"""
|
|
153
|
+
切换证书自动续期状态
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
cert_id: 证书 ID
|
|
157
|
+
enabled: 是否启用
|
|
158
|
+
|
|
159
|
+
Returns:
|
|
160
|
+
更新后的证书对象或 None
|
|
161
|
+
"""
|
|
162
|
+
logger.info(f"Toggling auto-renew for certificate {cert_id} to: {enabled}")
|
|
163
|
+
|
|
164
|
+
if enabled:
|
|
165
|
+
updated_cert = await enable_auto_renew(cert_id)
|
|
166
|
+
else:
|
|
167
|
+
updated_cert = await disable_auto_renew(cert_id)
|
|
168
|
+
|
|
169
|
+
return updated_cert
|
|
170
|
+
|
|
171
|
+
async def record_renewal_result(self, cert_id: int, success: bool, error: Optional[str] = None) -> Optional[
|
|
172
|
+
CaddyCertificate]:
|
|
173
|
+
"""
|
|
174
|
+
记录续期结果
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
cert_id: 证书 ID
|
|
178
|
+
success: 是否成功
|
|
179
|
+
error: 错误信息(如果失败)
|
|
180
|
+
|
|
181
|
+
Returns:
|
|
182
|
+
更新后的证书对象或 None
|
|
183
|
+
"""
|
|
184
|
+
logger.info(f"Recording renewal result for certificate {cert_id}: success={success}")
|
|
185
|
+
return await record_renew_attempt(cert_id, success, error)
|
|
186
|
+
|
|
187
|
+
async def remove_certificate(self, cert_id: int) -> bool:
|
|
188
|
+
"""
|
|
189
|
+
删除证书
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
cert_id: 证书 ID
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
是否删除成功
|
|
196
|
+
"""
|
|
197
|
+
logger.info(f"Removing certificate: {cert_id}")
|
|
198
|
+
|
|
199
|
+
# 验证证书存在
|
|
200
|
+
existing_cert = await get_certificate_by_id(cert_id)
|
|
201
|
+
if not existing_cert:
|
|
202
|
+
logger.warning(f"Certificate not found: {cert_id}")
|
|
203
|
+
return False
|
|
204
|
+
|
|
205
|
+
# 删除数据库记录
|
|
206
|
+
success = await delete_certificate(cert_id)
|
|
207
|
+
|
|
208
|
+
if success:
|
|
209
|
+
logger.info(f"Certificate removed: {cert_id}")
|
|
210
|
+
|
|
211
|
+
return success
|
|
212
|
+
|
|
213
|
+
async def get_certificate_details(self, cert_id: int) -> Optional[CaddyCertificate]:
|
|
214
|
+
"""
|
|
215
|
+
获取证书详情
|
|
216
|
+
|
|
217
|
+
Args:
|
|
218
|
+
cert_id: 证书 ID
|
|
219
|
+
|
|
220
|
+
Returns:
|
|
221
|
+
证书对象或 None
|
|
222
|
+
"""
|
|
223
|
+
return await get_certificate_by_id(cert_id)
|
|
224
|
+
|
|
225
|
+
async def get_certificate_by_domain_name(self, domain: str) -> Optional[CaddyCertificate]:
|
|
226
|
+
"""
|
|
227
|
+
根据域名获取证书
|
|
228
|
+
|
|
229
|
+
Args:
|
|
230
|
+
domain: 域名
|
|
231
|
+
|
|
232
|
+
Returns:
|
|
233
|
+
证书对象或 None
|
|
234
|
+
"""
|
|
235
|
+
return await get_certificate_by_domain(domain)
|
|
236
|
+
|
|
237
|
+
async def list_certificates(self, filters: Optional[Dict[str, Any]] = None) -> List[CaddyCertificate]:
|
|
238
|
+
"""
|
|
239
|
+
列出证书
|
|
240
|
+
|
|
241
|
+
Args:
|
|
242
|
+
filters: 过滤条件
|
|
243
|
+
|
|
244
|
+
Returns:
|
|
245
|
+
证书列表
|
|
246
|
+
"""
|
|
247
|
+
return await get_all_certificates(filters)
|
|
248
|
+
|
|
249
|
+
async def list_active_certificates(self) -> List[CaddyCertificate]:
|
|
250
|
+
"""
|
|
251
|
+
列出所有激活的证书
|
|
252
|
+
|
|
253
|
+
Returns:
|
|
254
|
+
激活证书列表
|
|
255
|
+
"""
|
|
256
|
+
return await get_active_certificates()
|
|
257
|
+
|
|
258
|
+
async def list_expiring_certificates(self, days: int = 30) -> List[CaddyCertificate]:
|
|
259
|
+
"""
|
|
260
|
+
列出即将过期的证书
|
|
261
|
+
|
|
262
|
+
Args:
|
|
263
|
+
days: 多少天内过期
|
|
264
|
+
|
|
265
|
+
Returns:
|
|
266
|
+
即将过期的证书列表
|
|
267
|
+
"""
|
|
268
|
+
return await get_expiring_certificates(days)
|
|
269
|
+
|
|
270
|
+
async def get_certificate_statistics_summary(self) -> Dict[str, int]:
|
|
271
|
+
"""
|
|
272
|
+
获取证书统计摘要
|
|
273
|
+
|
|
274
|
+
Returns:
|
|
275
|
+
统计信息字典
|
|
276
|
+
"""
|
|
277
|
+
return await get_certificate_statistics()
|
|
278
|
+
|
|
279
|
+
async def _validate_certificate_create(self, cert: CaddyCertificate):
|
|
280
|
+
"""
|
|
281
|
+
验证证书创建的业务规则
|
|
282
|
+
|
|
283
|
+
Args:
|
|
284
|
+
cert: 证书对象
|
|
285
|
+
|
|
286
|
+
Raises:
|
|
287
|
+
ValueError: 业务规则违反
|
|
288
|
+
"""
|
|
289
|
+
# 验证域名格式
|
|
290
|
+
if not self._is_valid_domain(cert.domain):
|
|
291
|
+
raise ValueError(f"Invalid domain format: {cert.domain}")
|
|
292
|
+
|
|
293
|
+
# 验证过期时间
|
|
294
|
+
if cert.expires_at and cert.expires_at <= datetime.utcnow():
|
|
295
|
+
raise ValueError("Certificate expiration time must be in the future")
|
|
296
|
+
|
|
297
|
+
# 验证续期提前天数
|
|
298
|
+
if cert.renew_before_days < 7 or cert.renew_before_days > 90:
|
|
299
|
+
raise ValueError(f"Renew before days must be between 7 and 90: {cert.renew_before_days}")
|
|
300
|
+
|
|
301
|
+
# 验证 ACME 提供商
|
|
302
|
+
valid_providers = ['letsencrypt', 'letsencrypt-staging', 'zerossl', 'buypass']
|
|
303
|
+
if cert.acme_provider not in valid_providers:
|
|
304
|
+
raise ValueError(f"Invalid ACME provider: {cert.acme_provider}. Must be one of {valid_providers}")
|
|
305
|
+
|
|
306
|
+
# 验证 ACME 挑战类型
|
|
307
|
+
valid_challenges = ['http-01', 'dns-01', 'tls-alpn-01']
|
|
308
|
+
if cert.acme_challenge_type not in valid_challenges:
|
|
309
|
+
raise ValueError(
|
|
310
|
+
f"Invalid ACME challenge type: {cert.acme_challenge_type}. Must be one of {valid_challenges}")
|
|
311
|
+
|
|
312
|
+
def _is_valid_domain(self, domain: str) -> bool:
|
|
313
|
+
"""
|
|
314
|
+
验证域名格式
|
|
315
|
+
|
|
316
|
+
Args:
|
|
317
|
+
domain: 域名字符串
|
|
318
|
+
|
|
319
|
+
Returns:
|
|
320
|
+
是否为有效域名
|
|
321
|
+
"""
|
|
322
|
+
import re
|
|
323
|
+
# 简单的域名验证正则(支持通配符)
|
|
324
|
+
pattern = r'^(\*\.)?([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$'
|
|
325
|
+
return bool(re.match(pattern, domain))
|