Как более эффективно добавить диск к виртуальному хосту VMware с помощью официального модуля Ansible? - PullRequest
0 голосов
/ 10 ноября 2019

Env

  • Версия ОС: CentOS 7.5
  • Версия Ansible: 2.8.4 с python 2.7.5
  • Версия ESXi и VCenter: 6.5.2

Цель

Я уже выполнил свой код, но мне интересно, есть ли лучший способ добавить диск к хосту виртуальной машины с помощью Ansible offical module .

My Method

Ответное сообщение от vmware_guest_disk_facts

TASK [get VM info] *******************************************************************************************************
ok: [TFGH0001.TFGH.COM -> localhost] => changed=false 
  guest_disk_facts:
    '0':
      backing_datastore: VCENTER01_DS01
      backing_eagerlyscrub: false
      backing_filename: '[VCENTER01_DS01] TFGH0001/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

My Playbook

---
  - hosts: all
    remote_user: kai
    become: yes
    become_user: root
    become_method: sudo
    gather_facts: true

    vars:
      vcenter_host: "VCENTER01"
      vcenter_username: "TFGH\\kaikudou"
      vcenter_password: xxxxxxxxx
      target_host: "TFGH0001"

    tasks:

    - name: get VM info
      vmware_guest_disk_facts:
        hostname: "{{ vcenter_host }}"
        username: "{{ vcenter_username }}"
        password: "{{ vcenter_password }}"
        validate_certs: False
        datacenter: "{{ vcenter_host }}"
        name: "{{ target_host }}"
      delegate_to: localhost
      register: vm_disk_info

    # - name: show vm_disk_info
    #   debug:
    #     msg: "{{ vm_disk_info.guest_disk_facts['0'].backing_datastore }}"

    - name: Set empty list to store varialbe
      set_fact:
        all_scsi_number_list: []  # A list to store all scsi device number
        scsi_0: []  # A list to store scsi 0's device for counting the quantity
        scsi_1: []  # A list to store scsi 1's device for counting the quantity
        scsi_2: []  # A list to store scsi 2's device for counting the quantity
        scsi_3: []  # A list to store scsi 3's device for counting the quantity
        all_unit_number_list: []  # A list to store the device number from scsi controller   

    - name: Set variable of datastore
      set_fact:
        host_datastore: "{{ vm_disk_info.guest_disk_facts['0'].backing_datastore }}"

    - name: Store scsi_number into all_scsi_number_list
      set_fact:
        all_scsi_number_list: "{{ all_scsi_number_list + [vm_disk_info.guest_disk_facts[item].controller_key] }}"
      loop: "{{ vm_disk_info.guest_disk_facts.keys() }}"

    - name: Find out scsi_controller 0 and store into scsi_0
      set_fact:
        scsi_0 : "{{ scsi_0 + [item] }}"
      loop: "{{ all_scsi_number_list }}"
      when: item == 1000

    - name: Find out the scsi_controller 1 and store into scsi_1
      set_fact:
        scsi_1 : "{{ scsi_1 + [item] }}"
      loop: "{{ all_scsi_number_list }}"
      when: item == 1001

    - name: Find out the scsi_controller 2 and store into scsi_2
      set_fact:
        scsi_2 : "{{ scsi_2 + [item] }}"
      loop: "{{ all_scsi_number_list }}"
      when: item == 1002

    - name: Find out the scsi_controller 3 and store into scsi_3
      set_fact:
        scsi_3 : "{{ scsi_3 + [item] }}"
      loop: "{{ all_scsi_number_list }}"
      when: item == 1003

    - name: Calcualte the quantity of scsi_*
      set_fact:
        scsi_0_number: "{{ scsi_0 | length }}"
        scsi_1_number: "{{ scsi_1 | length }}"
        scsi_2_number: "{{ scsi_2 | length }}"
        scsi_3_number: "{{ scsi_3 | length }}"

    - name: Verify the scsi controller's number because snapshot will also cost the device so less than 7 to prevent
      set_fact:
        scsi_number: "{{ item.src }}"
      loop:
        - { src: "0", when: "{{ (scsi_0_number <= '6' and scsi_0_number != '0') or (scsi_0_number == '0') }}" }
        - { src: "1", when: "{{ (scsi_1_number <= '6' and scsi_1_number != '0') or (scsi_1_number == '0') }}" }
        - { src: "2", when: "{{ (scsi_2_number <= '6' and scsi_2_number != '0') or (scsi_2_number == '0') }}" }
        - { src: "3", when: "{{ (scsi_3_number <= '6' and scsi_3_number != '0') or (scsi_3_number == '0') }}" }
      when: item.when

    # - name: Show scsi_number which we get
    #   debug:
    #     msg: "{{ scsi_number }}"

    - name: Change the scsi_number we obtained to 4 digit number
      set_fact:
        scsi_digit_number: "{{ item.src | int }}"
      loop:
        - { src: "1000", when: "{{ scsi_number == '0' }}" }
        - { src: "1001", when: "{{ scsi_number == '1' }}" }
        - { src: "1002", when: "{{ scsi_number == '2' }}" }
        - { src: "1003", when: "{{ scsi_number == '3' }}" }
      when: item.when

    # - name: Show scsi_digit_number which we get
    #   debug:
    #     msg: "{{ scsi_digit_number }}"

    - name: Check the number of devices from the scci_number we obtained
      set_fact:
        all_unit_number_list: "{{ all_unit_number_list + [vm_disk_info.guest_disk_facts[item].unit_number] }}"
      loop: "{{ vm_disk_info.guest_disk_facts.keys() }}"
      when: vm_disk_info.guest_disk_facts[item].controller_key == scsi_digit_number | int

    # - name: Show all_unit_number_list which we get
    #   debug:
    #     msg: "{{ all_unit_number_list | length | type_debug }}"

    - name: Find the max number in all_unit_number_list then plus 1 to add new disk
      set_fact:
        disk_number: "{{ all_unit_number_list | max + 1 }}"
      ignore_errors: yes

    - name: If we have to add new scsi controller then the all_unit_number_list will be empty list, so we need to prevent it failed
      set_fact:
        disk_number: 0
      when: all_unit_number_list | length == 0

    - name: add disk
      vmware_guest_disk:
        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_number | int }}"
            unit_number: "{{ disk_number | int }}"
            scsi_type: 'paravirtual'

