From d5ce4650156e50f6eb6924a6c84b0c9fb13e66cb Mon Sep 17 00:00:00 2001 From: nichenqin Date: Fri, 8 May 2026 10:12:49 +0800 Subject: [PATCH] feat: support swarm console install --- .github/workflows/ci.yml | 6 ++++++ README.md | 14 +++++++++++--- action.yml | 27 ++++++++++++++++++++++++++- scripts/run-deploy.sh | 28 +++++++++++++++++++++++++++- 4 files changed, 70 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e8b9034..6fc85c4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -95,6 +95,9 @@ jobs: INPUT_SSH_HOST: 203.0.113.10 INPUT_CONSOLE_DOMAIN: console.example.com INPUT_CONSOLE_DATABASE: pglite + INPUT_CONSOLE_ORCHESTRATOR: swarm + INPUT_CONSOLE_SWARM_STACK_NAME: appaloft-console + INPUT_CONSOLE_SWARM_INIT: "true" INPUT_CONSOLE_SKIP_DOCKER_INSTALL: "true" run: | tmp="$(mktemp -d)" @@ -107,6 +110,9 @@ jobs: grep -q '^SSH root@203.0.113.10:22$' "$tmp/argv" grep -q '^INSTALLER https://github.com/appaloft/appaloft/releases/download/v0.9.1/install.sh$' "$tmp/argv" + grep -q -- "--orchestrator 'swarm'" "$tmp/argv" + grep -q -- "--stack-name 'appaloft-console'" "$tmp/argv" + grep -q -- "--swarm-init" "$tmp/argv" grep -q '^HEALTH https://console.example.com/api/health$' "$tmp/argv" grep -q '^console-url=https://console.example.com$' "$tmp/github-output" diff --git a/README.md b/README.md index d0b54ba..29a07f4 100644 --- a/README.md +++ b/README.md @@ -87,13 +87,16 @@ jobs: ssh-private-key: ${{ secrets.APPALOFT_CONSOLE_SSH_PRIVATE_KEY }} console-domain: console.example.com console-database: pglite + console-orchestrator: compose console-skip-docker-install: true ``` The action connects to the SSH host, downloads the matching Appaloft release `install.sh`, runs the -self-hosted Docker installer with the selected public console origin, and verifies -`/api/health`. `console-url` may be supplied directly when the public origin is not -`https://`. This command is separate from `deploy`, so the original pure SSH CLI +self-hosted Docker installer with the selected public console origin and Docker orchestrator, and +verifies `/api/health`. `console-url` may be supplied directly when the public origin is not +`https://`. Set `console-orchestrator: swarm` to deploy the console as a Docker +Swarm stack; `console-swarm-init: true` may initialize a single-node Swarm manager when the host is +not already a manager. This command is separate from `deploy`, so the original pure SSH CLI deployment path remains available. ## Pull Request Preview @@ -322,9 +325,14 @@ source-link state, or the Appaloft server, not from committed config. | `console-url` | empty | Public console origin for `command: install-console`. Defaults to `https://` or `http://:`. | | `console-domain` | empty | Public console domain used to derive `console-url` when `console-url` is empty. | | `console-database` | `pglite` | Self-hosted console database backend for `command: install-console`; `pglite` or `postgres`. | +| `console-orchestrator` | `compose` | Self-hosted Docker orchestrator for `command: install-console`; `compose` or `swarm`. | | `console-http-host` | `0.0.0.0` | Host bind address passed to the self-hosted console installer. | | `console-http-port` | `3001` | Host HTTP port passed to the self-hosted console installer. | | `console-install-dir` | empty | Remote install directory passed to the self-hosted console installer. Empty uses the installer default. | +| `console-compose-project-name` | `appaloft` | Docker Compose project name passed to the self-hosted console installer. | +| `console-swarm-stack-name` | `appaloft` | Docker Swarm stack name passed to the self-hosted console installer. | +| `console-swarm-init` | `false` | Initialize a single-node Swarm manager when `console-orchestrator` is `swarm`. | +| `console-swarm-advertise-addr` | empty | Optional advertise address passed to `docker swarm init`. | | `console-image` | `ghcr.io/appaloft/appaloft` | Appaloft console image repository or full image reference passed to the self-hosted console installer. | | `console-installer-url` | empty | Override URL for the self-hosted `install.sh` used by `command: install-console`. | | `console-skip-docker-install` | `false` | Require Docker Engine to already exist on the SSH host during `command: install-console`. | diff --git a/action.yml b/action.yml index 9fe7157..415f345 100644 --- a/action.yml +++ b/action.yml @@ -54,6 +54,10 @@ inputs: description: Self-hosted console database backend for command=install-console. required: false default: "pglite" + console-orchestrator: + description: Self-hosted console Docker orchestrator for command=install-console. + required: false + default: "compose" console-http-host: description: Host bind address passed to the self-hosted console installer. required: false @@ -66,6 +70,22 @@ inputs: description: Remote install directory passed to the self-hosted console installer. Defaults to the installer default. required: false default: "" + console-compose-project-name: + description: Docker Compose project name passed to the self-hosted console installer. + required: false + default: "appaloft" + console-swarm-stack-name: + description: Docker Swarm stack name passed to the self-hosted console installer. + required: false + default: "appaloft" + console-swarm-init: + description: Initialize a single-node Swarm manager on the SSH host when command=install-console and console-orchestrator=swarm. + required: false + default: "false" + console-swarm-advertise-addr: + description: Optional advertise address passed to docker swarm init for command=install-console. + required: false + default: "" console-image: description: Appaloft console image repository or full image reference passed to the self-hosted console installer. required: false @@ -187,7 +207,7 @@ outputs: description: Self-hosted Appaloft console deployment detail URL when available. value: ${{ steps.deploy.outputs.deployment-url }} console-url: - description: Self-hosted Appaloft console URL used by server API mode. + description: Self-hosted Appaloft console URL installed by install-console or used by server API mode. value: ${{ steps.deploy.outputs.console-url }} preview-cleanup-status: description: Preview cleanup status when command is preview-cleanup. @@ -229,9 +249,14 @@ runs: INPUT_CONSOLE_URL: ${{ inputs.console-url }} INPUT_CONSOLE_DOMAIN: ${{ inputs.console-domain }} INPUT_CONSOLE_DATABASE: ${{ inputs.console-database }} + INPUT_CONSOLE_ORCHESTRATOR: ${{ inputs.console-orchestrator }} INPUT_CONSOLE_HTTP_HOST: ${{ inputs.console-http-host }} INPUT_CONSOLE_HTTP_PORT: ${{ inputs.console-http-port }} INPUT_CONSOLE_INSTALL_DIR: ${{ inputs.console-install-dir }} + INPUT_CONSOLE_COMPOSE_PROJECT_NAME: ${{ inputs.console-compose-project-name }} + INPUT_CONSOLE_SWARM_STACK_NAME: ${{ inputs.console-swarm-stack-name }} + INPUT_CONSOLE_SWARM_INIT: ${{ inputs.console-swarm-init }} + INPUT_CONSOLE_SWARM_ADVERTISE_ADDR: ${{ inputs.console-swarm-advertise-addr }} INPUT_CONSOLE_IMAGE: ${{ inputs.console-image }} INPUT_CONSOLE_INSTALLER_URL: ${{ inputs.console-installer-url }} INPUT_CONSOLE_SKIP_DOCKER_INSTALL: ${{ inputs.console-skip-docker-install }} diff --git a/scripts/run-deploy.sh b/scripts/run-deploy.sh index c2acc6d..a5f24c2 100755 --- a/scripts/run-deploy.sh +++ b/scripts/run-deploy.sh @@ -418,6 +418,15 @@ validate_console_install_inputs() { ;; esac + case "$console_orchestrator" in + compose|swarm) + ;; + *) + error "console-orchestrator must be compose or swarm" + exit 1 + ;; + esac + case "$console_http_port" in ''|*[!0-9]*) error "console-http-port must be a positive integer" @@ -462,10 +471,22 @@ run_console_install() { console_url="$(normalized_url "$console_url")" installer_url="$(console_installer_url_for_version "$input_version")" - install_args="--version $(shell_quote "$input_version") --web-origin $(shell_quote "$console_url") --database $(shell_quote "$console_database") --host $(shell_quote "$console_http_host") --port $(shell_quote "$console_http_port") --image $(shell_quote "$console_image")" + install_args="--version $(shell_quote "$input_version") --web-origin $(shell_quote "$console_url") --database $(shell_quote "$console_database") --orchestrator $(shell_quote "$console_orchestrator") --host $(shell_quote "$console_http_host") --port $(shell_quote "$console_http_port") --image $(shell_quote "$console_image")" if [ -n "$console_install_dir" ]; then install_args="$install_args --home $(shell_quote "$console_install_dir")" fi + if [ "$console_orchestrator" = "compose" ] && [ -n "$console_compose_project_name" ]; then + install_args="$install_args --project-name $(shell_quote "$console_compose_project_name")" + fi + if [ "$console_orchestrator" = "swarm" ] && [ -n "$console_swarm_stack_name" ]; then + install_args="$install_args --stack-name $(shell_quote "$console_swarm_stack_name")" + fi + if [ "$console_orchestrator" = "swarm" ] && truthy "$console_swarm_init"; then + install_args="$install_args --swarm-init" + fi + if [ "$console_orchestrator" = "swarm" ] && [ -n "$console_swarm_advertise_addr" ]; then + install_args="$install_args --swarm-advertise-addr $(shell_quote "$console_swarm_advertise_addr")" + fi if truthy "$console_skip_docker_install"; then install_args="$install_args --skip-docker-install" fi @@ -664,9 +685,14 @@ ssh_private_key_file="${INPUT_SSH_PRIVATE_KEY_FILE:-}" console_url="${INPUT_CONSOLE_URL:-}" console_domain="${INPUT_CONSOLE_DOMAIN:-}" console_database="${INPUT_CONSOLE_DATABASE:-pglite}" +console_orchestrator="${INPUT_CONSOLE_ORCHESTRATOR:-compose}" console_http_host="${INPUT_CONSOLE_HTTP_HOST:-0.0.0.0}" console_http_port="${INPUT_CONSOLE_HTTP_PORT:-3001}" console_install_dir="${INPUT_CONSOLE_INSTALL_DIR:-}" +console_compose_project_name="${INPUT_CONSOLE_COMPOSE_PROJECT_NAME:-appaloft}" +console_swarm_stack_name="${INPUT_CONSOLE_SWARM_STACK_NAME:-appaloft}" +console_swarm_init="${INPUT_CONSOLE_SWARM_INIT:-false}" +console_swarm_advertise_addr="${INPUT_CONSOLE_SWARM_ADVERTISE_ADDR:-}" console_image="${INPUT_CONSOLE_IMAGE:-ghcr.io/appaloft/appaloft}" console_skip_docker_install="${INPUT_CONSOLE_SKIP_DOCKER_INSTALL:-false}" state_backend="${INPUT_STATE_BACKEND:-}"