diff --git a/roles/healthcheck/defaults/main.yml b/roles/healthcheck/defaults/main.yml new file mode 100644 index 0000000..ea194cc --- /dev/null +++ b/roles/healthcheck/defaults/main.yml @@ -0,0 +1,11 @@ +# Post-update health check (quality gate) defaults. +# The role verifies that every Docker container is running after an OS update +# and records the result in the same update log used by the os-updates role. + +healthcheck_logging_enabled: "{{ os_update_logging_enabled | default(true) }}" +healthcheck_log_dir: "{{ os_update_log_dir | default('/ansible/logs') }}" +healthcheck_log_inventory: "{{ inventory_file | basename | splitext | first }}" +healthcheck_log_file: "{{ healthcheck_log_dir }}/{{ healthcheck_log_inventory }}/{{ ansible_facts['hostname'] }}/update.log" + +# When true, the role fails the playbook if any container is not running. +healthcheck_fail_on_unhealthy: false \ No newline at end of file diff --git a/roles/healthcheck/tasks/main.yml b/roles/healthcheck/tasks/main.yml new file mode 100644 index 0000000..3dd0693 --- /dev/null +++ b/roles/healthcheck/tasks/main.yml @@ -0,0 +1,85 @@ +# Post-update health check (quality gate). +# Detects whether Docker is installed and, if so, verifies that every +# container is in the running state. Results are appended to the update +# log as a "quality_gate" section, tied to the current update run via the +# os-updates preflight start timestamp. + +- name: Healthcheck - Detect Docker binary + ansible.builtin.command: which docker + register: healthcheck_docker_bin + changed_when: false + failed_when: false + +- name: Healthcheck - Record Docker presence + ansible.builtin.set_fact: + healthcheck_docker_installed: "{{ healthcheck_docker_bin.rc == 0 }}" + +- name: Healthcheck - List all container names + ansible.builtin.command: "docker ps -a --format {{ '{{' }}.Names{{ '}}' }}" + register: healthcheck_all_containers + changed_when: false + when: healthcheck_docker_installed | bool + +- name: Healthcheck - List running container names + ansible.builtin.command: "docker ps --filter status=running --format {{ '{{' }}.Names{{ '}}' }}" + register: healthcheck_running_containers + changed_when: false + when: healthcheck_docker_installed | bool + +- name: Healthcheck - Evaluate container health + ansible.builtin.set_fact: + healthcheck_total_containers: "{{ healthcheck_all_containers.stdout_lines | length }}" + healthcheck_running_count: "{{ healthcheck_running_containers.stdout_lines | length }}" + healthcheck_non_running_containers: "{{ (healthcheck_all_containers.stdout_lines | difference(healthcheck_running_containers.stdout_lines)) | list }}" + when: healthcheck_docker_installed | bool + +- name: Healthcheck - Determine overall result + ansible.builtin.set_fact: + healthcheck_all_running: "{{ (healthcheck_non_running_containers | length) == 0 }}" + healthcheck_passed: "{{ (healthcheck_non_running_containers | length) == 0 }}" + when: healthcheck_docker_installed | bool + +- name: Healthcheck - Default result when Docker is not installed + ansible.builtin.set_fact: + healthcheck_total_containers: 0 + healthcheck_running_count: 0 + healthcheck_non_running_containers: [] + healthcheck_all_running: true + healthcheck_passed: true + when: not (healthcheck_docker_installed | bool) + +- name: Healthcheck - Ensure log directory exists + ansible.builtin.file: + path: "{{ healthcheck_log_file | dirname }}" + state: directory + delegate_to: localhost + when: healthcheck_logging_enabled | bool + +- name: Healthcheck - Write quality gate section to update log + ansible.builtin.blockinfile: + path: "{{ healthcheck_log_file }}" + create: yes + marker: "# {mark} ANSIBLE-HEALTHCHECK" + block: | + quality_gate: + docker_installed: {{ healthcheck_docker_installed }} + total_containers: {{ healthcheck_total_containers }} + running_containers: {{ healthcheck_running_count }} + all_running: {{ healthcheck_all_running }} + non_running_containers: + {% for c in healthcheck_non_running_containers %} + - {{ c }} + {% endfor %} + healthcheck_passed: {{ healthcheck_passed }} + delegate_to: localhost + when: healthcheck_logging_enabled | bool + +- name: Healthcheck - Fail when containers are unhealthy (quality gate) + ansible.builtin.fail: + msg: >- + Quality gate failed: the following containers are not running: + {{ healthcheck_non_running_containers | join(', ') }} + when: + - healthcheck_fail_on_unhealthy | bool + - healthcheck_docker_installed | bool + - not (healthcheck_all_running | bool) \ No newline at end of file