refactor(acp): reorganize ACP roles and unify ingress under xworkmate-bridge

- Rename acp_codex, acp_gemini, acp_opencode roles to acp_server_*
- Consolidate ACP deployment logic into xworkmate_bridge role
- Introduce gateway_openclaw role for ingress management
- Update playbooks to use the refactored xworkmate_bridge role
- Unify domain and upstream configuration under xworkmate-bridge.svc.plus
This commit is contained in:
Haitao Pan 2026-04-18 14:30:39 +08:00
parent ae1d318332
commit 5fa35235e1
43 changed files with 229 additions and 252 deletions

View File

@ -4,9 +4,9 @@
become: true
gather_facts: true
roles:
- role: roles/vhosts/deploy_acp_vhosts/
- role: roles/vhosts/xworkmate_bridge/
vars:
deploy_acp_codex: true
deploy_acp_opencode: false
deploy_acp_gemini: false
tags: [deploy_acp_vhosts, acp_codex]
tags: [xworkmate_bridge, acp_codex]

View File

@ -4,9 +4,9 @@
become: true
gather_facts: true
roles:
- role: roles/vhosts/deploy_acp_vhosts/
- role: roles/vhosts/xworkmate_bridge/
vars:
deploy_acp_codex: false
deploy_acp_opencode: false
deploy_acp_gemini: true
tags: [deploy_acp_vhosts, acp_gemini]
tags: [xworkmate_bridge, acp_gemini]

View File

@ -4,9 +4,9 @@
become: true
gather_facts: true
roles:
- role: roles/vhosts/deploy_acp_vhosts/
- role: roles/vhosts/xworkmate_bridge/
vars:
deploy_acp_codex: false
deploy_acp_opencode: true
deploy_acp_gemini: false
tags: [deploy_acp_vhosts, acp_opencode]
tags: [xworkmate_bridge, acp_opencode]

View File

@ -4,5 +4,5 @@
become: true
gather_facts: true
roles:
- role: roles/vhosts/deploy_acp_vhosts/
tags: [deploy_acp_vhosts]
- role: roles/vhosts/xworkmate_bridge/
tags: [xworkmate_bridge]

View File

@ -1,54 +0,0 @@
---
deploy_acp_codex: true
deploy_acp_opencode: true
deploy_acp_gemini: true
xworkmate_bridge_service_name: xworkmate-bridge
# 引用全局 Secret
xworkmate_bridge_auth_token: "{{ lookup('ansible.builtin.env', 'BRIDGE_AUTH_TOKEN') | default(lookup('ansible.builtin.env', 'INTERNAL_SERVICE_TOKEN') | default('', true), true) }}"
xworkmate_bridge_listen_host: 127.0.0.1
xworkmate_bridge_listen_port: 8787
xworkmate_bridge_container_port: 8787
xworkmate_bridge_container_name: xworkmate-bridge-managed
xworkmate_bridge_base_dir: /opt/cloud-neutral/xworkmate-bridge
xworkmate_bridge_compose_file: "{{ xworkmate_bridge_base_dir }}/docker-compose.yml"
xworkmate_bridge_project_name: xworkmate-bridge
service_compose_image: "{{ lookup('ansible.builtin.env', 'SERVICE_COMPOSE_IMAGE') | default('', true) }}"
service_compose_registry_server: "{{ lookup('ansible.builtin.env', 'GHCR_REGISTRY') | default('ghcr.io', true) }}"
service_compose_registry_username: "{{ lookup('ansible.builtin.env', 'GHCR_USERNAME') | default('', true) }}"
service_compose_registry_password: "{{ lookup('ansible.builtin.env', 'GHCR_PASSWORD') | default(lookup('ansible.builtin.env', 'GHCR_TOKEN') | default('', true), true) }}"
xworkmate_bridge_container_env:
ACP_AUTH_TOKEN: "{{ xworkmate_bridge_auth_token }}"
INTERNAL_SERVICE_TOKEN: "{{ xworkmate_bridge_auth_token }}"
IMAGE: "{{ service_compose_image }}"
# 统一域名:全部指向 xworkmate-bridge.svc.plus
xworkmate_bridge_domain: xworkmate-bridge.svc.plus
xworkmate_bridge_public_base_url: https://xworkmate-bridge.svc.plus
xworkmate_bridge_service_domain: xworkmate-bridge.svc.plus
xworkmate_bridge_service_public_base_url: https://xworkmate-bridge.svc.plus
xworkmate_bridge_caddyfile_path: /etc/caddy/Caddyfile
xworkmate_bridge_caddy_conf_dir: /etc/caddy/conf.d
xworkmate_bridge_caddy_fragment_path: /etc/caddy/conf.d/acp-server.caddy
xworkmate_bridge_service_caddy_fragment_path: /etc/caddy/conf.d/xworkmate-bridge.caddy
# Upstream 配置
xworkmate_bridge_codex_upstream_host: 127.0.0.1
xworkmate_bridge_codex_upstream_port: 9010
xworkmate_bridge_opencode_upstream_host: 127.0.0.1
xworkmate_bridge_opencode_upstream_port: 3910
xworkmate_bridge_gemini_upstream_host: 127.0.0.1
xworkmate_bridge_gemini_upstream_port: 8791
xworkmate_bridge_openclaw_upstream_host: 127.0.0.1
xworkmate_bridge_openclaw_upstream_port: 18789
xworkmate_bridge_obsolete_caddy_fragment_paths:
- /etc/caddy/conf.d/acp-server.caddy
- /etc/caddy/conf.d/acp-server-codex.caddy
- /etc/caddy/conf.d/acp-server-opencode.caddy
- /etc/caddy/conf.d/acp-server-gemini.caddy
- /etc/caddy/conf.d/acp-server-bridge.caddy
- /etc/caddy/conf.d/acp-server-bridge-server.caddy
xworkmate_bridge_packages:
- caddy

