#!/usr/bin/env python3 from pyVmomi import vim import pyVim.connect import atexit import argparse from pprint import pprint import siteconf site_conf = siteconf.read() def get_args(): parser = argparse.ArgumentParser( description='Clone VM from template') parser.add_argument('-s', '--site', required=True, action='store', help='Name of the site to create VM on') parser.add_argument('-t', '--template', required=False, action='store', help='Name of the template you wish to clone') parser.add_argument('-v', '--vm-name', required=True, action='store', help='Name of the VM you wish to make') parser.add_argument('-c', '--cpu', required=False, type=int, action='store', default=1, help='Set number of CPUs') parser.add_argument('-m', '--memory', required=False, type=int, action='store', default=2048, help='[MB] Set memory size') parser.add_argument('-d', '--disk-size', required=False, type=int, action='store', default=0, help='[GB] Resize LVM disk to this size') parser.add_argument('--datastore', required=False, action='store', default=None, help='target datastore') args = parser.parse_args() args.disk_size = args.disk_size * 1024 * 1024 return args def wait_for_task(task): """ wait for a vCenter task to finish """ task_done = False while not task_done: if task.info.state == 'success': return task.info.result if task.info.state == 'error': print("there was an error") task_done = True def get_obj(content, vimtype, name): """ Return an object by name, if name is None the first found object is returned """ obj = None container = content.viewManager.CreateContainerView( content.rootFolder, vimtype, True) for c in container.view: if name: if c.name == name: obj = c break else: obj = c break return obj def clone_vm(content, template, vm_name, datacenter_name, datastore_name, cluster_or_host): datacenter = get_obj(content, [vim.Datacenter], datacenter_name) destfolder = datacenter.vmFolder datastore = get_obj(content, [vim.Datastore], datastore_name) cluster = get_obj(content, [vim.ClusterComputeResource], cluster_or_host) if cluster: resource_pool = cluster.resourcePool else: host = get_obj(content, [vim.ComputeResource], cluster_or_host) resource_pool = host.resourcePool relospec = vim.vm.RelocateSpec() relospec.datastore = datastore relospec.pool = resource_pool clonespec = vim.vm.CloneSpec() clonespec.location = relospec clonespec.powerOn = False print(f"cloning to VM '{vm_name}'...") task = template.Clone(folder=destfolder, name=vm_name, spec=clonespec) wait_for_task(task) def extend_disk(content, vm_name, extend_to_kb): vm = get_obj(content, [vim.VirtualMachine], vm_name) for dev in vm.config.hardware.device: #print("dev "+ dev.deviceInfo.label) if hasattr(dev.backing, 'fileName'): size_kb = dev.capacityInKB if size_kb > 5 * 1024 * 1024: # lvm disk if extend_to_kb > size_kb: disk_spec = vim.vm.device.VirtualDeviceSpec() disk_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.edit disk_spec.device = vim.vm.device.VirtualDisk() disk_spec.device.key = dev.key disk_spec.device.backing = vim.vm.device.VirtualDisk.FlatVer2BackingInfo() disk_spec.device.backing.fileName = dev.backing.fileName disk_spec.device.backing.diskMode = dev.backing.diskMode disk_spec.device.controllerKey = dev.controllerKey disk_spec.device.unitNumber = dev.unitNumber disk_spec.device.capacityInKB = extend_to_kb dev_changes = [] dev_changes.append(disk_spec) spec = vim.vm.ConfigSpec() spec.deviceChange = dev_changes print(f"extending disk '{dev.deviceInfo.label}' to {str(extend_to_kb)} kB") task = vm.ReconfigVM_Task(spec=spec) wait_for_task(task) def set_cpu_mem(content, vm_name, cpu, mem_mb): vm = get_obj(content, [vim.VirtualMachine], vm_name) spec = vim.vm.ConfigSpec() spec.numCPUs = cpu spec.memoryMB = mem_mb print(f"set cpu={str(cpu)}, memory={str(mem_mb)} MB") task = vm.ReconfigVM_Task(spec=spec) wait_for_task(task) def power_on(content, vm_name): vm = get_obj(content, [vim.VirtualMachine], vm_name) print(f"powering on '{vm_name}'") task = vm.PowerOn() wait_for_task(task) def main(): args = get_args() if not args.site in site_conf: print(f"site not found: {args.site}") exit(1) site = site_conf[args.site]; si = pyVim.connect.SmartConnect( host = site["vcenter"], user = site["vcenter_user"], pwd = site["vcenter_passwd"], disableSslCertValidation = True ) atexit.register(pyVim.connect.Disconnect, si) content = si.RetrieveContent() template_name = site["template"] if args.template is None: if len(site["template"]) == 1: template_name, = site["template"].values() else: print("specify `-t TEMPLATE` with:") for t in site["template"]: print(f" - {t} ({site['template'][t]})") print(f" - or any template in vsphere") exit(1) else: if args.template in site["template"]: template_name = site["template"][args.template] else: template_name = args.template template = get_obj(content, [vim.VirtualMachine], template_name) if not template: print("template not found") exit(1) print(f"template: {template_name}") vm = get_obj(content, [vim.VirtualMachine], args.vm_name) if vm: print(f"VM '{args.vm_name}' exists.") exit(1) datastore = site["datastore"] if args.datastore is not None: datastore = args.datastore clone_vm(content, template, args.vm_name, site["datacenter"], datastore, site["cluster_or_host"]) set_cpu_mem(content, args.vm_name, args.cpu, args.memory) extend_disk(content, args.vm_name, args.disk_size) power_on(content, args.vm_name) if __name__ == "__main__": main() # vim: set tabstop=4 shiftwidth=4 expandtab smarttab: