mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 10:59:59 +00:00
Every swarm job on ubuntu-26.04 runners (kernel 7.0) died at the NFS probe write with `[Errno 121] Remote I/O error`. ganesha's NFSv4 debug log in the rescue bundles shows the cause on every client, the same second as the failure: Request 2: opcode 46 is OP_GET_DIR_DELEGATION Status of OP_GET_DIR_DELEGATION in position 2 = NFS4ERR_OP_ILLEGAL Linux 6.19 added directory delegations: after ACCESS, CREATE, REMOVE or RENAME the client adds GET_DIR_DELEGATION to the directory's next GETATTR (`should_request_dir_deleg`, gated per request by the nfsv4 parameter `directory_delegations`). nfs-ganesha before 9.11 routes op 46 to `nfs4_op_illegal`, whose reply carries opcode 10044; the client decoder expects 46 and fails the call with EREMOTEIO. Upstream fixed it in nfs-ganesha#1385 (98eb77c4, first in V9.11), which answers NOTSUPP; the client then drops the capability. The distro packages the role installs predate it: Debian trixie 6.5-5, Ubuntu 26.04 6.5-8. Every client and the controller now read the server's installed nfs-ganesha release and, below 9.11, set `directory_delegations=N` right after the mount and before the first access (the mount itself never sends op 46), plus `options nfsv4 directory_delegations=N` in /etc/modprobe.d for later module loads. No ganesha release grants directory delegations, so the end state equals a fixed server. The parameter is kernel-wide and is only ever set to N, so clients sharing one kernel cannot flip it back on each other. Servers on 9.11 or later and the kernel nfsd flavor keep the client default. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
66 lines
2.2 KiB
YAML
66 lines
2.2 KiB
YAML
---
|
|
- name: "🔍 Detect controller {{ DIR_VAR_LIB }} pre-mount state"
|
|
ansible.builtin.script:
|
|
cmd: "{{ lookup('path_absolute', 'roles/svc-storage-nfs-client/files/shell/premount_state.sh') }}"
|
|
executable: /bin/bash
|
|
environment:
|
|
DIR_VAR_LIB: "{{ DIR_VAR_LIB }}"
|
|
register: _ctrl_premount_state
|
|
changed_when: false
|
|
|
|
- name: "✅ Assert controller {{ DIR_VAR_LIB }} has no pre-existing data (mount hides it)"
|
|
ansible.builtin.assert:
|
|
that:
|
|
- >-
|
|
'STATE=mounted' in _ctrl_premount_state.stdout
|
|
or 'STATE=empty' in _ctrl_premount_state.stdout
|
|
fail_msg: >-
|
|
Pre-existing local data found at controller {{ DIR_VAR_LIB }}; NFS
|
|
mount-over would silently hide it. Migrate or remove the local tree
|
|
on the controller, then re-run the deploy. Probe said:
|
|
{{ _ctrl_premount_state.stdout | trim }}
|
|
|
|
- name: "✅ Ensure controller mount point exists"
|
|
ansible.builtin.file:
|
|
path: "{{ DIR_VAR_LIB }}"
|
|
state: directory
|
|
owner: root
|
|
group: root
|
|
mode: "0755"
|
|
|
|
- name: "📦 Install the NFS client"
|
|
package_install:
|
|
id: nfs-client
|
|
|
|
- name: "🔎 Read current mount source at controller {{ DIR_VAR_LIB }}"
|
|
ansible.builtin.command:
|
|
cmd: "findmnt -n -o SOURCE {{ DIR_VAR_LIB }}"
|
|
register: _ctrl_mount_src
|
|
changed_when: false
|
|
failed_when: false
|
|
|
|
- name: "🔌 Unmount foreign source so the ephemeral (re)mount is not refused"
|
|
ansible.posix.mount:
|
|
path: "{{ DIR_VAR_LIB }}"
|
|
state: unmounted
|
|
when:
|
|
- "'STATE=mounted' in _ctrl_premount_state.stdout"
|
|
- (_ctrl_mount_src.stdout | trim) | length > 0
|
|
- (_ctrl_mount_src.stdout | trim) != STORAGE_NFS_CONTROLLER_SRC
|
|
|
|
- name: "🔗 Mount cluster-shared infinito state on controller"
|
|
ansible.posix.mount:
|
|
path: "{{ DIR_VAR_LIB }}"
|
|
src: "{{ STORAGE_NFS_CONTROLLER_SRC }}"
|
|
fstype: "{{ STORAGE_NFS_FSTYPE }}"
|
|
opts: "{{ STORAGE_NFS_MOUNT_OPTS }}"
|
|
state: ephemeral
|
|
register: _ctrl_nfs_mount
|
|
retries: 12
|
|
delay: 5
|
|
until: _ctrl_nfs_mount is succeeded
|
|
|
|
- name: "🔧 Align the controller's directory delegations with the ganesha server"
|
|
ansible.builtin.include_tasks: "{{ lookup('path_absolute', 'roles/svc-storage-nfs-client/tasks/directory_delegations.yml') }}"
|
|
when: lookup('nfs_flavor') == 'ganesha'
|