wulf-ansible/playbooks/n8n.yml
lorentz 323616f802 Force local connection on delegated op tasks
delegate_to: localhost alone still uses SSH, which hangs on the
Semaphore controller. Add connection: local so the op tasks run in
the controller process directly.
2026-04-21 01:56:22 +00:00

118 lines
No EOL
3.5 KiB
YAML

- name: Deploy n8n
hosts: all
become: true
vars:
stack_dir: "/opt/stacks/{{ stack_name }}"
pre_tasks:
- name: Fail if stack_name is not set
fail:
msg: "stack_name is required"
when: stack_name is not defined or stack_name | length == 0
- name: Fail if n8n_url is not set
fail:
msg: "n8n_url is required"
when: n8n_url is not defined or n8n_url | length == 0
tasks:
# 🔎 Check if 1Password item exists
- name: Check if 1Password item exists
shell: |
op item get "{{ stack_name }}" --vault="Automation"
register: op_check
failed_when: false
changed_when: false
check_mode: no
delegate_to: localhost
connection: local
become: false
no_log: true
environment:
OP_SERVICE_ACCOUNT_TOKEN: "{{ lookup('env','OP_SERVICE_ACCOUNT_TOKEN') }}"
# 🔐 Load existing secrets
- name: Load secrets from 1Password
when: op_check.rc == 0
shell: |
op item get "{{ stack_name }}" --vault="Automation" --format json
register: op_item
check_mode: no
delegate_to: localhost
connection: local
become: false
no_log: true
environment:
OP_SERVICE_ACCOUNT_TOKEN: "{{ lookup('env','OP_SERVICE_ACCOUNT_TOKEN') }}"
- name: Set secrets from 1Password
when: op_check.rc == 0
no_log: true
set_fact:
n8n_postgres_password: "{{ (op_item.stdout | from_json).fields | selectattr('label','equalto','postgres_password') | map(attribute='value') | first }}"
n8n_encryption_key: "{{ (op_item.stdout | from_json).fields | selectattr('label','equalto','encryption_key') | map(attribute='value') | first }}"
# 🔑 Generate if new
- name: Generate postgres password
when: op_check.rc != 0
no_log: true
set_fact:
n8n_postgres_password: "{{ lookup('password','/dev/null length=32 chars=ascii_letters') }}"
- name: Generate encryption key
when: op_check.rc != 0
no_log: true
set_fact:
n8n_encryption_key: "{{ lookup('password','/dev/null length=64 chars=hexdigits') }}"
# 📦 Store in 1Password
- name: Create 1Password item
when: op_check.rc != 0
delegate_to: localhost
connection: local
become: false
no_log: true
shell: |
op item create \
--category="Server" \
--title="{{ stack_name }}" \
--vault="Automation" \
"url=https://{{ n8n_url }}" \
"username={{ n8n_editor_email }}" \
"password={{ n8n_editor_password }}" \
"postgres_password={{ n8n_postgres_password }}" \
"encryption_key={{ n8n_encryption_key }}"
environment:
OP_SERVICE_ACCOUNT_TOKEN: "{{ lookup('env','OP_SERVICE_ACCOUNT_TOKEN') }}"
# 🧱 Infrastructure
- name: Ensure stack directory exists
file:
path: "{{ stack_dir }}"
state: directory
mode: "0755"
- name: Ensure pangolin network exists
community.docker.docker_network:
name: pangolin
state: present
# 📄 Templates
- name: Render .env
template:
src: templates/n8n.env.j2
dest: "{{ stack_dir }}/.env"
mode: "0600"
- name: Render compose file
template:
src: templates/n8n-compose.yml.j2
dest: "{{ stack_dir }}/compose.yml"
# 🚀 Deploy
- name: Deploy stack
command: docker compose up -d
args:
chdir: "{{ stack_dir }}"
when: not ansible_check_mode