View File

@ -1,183 +0,0 @@
---
- name: Install xworkmate-bridge prerequisites
ansible.builtin.package:
name: "{{ xworkmate_bridge_packages }}"
state: present
- name: Ensure xworkmate-bridge compose directory exists
ansible.builtin.file:
path: "{{ xworkmate_bridge_base_dir }}"
state: directory
owner: root
group: root
mode: "0755"
- name: Assert xworkmate-bridge deploy uses prebuilt registry image
ansible.builtin.assert:
that:
- service_compose_image | trim | length > 0
- "'/' in (service_compose_image | trim)"
- "':' in (service_compose_image | trim)"
fail_msg: >-
XWORKMATE_BRIDGE deploy requires a prebuilt image reference via
SERVICE_COMPOSE_IMAGE. This role must only pull the build job image
and must never fall back to binary artifact or remote build flows.
- name: Log into container registry for xworkmate-bridge
ansible.builtin.shell: |
set -euo pipefail
printf '%s' '{{ service_compose_registry_password }}' | docker login {{ service_compose_registry_server }} -u '{{ service_compose_registry_username }}' --password-stdin
args:
executable: /bin/bash
no_log: true
when:
- service_compose_registry_username | length > 0
- service_compose_registry_password | length > 0
- name: Render xworkmate-bridge compose file
ansible.builtin.template:
src: docker-compose.yml.j2
dest: "{{ xworkmate_bridge_compose_file }}"
owner: root
group: root
mode: "0644"
- name: Validate xworkmate-bridge compose file
ansible.builtin.command: >-
docker compose
--project-name {{ xworkmate_bridge_project_name }}
-f {{ xworkmate_bridge_compose_file }}
config
args:
chdir: "{{ xworkmate_bridge_base_dir }}"
changed_when: false
- name: Stop legacy xworkmate-bridge systemd service
ansible.builtin.systemd:
name: "{{ xworkmate_bridge_service_name }}"
enabled: false
state: stopped
daemon_reload: true
failed_when: false
when:
- not ansible_check_mode
- name: Remove legacy xworkmate-bridge systemd unit
ansible.builtin.file:
path: "/etc/systemd/system/{{ xworkmate_bridge_service_name }}.service"
state: absent
- name: Pull xworkmate-bridge image
ansible.builtin.command: >-
docker compose
--project-name {{ xworkmate_bridge_project_name }}
-f {{ xworkmate_bridge_compose_file }}
pull bridge
args:
chdir: "{{ xworkmate_bridge_base_dir }}"
when:
- not ansible_check_mode
- name: Start xworkmate-bridge compose target
ansible.builtin.command: >-
docker compose
--project-name {{ xworkmate_bridge_project_name }}
-f {{ xworkmate_bridge_compose_file }}
up -d --force-recreate --remove-orphans bridge
args:
chdir: "{{ xworkmate_bridge_base_dir }}"
when:
- not ansible_check_mode
- name: Include Codex ACP provider role
ansible.builtin.import_role:
name: roles/vhosts/acp_codex
vars:
acp_codex_manage_caddy: false
when:
- deploy_acp_codex | bool
- name: Include OpenCode ACP provider role
ansible.builtin.import_role:
name: roles/vhosts/acp_opencode
vars:
acp_opencode_manage_caddy: false
when:
- deploy_acp_opencode | bool
- name: Include Gemini ACP provider role
ansible.builtin.import_role:
name: roles/vhosts/acp_gemini
when:
- deploy_acp_gemini | bool
- name: Ensure Caddy fragment directory exists for ACP ingress
ansible.builtin.file:
path: "{{ xworkmate_bridge_caddy_conf_dir }}"
state: directory
owner: root
group: root
mode: "0755"
- name: Inspect Caddy main file attributes
ansible.builtin.command:
cmd: lsattr "{{ xworkmate_bridge_caddyfile_path }}"
register: xworkmate_bridge_caddyfile_attrs
changed_when: false
failed_when: false
- name: Remove immutable flag from Caddy main file when present
ansible.builtin.command:
cmd: chattr -i "{{ xworkmate_bridge_caddyfile_path }}"
when:
- "'i' in (xworkmate_bridge_caddyfile_attrs.stdout | default(''))"
changed_when: true
- name: Ensure ACP Caddy import is present in main file
ansible.builtin.lineinfile:
path: "{{ xworkmate_bridge_caddyfile_path }}"
line: "import {{ xworkmate_bridge_caddy_conf_dir }}/*.caddy"
insertafter: EOF
create: true
owner: root
group: root
mode: "0644"
state: present
notify: Reload caddy
- name: Restore immutable flag on Caddy main file when it was originally present
ansible.builtin.command:
cmd: chattr +i "{{ xworkmate_bridge_caddyfile_path }}"
when:
- "'i' in (xworkmate_bridge_caddyfile_attrs.stdout | default(''))"
changed_when: true
- name: Deploy xworkmate-bridge public Caddy site
ansible.builtin.template:
src: xworkmate-bridge-site.caddy.j2
dest: "{{ xworkmate_bridge_service_caddy_fragment_path }}"
owner: root
group: root
mode: "0644"
notify: Reload caddy
- name: Remove deprecated ACP Caddy fragments
ansible.builtin.file:
path: "{{ item }}"
state: absent
loop: "{{ xworkmate_bridge_obsolete_caddy_fragment_paths }}"
notify: Reload caddy
- name: Ensure Caddy is enabled and running for ACP ingress
ansible.builtin.systemd:
name: caddy
enabled: true
state: started
when:
- not ansible_check_mode
- name: Include ACP ingress validation tasks
ansible.builtin.import_tasks: validate.yml
tags: [deploy_acp_vhosts, deploy_acp_vhosts_validate]
when:
- not ansible_check_mode