Согласно Официальный документ VMware 1 VMХост может иметь только 4 контроллера SCSI, и каждое из них может иметь 15 устройств для подключения. Поэтому я должен написать много условий, чтобы предотвратить это.

Странно то, что при добавлении жесткого диска из VCenter это не вызовет проблемы, когда количество жестких дисков превышает 7. Однако модуль Ansible не может увеличить жесткий диск, когда unit_number превышает 7, и долженсмените другой контроллер SCSI.

Есть ли другой способ, кроме этого? или что-то, к чему я могу обратиться и изучить это?

Спасибо за вашу помощь и совет!

1 Ответ

0 голосов
/ 11 ноября 2019

Я попытался перефразировать проблему немного. Это далеко от совершенства, так как не будет учитываться «дыры» в нумерации (то есть диск или контроллеры удалены из последовательности). Но я не думаю, что ваша текущая реализация тоже. Мой должен работать с гораздо меньшим количеством назначаемых переменных и изящно завершится неудачей, если больше не будет доступных слотов.

  • Получить информацию о диске от гостя (вставлено в переменную для примера).
  • Из информации, цикл на номер настроенного контроллера. Для каждого контроллера запишите его ключ, номер, количество устройств и максимально настроенный идентификатор устройства.
  • Извлеките из списка первый контроллер, имеющий доступный слот
  • Если это не удастся, создайте пустую информацию о контроллере, увеличивающуюсяномер устройства 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 }}"

...