playbooks/roles/vhosts/gateway_openclaw/tasks/main.yml

468 lines
16 KiB
YAML

---
- name: Inspect existing OpenClaw gateway JSON config
ansible.builtin.stat:
path: "{{ gateway_openclaw_config_path }}"
register: gateway_openclaw_existing_config_stat
no_log: true
- name: Read existing OpenClaw gateway JSON config
ansible.builtin.slurp:
path: "{{ gateway_openclaw_config_path }}"
register: gateway_openclaw_existing_config_raw
when: gateway_openclaw_existing_config_stat.stat.exists | default(false)
no_log: true
- name: Resolve OpenClaw gateway secrets
ansible.builtin.set_fact:
gateway_openclaw_effective_gateway_token: >-
{{
gateway_openclaw_gateway_token
if (gateway_openclaw_gateway_token | trim | length > 0)
else (
(
gateway_openclaw_existing_config_raw.content | default('') | b64decode | from_json
).gateway.auth.token | default('')
)
}}
no_log: true
- name: Assert OpenClaw gateway secrets are provided
ansible.builtin.assert:
that:
- gateway_openclaw_effective_gateway_token | trim | length > 0
fail_msg: >-
gateway_openclaw_gateway_token is required. Pass it with -e or keep an
existing {{ gateway_openclaw_config_path }} with gateway.auth.token; do
not commit it into inventory/defaults.
no_log: true
- name: Ensure OpenClaw gateway config directory exists
ansible.builtin.file:
path: "{{ gateway_openclaw_config_path | dirname }}"
state: directory
owner: "{{ gateway_openclaw_service_user }}"
group: "{{ gateway_openclaw_service_group }}"
mode: "0700"
- name: Ensure OpenClaw workspace directory exists
ansible.builtin.file:
path: "{{ gateway_openclaw_workspace_path }}"
state: directory
owner: "{{ gateway_openclaw_service_user }}"
group: "{{ gateway_openclaw_service_group }}"
mode: "{{ gateway_openclaw_workspace_mode }}"
- name: Ensure OpenClaw compile cache directory exists
ansible.builtin.file:
path: "{{ gateway_openclaw_compile_cache_dir }}"
state: directory
owner: "{{ gateway_openclaw_service_user }}"
group: "{{ gateway_openclaw_service_group }}"
mode: "0755"
- name: Ensure OpenClaw extension backup directory exists
ansible.builtin.file:
path: "{{ gateway_openclaw_extension_backup_dir }}"
state: directory
owner: "{{ gateway_openclaw_service_user }}"
group: "{{ gateway_openclaw_service_group }}"
mode: "0700"
- name: Install required OpenClaw gateway package version
ansible.builtin.command:
cmd: >-
npm install --global --omit=dev --no-audit --no-fund
--prefix "{{ gateway_openclaw_home }}/.local"
"{{ gateway_openclaw_npm_package_spec }}"
environment:
HOME: "{{ gateway_openclaw_home }}"
PATH: "{{ gateway_openclaw_service_path }}"
OPENCLAW_NO_RESPAWN: "1"
NODE_COMPILE_CACHE: "{{ gateway_openclaw_compile_cache_dir }}"
become: true
become_user: "{{ gateway_openclaw_service_user }}"
register: gateway_openclaw_package_install
changed_when: >-
'added ' in (gateway_openclaw_package_install.stdout | default('')) or
'removed ' in (gateway_openclaw_package_install.stdout | default('')) or
'changed ' in (gateway_openclaw_package_install.stdout | default(''))
when:
- not ansible_check_mode
notify: Restart openclaw gateway
- name: Move stale OpenClaw plugin backups out of extension scan path
ansible.builtin.shell: |
set -euo pipefail
shopt -s nullglob
moved=0
for backup_path in "{{ gateway_openclaw_home }}/.openclaw/extensions"/openclaw-multi-session-plugins.backup.*; do
backup_name="$(basename "$backup_path")"
backup_target="{{ gateway_openclaw_extension_backup_dir }}/${backup_name}"
if [ -e "$backup_target" ]; then
rm -rf "$backup_path"
else
mv "$backup_path" "$backup_target"
fi
moved=1
done
chown -R "{{ gateway_openclaw_service_user }}:{{ gateway_openclaw_service_group }}" "{{ gateway_openclaw_extension_backup_dir }}"
echo "moved=${moved}"
args:
executable: /bin/bash
register: gateway_openclaw_stale_extension_backups
changed_when: "'moved=1' in (gateway_openclaw_stale_extension_backups.stdout | default(''))"
when:
- not ansible_check_mode
- name: Inspect OpenClaw gateway JSON config attributes
ansible.builtin.command:
cmd: lsattr "{{ gateway_openclaw_config_path }}"
register: gateway_openclaw_config_attrs
changed_when: false
failed_when: false
- name: Remove immutable flag from OpenClaw gateway JSON config when present
ansible.builtin.command:
cmd: chattr -i "{{ gateway_openclaw_config_path }}"
when:
- "'i' in (gateway_openclaw_config_attrs.stdout | default(''))"
changed_when: true
- name: Deploy OpenClaw gateway JSON config
ansible.builtin.template:
src: openclaw.json.j2
dest: "{{ gateway_openclaw_config_path }}"
owner: "{{ gateway_openclaw_service_user }}"
group: "{{ gateway_openclaw_service_group }}"
mode: "0600"
diff: false
notify: Restart openclaw gateway
- name: Inspect OpenClaw package manifest
ansible.builtin.stat:
path: "{{ gateway_openclaw_install_dir }}/package.json"
register: gateway_openclaw_package_manifest
- name: Ensure OpenClaw package install directory is owned by service user
ansible.builtin.file:
path: "{{ gateway_openclaw_install_dir }}"
state: directory
owner: "{{ gateway_openclaw_service_user }}"
group: "{{ gateway_openclaw_service_group }}"
recurse: true
when:
- gateway_openclaw_package_manifest.stat.exists | default(false)
- name: Repair OpenClaw package runtime dependencies as service user
ansible.builtin.command:
cmd: npm install --omit=dev --no-audit --no-fund --prefix "{{ gateway_openclaw_install_dir }}"
environment:
HOME: "{{ gateway_openclaw_home }}"
PATH: "{{ gateway_openclaw_service_path }}"
OPENCLAW_NO_RESPAWN: "1"
NODE_COMPILE_CACHE: "{{ gateway_openclaw_compile_cache_dir }}"
become: true
become_user: "{{ gateway_openclaw_service_user }}"
register: gateway_openclaw_package_deps
changed_when: >-
'added ' in (gateway_openclaw_package_deps.stdout | default('')) or
'removed ' in (gateway_openclaw_package_deps.stdout | default('')) or
'changed ' in (gateway_openclaw_package_deps.stdout | default(''))
when:
- gateway_openclaw_package_manifest.stat.exists | default(false)
- not ansible_check_mode
- name: Inspect OpenClaw extension package manifests
ansible.builtin.stat:
path: "{{ item }}/package.json"
register: gateway_openclaw_extension_manifests
loop: "{{ gateway_openclaw_extension_dependency_dirs }}"
- name: Repair OpenClaw extension runtime dependencies as service user
ansible.builtin.command:
cmd: npm install --omit=dev --no-audit --no-fund --prefix "{{ item.item }}"
environment:
HOME: "{{ gateway_openclaw_home }}"
PATH: "{{ gateway_openclaw_service_path }}"
OPENCLAW_NO_RESPAWN: "1"
NODE_COMPILE_CACHE: "{{ gateway_openclaw_compile_cache_dir }}"
become: true
become_user: "{{ gateway_openclaw_service_user }}"
register: gateway_openclaw_extension_deps
changed_when: >-
'added ' in (gateway_openclaw_extension_deps.stdout | default('')) or
'removed ' in (gateway_openclaw_extension_deps.stdout | default('')) or
'changed ' in (gateway_openclaw_extension_deps.stdout | default(''))
loop: "{{ gateway_openclaw_extension_manifests.results }}"
when:
- item.stat.exists | default(false)
- not ansible_check_mode
- name: Repair OpenClaw 2026.5 route state as service user
ansible.builtin.command:
cmd: "{{ gateway_openclaw_binary_path }} doctor --fix --non-interactive"
environment:
HOME: "{{ gateway_openclaw_home }}"
PATH: "{{ gateway_openclaw_service_path }}"
OPENCLAW_NO_RESPAWN: "1"
NODE_COMPILE_CACHE: "{{ gateway_openclaw_compile_cache_dir }}"
OPENCLAW_SERVICE_REPAIR_POLICY: external
become: true
become_user: "{{ gateway_openclaw_service_user }}"
register: gateway_openclaw_doctor_repair
changed_when: >-
((gateway_openclaw_doctor_repair.stdout | default('')) ~ '\n' ~
(gateway_openclaw_doctor_repair.stderr | default('')))
is search('(?i)(fixed|repaired|migrated|rewrote|removed|set |moved |updated|archived)')
when:
- gateway_openclaw_doctor_repair_enabled | bool
- not ansible_check_mode
notify: Restart openclaw gateway
- name: Restore immutable flag on OpenClaw gateway JSON config
ansible.builtin.command:
cmd: chattr +i "{{ gateway_openclaw_config_path }}"
when:
- "'i' in (gateway_openclaw_config_attrs.stdout | default(''))"
- not ansible_check_mode
changed_when: true
- name: Inspect OpenClaw gateway binary
ansible.builtin.stat:
path: "{{ gateway_openclaw_binary_path }}"
follow: true
register: gateway_openclaw_binary
- name: Fail when OpenClaw gateway binary is missing or not executable
ansible.builtin.assert:
that:
- gateway_openclaw_binary.stat.exists | default(false)
- gateway_openclaw_binary.stat.executable | default(false)
fail_msg: "OpenClaw gateway binary is missing or not executable: {{ gateway_openclaw_binary_path }}"
- name: Check OpenClaw gateway version
ansible.builtin.command:
cmd: "{{ gateway_openclaw_binary_path }} --version"
environment:
HOME: "{{ gateway_openclaw_home }}"
PATH: "{{ gateway_openclaw_service_path }}"
OPENCLAW_NO_RESPAWN: "1"
NODE_COMPILE_CACHE: "{{ gateway_openclaw_compile_cache_dir }}"
become: true
become_user: "{{ gateway_openclaw_service_user }}"
register: gateway_openclaw_version
changed_when: false
when:
- not ansible_check_mode
- name: Assert OpenClaw gateway version is pinned
ansible.builtin.assert:
that:
- gateway_openclaw_version.stdout is search('OpenClaw ' ~ gateway_openclaw_required_version)
fail_msg: >-
OpenClaw gateway must run {{ gateway_openclaw_required_version }} after the
package upgrade. Actual version output: {{ gateway_openclaw_version.stdout | default('') }}
when:
- not ansible_check_mode
- name: Ensure OpenClaw user systemd unit directory exists
ansible.builtin.file:
path: "{{ gateway_openclaw_user_service_unit_path | dirname }}"
state: directory
owner: "{{ gateway_openclaw_service_user }}"
group: "{{ gateway_openclaw_service_group }}"
mode: "0755"
- name: Deploy OpenClaw user systemd unit
ansible.builtin.template:
src: openclaw-gateway.user.service.j2
dest: "{{ gateway_openclaw_user_service_unit_path }}"
owner: "{{ gateway_openclaw_service_user }}"
group: "{{ gateway_openclaw_service_group }}"
mode: "0644"
register: gateway_openclaw_user_service_unit
- name: Deploy OpenClaw user systemd shell environment
ansible.builtin.template:
src: openclaw-user-systemd.sh.j2
dest: "{{ gateway_openclaw_profile_script_path }}"
owner: root
group: root
mode: "0644"
- name: Enable OpenClaw service user linger
ansible.builtin.command:
cmd: "loginctl enable-linger {{ gateway_openclaw_service_user }}"
creates: "/var/lib/systemd/linger/{{ gateway_openclaw_service_user }}"
when:
- not ansible_check_mode
- name: Ensure OpenClaw service user manager is running
ansible.builtin.systemd:
name: "user@{{ gateway_openclaw_service_uid }}.service"
state: started
when:
- not ansible_check_mode
- name: Stop and disable stale root-managed OpenClaw gateway service
ansible.builtin.systemd:
name: "{{ gateway_openclaw_service_name }}"
enabled: false
state: stopped
failed_when: false
when:
- not ansible_check_mode
- name: Inspect stale OpenClaw gateway root systemd unit attributes
ansible.builtin.command:
cmd: lsattr "{{ gateway_openclaw_service_unit_path }}"
register: gateway_openclaw_unit_attrs
changed_when: false
failed_when: false
- name: Remove immutable flag from stale OpenClaw gateway root systemd unit when present
ansible.builtin.command:
cmd: chattr -i "{{ gateway_openclaw_service_unit_path }}"
when:
- "'i' in (gateway_openclaw_unit_attrs.stdout | default(''))"
changed_when: true
- name: Remove stale root-managed OpenClaw gateway systemd unit
ansible.builtin.file:
path: "{{ gateway_openclaw_service_unit_path }}"
state: absent
register: gateway_openclaw_removed_root_service_unit
- name: Reload root systemd after removing stale OpenClaw gateway unit
ansible.builtin.systemd:
daemon_reload: true
when:
- gateway_openclaw_removed_root_service_unit.changed | default(false)
- not ansible_check_mode
- name: Reload OpenClaw user systemd manager
ansible.builtin.command:
cmd: systemctl --user daemon-reload
environment:
HOME: "{{ gateway_openclaw_home }}"
XDG_RUNTIME_DIR: "/run/user/{{ gateway_openclaw_service_uid }}"
DBUS_SESSION_BUS_ADDRESS: "unix:path=/run/user/{{ gateway_openclaw_service_uid }}/bus"
become: true
become_user: "{{ gateway_openclaw_service_user }}"
changed_when: false
when:
- not ansible_check_mode
- name: Ensure OpenClaw user gateway service is enabled and running
ansible.builtin.command:
cmd: >-
systemctl --user enable
{{ '--now' if not (gateway_openclaw_user_service_unit.changed | default(false)) else '' }}
{{ gateway_openclaw_service_name }}.service
environment:
HOME: "{{ gateway_openclaw_home }}"
XDG_RUNTIME_DIR: "/run/user/{{ gateway_openclaw_service_uid }}"
DBUS_SESSION_BUS_ADDRESS: "unix:path=/run/user/{{ gateway_openclaw_service_uid }}/bus"
become: true
become_user: "{{ gateway_openclaw_service_user }}"
register: gateway_openclaw_user_service_enable
changed_when: >-
'Created symlink' in (gateway_openclaw_user_service_enable.stdout | default('')) or
'Created symlink' in (gateway_openclaw_user_service_enable.stderr | default(''))
when:
- not ansible_check_mode
- name: Restart OpenClaw user gateway service after unit changes
ansible.builtin.command:
cmd: "systemctl --user restart {{ gateway_openclaw_service_name }}.service"
environment:
HOME: "{{ gateway_openclaw_home }}"
XDG_RUNTIME_DIR: "/run/user/{{ gateway_openclaw_service_uid }}"
DBUS_SESSION_BUS_ADDRESS: "unix:path=/run/user/{{ gateway_openclaw_service_uid }}/bus"
become: true
become_user: "{{ gateway_openclaw_service_user }}"
when:
- gateway_openclaw_user_service_unit.changed | default(false)
- not ansible_check_mode
- name: Ensure Caddy fragment directory exists
ansible.builtin.file:
path: "{{ gateway_openclaw_caddy_conf_dir }}"
state: directory
owner: root
group: root
mode: "0755"
- name: Inspect Caddy main file attributes
ansible.builtin.command:
cmd: lsattr "{{ gateway_openclaw_caddyfile_path }}"
register: gateway_openclaw_caddyfile_attrs
changed_when: false
failed_when: false
- name: Remove immutable flag from Caddy main file when present
ansible.builtin.command:
cmd: chattr -i "{{ gateway_openclaw_caddyfile_path }}"
when:
- "'i' in (gateway_openclaw_caddyfile_attrs.stdout | default(''))"
changed_when: true
- name: Ensure Caddy imports managed fragments
ansible.builtin.lineinfile:
path: "{{ gateway_openclaw_caddyfile_path }}"
line: "import {{ gateway_openclaw_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 "{{ gateway_openclaw_caddyfile_path }}"
when:
- "'i' in (gateway_openclaw_caddyfile_attrs.stdout | default(''))"
- not ansible_check_mode
changed_when: true
- name: Inspect OpenClaw Caddy fragment attributes
ansible.builtin.command:
cmd: lsattr "{{ gateway_openclaw_caddy_fragment_path }}"
register: gateway_openclaw_caddy_fragment_attrs
changed_when: false
failed_when: false
- name: Remove immutable flag from OpenClaw Caddy fragment when present
ansible.builtin.command:
cmd: chattr -i "{{ gateway_openclaw_caddy_fragment_path }}"
when:
- "'i' in (gateway_openclaw_caddy_fragment_attrs.stdout | default(''))"
changed_when: true
- name: Deploy OpenClaw public Caddy site
ansible.builtin.template:
src: openclaw.svc.plus.caddy.j2
dest: "{{ gateway_openclaw_caddy_fragment_path }}"
owner: root
group: root
mode: "0644"
notify: Reload caddy
- name: Restore immutable flag on OpenClaw Caddy fragment
ansible.builtin.command:
cmd: chattr +i "{{ gateway_openclaw_caddy_fragment_path }}"
when:
- "'i' in (gateway_openclaw_caddy_fragment_attrs.stdout | default(''))"
- not ansible_check_mode
changed_when: true
- name: Ensure Caddy is enabled and running
ansible.builtin.systemd:
name: caddy
enabled: true
state: started
when:
- not ansible_check_mode