Я попытался перефразировать проблему немного. Это далеко от совершенства, так как не будет учитываться «дыры» в нумерации (то есть диск или контроллеры удалены из последовательности). Но я не думаю, что ваша текущая реализация тоже. Мой должен работать с гораздо меньшим количеством назначаемых переменных и изящно завершится неудачей, если больше не будет доступных слотов.
- Получить информацию о диске от гостя (вставлено в переменную для примера).
- Из информации, цикл на номер настроенного контроллера. Для каждого контроллера запишите его ключ, номер, количество устройств и максимально настроенный идентификатор устройства.
- Извлеките из списка первый контроллер, имеющий доступный слот
- Если это не удастся, создайте пустую информацию о контроллере, увеличивающуюсяномер устройства scsi или сбой при достижении максимального значения.
Примечание. Я использовал json_query, поэтому для запуска примера вам понадобится pip(3) install jmespath
на вашем компьютере контроллера ANSIBLE.
playbook:
---
- name: My take to your vmware disk management question
hosts: localhost
gather_facts: false
vars:
# Info copied from your example.
vcenter_host: "VCENTER01"
vcenter_username: "TFGH\\kaikudou"
vcenter_password: xxxxxxxxx
target_host: "TFGH0001"
# Max number of devices per scsi controller
scsi_max_devices: 15
# Max id for scsi controllers
scsi_max_controller_id: 3
# Calling the two following vars before getting facts will fail
# but since we don't need to loop to get them they can be statically
# declared in playbook vars
scsi_controller_unique_keys: >-
{{
vm_disk_info.guest_disk_facts
| dict2items
| map(attribute='value.controller_key')
| list
| unique
| sort
}}
host_datastore: "{{ vm_disk_info.guest_disk_facts['0'].backing_datastore }}"
# Your example data to play with (minified, single line)
# To take from module call return IRL.
vm_disk_info: {"guest_disk_facts":{"0":{"backing_datastore":"VCENTER01_DS01","backing_eagerlyscrub":false,"backing_filename":"[VCENTER01_DS01] TCB0945/TFGH0001-000001.vmdk","backing_thinprovisioned":false,"backing_type":"FlatVer2","backing_uuid":"6000C294-d22d-06a9-c89b-119e13fffe33","backing_writethrough":false,"capacity_in_bytes":32212254720,"capacity_in_kb":31457280,"controller_key":1000,"key":2000,"label":"Hard disk 1","summary":"31,457,280 KB","unit_number":0},"1":{"backing_datastore":"VCENTER01_DS01","backing_eagerlyscrub":false,"backing_filename":"[VCENTER01_DS01] TFGH0001/TFGH0001_3.vmdk","backing_thinprovisioned":false,"backing_type":"FlatVer2","backing_uuid":"6000C293-ae37-30f6-b684-d5b2416ff2f8","backing_writethrough":false,"capacity_in_bytes":10737418240,"capacity_in_kb":10485760,"controller_key":1000,"key":2001,"label":"Hard disk 2","summary":"10,485,760 KB","unit_number":1}}}
tasks:
- name: Create a list holding all the info we need for each existing controller
vars:
scsi_controller_devices_query: >-
[?to_string(value.controller_key)=='{{ controller_key }}'].value.unit_number[]
scsi_controller_devices: >-
{{
vm_disk_info.guest_disk_facts |
dict2items |
json_query(scsi_controller_devices_query)
}}
# Construct object directly as json so that we retain int type for further comparison usage.
current_controller: >-
{
"controller_number": {{ controller_number | int }},
"controller_key": {{ controller_key | int }},
"number_of_devices": {{ scsi_controller_devices | length | int }},
"max_unit_number": {{ scsi_controller_devices | max | int }},
}
set_fact:
scsi_controllers_info: "{{ scsi_controllers_info | default([]) + [current_controller] }}"
loop: "{{ scsi_controller_unique_keys }}"
loop_control:
loop_var: controller_key
index_var: controller_number
- block:
# Note: This was already sorted when we got controllers list in our first loop
- name: "Extract first controller having less than {{ scsi_max_devices }} disks"
set_fact:
scsi_controller: >-
{{
(
scsi_controllers_info |
selectattr('number_of_devices', '<', scsi_max_devices) |
list
).0
}}
rescue:
- name: Fail if we cannot add an other controller id
# i.e.controllernumber of our last element in list is equal (or greater for tests) that scsi_max_controller_id
fail:
msg: All scsi controllers are full, disk cannot be added.
when: scsi_controllers_info[-1].controller_number >= scsi_max_controller_id
- name: Return an empty controller with incremented id
set_fact:
scsi_controller: >-
{
"controller_number": {{ scsi_controllers_info[-1].controller_number + 1 | int }},
"controller_key": {{ scsi_controllers_info[-1].controller_key + 1 | int }},
"number_of_devices": 0,
"max_unit_number": -1,
}
- name: Show what the call to vmware_guest_disk would look like
vars:
vmware_guest_disk_params:
hostname: "{{ vcenter_host }}"
username: "{{ vcenter_username }}"
password: "{{ vcenter_password }}"
validate_certs: False
datacenter: "{{ vcenter_host }}"
name: "{{ target_host }}"
disk:
- size_gb: 2
type: thin
state: present
datastore: "{{ host_datastore }}"
# autoselect_datastore: True
scsi_controller: "{{ scsi_controller.controller_number }}"
unit_number: "{{ scsi_controller.max_unit_number + 1 }}"
scsi_type: 'paravirtual'
debug:
msg: "{{ vmware_guest_disk_params }}"