community.vmware icon indicating copy to clipboard operation
community.vmware copied to clipboard

ESXi without vCenter - Duplicate existing template VM

Open linuxcrash opened this issue 4 years ago • 3 comments

SUMMARY

It seems currently there is no way of duplicating an existing VM that is available on an ESXi server running without vCenter.

The story goes like this: User uploads a Windows template OVA that gets successfully registered on the ESXi. Now this template VM is used to get copied as instances of real VM's. Since the clone opration is only available to ESXi hosts that are connected to a vCenter, this operation does not work using community.vmware.vmware_guest.

ISSUE TYPE
  • Feature Idea
COMPONENT NAME

community.vmware.vmware_guest_copy

ADDITIONAL INFORMATION

Required functionality implemented:

  1. User defines the source VM name (required to have the VM powered off during all operations).
  2. Source VM folder get copied to new folder using defined destination VM name on defined destination datastore on the same ESXi.
  3. Rename the .vmx file in destination folder using specified destination VM name.
  4. Register the renamed .vmx file to ESXi inventory.
  - name: Copy VM from local VM
    community.vmware.vmware_guest_copy:
      hostname: '{{ esxi_host }}'
      username: '{{ esxi_user }}'
      password: '{{ esxi_pw }}'
      name: New-VM1
      sourcevmname: Win2016-TemplateVM
      folder: vm
      datastore: VM-DS01
      state: present
      validate_certs: no
    delegate_to: localhost

linuxcrash avatar Mar 14 '21 12:03 linuxcrash

Files identified in the description: None

If these files are inaccurate, please update the component name section of the description or use the !component bot command.

click here for bot help

ansibullbot avatar Mar 14 '21 12:03 ansibullbot

Thanks, @linuxcrash for the feature idea.

As you say, unfortunately, there isn't API to clone on ESXi only environment without vCenter.
As an alternative, you can clone with vmkfstools command and so on via SSH.
For example, the following playbook can clone a new vm from a template on ESXi only environment.

My Environment Information

pip list | grep -e ansible -e pyvmomi -e '-' -e Pack
Package      Version
------------ ---------
ansible-base 2.10.8
pyvmomi      7.0.2

community.vmware is the latest version.
ESXi is 7.0.

ansible.cfg

$ ansible-config dump --only-changed
HOST_KEY_CHECKING(/PATH/ansible.cfg) = True

inventory.yml

---
all:
  hosts:
    esxi-test03:
      ansible_host: 192.xxx.xxx.xxx
  vars:
    ansible_user: root
    ansible_password: secret

clone_vm_without_vcenter_sample.yml

---
- name: Sample Playbook for cloning a vm  on ESXi only environment without vCenter
  hosts: all
  gather_facts: false
  vars:
    clone_vms:  # is new vm list for you want
      - name: clone_vm01
        disk_type: thin
    datastore_name: VM3  # is datastore name to be deployed of VM
    template: test_vm2  # is template vm name from you want to use
  tasks:
    - name: Enable SSH Service of ESXi host
      community.vmware.vmware_host_service_manager:
        hostname: "{{ ansible_host }}"
        username: "{{ ansible_user }}"
        password: "{{ ansible_password }}"
        validate_certs: false
        esxi_hostname: "{{ inventory_hostname }}"
        service_name: TSM-SSH
        state: present
      delegate_to: localhost

    - name: Gather datastores information
      community.vmware.vmware_datastore_info:
        hostname: "{{ ansible_host }}"
        username: "{{ ansible_user }}"
        password: "{{ ansible_password }}"
        validate_certs: false
        datacenter: ha-datacenter
      delegate_to: localhost
      register: datastore_result

    - name: Set datastore_path variable
      set_fact:
        datastore_path: "{{ item.url }}"
      loop: "{{ datastore_result.datastores }}"
      when:
        - item.name == datastore_name

    - when:
        - datastore_path is defined
      block:
        - name: Create a directory to store virtual machines
          file:
            path: "{{ datastore_path }}/{{ item.name }}"
            mode: 0755
            state: directory
          loop: "{{ clone_vms }}"

        - name: Copy vmdk file(Multiple file support)
          shell: >-
                 for vmdk in $(find {{ datastore_path }}/{{ template }} -name "*.vmdk" | grep -v flat | awk -F / '{print $(NF)}') ; do
                     rename_vmdk=`echo $vmdk | sed -e "s/{{ template }}\(.*\)/{{ item.name }}\1/g"`
                     vmkfstools -i {{ datastore_path }}/{{ template }}/$vmdk -d {{ item.disk_type }} {{ datastore_path }}/{{ item.name }}/$rename_vmdk
                 done
          loop: "{{ clone_vms }}"

        - name: Copy vmx file
          copy:
            src: "{{ datastore_path }}/{{ template }}/{{ template }}.vmx"
            dest: "{{ datastore_path }}/{{ item.name }}/{{ item.name }}.vmx"
            mode: 0644
            remote_src: true
          loop: "{{ clone_vms }}"

        - name: Replace vmx file parameter
          replace:
            path: "{{ datastore_path }}/{{ item.name }}/{{ item.name }}.vmx"
            regexp: "{{ template }}(\\.vmdk|\\.nvram|\"$)"
            replace: "{{ item.name }}\\1"
          loop: "{{ clone_vms }}"

        - name: Register VM to inventory
          community.vmware.vmware_guest_register_operation:
            hostname: "{{ ansible_host }}"
            username: "{{ ansible_user }}"
            password: "{{ ansible_password }}"
            validate_certs: false
            folder: '/vm'
            esxi_hostname: "{{ inventory_hostname }}"
            name: "{{ item.name }}"
            path: "[{{ datastore_name }}] {{ item.name }}/{{ item.name }}.vmx"
            state: present
          delegate_to: localhost
          loop: "{{ clone_vms }}"

execute playbook

$ ansible-playbook -i inventory.yml clone_vm_without_vcenter_sample.yml

How about this like?

sky-joker avatar Apr 18 '21 14:04 sky-joker

@sky-joker you legend. Just the code I was looking for.

nectarbomb avatar May 30 '22 11:05 nectarbomb