- 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="semaphore-ansible" 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: "{{ OP_SERVICE_ACCOUNT_TOKEN }}" # 🔐 Load existing secrets - name: Load secrets from 1Password when: op_check.rc == 0 shell: | op item get "{{ stack_name }}" --vault="semaphore-ansible" --format json register: op_item check_mode: no delegate_to: localhost connection: local become: false no_log: true environment: OP_SERVICE_ACCOUNT_TOKEN: "{{ 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="semaphore-ansible" \ "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: "{{ 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