View File

@ -0,0 +1,23 @@
---
xworkmate_bridge_caddyfile_path: /etc/caddy/Caddyfile
xworkmate_bridge_caddy_conf_dir: /etc/caddy/conf.d
xworkmate_bridge_service_caddy_fragment_path: /etc/caddy/conf.d/xworkmate-bridge.caddy
xworkmate_bridge_domain: xworkmate-bridge.svc.plus
xworkmate_bridge_public_base_url: https://xworkmate-bridge.svc.plus
xworkmate_bridge_codex_upstream_host: 127.0.0.1
xworkmate_bridge_codex_upstream_port: 9010
xworkmate_bridge_opencode_upstream_host: 127.0.0.1
xworkmate_bridge_opencode_upstream_port: 3910
xworkmate_bridge_gemini_upstream_host: 127.0.0.1
xworkmate_bridge_gemini_upstream_port: 8791
xworkmate_bridge_openclaw_upstream_host: 127.0.0.1
xworkmate_bridge_openclaw_upstream_port: 18789
xworkmate_bridge_obsolete_caddy_fragment_paths:
- /etc/caddy/conf.d/acp-server.caddy
- /etc/caddy/conf.d/acp-server-codex.caddy
- /etc/caddy/conf.d/acp-server-opencode.caddy
- /etc/caddy/conf.d/acp-server-gemini.caddy
- /etc/caddy/conf.d/acp-server-bridge.caddy
- /etc/caddy/conf.d/acp-server-bridge-server.caddy

View File

