k3s_nodo.yml

# Actualiza k3s en un nodo (lo usa playbooks/k3s.yml). Si algo falla, devuelve el nodo al
# clúster (uncordon) y para todo el playbook.
- name: Comprobar el clúster
  ansible.builtin.include_tasks: comprobar_cluster.yml

- name: Versión actual de k3s en el nodo
  ansible.builtin.command: >-
    kubectl --kubeconfig {{ kubeconfig }} get node {{ inventory_hostname }}
    -o jsonpath={.status.nodeInfo.kubeletVersion}
  register: k3s_actual
  changed_when: false
  delegate_to: localhost
  check_mode: false

- name: ¿Parche o cambio de rama?
  ansible.builtin.set_fact:
    k3s_cambio_rama: "{{ (k3s_actual.stdout.split('.')[1] | int) != (version.split('.')[1] | int) }}"
    k3s_hace_falta: "{{ k3s_actual.stdout != version }}"

- name: Plan
  ansible.builtin.debug:
    msg: >-
      {{ 'SIMULACIÓN: ' if ansible_check_mode else '' }}{{ inventory_hostname }}:
      {{ k3s_actual.stdout }} → {{ version }}
      {{ ('(ya está al día)' if not k3s_hace_falta else ('cambio de rama: con drain' if k3s_cambio_rama else 'parche: sin drain')) }}

- name: Aviso de corte (cambio de rama)
  ansible.builtin.debug:
    msg: >-
      ⚠ El drain borra los emptyDir de los pods de {{ inventory_hostname }} (p. ej. el histórico
      de Prometheus si está ahí) y deja en Pending, hasta el uncordon, las apps con volúmenes
      local-path en este nodo (docs/almacenamiento.md).
  when: k3s_hace_falta and k3s_cambio_rama

- name: Actualizar k3s en {{ inventory_hostname }}
  when: k3s_hace_falta and not ansible_check_mode
  block:
    - name: Sacar el nodo del clúster (drain, solo en cambio de rama)
      ansible.builtin.command: >-
        kubectl --kubeconfig {{ kubeconfig }} drain {{ inventory_hostname }}
        --ignore-daemonsets --delete-emptydir-data --timeout=10m
      delegate_to: localhost
      changed_when: true
      when: k3s_cambio_rama

    # nodo-mantenimiento no acepta argumentos: la versión va en este fichero, que valida.
    - name: Dejar la versión pedida para nodo-mantenimiento
      ansible.builtin.copy:
        content: "{{ version }}\n"
        dest: /var/lib/ansible/k3s-version
        mode: "0600"

    - name: Instalar el binario nuevo
      ansible.builtin.include_tasks: estado.yml
      vars:
        accion: k3s

    - name: Esperar a que el nodo esté Ready con {{ version }}
      ansible.builtin.shell: |
        set -o pipefail
        kubectl --kubeconfig {{ kubeconfig }} get node {{ inventory_hostname }} \
          -o jsonpath='{.status.nodeInfo.kubeletVersion} {.status.conditions[?(@.type=="Ready")].status}'
      args:
        executable: /bin/bash
      register: k3s_nodo
      until: k3s_nodo.stdout == version ~ ' True'
      retries: 60
      delay: 10
      changed_when: false
      delegate_to: localhost

    - name: etcd sano (masters)
      ansible.builtin.command: kubectl --kubeconfig {{ kubeconfig }} get --raw /readyz?verbose
      register: k3s_readyz
      until: "'[+]etcd ok' in k3s_readyz.stdout"
      retries: 30
      delay: 10
      changed_when: false
      delegate_to: localhost
      when: inventory_hostname in groups['masters']
  always:
    - name: Devolver el nodo al clúster (uncordon)
      ansible.builtin.command: kubectl --kubeconfig {{ kubeconfig }} uncordon {{ inventory_hostname }}
      delegate_to: localhost
      changed_when: true
      when: k3s_cambio_rama

    - name: Borrar el fichero de versión
      ansible.builtin.file:
        path: /var/lib/ansible/k3s-version
        state: absent