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 @@
|
|
|
1
|
+
import{I as t,J as a,K as L,r as c,x as N,E as s}from"./index-CiFlm8oc.js";const $={PENDING:{label:"待调度",color:"var(--text-secondary)",bgColor:"var(--bg-tertiary)",icon:"i-carbon-time"},RUNNING:{label:"运行中",color:"var(--primary-500)",bgColor:"rgba(22, 119, 255, 0.15)",icon:"i-carbon-in-progress"},SUCCESS:{label:"成功",color:"var(--success-500)",bgColor:"rgba(82, 196, 26, 0.15)",icon:"i-carbon-checkmark-filled"},FAILURE:{label:"失败",color:"var(--error-500)",bgColor:"rgba(255, 77, 79, 0.15)",icon:"i-carbon-warning-alt-filled"},CANCELLED:{label:"已取消",color:"var(--warning-600)",bgColor:"rgba(250, 173, 20, 0.2)",icon:"i-carbon-close-outline"},PAUSED:{label:"已暂停",color:"var(--warning-500)",bgColor:"rgba(250, 173, 20, 0.15)",icon:"i-carbon-pause"}},Q={PENDING:{label:"等待中",color:"var(--text-secondary)",bgColor:"var(--bg-tertiary)",icon:"i-carbon-time"},RUNNING:{label:"执行中",color:"var(--primary-500)",bgColor:"rgba(22, 119, 255, 0.15)",icon:"i-carbon-in-progress"},SUSPENDED:{label:"挂起",color:"var(--warning-600)",bgColor:"rgba(250, 173, 20, 0.15)",icon:"i-carbon-pause"},SUCCESS:{label:"成功",color:"var(--success-500)",bgColor:"rgba(82, 196, 26, 0.15)",icon:"i-carbon-checkmark-filled"},FAILURE:{label:"失败",color:"var(--error-500)",bgColor:"rgba(255, 77, 79, 0.15)",icon:"i-carbon-close"},SKIPPED:{label:"跳过",color:"var(--text-tertiary)",bgColor:"var(--bg-secondary)",icon:"i-carbon-skip-forward"},RETRYING:{label:"重试中",color:"var(--primary-600)",bgColor:"rgba(22, 119, 255, 0.2)",icon:"i-carbon-renew"},CANCELLED:{label:"已取消",color:"var(--text-secondary)",bgColor:"rgba(0, 0, 0, 0.05)",icon:"i-carbon-close"}},X={OPEN:{label:"未处理",color:"var(--error-600)",bgColor:"rgba(255, 99, 71, 0.12)",icon:"i-carbon-warning-alt"},ACKED:{label:"已知晓",color:"var(--warning-700)",bgColor:"rgba(250, 173, 20, 0.18)",icon:"i-carbon-reminder"},RESOLVED:{label:"已解决",color:"var(--success-600)",bgColor:"rgba(82, 196, 26, 0.18)",icon:"i-carbon-checkmark"}},Z={CRITICAL:{label:"致命",color:"var(--error-600)",icon:"i-carbon-warning-alt-filled"},MAJOR:{label:"严重",color:"var(--warning-700)",icon:"i-carbon-warning-filled"},MINOR:{label:"提示",color:"var(--primary-600)",icon:"i-carbon-information-filled"}},oo=[{type:"ACTION",label:"HTTP 请求",icon:"i-carbon-api",color:"var(--primary-500)",description:"发送 HTTP 请求",defaultConfig:{async_mode:!1,request:{method:"GET",url:"https://example.com",timeout_seconds:10},context_mappings:{},retry_policy:{enabled:!0,max_attempts:3,interval_seconds:5}}},{type:"TRANSFORM",label:"数据加工",icon:"i-carbon-data-enrichment",color:"var(--success-500)",description:"JSON 数据转换",defaultConfig:{engine:"JINJA2",output_schema:{}}},{type:"LOGIC",label:"条件判断",icon:"i-carbon-direction-fork",color:"var(--warning-500)",description:"If/Else 分支",defaultConfig:{condition:"{{ context.__runtime__.last_output.ok }}"}},{type:"FORK",label:"并行分支",icon:"i-carbon-flow-stream",color:"var(--warning-600)",description:"同时触发多个下游任务",defaultConfig:{branch_node_ids:[],branch_labels:{}}},{type:"LOOP",label:"循环控制",icon:"i-carbon-loop",color:"var(--purple-500)",description:"迭代循环",defaultConfig:{condition:"{{ context.loop_index > 10 or context.__runtime__.last_status != 'SUCCESS' }}",max_iterations:10,loop_next_id:void 0}},{type:"JOIN",label:"汇聚节点",icon:"i-carbon-arrows-vertical",color:"var(--gray-500)",description:"合并分支",defaultConfig:{mode:"ALL",timeout_seconds:3600}}],O=o=>({...o||{},_t:Date.now()}),R=o=>t.Get(a.WORKFLOW_DEFINITIONS,{params:O(o)}),m=o=>t.Get(a.WORKFLOW_DEFINITION_DETAIL(o),{params:{_t:Date.now()}}),S=o=>t.Post(a.WORKFLOW_DEFINITIONS,o),T=(o,n)=>t.Put(a.WORKFLOW_DEFINITION_DETAIL(o),n),y=o=>t.Delete(a.WORKFLOW_DEFINITION_DETAIL(o)),C=o=>t.Post(a.WORKFLOW_DEFINITION_TOGGLE(o)),F=(o,n)=>t.Post(a.WORKFLOW_DEFINITION_DUPLICATE(o),n),k=o=>t.Post(a.WORKFLOW_DEFINITION_PUBLISH(o)),K=o=>t.Post(a.WORKFLOW_DEFINITION_VALIDATE(o)),P=o=>t.Get(a.WORKFLOW_DEFINITION_VERSIONS(o),{params:{_t:Date.now()}}),x=(o,n)=>t.Post(a.WORKFLOW_DEFINITION_ROLLBACK(o),n),G=()=>t.Get(a.WORKFLOW_STATS,{params:{_t:Date.now()}}),eo=o=>t.Get(a.WORKFLOW_RUNS,{params:O(o)}),ro=o=>t.Get(a.WORKFLOW_RUN_GRAPH(o),{params:{_t:Date.now()}}),to=(o,n)=>t.Get(a.WORKFLOW_NODE_LOGS(o,n),{params:{_t:Date.now()}}),ao=(o,n)=>t.Post(a.WORKFLOW_TRIGGER_RUN(o),n),no=o=>t.Get(a.WORKFLOW_ALERTS,{params:O(o)}),io=(o,n)=>t.Post(a.WORKFLOW_ALERT_ACK(o),n),so=(o,n)=>t.Post(a.WORKFLOW_ALERT_RESOLVE(o),n),co=L("workflow",()=>{const o=c([]),n=c(0),g=c(!1),_=c(!1),W=c(null),l=c(null),b=c({nodes:[],edges:[]}),d=c({name:"",description:"",schedule:"0 0 0 * * *",timezone:"Asia/Shanghai",tags:[],is_active:!0,global_context:{}}),v=c({}),p=c(!1),D=c({}),h=N(()=>l.value&&o.value.find(e=>e.id===l.value)||null),I=N(()=>b.value.nodes.length>0),w=e=>{l.value=e},A=e=>{e?(b.value=JSON.parse(JSON.stringify(e.graph_data||{nodes:[],edges:[]})),v.value=JSON.parse(JSON.stringify(e.nodes_config||{})),d.value={name:e.name,description:e.description,schedule:e.schedule,timezone:e.timezone||"Asia/Shanghai",tags:e.tags||[],is_active:e.is_active,global_context:e.global_context||{}}):(b.value={nodes:[],edges:[]},v.value={},d.value={name:"",description:"",schedule:"0 0 0 * * *",timezone:"Asia/Shanghai",tags:[],is_active:!0,global_context:{}}),p.value=!1},f=async e=>{g.value=!0;try{const r=await R(e);return o.value=r?.list||[],n.value=r?.total||0,!l.value&&o.value.length>0&&(l.value=o.value[0].id),r}catch(r){throw s.error("获取编排列表失败"),r}finally{g.value=!1}},E=async e=>{const r=await m(e),i=o.value.findIndex(u=>u.id===e);return i>=0?o.value[i]=r:o.value.unshift(r),l.value=e,r};return{definitions:o,total:n,loading:g,stats:W,statsLoading:_,selectedId:l,designerGraph:b,designerMeta:d,designerNodesConfig:v,designerDirty:p,versionHistories:D,currentDefinition:h,hasGraphDraft:I,setSelectedId:w,resetDesigner:A,fetchDefinitionsAction:f,fetchDefinitionDetailAction:E,saveDefinition:async(e,r)=>{try{const i=r?await T(r,e):await S(e);return s.success("工作流保存成功"),await f(),i}catch(i){throw s.error("保存失败"),i}},removeDefinition:async e=>{await y(e),o.value=o.value.filter(r=>r.id!==e),l.value===e&&(l.value=o.value[0]?.id||null),s.success("已删除")},toggleDefinitionStatus:async e=>{const r=await C(e),i=o.value.findIndex(u=>u.id===e);return i>=0&&(o.value[i]=r),s.success(r.is_active?"已启用":"已停用"),r},duplicateDefinitionAction:async(e,r)=>{const u=await F(e,{source_workflow_id:e,name:r});return o.value.unshift(u),s.success("复制成功"),u},fetchWorkflowStatsAction:async()=>{_.value=!0;try{const e=await G();return W.value=e,e}catch{return null}finally{_.value=!1}},validateCurrentDesigner:async e=>{try{const r=await K(e);return r.valid?s.success("校验通过"):s.warning(`校验未通过:${(r.issues||[]).join(";")}`),r}catch(r){throw s.error("校验失败"),r}},publishDefinition:async e=>{try{const r=await k(e);return s.success("已发布最新版本"),await f(),r}catch(r){throw s.error("发布失败"),r}},fetchWorkflowVersionsAction:async e=>{const r=await P(e);return D.value[e]=r.versions||[],r},rollbackWorkflowVersionAction:async(e,r)=>{const i=await x(e,r);return s.success("已回滚到指定版本"),await Promise.all([E(e),f()]),i}}});export{oo as D,Q as N,$ as W,X as a,Z as b,io as c,to as d,ro as e,no as f,eo as g,so as r,ao as t,co as u};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<link rel="icon" type="image/svg+xml" href="/adminops/vite.svg" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
|
7
|
+
<meta name="theme-color" content="#ffffff" />
|
|
8
|
+
<meta name="description" content="现代化 OPS 运维管理平台" />
|
|
9
|
+
<title>OPS 管理平台</title>
|
|
10
|
+
<script type="module" crossorigin src="/adminops/assets/index-CiFlm8oc.js"></script>
|
|
11
|
+
<link rel="stylesheet" crossorigin href="/adminops/assets/index-UW0T1Dkc.css">
|
|
12
|
+
</head>
|
|
13
|
+
<body>
|
|
14
|
+
<div id="app"></div>
|
|
15
|
+
</body>
|
|
16
|
+
</html>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Command line interface helpers for Cancan Microstack."""
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def log(message: str, **fields: Any) -> None:
|
|
7
|
+
"""Lightweight structured logger for CLI feedback."""
|
|
8
|
+
|
|
9
|
+
prefix = datetime.now().isoformat(timespec="seconds")
|
|
10
|
+
extras = " ".join(f"{key}={value}" for key, value in fields.items() if value is not None)
|
|
11
|
+
print(f"[{prefix}] {message} {extras}".strip())
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
from .main import main # noqa: E402 (import after helper definition)
|
|
@@ -0,0 +1,552 @@
|
|
|
1
|
+
"""Argparse-based CLI for Cancan Microstack."""
|
|
2
|
+
import argparse
|
|
3
|
+
import os
|
|
4
|
+
import time
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Sequence
|
|
7
|
+
|
|
8
|
+
from .. import __version__
|
|
9
|
+
from ..core.stack_manager import StackManager
|
|
10
|
+
from ..core.stack_manager import StackOptions
|
|
11
|
+
from ..core.microstack import CancanMicrostack
|
|
12
|
+
from . import log
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
16
|
+
parser = argparse.ArgumentParser(prog="cancan", description="Cancan Microstack helper commands")
|
|
17
|
+
sub = parser.add_subparsers(dest="command", required=True)
|
|
18
|
+
|
|
19
|
+
assets_parser = sub.add_parser("assets", help="Inspect packaged assets")
|
|
20
|
+
assets_sub = assets_parser.add_subparsers(dest="assets_command", required=True)
|
|
21
|
+
|
|
22
|
+
list_parser = assets_sub.add_parser("list", help="List assets")
|
|
23
|
+
list_parser.add_argument("subdir", nargs="?", help="Optional asset subdirectory filter")
|
|
24
|
+
|
|
25
|
+
export_parser = assets_sub.add_parser("export", help="Export asset to destination")
|
|
26
|
+
export_parser.add_argument("logical_name", help="Asset logical name, e.g. docker/docker-compose.infra.yml")
|
|
27
|
+
export_parser.add_argument("destination", help="Destination file or directory path")
|
|
28
|
+
export_parser.add_argument("--overwrite", action="store_true", help="Overwrite destination when it exists")
|
|
29
|
+
|
|
30
|
+
compose_parser = sub.add_parser("compose", help="Compose orchestration helpers")
|
|
31
|
+
compose_sub = compose_parser.add_subparsers(dest="compose_command", required=True)
|
|
32
|
+
build_parser = compose_sub.add_parser("build", help="Generate merged compose stack")
|
|
33
|
+
build_parser.add_argument("--workspace", default=".", help="Workspace root (default: current directory)")
|
|
34
|
+
build_parser.add_argument("--service-file", help="Optional service compose file from workspace")
|
|
35
|
+
build_parser.add_argument("--override", action="append", default=[], help="Additional override compose files")
|
|
36
|
+
build_parser.add_argument("--output", help="Target compose file path (default: compose.cancan.yml)")
|
|
37
|
+
build_parser.add_argument(
|
|
38
|
+
"--bootstrap",
|
|
39
|
+
action=argparse.BooleanOptionalAction,
|
|
40
|
+
default=True,
|
|
41
|
+
help="Export missing workspace assets (infra compose, Caddy/service Dockerfiles, DDL)",
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
svc_parser = sub.add_parser("services", help="Run bundled services")
|
|
45
|
+
svc_sub = svc_parser.add_subparsers(dest="services_command", required=True)
|
|
46
|
+
run_parser = svc_sub.add_parser("run", help="Run a managed service")
|
|
47
|
+
run_parser.add_argument("name", choices=["controllersrv", "infrasrv", "opsbffsrv"], help="Service name")
|
|
48
|
+
run_parser.add_argument("--host", default="0.0.0.0", help="Host binding")
|
|
49
|
+
run_parser.add_argument("--port", type=int, help="Port binding (defaults depend on service)")
|
|
50
|
+
run_parser.add_argument("--workspace", default=".", help="Workspace root (default: current directory)")
|
|
51
|
+
|
|
52
|
+
sub.add_parser("version", help="Show version")
|
|
53
|
+
|
|
54
|
+
doctor_parser = sub.add_parser("doctor", help="Diagnose environment & config readiness before stack up")
|
|
55
|
+
doctor_parser.add_argument("--workspace", default=".", help="Workspace root (default: current directory)")
|
|
56
|
+
|
|
57
|
+
init_parser = sub.add_parser("init", help="Scaffold a minimal runnable workspace (compose sample + .env + overrides)")
|
|
58
|
+
init_parser.add_argument("--workspace", default=".", help="Target workspace dir (default: current directory)")
|
|
59
|
+
|
|
60
|
+
stack_parser = sub.add_parser("stack", help="Start/stop the whole microstack")
|
|
61
|
+
stack_sub = stack_parser.add_subparsers(dest="stack_command", required=True)
|
|
62
|
+
|
|
63
|
+
stack_up = stack_sub.add_parser("up", help="Build + bootstrap + start controllersrv + compose up")
|
|
64
|
+
stack_up.add_argument("--workspace", default=".", help="Workspace root (default: current directory)")
|
|
65
|
+
stack_up.add_argument("--service-file", default="docker-compose.services.yml", help="Business compose file")
|
|
66
|
+
stack_up.add_argument("--override", action="append", default=[], help="Additional override compose files")
|
|
67
|
+
stack_up.add_argument("--output", help="Target compose file path (default: compose.cancan.yml)")
|
|
68
|
+
stack_up.add_argument(
|
|
69
|
+
"--bootstrap",
|
|
70
|
+
action=argparse.BooleanOptionalAction,
|
|
71
|
+
default=True,
|
|
72
|
+
help="Export missing workspace assets (infra compose, Caddy/service Dockerfiles, DDL, adminops)",
|
|
73
|
+
)
|
|
74
|
+
stack_up.add_argument(
|
|
75
|
+
"--with-controllersrv",
|
|
76
|
+
action=argparse.BooleanOptionalAction,
|
|
77
|
+
default=True,
|
|
78
|
+
help="Start/ensure host controllersrv is running before bringing up containers",
|
|
79
|
+
)
|
|
80
|
+
stack_up.add_argument("--controllersrv-host", default="127.0.0.1", help="controllersrv bind host")
|
|
81
|
+
stack_up.add_argument("--controllersrv-port", default=22100, type=int, help="controllersrv bind port")
|
|
82
|
+
stack_up.add_argument(
|
|
83
|
+
"--engine",
|
|
84
|
+
choices=["auto", "docker", "podman"],
|
|
85
|
+
default="auto",
|
|
86
|
+
help="Container engine for compose command detection",
|
|
87
|
+
)
|
|
88
|
+
stack_up.add_argument(
|
|
89
|
+
"--build",
|
|
90
|
+
action="store_true",
|
|
91
|
+
help="Force rebuild images (equivalent to compose up --build)",
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
stack_down = stack_sub.add_parser("down", help="Compose down + stop controllersrv")
|
|
95
|
+
stack_down.add_argument("--workspace", default=".", help="Workspace root (default: current directory)")
|
|
96
|
+
stack_down.add_argument("--compose-file", default="compose.cancan.yml", help="Compose file to use")
|
|
97
|
+
stack_down.add_argument(
|
|
98
|
+
"--with-controllersrv",
|
|
99
|
+
action=argparse.BooleanOptionalAction,
|
|
100
|
+
default=True,
|
|
101
|
+
help="Stop host controllersrv after bringing down containers",
|
|
102
|
+
)
|
|
103
|
+
stack_down.add_argument(
|
|
104
|
+
"--volumes",
|
|
105
|
+
action="store_true",
|
|
106
|
+
help="Remove named volumes when bringing stack down",
|
|
107
|
+
)
|
|
108
|
+
stack_down.add_argument(
|
|
109
|
+
"--engine",
|
|
110
|
+
choices=["auto", "docker", "podman"],
|
|
111
|
+
default="auto",
|
|
112
|
+
help="Container engine for compose command detection",
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
stack_status = stack_sub.add_parser("status", help="Show stack status (controllersrv + compose ps)")
|
|
116
|
+
stack_status.add_argument("--workspace", default=".", help="Workspace root (default: current directory)")
|
|
117
|
+
stack_status.add_argument("--compose-file", default="compose.cancan.yml", help="Compose file to use")
|
|
118
|
+
stack_status.add_argument(
|
|
119
|
+
"--engine",
|
|
120
|
+
choices=["auto", "docker", "podman"],
|
|
121
|
+
default="auto",
|
|
122
|
+
help="Container engine for compose command detection",
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
controllersrv_parser = sub.add_parser("controllersrv", help="Manage host controllersrv daemon")
|
|
126
|
+
controllersrv_sub = controllersrv_parser.add_subparsers(dest="controllersrv_command", required=True)
|
|
127
|
+
|
|
128
|
+
controllersrv_restart = controllersrv_sub.add_parser(
|
|
129
|
+
"restart",
|
|
130
|
+
help="Stop existing daemon (if any) and start a fresh controllersrv on the host",
|
|
131
|
+
)
|
|
132
|
+
controllersrv_restart.add_argument("--workspace", default=".", help="Workspace root (default: current directory)")
|
|
133
|
+
controllersrv_restart.add_argument("--host", default="127.0.0.1", help="controllersrv bind host")
|
|
134
|
+
controllersrv_restart.add_argument("--port", type=int, default=22100, help="controllersrv bind port")
|
|
135
|
+
controllersrv_restart.add_argument(
|
|
136
|
+
"--engine",
|
|
137
|
+
choices=["auto", "docker", "podman"],
|
|
138
|
+
default="auto",
|
|
139
|
+
help="Container engine preference propagated into controllersrv (auto = detect)",
|
|
140
|
+
)
|
|
141
|
+
controllersrv_restart.add_argument(
|
|
142
|
+
"--wait",
|
|
143
|
+
action=argparse.BooleanOptionalAction,
|
|
144
|
+
default=True,
|
|
145
|
+
help="Wait for /internal/health after restart (default: enabled)",
|
|
146
|
+
)
|
|
147
|
+
controllersrv_restart.add_argument(
|
|
148
|
+
"--timeout",
|
|
149
|
+
type=float,
|
|
150
|
+
default=8.0,
|
|
151
|
+
help="Seconds to wait for controllersrv health before reporting timeout",
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
return parser
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def _write_text_if_missing(path: Path, content: str) -> None:
|
|
158
|
+
"""仅在文件不存在时写入内容。
|
|
159
|
+
Write content only when the file does not exist.
|
|
160
|
+
"""
|
|
161
|
+
|
|
162
|
+
if path.exists():
|
|
163
|
+
return
|
|
164
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
165
|
+
path.write_text(content, encoding="utf-8")
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def _seed_env_file(workspace: Path, stack: CancanMicrostack) -> None:
|
|
169
|
+
"""缺失时从模板生成工作区 .env,并填入新鲜的 AUTH_TOTP_FERNET_KEY。
|
|
170
|
+
Create workspace .env from the template (when missing) with a fresh TOTP encryption key.
|
|
171
|
+
|
|
172
|
+
说明 / Note: opsbffsrv 生产模式下要求 AUTH_TOTP_FERNET_KEY 非空,否则拒绝启动;
|
|
173
|
+
这里为每个工作区生成一个稳定的真实 key,既保证开箱即用,又避免共享弱默认。
|
|
174
|
+
opsbffsrv refuses to start in prod mode with an empty key; we generate a real,
|
|
175
|
+
per-workspace key so the stack works out of the box without a shared weak default.
|
|
176
|
+
"""
|
|
177
|
+
|
|
178
|
+
env_path = workspace / ".env"
|
|
179
|
+
if env_path.exists():
|
|
180
|
+
return
|
|
181
|
+
try:
|
|
182
|
+
template = stack.assets.read_text("env/.env.example")
|
|
183
|
+
except Exception:
|
|
184
|
+
return
|
|
185
|
+
|
|
186
|
+
key = ""
|
|
187
|
+
try:
|
|
188
|
+
from cryptography.fernet import Fernet
|
|
189
|
+
key = Fernet.generate_key().decode()
|
|
190
|
+
except Exception:
|
|
191
|
+
key = ""
|
|
192
|
+
|
|
193
|
+
lines = []
|
|
194
|
+
for line in template.splitlines():
|
|
195
|
+
if key and line.startswith("AUTH_TOTP_FERNET_KEY="):
|
|
196
|
+
lines.append(f"AUTH_TOTP_FERNET_KEY={key}")
|
|
197
|
+
else:
|
|
198
|
+
lines.append(line)
|
|
199
|
+
env_path.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def _bootstrap_workspace_files(workspace: Path, stack: CancanMicrostack) -> None:
|
|
203
|
+
"""为 compose 运行准备工作区文件(缺失则创建)。
|
|
204
|
+
Bootstrap workspace files needed to run compose (create when missing).
|
|
205
|
+
|
|
206
|
+
目标 / Goals:
|
|
207
|
+
- 在缺失时导出运行时资产到工作区:infra compose、Caddy/Service Dockerfile、DDL、adminops 前端。
|
|
208
|
+
Export runtime assets into the workspace when missing: infra compose,
|
|
209
|
+
Caddy/service Dockerfiles, DDL, and the adminops frontend.
|
|
210
|
+
|
|
211
|
+
说明 / Note: 容器内服务直接以 ``python -m cancan_microstack.cmd.<svc>.run`` 运行**已安装的包**,
|
|
212
|
+
不再需要工作区里的 ``cmd/*`` 包装脚本(旧布局遗留,已移除)。
|
|
213
|
+
Containerized services run the installed package directly via
|
|
214
|
+
``python -m cancan_microstack.cmd.<svc>.run``; no workspace ``cmd/*`` wrappers are needed.
|
|
215
|
+
"""
|
|
216
|
+
|
|
217
|
+
def _export_asset_if_missing(logical_name: str, destination: Path) -> None:
|
|
218
|
+
"""Export packaged assets on demand without overwriting user changes.
|
|
219
|
+
|
|
220
|
+
按需导出打包资产,避免覆盖用户在工作区中的自定义内容。
|
|
221
|
+
"""
|
|
222
|
+
|
|
223
|
+
if destination.exists():
|
|
224
|
+
return
|
|
225
|
+
try:
|
|
226
|
+
stack.export_asset(logical_name, destination, overwrite=False)
|
|
227
|
+
except FileExistsError:
|
|
228
|
+
pass
|
|
229
|
+
|
|
230
|
+
# Optional export: infra compose file for include-based docker-compose.yml.
|
|
231
|
+
# 可选导出:用于 include 的 infra compose 文件(缺失才导出)。
|
|
232
|
+
target_infra_file = workspace / "infra" / "docker-compose.infra.yml"
|
|
233
|
+
_export_asset_if_missing("docker/docker-compose.infra.yml", target_infra_file)
|
|
234
|
+
|
|
235
|
+
# Export base Dockerfile scaffolds for caddy + python services when missing.
|
|
236
|
+
# 导出 Caddy 与 Python 服务镜像的基础脚手架(缺失时才复制)。
|
|
237
|
+
_export_asset_if_missing("builds/caddy", workspace / "builds" / "caddy")
|
|
238
|
+
_export_asset_if_missing("builds/service", workspace / "builds" / "service")
|
|
239
|
+
|
|
240
|
+
# Ensure Postgres init scripts exist so compose can create logical databases on first boot.
|
|
241
|
+
# 确保 PostgreSQL 初始化脚本存在,便于首次启动时创建 infra/ops/biz 数据库。
|
|
242
|
+
_export_asset_if_missing("ddl/create_db.sql", workspace / "ddl" / "create_db.sql")
|
|
243
|
+
|
|
244
|
+
# Export the env template and seed a workspace .env (with a fresh TOTP key) when missing.
|
|
245
|
+
# 导出 env 模板;缺失时生成带新鲜 TOTP 密钥的工作区 .env(供 compose 注入凭据/密钥)。
|
|
246
|
+
_export_asset_if_missing("env/.env.example", workspace / ".env.example")
|
|
247
|
+
_seed_env_file(workspace, stack)
|
|
248
|
+
|
|
249
|
+
# Export adminops frontend into workspace for Caddy to serve.
|
|
250
|
+
# 导出 adminops 前端到工作区,供 Caddy 静态挂载使用。
|
|
251
|
+
target_adminops_dir = workspace / "builds" / "caddy" / "www" / "adminops"
|
|
252
|
+
should_export_adminops = (not target_adminops_dir.exists())
|
|
253
|
+
if target_adminops_dir.exists() and target_adminops_dir.is_dir():
|
|
254
|
+
try:
|
|
255
|
+
should_export_adminops = not any(target_adminops_dir.iterdir())
|
|
256
|
+
except OSError:
|
|
257
|
+
should_export_adminops = True
|
|
258
|
+
|
|
259
|
+
if should_export_adminops:
|
|
260
|
+
try:
|
|
261
|
+
stack.export_asset("www/adminops", target_adminops_dir, overwrite=False)
|
|
262
|
+
except FileExistsError:
|
|
263
|
+
# Race: another process created it.
|
|
264
|
+
# 竞态条件:目录被并发创建,忽略即可。
|
|
265
|
+
pass
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
_SERVICES_COMPOSE_SAMPLE = """\
|
|
269
|
+
# 你的业务服务;`cancan compose build` 会把它与内置基础设施 compose 合并。
|
|
270
|
+
# Your business services. Merged with the bundled infra compose by `cancan compose build`.
|
|
271
|
+
services:
|
|
272
|
+
# 示例服务 —— 替换为你自己的。Example service — replace with your own.
|
|
273
|
+
app.service:
|
|
274
|
+
# build: ./app # 你的业务镜像 / your business image
|
|
275
|
+
image: app_python_service:latest
|
|
276
|
+
networks: [app_network]
|
|
277
|
+
expose: ["8000"]
|
|
278
|
+
# depends_on / environment / volumes ... 按需添加 / add as needed
|
|
279
|
+
"""
|
|
280
|
+
|
|
281
|
+
_OVERRIDES_README = """\
|
|
282
|
+
# cancan_overrides
|
|
283
|
+
|
|
284
|
+
在这里放你要替换的 cancan 内置服务文件(免 fork)。运行时会优先加载本目录。
|
|
285
|
+
Drop files here to override cancan's bundled services without forking; loaded with priority at runtime.
|
|
286
|
+
|
|
287
|
+
例 / Example:
|
|
288
|
+
cancan_overrides/infrasrv/conf/config.py # 只放你要改的文件 / only the files you change
|
|
289
|
+
|
|
290
|
+
也可用环境变量 CANCAN_OVERRIDE_ROOT 指定其它目录。
|
|
291
|
+
You can also point CANCAN_OVERRIDE_ROOT at a different directory.
|
|
292
|
+
"""
|
|
293
|
+
|
|
294
|
+
_WS_GITIGNORE = """\
|
|
295
|
+
.env
|
|
296
|
+
server_log_data/
|
|
297
|
+
compose.cancan.yml
|
|
298
|
+
builds/caddy/logs/
|
|
299
|
+
"""
|
|
300
|
+
|
|
301
|
+
_WS_README = """\
|
|
302
|
+
# Cancan workspace
|
|
303
|
+
|
|
304
|
+
```bash
|
|
305
|
+
cancan doctor # 预检环境 / pre-flight checks
|
|
306
|
+
cancan stack up # 启动整套栈 / bring the stack up
|
|
307
|
+
cancan stack status
|
|
308
|
+
cancan stack down
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
- 业务服务写在 `docker-compose.services.yml`。Business services live in `docker-compose.services.yml`.
|
|
312
|
+
- 配置与密钥在 `.env`(已自动生成 TOTP 加密 key;生产请修改弱默认值)。
|
|
313
|
+
Config & secrets in `.env` (a TOTP key is generated for you; change weak defaults before production).
|
|
314
|
+
- 用 `cancan_overrides/<service>/` 免 fork 覆盖内置服务。Override bundled services via `cancan_overrides/<service>/`.
|
|
315
|
+
"""
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
def _scaffold_workspace(workspace: Path, stack: CancanMicrostack) -> None:
|
|
319
|
+
"""生成一个最小可跑的工作区 / Scaffold a minimal runnable workspace."""
|
|
320
|
+
|
|
321
|
+
workspace.mkdir(parents=True, exist_ok=True)
|
|
322
|
+
# 复用同一套资产 bootstrap(infra compose / Caddy·service Dockerfile / ddl / adminops / .env)。
|
|
323
|
+
# Reuse the same asset bootstrap.
|
|
324
|
+
_bootstrap_workspace_files(workspace, stack)
|
|
325
|
+
# 仅 scaffold 才生成的文件 / scaffold-only files.
|
|
326
|
+
_write_text_if_missing(workspace / "docker-compose.services.yml", _SERVICES_COMPOSE_SAMPLE)
|
|
327
|
+
_write_text_if_missing(workspace / "cancan_overrides" / "README.md", _OVERRIDES_README)
|
|
328
|
+
_write_text_if_missing(workspace / ".gitignore", _WS_GITIGNORE)
|
|
329
|
+
_write_text_if_missing(workspace / "README.md", _WS_README)
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
def main(argv: Sequence[str] | None = None) -> int:
|
|
333
|
+
parser = build_parser()
|
|
334
|
+
args = parser.parse_args(list(argv) if argv is not None else None)
|
|
335
|
+
|
|
336
|
+
# The service container image installs `cancan-microstack==${CANCAN_VERSION}`,
|
|
337
|
+
# so expose the package version to every compose subprocess. setdefault keeps
|
|
338
|
+
# an explicit user override (e.g. building a different/dev version) intact.
|
|
339
|
+
os.environ.setdefault("CANCAN_VERSION", __version__)
|
|
340
|
+
|
|
341
|
+
stack = CancanMicrostack()
|
|
342
|
+
stack_manager = StackManager(stack)
|
|
343
|
+
|
|
344
|
+
if args.command == "assets":
|
|
345
|
+
if args.assets_command == "list":
|
|
346
|
+
records = stack.assets.list_assets(args.subdir)
|
|
347
|
+
for record in records:
|
|
348
|
+
log("asset", name=record.logical_name, path=record.path, is_dir=record.is_dir)
|
|
349
|
+
return 0
|
|
350
|
+
if args.assets_command == "export":
|
|
351
|
+
destination = Path(args.destination).expanduser().resolve()
|
|
352
|
+
stack.export_asset(args.logical_name, destination, overwrite=args.overwrite)
|
|
353
|
+
return 0
|
|
354
|
+
|
|
355
|
+
if args.command == "compose" and args.compose_command == "build":
|
|
356
|
+
workspace = Path(args.workspace).expanduser().resolve()
|
|
357
|
+
service_file = Path(args.service_file).resolve() if args.service_file else None
|
|
358
|
+
overrides = [Path(item).expanduser().resolve() for item in args.override]
|
|
359
|
+
output = Path(args.output).expanduser().resolve() if args.output else None
|
|
360
|
+
if args.bootstrap:
|
|
361
|
+
_bootstrap_workspace_files(workspace, stack)
|
|
362
|
+
stack.build_compose(workspace=workspace, service_file=service_file, overrides=overrides, output=output)
|
|
363
|
+
log("compose written", path=output or workspace / "compose.cancan.yml")
|
|
364
|
+
return 0
|
|
365
|
+
|
|
366
|
+
if args.command == "stack":
|
|
367
|
+
if args.stack_command == "up":
|
|
368
|
+
workspace = Path(args.workspace).expanduser().resolve()
|
|
369
|
+
service_file = Path(args.service_file).expanduser().resolve() if args.service_file else None
|
|
370
|
+
overrides = [Path(item).expanduser().resolve() for item in args.override]
|
|
371
|
+
output = Path(args.output).expanduser().resolve() if args.output else None
|
|
372
|
+
|
|
373
|
+
if args.bootstrap:
|
|
374
|
+
_bootstrap_workspace_files(workspace, stack)
|
|
375
|
+
|
|
376
|
+
start_time = time.perf_counter()
|
|
377
|
+
|
|
378
|
+
def _step(msg: str) -> float:
|
|
379
|
+
now = time.perf_counter()
|
|
380
|
+
elapsed = now - start_time
|
|
381
|
+
print(f"[stack] +{elapsed:0.2f}s {msg}")
|
|
382
|
+
return now
|
|
383
|
+
|
|
384
|
+
_step(f"workspace={workspace}")
|
|
385
|
+
|
|
386
|
+
options = StackOptions(
|
|
387
|
+
workspace=workspace,
|
|
388
|
+
service_file=service_file,
|
|
389
|
+
overrides=overrides,
|
|
390
|
+
output=output,
|
|
391
|
+
bootstrap=args.bootstrap,
|
|
392
|
+
engine=(None if args.engine == "auto" else args.engine),
|
|
393
|
+
controllersrv_host=args.controllersrv_host,
|
|
394
|
+
controllersrv_port=args.controllersrv_port,
|
|
395
|
+
with_controllersrv=args.with_controllersrv,
|
|
396
|
+
)
|
|
397
|
+
|
|
398
|
+
compose_file = stack_manager.build(options)
|
|
399
|
+
if options.with_controllersrv:
|
|
400
|
+
_step(f"start controllersrv (engine={options.engine or 'auto'})")
|
|
401
|
+
pid = stack_manager.start_controllersrv(options)
|
|
402
|
+
log("controllersrv", status="running", pid=pid, host=options.controllersrv_host,
|
|
403
|
+
port=options.controllersrv_port)
|
|
404
|
+
paths = stack_manager.get_controllersrv_daemon_paths(workspace)
|
|
405
|
+
print(f"[stack] controllersrv pid={pid} log={paths.log_file} pidfile={paths.pid_file}")
|
|
406
|
+
|
|
407
|
+
_step("wait controllersrv /internal/health")
|
|
408
|
+
ready = stack_manager.wait_controllersrv_ready(
|
|
409
|
+
host=options.controllersrv_host,
|
|
410
|
+
port=options.controllersrv_port,
|
|
411
|
+
timeout_seconds=8.0,
|
|
412
|
+
)
|
|
413
|
+
if not ready:
|
|
414
|
+
print(
|
|
415
|
+
"[stack] WARNING: controllersrv health not ready yet. "
|
|
416
|
+
"If startup is slow, check its log: "
|
|
417
|
+
f"{paths.log_file}"
|
|
418
|
+
)
|
|
419
|
+
|
|
420
|
+
_step(f"compose up -d{' --build' if args.build else ''} (engine={options.engine or 'auto'})")
|
|
421
|
+
print(f"[stack] compose logs -> {workspace / 'server_log_data' / 'stack' / 'compose.up.log'}")
|
|
422
|
+
stack_manager.compose_up(
|
|
423
|
+
workspace=workspace,
|
|
424
|
+
compose_file=compose_file,
|
|
425
|
+
engine=options.engine,
|
|
426
|
+
build=args.build,
|
|
427
|
+
)
|
|
428
|
+
_step("done")
|
|
429
|
+
log("stack", status="up", compose_file=compose_file)
|
|
430
|
+
return 0
|
|
431
|
+
|
|
432
|
+
if args.stack_command == "down":
|
|
433
|
+
workspace = Path(args.workspace).expanduser().resolve()
|
|
434
|
+
compose_file = Path(args.compose_file).expanduser().resolve()
|
|
435
|
+
engine = None if args.engine == "auto" else args.engine
|
|
436
|
+
|
|
437
|
+
stack_manager.compose_down(
|
|
438
|
+
workspace=workspace,
|
|
439
|
+
compose_file=compose_file,
|
|
440
|
+
engine=engine,
|
|
441
|
+
remove_volumes=args.volumes,
|
|
442
|
+
)
|
|
443
|
+
if args.with_controllersrv:
|
|
444
|
+
stopped = stack_manager.stop_controllersrv(workspace)
|
|
445
|
+
log("controllersrv", status=("stopped" if stopped else "not_running"))
|
|
446
|
+
log("stack", status="down")
|
|
447
|
+
return 0
|
|
448
|
+
|
|
449
|
+
if args.stack_command == "status":
|
|
450
|
+
workspace = Path(args.workspace).expanduser().resolve()
|
|
451
|
+
compose_file = Path(args.compose_file).expanduser().resolve()
|
|
452
|
+
engine = None if args.engine == "auto" else args.engine
|
|
453
|
+
|
|
454
|
+
# controllersrv status via pidfile
|
|
455
|
+
from ..runtime.host_daemon import default_daemon_paths
|
|
456
|
+
from ..runtime.host_daemon import read_pid
|
|
457
|
+
|
|
458
|
+
paths = default_daemon_paths(workspace, name="controllersrv")
|
|
459
|
+
pid = read_pid(paths.pid_file)
|
|
460
|
+
log("controllersrv", pid=pid, pid_file=str(paths.pid_file))
|
|
461
|
+
stack_manager.compose_ps(workspace=workspace, compose_file=compose_file, engine=engine)
|
|
462
|
+
return 0
|
|
463
|
+
|
|
464
|
+
if args.command == "controllersrv":
|
|
465
|
+
workspace = Path(args.workspace).expanduser().resolve()
|
|
466
|
+
engine = None if args.engine == "auto" else args.engine
|
|
467
|
+
options = StackOptions(
|
|
468
|
+
workspace=workspace,
|
|
469
|
+
service_file=None,
|
|
470
|
+
overrides=[],
|
|
471
|
+
output=None,
|
|
472
|
+
bootstrap=False,
|
|
473
|
+
engine=engine,
|
|
474
|
+
controllersrv_host=args.host,
|
|
475
|
+
controllersrv_port=args.port,
|
|
476
|
+
with_controllersrv=True,
|
|
477
|
+
)
|
|
478
|
+
|
|
479
|
+
if args.controllersrv_command == "restart":
|
|
480
|
+
stopped = stack_manager.stop_controllersrv(workspace)
|
|
481
|
+
log(
|
|
482
|
+
"controllersrv",
|
|
483
|
+
action="stop",
|
|
484
|
+
status=("stopped" if stopped else "not_running"),
|
|
485
|
+
workspace=str(workspace),
|
|
486
|
+
)
|
|
487
|
+
pid = stack_manager.start_controllersrv(options)
|
|
488
|
+
log(
|
|
489
|
+
"controllersrv",
|
|
490
|
+
action="start",
|
|
491
|
+
status="running",
|
|
492
|
+
pid=pid,
|
|
493
|
+
host=options.controllersrv_host,
|
|
494
|
+
port=options.controllersrv_port,
|
|
495
|
+
engine=options.engine or "auto",
|
|
496
|
+
)
|
|
497
|
+
if args.wait:
|
|
498
|
+
ready = stack_manager.wait_controllersrv_ready(
|
|
499
|
+
host=options.controllersrv_host,
|
|
500
|
+
port=options.controllersrv_port,
|
|
501
|
+
timeout_seconds=args.timeout,
|
|
502
|
+
)
|
|
503
|
+
log(
|
|
504
|
+
"controllersrv",
|
|
505
|
+
action="wait_health",
|
|
506
|
+
status=("ready" if ready else "timeout"),
|
|
507
|
+
timeout=args.timeout,
|
|
508
|
+
)
|
|
509
|
+
if not ready:
|
|
510
|
+
print(
|
|
511
|
+
"[controllersrv] WARNING: health check timeout; "
|
|
512
|
+
"inspect daemon logs if startup takes longer than expected."
|
|
513
|
+
)
|
|
514
|
+
return 0
|
|
515
|
+
|
|
516
|
+
if args.command == "services" and args.services_command == "run":
|
|
517
|
+
workspace = Path(args.workspace).expanduser().resolve()
|
|
518
|
+
default_ports = {
|
|
519
|
+
"controllersrv": 22100,
|
|
520
|
+
"infrasrv": 8080,
|
|
521
|
+
"opsbffsrv": 8080,
|
|
522
|
+
}
|
|
523
|
+
stack.run_service(
|
|
524
|
+
args.name,
|
|
525
|
+
host=args.host,
|
|
526
|
+
port=(args.port if args.port is not None else default_ports[args.name]),
|
|
527
|
+
workspace=workspace,
|
|
528
|
+
)
|
|
529
|
+
return 0
|
|
530
|
+
|
|
531
|
+
if args.command == "version":
|
|
532
|
+
print(__version__)
|
|
533
|
+
return 0
|
|
534
|
+
|
|
535
|
+
if args.command == "doctor":
|
|
536
|
+
from ..core.doctor import run_doctor
|
|
537
|
+
|
|
538
|
+
workspace = Path(args.workspace).expanduser().resolve()
|
|
539
|
+
return run_doctor(workspace)
|
|
540
|
+
|
|
541
|
+
if args.command == "init":
|
|
542
|
+
workspace = Path(args.workspace).expanduser().resolve()
|
|
543
|
+
_scaffold_workspace(workspace, stack)
|
|
544
|
+
log("init", workspace=str(workspace), status="ready", next="cancan doctor && cancan stack up")
|
|
545
|
+
return 0
|
|
546
|
+
|
|
547
|
+
parser.error("Unsupported command")
|
|
548
|
+
return 1
|
|
549
|
+
|
|
550
|
+
|
|
551
|
+
if __name__ == "__main__":
|
|
552
|
+
raise SystemExit(main())
|