@ -1,3 +1,4 @@
---
- name: Reload caddy
ansible.builtin.systemd:
name: caddy

View File

@ -0,0 +1,65 @@
---
- name: Ensure Caddy fragment directory exists
ansible.builtin.file:
path: "{{ xworkmate_bridge_caddy_conf_dir }}"
state: directory
owner: root
group: root
mode: "0755"
- name: Inspect Caddy main file attributes
ansible.builtin.command:
cmd: lsattr "{{ xworkmate_bridge_caddyfile_path }}"
register: xworkmate_bridge_caddyfile_attrs
changed_when: false
failed_when: false
- name: Remove immutable flag from Caddy main file when present
ansible.builtin.command:
cmd: chattr -i "{{ xworkmate_bridge_caddyfile_path }}"
when:
- "'i' in (xworkmate_bridge_caddyfile_attrs.stdout | default(''))"
changed_when: true
- name: Ensure ACP Caddy import is present in main file
ansible.builtin.lineinfile:
path: "{{ xworkmate_bridge_caddyfile_path }}"
line: "import {{ xworkmate_bridge_caddy_conf_dir }}/*.caddy"
insertafter: EOF
create: true
owner: root
group: root
mode: "0644"
state: present
notify: Reload caddy
- name: Restore immutable flag on Caddy main file
ansible.builtin.command:
cmd: chattr +i "{{ xworkmate_bridge_caddyfile_path }}"
when:
- "'i' in (xworkmate_bridge_caddyfile_attrs.stdout | default(''))"
changed_when: true
- name: Deploy xworkmate-bridge public Caddy site
ansible.builtin.template:
src: xworkmate-bridge-site.caddy.j2
dest: "{{ xworkmate_bridge_service_caddy_fragment_path }}"
owner: root
group: root
mode: "0644"
notify: Reload caddy
- name: Remove deprecated ACP Caddy fragments
ansible.builtin.file:
path: "{{ item }}"
state: absent
loop: "{{ xworkmate_bridge_obsolete_caddy_fragment_paths }}"
notify: Reload caddy
- name: Ensure Caddy is enabled and running
ansible.builtin.systemd:
name: caddy
enabled: true
state: started
when:
- not ansible_check_mode

View File

@ -1,10 +1,33 @@
---
xworkmate_bridge_service_name: xworkmate-bridge
# 引用全局 Secret
xworkmate_bridge_auth_token: "{{ lookup('ansible.builtin.env', 'BRIDGE_AUTH_TOKEN') | default(lookup('ansible.builtin.env', 'INTERNAL_SERVICE_TOKEN') | default('', true), true) }}"
xworkmate_bridge_listen_host: 127.0.0.1
xworkmate_bridge_listen_port: 8787
xworkmate_bridge_container_port: 8787
xworkmate_bridge_container_name: xworkmate-bridge-managed
xworkmate_bridge_base_dir: /opt/cloud-neutral/xworkmate-bridge
xworkmate_bridge_domain: xworkmate-bridge.svc.plus
xworkmate_bridge_listen_addr: 127.0.0.1:8787
xworkmate_bridge_compose_file: "{{ xworkmate_bridge_base_dir }}/docker-compose.yml"
xworkmate_bridge_project_name: xworkmate-bridge
service_compose_image: "{{ lookup('ansible.builtin.env', 'SERVICE_COMPOSE_IMAGE') | default('', true) }}"
service_compose_registry_server: "{{ lookup('ansible.builtin.env', 'GHCR_REGISTRY') | default('ghcr.io', true) }}"
service_compose_registry_username: "{{ lookup('ansible.builtin.env', 'GHCR_USERNAME') | default('', true) }}"
service_compose_registry_password: "{{ lookup('ansible.builtin.env', 'GHCR_PASSWORD') | default(lookup('ansible.builtin.env', 'GHCR_TOKEN') | default('', true), true) }}"
xworkmate_bridge_container_env:
ACP_AUTH_TOKEN: "{{ xworkmate_bridge_auth_token }}"
INTERNAL_SERVICE_TOKEN: "{{ xworkmate_bridge_auth_token }}"
IMAGE: "{{ service_compose_image }}"
# Provider Endpoints
xworkmate_bridge_openclaw_url: "https://xworkmate-bridge.svc.plus/gateway/openclaw/"
xworkmate_bridge_codex_rpc_url: "https://xworkmate-bridge.svc.plus/acp-server/codex/acp/rpc"
xworkmate_bridge_opencode_rpc_url: "https://xworkmate-bridge.svc.plus/acp-server/opencode/acp/rpc"
xworkmate_bridge_gemini_rpc_url: "https://xworkmate-bridge.svc.plus/acp-server/gemini/acp/rpc"
# ACP Deployment Flags
deploy_acp_codex: true
deploy_acp_opencode: true
deploy_acp_gemini: true
# 统一域名:全部指向 xworkmate-bridge.svc.plus
xworkmate_bridge_domain: xworkmate-bridge.svc.plus
xworkmate_bridge_public_base_url: https://xworkmate-bridge.svc.plus
xworkmate_bridge_service_domain: xworkmate-bridge.svc.plus
xworkmate_bridge_service_public_base_url: https://xworkmate-bridge.svc.plus
xworkmate_bridge_packages:
- caddy

