--- - name: Stage 1 - Add Ubuntu VM to in-memory inventory hosts: localhost connection: local gather_facts: false become: false tasks: - name: Add Ubuntu VM to in-memory inventory ansible.builtin.add_host: name: ubuntu-resize-target groups: ubuntu_resize_group ansible_host: "{{ vm_ip }}" ansible_user: "{{ ansible_user }}" ansible_password: "{{ ansible_password }}" ansible_become: true ansible_become_password: "{{ ansible_become_password }}" ansible_ssh_common_args: "-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" - name: Stage 2 - Wait for SSH port hosts: localhost connection: local gather_facts: false become: false tasks: - name: Wait for SSH port on Ubuntu VM ansible.builtin.wait_for: host: "{{ vm_ip }}" port: 22 timeout: 60 sleep: 2 - name: Stage 3 - Read current guest disk size hosts: ubuntu_resize_group gather_facts: false become: true vars: ansible_python_interpreter: /usr/bin/python3 tasks: - name: Get current size of /dev/sda in bytes ansible.builtin.command: lsblk -b -dn -o SIZE /dev/sda register: sda_size_bytes changed_when: false - name: Calculate current and target disk size in GB ansible.builtin.set_fact: current_disk_gb: "{{ (sda_size_bytes.stdout | int) // 1024 // 1024 // 1024 }}" target_disk_gb: "{{ ((sda_size_bytes.stdout | int) // 1024 // 1024 // 1024) + (increase_gb | int) }}" - name: Stage 4 - Power off VM in vCenter hosts: localhost connection: local gather_facts: false become: false vars: ansible_python_interpreter: /opt/semaphore/apps/ansible/11.1.0/venv/bin/python3 tasks: - name: Show resize plan ansible.builtin.debug: msg: - "VM: {{ vm_name }}" - "VM IP: {{ vm_ip }}" - "Current disk: {{ hostvars['ubuntu-resize-target']['current_disk_gb'] }} GB" - "Target disk: {{ hostvars['ubuntu-resize-target']['target_disk_gb'] }} GB" - name: Power off VM gracefully community.vmware.vmware_guest_powerstate: hostname: "{{ vsphere_server }}" username: "{{ vsphere_user }}" password: "{{ vsphere_password }}" validate_certs: false datacenter: "{{ vsphere_datacenter }}" name: "{{ vm_name }}" state: powered-off delegate_to: localhost - name: Wait until SSH port is closed ansible.builtin.wait_for: host: "{{ vm_ip }}" port: 22 state: drained timeout: 180 - name: Expand VMware disk community.vmware.vmware_guest_disk: hostname: "{{ vsphere_server }}" username: "{{ vsphere_user }}" password: "{{ vsphere_password }}" validate_certs: false datacenter: "{{ vsphere_datacenter }}" name: "{{ vm_name }}" disk: - state: present unit_number: 0 controller_number: 0 size_gb: "{{ hostvars['ubuntu-resize-target']['target_disk_gb'] }}" delegate_to: localhost - name: Power on VM community.vmware.vmware_guest_powerstate: hostname: "{{ vsphere_server }}" username: "{{ vsphere_user }}" password: "{{ vsphere_password }}" validate_certs: false datacenter: "{{ vsphere_datacenter }}" name: "{{ vm_name }}" state: powered-on delegate_to: localhost - name: Wait for SSH port to return ansible.builtin.wait_for: host: "{{ vm_ip }}" port: 22 timeout: 300 sleep: 5 - name: Stage 5 - Wait for SSH session after reboot hosts: ubuntu_resize_group gather_facts: false vars: ansible_python_interpreter: /usr/bin/python3 tasks: - name: Wait for SSH connection ansible.builtin.wait_for_connection: timeout: 300 - name: Stage 6 - Expand partition, LVM and filesystem inside Ubuntu hosts: ubuntu_resize_group gather_facts: false become: true vars: ansible_python_interpreter: /usr/bin/python3 root_disk: /dev/sda root_partition_number: 3 root_partition: /dev/sda3 root_lv: /dev/mapper/ubuntu--vg-ubuntu--lv tasks: - name: Rescan SCSI bus ansible.builtin.shell: | for host in /sys/class/scsi_host/host*; do echo "- - -" > "$host/scan" done args: executable: /bin/bash changed_when: true - name: Wait after rescan ansible.builtin.pause: seconds: 5 - name: Ensure growpart is installed ansible.builtin.apt: name: cloud-guest-utils state: present update_cache: yes - name: Expand partition if needed ansible.builtin.command: "growpart {{ root_disk }} {{ root_partition_number }}" register: growpart_result changed_when: "'CHANGED:' in growpart_result.stdout" failed_when: > growpart_result.rc != 0 and 'NOCHANGE:' not in growpart_result.stdout - name: Resize LVM physical volume ansible.builtin.command: "pvresize {{ root_partition }}" register: pvresize_result failed_when: false changed_when: true - name: Extend root logical volume and filesystem ansible.builtin.command: "lvextend -r -l +100%FREE {{ root_lv }}" register: lvextend_result failed_when: false changed_when: true - name: Show final disk state ansible.builtin.shell: | pvs vgs lvs df -h / args: executable: /bin/bash register: final_state changed_when: false - name: Print final disk state ansible.builtin.debug: var: final_state.stdout_lines