fix(partitioning): resolve vmware disks by scsi target instead of the sdX letter

This commit is contained in:
2026-09-15 20:01:40 +02:00
parent b927099087
commit 96220d424e
3 changed files with 69 additions and 0 deletions

View File

@@ -538,6 +538,8 @@ When `hypervisor.type: vmware` uses the `vmware_tools` connection:
`system.disks[0]` is the OS disk (no `mount.path`). Additional entries define data disks.
On VMware, `device` is resolved on the target from the SCSI address instead: entry N is the disk at target N on the first SCSI controller (N+1 from index 7 on, since unit 7 is reserved). The kernel's `sdX` order is not stable between the install environment and the installed system, so a letter-derived path can point at another disk.
| Key | Type | Description |
| ------------- | ------ | ------------------------------------------------------ |
| `size` | number | Disk size in GB (required for virtual) |

View File

@@ -0,0 +1,61 @@
---
# The virtualization role attaches system.disks to SCSI controller 0 in list order, and
# vSphere never gives a disk unit 7 (the controller's own address). The kernel's sdX order
# is not that order and differs between the install environment and the installed OS, so
# a disk derived as /dev/sd<letter of its index> can be the wrong one. Resolve by target.
- name: List disks with their SCSI address
ansible.builtin.command: lsblk -dnpo NAME,TYPE,HCTL
register: partitioning_vmware_lsblk
changed_when: false
- name: Map SCSI targets to devices
vars:
_scsi: >-
{%- set out = [] -%}
{%- for line in partitioning_vmware_lsblk.stdout_lines -%}
{%- set p = line.split() -%}
{%- if (p | length) == 3 and p[1] == 'disk' and p[2] is match('^\d+:0:\d+:0$') -%}
{%- set _ = out.append({'name': p[0], 'host': p[2].split(':')[0], 'target': p[2].split(':')[2]}) -%}
{%- endif -%}
{%- endfor -%}
{{ out }}
ansible.builtin.set_fact:
partitioning_vmware_hosts: "{{ _scsi | map(attribute='host') | unique | list }}"
partitioning_vmware_targets: "{{ _scsi | items2dict(key_name='target', value_name='name') }}"
partitioning_vmware_target_count: "{{ _scsi | length }}"
- name: Assert the system disks sit on one SCSI controller with unique targets
ansible.builtin.assert:
that:
- partitioning_vmware_hosts | length == 1
- partitioning_vmware_targets | length == partitioning_vmware_target_count | int
fail_msg: >-
Expected every disk on one SCSI controller with unique targets, got
{{ partitioning_vmware_lsblk.stdout_lines | select('search', ' disk ') | list }}.
quiet: true
- name: Assert each system disk has a device at its SCSI target
vars:
_target: "{{ (idx if idx < 7 else idx + 1) | string }}"
ansible.builtin.assert:
that:
- _target in partitioning_vmware_targets
fail_msg: "system.disks[{{ idx }}] ({{ item.size }} GB) expects a disk at SCSI target {{ _target }}, none found."
quiet: true
loop: "{{ system_cfg.disks }}"
loop_control:
index_var: idx
label: "{{ idx }}"
- name: Point system disks and install_drive at the resolved devices
vars:
_disks: >-
{%- set out = [] -%}
{%- for d in system_cfg.disks -%}
{%- set dev = partitioning_vmware_targets[(loop.index0 if loop.index0 < 7 else loop.index0 + 1) | string] -%}
{%- set _ = out.append(d | combine({'device': dev, 'partition': dev ~ '1'})) -%}
{%- endfor -%}
{{ out }}
ansible.builtin.set_fact:
system_cfg: "{{ system_cfg | combine({'disks': _disks}) }}"
install_drive: "{{ _disks[0].device }}"

View File

@@ -1,4 +1,10 @@
---
- name: Resolve VMware disks by SCSI target
when:
- hypervisor_type == "vmware"
- system_cfg.type == "virtual"
ansible.builtin.include_tasks: _resolve_vmware_disks.yml
- name: Detect system sizing
ansible.builtin.include_tasks: _detect_sizing.yml