View File

@ -0,0 +1,15 @@
---
dependencies:
- role: roles/vhosts/acp_server_codex
when: deploy_acp_codex | default(true) | bool
vars:
acp_codex_manage_caddy: false
- role: roles/vhosts/acp_server_opencode
when: deploy_acp_opencode | default(true) | bool
vars:
acp_opencode_manage_caddy: false
- role: roles/vhosts/acp_server_gemini
when: deploy_acp_gemini | default(true) | bool
vars:
acp_gemini_manage_caddy: false
- role: roles/vhosts/gateway_openclaw

View File

@ -1,4 +1,10 @@
---
- name: Install xworkmate-bridge prerequisites
ansible.builtin.package:
name:
- caddy
state: present
- name: Ensure xworkmate-bridge base directory exists
ansible.builtin.file:
path: "{{ xworkmate_bridge_base_dir }}"
@ -15,3 +21,84 @@
group: root
mode: "0644"
notify: Reload bridge
- name: Assert xworkmate-bridge deploy uses prebuilt registry image
ansible.builtin.assert:
that:
- service_compose_image | trim | length > 0
- "'/' in (service_compose_image | trim)"
- "':' in (service_compose_image | trim)"
fail_msg: >-
XWORKMATE_BRIDGE deploy requires a prebuilt image reference via
SERVICE_COMPOSE_IMAGE.
- name: Log into container registry for xworkmate-bridge
ansible.builtin.shell: |
set -euo pipefail
printf '%s' '{{ service_compose_registry_password }}' | docker login {{ service_compose_registry_server }} -u '{{ service_compose_registry_username }}' --password-stdin
args:
executable: /bin/bash
no_log: true
when:
- service_compose_registry_username | length > 0
- service_compose_registry_password | length > 0
- name: Render xworkmate-bridge compose file
ansible.builtin.template:
src: docker-compose.yml.j2
dest: "{{ xworkmate_bridge_compose_file }}"
owner: root
group: root
mode: "0644"
- name: Validate xworkmate-bridge compose file
ansible.builtin.command: >-
docker compose
--project-name {{ xworkmate_bridge_project_name }}
-f {{ xworkmate_bridge_compose_file }}
config
args:
chdir: "{{ xworkmate_bridge_base_dir }}"
changed_when: false
- name: Stop legacy xworkmate-bridge systemd service
ansible.builtin.systemd:
name: "{{ xworkmate_bridge_service_name }}"
enabled: false
state: stopped
daemon_reload: true
failed_when: false
when:
- not ansible_check_mode
- name: Remove legacy xworkmate-bridge systemd unit
ansible.builtin.file:
path: "/etc/systemd/system/{{ xworkmate_bridge_service_name }}.service"
state: absent
- name: Pull xworkmate-bridge image
ansible.builtin.command: >-
docker compose
--project-name {{ xworkmate_bridge_project_name }}
-f {{ xworkmate_bridge_compose_file }}
pull bridge
args:
chdir: "{{ xworkmate_bridge_base_dir }}"
when:
- not ansible_check_mode
- name: Start xworkmate-bridge compose target
ansible.builtin.command: >-
docker compose
--project-name {{ xworkmate_bridge_project_name }}
-f {{ xworkmate_bridge_compose_file }}
up -d --force-recreate --remove-orphans bridge
args:
chdir: "{{ xworkmate_bridge_base_dir }}"
when:
- not ansible_check_mode
- name: Include ACP ingress validation tasks
ansible.builtin.import_tasks: validate.yml
tags: [xworkmate_bridge, xworkmate_bridge_validate]
when:
- not ansible_check_mode