prole/infrastructure/roles/k3s/tasks/refresh_server.yml
chrisfu a43aed7134 k3s: eliminate localhost registry + dedupe common-core
- Ensure k3s mode uses the k3s registry endpoint and avoid localhost/k3d image prefixes.

- Make ArgoCD repo-server cmp symlink creation idempotent.

- Normalize common-core provisioning to knoe-system and add repair-time dedupe of stray default-namespace installs.

- Add k3s MariaDB datastore/refresh playbooks and regression tests.
2026-03-05 14:31:33 -08:00

196 lines
6.7 KiB
YAML

---
- name: Guard - require explicit confirmation for k3s server refresh
ansible.builtin.assert:
that:
- k3s_role == 'server'
- k3s_state == 'present'
- (k3s_refresh_confirm | default('')) == 'YES'
fail_msg: >-
Refusing to refresh k3s server without explicit confirmation.
Set k3s_refresh_confirm=YES and re-run (this is destructive: it wipes k3s state).
- name: Read current k3s config (to detect current data-dir)
ansible.builtin.stat:
path: /etc/rancher/k3s/config.yaml
register: _k3s_refresh_config_stat
- name: Slurp current k3s config
ansible.builtin.slurp:
src: /etc/rancher/k3s/config.yaml
register: _k3s_refresh_config_slurp
when: _k3s_refresh_config_stat.stat.exists
- name: Set refresh source/target data-dir
ansible.builtin.set_fact:
_k3s_refresh_cfg: >-
{{
(_k3s_refresh_config_slurp.content | b64decode | from_yaml)
if (_k3s_refresh_config_stat.stat.exists | bool)
else {}
}}
k3s_refresh_source_data_dir: >-
{{
_k3s_refresh_cfg.get('data-dir')
| default((k3s_data_dir | default('/var/lib/rancher/k3s')), true)
}}
k3s_refresh_target_data_dir: "{{ k3s_data_dir | default('/var/lib/rancher/k3s') }}"
- name: Preflight - check external datastore TCP reachability (best-effort)
ansible.builtin.wait_for:
host: "{{ k3s_datastore_mariadb_host }}"
port: "{{ k3s_datastore_mariadb_port | default(3306) }}"
connect_timeout: 2
timeout: 5
state: started
when:
- (k3s_datastore_endpoint | default('') | length) > 0
- k3s_datastore_mariadb_host is defined
changed_when: false
failed_when: false
- name: Create refresh backup directory
ansible.builtin.file:
path: "{{ k3s_refresh_backup_root }}/{{ inventory_hostname }}/{{ ansible_date_time.iso8601_basic_short }}"
state: directory
mode: "0700"
register: _k3s_refresh_backup_dir
- name: Stat k3s token/tls artifacts (source data-dir)
ansible.builtin.stat:
path: "{{ item }}"
loop:
- "{{ k3s_refresh_source_data_dir }}/server/token"
- "{{ k3s_refresh_source_data_dir }}/server/node-token"
# Minimal TLS set to preserve agent trust (CA hash) while allowing k3s to
# regenerate component creds and `server/cred/*.kubeconfig`.
- "{{ k3s_refresh_source_data_dir }}/server/tls/server-ca.crt"
- "{{ k3s_refresh_source_data_dir }}/server/tls/server-ca.key"
- "{{ k3s_refresh_source_data_dir }}/server/tls/client-ca.crt"
- "{{ k3s_refresh_source_data_dir }}/server/tls/client-ca.key"
- "{{ k3s_refresh_source_data_dir }}/server/tls/request-header-ca.crt"
- "{{ k3s_refresh_source_data_dir }}/server/tls/request-header-ca.key"
- "{{ k3s_refresh_source_data_dir }}/server/tls/service.key"
- "{{ k3s_refresh_source_data_dir }}/server/tls/service.current.key"
register: _k3s_refresh_artifacts
- name: Back up k3s token/tls artifacts (remote->remote)
ansible.builtin.copy:
remote_src: true
src: "{{ item.item }}"
dest: "{{ _k3s_refresh_backup_dir.path }}/"
mode: preserve
loop: "{{ _k3s_refresh_artifacts.results }}"
when: item.stat.exists
- name: Read preserved server token (source data-dir)
ansible.builtin.slurp:
src: "{{ k3s_refresh_source_data_dir }}/server/token"
register: _k3s_refresh_token_slurp
when: >-
{{
(
_k3s_refresh_artifacts.results
| selectattr('item', 'equalto', (k3s_refresh_source_data_dir ~ '/server/token'))
| map(attribute='stat.exists')
| first
)
| default(false)
}}
no_log: true
- name: Ensure we have a token to preserve
ansible.builtin.assert:
that:
- (k3s_token | default('') | length) > 0 or (_k3s_refresh_token_slurp is defined)
fail_msg: >-
No existing token file was found under {{ k3s_refresh_source_data_dir }}/server/token,
and k3s_token is empty. Refusing to proceed because this would change the join token.
- name: Force k3s_token to preserved token (so rendered config matches what we restore)
ansible.builtin.set_fact:
k3s_token: "{{ (_k3s_refresh_token_slurp.content | b64decode | trim) if (_k3s_refresh_token_slurp is defined) else k3s_token }}"
no_log: true
- name: Stop k3s services before refresh
ansible.builtin.service:
name: "{{ item }}"
state: stopped
enabled: false
loop:
- k3s
- k3s-agent
failed_when: false
- name: Uninstall and wipe k3s state (blank slate)
ansible.builtin.import_tasks: cleanup.yml
- name: Wipe target k3s data-dir (blank slate except restored token/CA)
ansible.builtin.file:
path: "{{ k3s_refresh_target_data_dir }}"
state: absent
- name: Recreate target server directory
ansible.builtin.file:
path: "{{ k3s_refresh_target_data_dir }}/server"
state: directory
mode: "0700"
- name: Recreate target tls directory
ansible.builtin.file:
path: "{{ k3s_refresh_target_data_dir }}/server/tls"
state: directory
mode: "0700"
- name: Restore preserved minimal tls artifacts into target data-dir
ansible.builtin.copy:
remote_src: true
src: "{{ item }}"
dest: "{{ k3s_refresh_target_data_dir }}/server/tls/"
mode: preserve
loop:
- "{{ _k3s_refresh_backup_dir.path }}/server-ca.crt"
- "{{ _k3s_refresh_backup_dir.path }}/server-ca.key"
- "{{ _k3s_refresh_backup_dir.path }}/client-ca.crt"
- "{{ _k3s_refresh_backup_dir.path }}/client-ca.key"
- "{{ _k3s_refresh_backup_dir.path }}/request-header-ca.crt"
- "{{ _k3s_refresh_backup_dir.path }}/request-header-ca.key"
- "{{ _k3s_refresh_backup_dir.path }}/service.key"
- "{{ _k3s_refresh_backup_dir.path }}/service.current.key"
failed_when: false
- name: Install and start k3s
ansible.builtin.import_tasks: install.yml
- name: Configure k3s add-ons
ansible.builtin.import_tasks: configure.yml
when: k3s_refresh_run_configure | bool
- name: Verify k3s API is responsive after refresh
ansible.builtin.command: k3s kubectl get nodes
register: _k3s_refresh_nodes
changed_when: false
until: _k3s_refresh_nodes.rc == 0
retries: 18
delay: 10
- name: Read k3s node-token after refresh
ansible.builtin.slurp:
src: "{{ k3s_refresh_target_data_dir }}/server/node-token"
register: _k3s_refresh_node_token
changed_when: false
until: _k3s_refresh_node_token is succeeded
retries: 18
delay: 10
no_log: true
- name: Assert node-token is preserved (when token is in node-token format)
ansible.builtin.assert:
that:
- (k3s_token | default('')) == (_k3s_refresh_node_token.content | b64decode | trim)
fail_msg: >-
Refusing to continue: expected regenerated node-token to match preserved k3s_token,
but it differs. This indicates the join token changed.
when:
- (k3s_token | default('')) is match('^K10[0-9a-f]+::server:.+')