--- - name: Require explicit approval before deploying the Matrix stack ansible.builtin.assert: that: - matrix_stack_enabled | bool fail_msg: >- Refusing Matrix deployment until matrix_stack_enabled=true is set deliberately. - name: Require Helm on the Matrix host ansible.builtin.command: argv: [helm, version, --short] changed_when: false - name: Require non-secret values directory exists on the host ansible.builtin.stat: path: "{{ matrix_stack_values_dir }}" register: _values_dir - name: Assert values directory exists and is root-owned ansible.builtin.assert: that: - _values_dir.stat.exists - _values_dir.stat.isdir - _values_dir.stat.pw_name == 'root' - _values_dir.stat.gr_name == 'root' - _values_dir.stat.mode == '0700' fail_msg: >- Create the root-owned directory {{ matrix_stack_values_dir }} with mode 0700 and place the non-secret values files in it. - name: Require each non-secret values file exists on the host ansible.builtin.stat: path: "{{ matrix_stack_values_dir }}/{{ item }}" loop: "{{ matrix_stack_values_files }}" register: _values_files - name: Assert all values files exist and are root-owned ansible.builtin.assert: that: - item.stat.exists - item.stat.isreg - item.stat.pw_name == 'root' - item.stat.gr_name == 'root' - item.stat.mode in ['0600', '0640'] fail_msg: >- Values file {{ item.stat.path }} must be root-owned with restricted permissions (0600 or 0640) and must not contain secrets. loop: "{{ _values_files.results }}" loop_control: label: "{{ item.stat.path | default(item.item) }}" - name: Build helm value arguments ansible.builtin.set_fact: _helm_values_args: >- {%- for f in matrix_stack_values_files -%} --values {{ matrix_stack_values_dir }}/{{ f }} {% endfor -%} - name: Render the ESS chart without applying it (dry-run validation) ansible.builtin.command: cmd: >- helm template {{ matrix_stack_release_name }} {{ matrix_stack_chart_ref }} --version {{ matrix_stack_chart_version }} --namespace {{ matrix_namespace }} --create-namespace {{ _helm_values_args }} environment: KUBECONFIG: "{{ k3s_kubeconfig_path | default('/etc/rancher/k3s/k3s.yaml') }}" changed_when: false register: _chart_render # No secrets in values, but render output may contain initSecrets-generated placeholders - name: Verify the chart renders without errors ansible.builtin.assert: that: - _chart_render.rc == 0 - _chart_render.stdout | length > 0 fail_msg: >- Helm template rendering failed. Check values files for syntax errors. Output: {{ _chart_render.stderr | default('(none)') }} - name: Deploy the ESS chart via Helm upgrade --install ansible.builtin.command: cmd: >- helm upgrade --install {{ matrix_stack_release_name }} {{ matrix_stack_chart_ref }} --version {{ matrix_stack_chart_version }} --namespace {{ matrix_namespace }} --create-namespace {{ _helm_values_args }} --wait --timeout 15m environment: KUBECONFIG: "{{ k3s_kubeconfig_path | default('/etc/rancher/k3s/k3s.yaml') }}" changed_when: true register: _helm_deploy # initSecrets may generate passwords at deploy time; those stay in-cluster only