Skip to content

Instantly share code, notes, and snippets.

@snobear
Last active October 17, 2023 06:39
Show Gist options
  • Star 39 You must be signed in to star a gist
  • Fork 15 You must be signed in to fork a gist
  • Save snobear/8788977 to your computer and use it in GitHub Desktop.
Save snobear/8788977 to your computer and use it in GitHub Desktop.
Clone VM from template with pyVmomi
#!/usr/bin/env python
"""
NOTE:
This gist has been moved to EZmomi:
https://github.com/snobear/ezmomi
Give it a star or fork. Contributions are more than welcome. I'm hoping it will become an easy cli tool for
common VMware tasks.
(Notes from the original gist start here)
Example usage:
./clone.py --hostname test01 --template CentOS65 --ips 172.9.9.11 172.12.120.22 --cpus 2 --mem 4
Pip requirements:
-----------------
ecdsa==0.10
netaddr==0.7.10
pycrypto==2.6.1
pyvmomi==5.5.0
wsgiref==0.1.2
"""
from pyVim.connect import SmartConnect, Disconnect
from pyVmomi import vim, vmodl
import atexit
import os
import sys
from pprint import pprint, pformat
import time
from netaddr import IPNetwork, IPAddress
import argparse
import getpass
from settings import *
from copy import deepcopy
"""
Send an email
"""
def send_email(deploy_settings, ip_settings, output):
# Import smtplib for the actual sending function
import smtplib
from email.mime.text import MIMEText
me = os.getenv("SUDO_USER") # who ran sudo
if me is None:
me = os.getenv("USER") # will always be root when this scripts is run as sudo
email_body = "%s" % output
msg = MIMEText(email_body)
msg['Subject'] = "%s - VM deploy complete" % deploy_settings["new_vm_name"]
msg['From'] = deploy_settings["mailfrom"]
msg['To'] = me
s = smtplib.SMTP('localhost')
s.sendmail(deploy_settings["mailfrom"] , [me], msg.as_string())
s.quit()
"""
Waits and provides updates on a vSphere task
"""
def WaitTask(task, actionName='job', hideResult=False):
#print 'Waiting for %s to complete.' % actionName
while task.info.state == vim.TaskInfo.State.running:
time.sleep(2)
if task.info.state == vim.TaskInfo.State.success:
if task.info.result is not None and not hideResult:
out = '%s completed successfully, result: %s' % (actionName, task.info.result)
else:
out = '%s completed successfully.' % actionName
else:
out = '%s did not complete successfully: %s' % (actionName, task.info.error)
print out
raise task.info.error # should be a Fault... check XXX
# may not always be applicable, but can't hurt.
return task.info.result
"""
Get the vsphere object associated with a given text name
"""
def get_obj(content, vimtype, name):
obj = None
container = content.viewManager.CreateContainerView(content.rootFolder, vimtype, True)
for c in container.view:
if c.name == name:
obj = c
break
return obj
"""
Connect to vCenter server and deploy a VM from template
"""
def clone(deploy_settings, ip_settings):
fqdn = "%s.%s" % (deploy_settings["new_vm_name"], ip_settings[0]["domain"])
# connect to vCenter server
try:
si = SmartConnect(host=deploy_settings["vserver"], user=deploy_settings["username"], pwd=deploy_settings["password"], port=int(deploy_settings["port"]))
except IOError, e:
sys.exit("Unable to connect to vsphere server. Error message: %s" % e)
# add a clean up routine
atexit.register(Disconnect, si)
content = si.RetrieveContent()
# get the vSphere objects associated with the human-friendly labels we supply
datacenter = get_obj(content, [vim.Datacenter], ip_settings[0]["datacenter_name"])
# get the folder where VMs are kept for this datacenter
destfolder = datacenter.vmFolder
cluster = get_obj(content, [vim.ClusterComputeResource], ip_settings[0]["cluster_name"])
resource_pool = cluster.resourcePool # use same root resource pool that my desired cluster uses
datastore = get_obj(content, [vim.Datastore], ip_settings[0]["datastore_name"])
template_vm = get_obj(content, [vim.VirtualMachine], deploy_settings["template_name"])
# Relocation spec
relospec = vim.vm.RelocateSpec()
relospec.datastore = datastore
relospec.pool = resource_pool
'''
Networking config for VM and guest OS
'''
devices = []
adaptermaps = []
# create a Network device for each static IP
for key, ip in enumerate(ip_settings):
# VM device
nic = vim.vm.device.VirtualDeviceSpec()
nic.operation = vim.vm.device.VirtualDeviceSpec.Operation.add # or edit if a device exists
nic.device = vim.vm.device.VirtualVmxnet3()
nic.device.wakeOnLanEnabled = True
nic.device.addressType = 'assigned'
nic.device.key = 4000 # 4000 seems to be the value to use for a vmxnet3 device
nic.device.deviceInfo = vim.Description()
nic.device.deviceInfo.label = "Network Adapter %s" % (key + 1 )
nic.device.deviceInfo.summary = ip_settings[key]["network_name"]
nic.device.backing = vim.vm.device.VirtualEthernetCard.NetworkBackingInfo()
nic.device.backing.network = get_obj(content, [vim.Network], ip_settings[key]["network_name"])
nic.device.backing.deviceName = ip_settings[key]["network_name"]
nic.device.backing.useAutoDetect = False
nic.device.connectable = vim.vm.device.VirtualDevice.ConnectInfo()
nic.device.connectable.startConnected = True
nic.device.connectable.allowGuestControl = True
devices.append(nic)
# guest NIC settings, i.e. "adapter map"
guest_map = vim.vm.customization.AdapterMapping()
guest_map.adapter = vim.vm.customization.IPSettings()
guest_map.adapter.ip = vim.vm.customization.FixedIp()
guest_map.adapter.ip.ipAddress = str(ip_settings[key]["ip"])
guest_map.adapter.subnetMask = str(ip_settings[key]["subnet_mask"])
# these may not be set for certain IPs, e.g. storage IPs
try:
guest_map.adapter.gateway = ip_settings[key]["gateway"]
except:
pass
try:
guest_map.adapter.dnsDomain = ip_settings[key]["domain"]
except:
pass
adaptermaps.append(guest_map)
# VM config spec
vmconf = vim.vm.ConfigSpec()
vmconf.numCPUs = deploy_settings['cpus']
vmconf.memoryMB = deploy_settings['mem']
vmconf.cpuHotAddEnabled = True
vmconf.memoryHotAddEnabled = True
vmconf.deviceChange = devices
# DNS settings
globalip = vim.vm.customization.GlobalIPSettings()
globalip.dnsServerList = deploy_settings['dns_servers']
globalip.dnsSuffixList = ip_settings[0]['domain']
# Hostname settings
ident = vim.vm.customization.LinuxPrep()
ident.domain = ip_settings[0]['domain']
ident.hostName = vim.vm.customization.FixedName()
ident.hostName.name = deploy_settings["new_vm_name"]
customspec = vim.vm.customization.Specification()
customspec.nicSettingMap = adaptermaps
customspec.globalIPSettings = globalip
customspec.identity = ident
# Clone spec
clonespec = vim.vm.CloneSpec()
clonespec.location = relospec
clonespec.config = vmconf
clonespec.customization = customspec
clonespec.powerOn = True
clonespec.template = False
# fire the clone task
task = template_vm.Clone(folder=destfolder, name=deploy_settings["new_vm_name"].title(), spec=clonespec)
result = WaitTask(task, 'VM clone task')
# send notification
send_email(deploy_settings, ip_settings, output)
def main(**kwargs):
deploy_settings["new_vm_name"] = kwargs['hostname'].lower()
deploy_settings['cpus'] = kwargs['cpus']
deploy_settings['mem'] = kwargs['mem'] * 1024
# initialize a list to hold our network settings
ip_settings = list()
'''
Get settings for each IP given
'''
for key, ip_string in enumerate(kwargs['ips']):
# convert ip from string to the "IPAddress" type
ip = IPAddress(ip_string)
# determine network this IP is in
for network_address in net:
if ip in network_address:
net[network_address]["ip"] = ip
ip_settings.append(net[network_address])
# throw an error if we couldn't find a network for this ip
if not any(d['ip'] == ip for d in ip_settings):
sys.exit("ERROR: I don't know what network %s is in. Please add settings for this network." % ip_string)
# our default domain
if 'domain' not in ip_settings[0]:
ip_settings[0]['domain'] = 'example.com'
# what VM template to use
deploy_settings['template_name'] = kwargs['template']
# clone template to a new VM with our specified settings
clone(deploy_settings, ip_settings)
"""
Main program
"""
if __name__ == "__main__":
if getpass.getuser() != 'root':
sys.exit("You must be root to run this. Quitting.")
# Define command line arguments
parser = argparse.ArgumentParser(description='Deploy a new VM in vSphere')
parser.add_argument('--template', type=str, help='VMware template to clone', default='CentOS65')
parser.add_argument('--hostname', type=str, required=True, help='New host name',)
parser.add_argument('--ips', type=str, help='Static IPs of new host, separated by a space', nargs='+', required=True)
parser.add_argument('--cpus', type=int, help='Number of CPUs', default=1)
parser.add_argument('--mem', type=int, help='Memory in GB', default=3)
# Parse arguments and hand off to main()
args = parser.parse_args()
main(**vars(args))
"""
Network, VMware, and general settings for deploying a new Linux VM
"""
from netaddr import IPNetwork, IPAddress
"""
General settings
"""
deploy_settings = dict()
deploy_settings["dns_servers"] = ['8.8.8.8','8.8.4.4']
deploy_settings["vserver"] = "vcenter.example.com"
deploy_settings["port"] = 443
deploy_settings["username"] = "admin"
deploy_settings["password"] = "password"
deploy_settings["mailfrom"] = 'root@example.com'
"""
Networks
"""
# define settings for each of our networks
net = dict()
internal_omaha = IPNetwork("172.9.9.0/24")
net[internal_omaha] = dict()
net[internal_omaha]["datacenter_name"] = 'Omaha'
net[internal_omaha]["cluster_name"] = 'Omaha Server Cluster'
net[internal_omaha]["datastore_name"] = 'Omaha datastore'
net[internal_omaha]["network_name"] = 'Omaha Internal 1'
net[internal_omaha]["gateway"] = '172.9.9.1'
net[internal_omaha]["subnet_mask"] = str(internal_omaha.netmask)
routable_omaha = IPNetwork("123.456.78.90/25")
net[routable_omaha] = dict()
net[routable_omaha]["datacenter_name"] = 'Omaha'
net[routable_omaha]["cluster_name"] = 'Omaha Server Cluster'
net[routable_omaha]["datastore_name"] = 'Omaha datastore'
net[routable_omaha]["network_name"] = 'Omaha Routable 1'
net[routable_omaha]["gateway"] = '123.456.78.91'
net[routable_omaha]["subnet_mask"] = str(routable_omaha.netmask)
'''
Storage networks
'''
internal_storage = IPNetwork("172.12.120.1/24")
net[internal_storage] = dict()
net[internal_storage]["network_name"] = '172.12.120.x storage net'
net[internal_storage]["subnet_mask"] = str(internal_storage.netmask)
@reubenur-rahman
Copy link

Hi ,

I am facing a problem while setting network for multiple NIC . Exactly when I am doing nicspec.device.backing.network = net_obj . I am facing exception. Any clues ????

                nic_nets = ['DataPortGroup', 'ManagementPortGroup','TrunkPortgroup'']

                devices = []
                nicspec = vim.vm.device.VirtualDeviceSpec()
                for device in template_vm.config.hardware.device:
                    if isinstance(device, vim.vm.device.VirtualEthernetCard):
                        for net_name in nic_nets:
                            nicspec.operation = vim.vm.device.VirtualDeviceSpec.Operation.edit
                            #nicspec.device = device
                            print net_name
                            net_obj = self.get_obj(content, [vim.Network], net_name)
                            nicspec.device.backing.network = net_obj
                            nicspec.device.backing.deviceName = net_name
                            devices.append(nicspec)

@snobear
Copy link
Author

snobear commented Apr 14, 2014

@rreubenur - do you have a NIC already present in your template? You may need an existing NIC in order to do Operation.edit on it.

With that said, I just updated the script to allow for multiple NICs. If you go with this newer version, you'll want to convert your template to a VM, delete all NICs, and then convert the VM back to a template.

If you still have issues, let me know the exact exception or error messages you're getting and I'll try to help.

@reubenur-rahman
Copy link

Ah ! I'm a dumb a%@ . I was not initializing vim.vm.device.VirtualEthernetCard.NetworkBackingInfo() .

Any how great job and Thank you very much for the updated code !

@AlexRaskosov
Copy link

@snobear - have you ever faced with situation when you need to attach 2 networks during VM creation: one without DHCP (like in your example) and one with DHCP (just create device without AdapterMapping)?
I will be really appreciate you if you can help.

@snobear
Copy link
Author

snobear commented May 29, 2014

@AlexRaskosov - No I have not tried to do DHCP yet with pyvmomi. However, I'm about to work on adding that and will let you know.

Seeing there has been a good bit of interest in this gist, I'm going to create a github repository to start building this script out a little more into a useful tool to abstract pyvmomi and make common vmware tasks easier. I'd love some contributors to help! Will keep you posted on that.

@snobear
Copy link
Author

snobear commented Jun 2, 2014

I moved this script to its own repo

https://github.com/snobear/ezmomi

Please lend a hand in making this an easy cli tool using pyvmomi for common vmware tasks.

@jon67400
Copy link

Hello,

I have a problem when I use this method

device = template_vm.config.hardware.device

Do you have an idea to help me?

raceback (most recent call last):
File "vsphere.py", line 460, in
opt_parser(opt)
File "vsphere.py", line 423, in opt_parser
vm_parser(opt)
File "vsphere.py", line 238, in vm_parser
vm_create(opt)
File "vsphere.py", line 157, in vm_create
device = template_vm.config.hardware.device
File "/Library/Python/2.7/site-packages/pyVmomi/VmomiSupport.py", line 563, in call
return self.f(args, *kwargs)
File "/Library/Python/2.7/site-packages/pyVmomi/VmomiSupport.py", line 386, in InvokeAccessor
return self.stub.InvokeAccessor(self, info)
File "/Library/Python/2.7/site-packages/pyVmomi/StubAdapterAccessorImpl.py", line 42, in InvokeAccessor
options=self.pcType.RetrieveOptions(maxObjects=1))
File "/Library/Python/2.7/site-packages/pyVmomi/VmomiSupport.py", line 569, in
self.f(
(self.args + (obj,) + args), _kwargs)
File "/Library/Python/2.7/site-packages/pyVmomi/VmomiSupport.py", line 378, in _InvokeMethod
return self._stub.InvokeMethod(self, info, args)
File "/Library/Python/2.7/site-packages/pyVmomi/SoapAdapter.py", line 1292, in InvokeMethod
raise exc
pyVmomi.SoapAdapter.ParserError: 'xml document: \x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03\xd5\x1b]s\xe3\xb8\xed\xfd~\x85&O\xed\x83\xad\x0f\xcb\x92\xedju\x93\xd8\xbb\xdd\xccn6\x998\xc9v\xda\xe9th\x89\xb6\xd9H\x94
RJ\xdc__P\xd4\xa7-'r.\xb9\x9b\xcedb\x11\x00\t\x10\x04\x01\x10\xa2\x9c
\x9f\xc3@\xc9p\xc2HD?\x9d\xe9C\xedL\xc1\xd4\x8b|B7\x9f\xce\xee\xef\xbe\x0c&g\xbf\xba\xbf8,B1\xa6\xd9\xec3\xcdp\x10\xc5X\x81n\x94\xcd$\xd8\xfbt\xb6\xe5<\x9e\xa9
\xf3\xb68Dl\x08X\x81\x1aF\xc9F\x15\x0fj9\xa6z\xf6K\xabk\xd6\xa7\xabdYw}f~\xd5\xed\xe9\xe9i\xf84\xca\xa9\rM\xd3\xd5\xbf]}
\xe6#5\xa8\xc9\xeb\xd4\x03B\x19G\xd4\xc3g\x8d\xc9^D\xfe\x0e\x9a\xb7\x98'\x04g\xf8&\x01)\x12N0\xfb\xfc|\x8bY\x1cQV\xe8\xe1\xd3Y\x9a\xd0YFBc|\xe6:\t\xe6\xd0\xccP\xe0:\xd1\xea\xdf\xd8\xe3,\x7fP\xf8.\xc6\x9f\xce\x1eH\xc2S\x14!oK(\xb0\xcb\xc2\x81aL\x1c\x15(\'\x06\x16K\xcc]\x87\xa2\x10\xbb^D\xd7d\xe3\xa8y\xc3\x81\x01\x15\x98\xcb\xack\x98yNyI\xd7\x11\xf0\xf7\xb6\x88n\xf0\x83\S\xd7\xd0\xf4\xf1@\xd3\x07\xda\xf4N\xd7f\xe3\xc9ll\x0f\x8d\xb152\xc7\x7fw\xd46\xa9\x13\xc2\x1a\xad\t\xf6]}jky'\xfdN\xd3f\xf9\x1fPWh)\x1e\xc7a\x1c \x8e\x07 \xb5_J\xb9I1\xe3
\xd2 \xf8!\x9a\x0b\xbc"\x88_\x7f\xfdq\xaf~'4}Vl\xe5O\x969X\x11\xfegGm\x93:\x85\x11\x82B\x9e\x07\xba\xe6\xa8e\xdbIS\xe2\xbb\xa6\xa1\xfb\xc82G\x03\xcdX\xeb\x03\xcf\xd3F\x83\x11\x9e\x8c\x07\xfa\xd80\xc7\xd8\x1cas\x05J\xccI\x9dr-\xefEk\xac\xe9\xbe?B\xd3\x81o\x1b\xe6\xb2FhkSk\xae\xd6\x96\xb1\xd2\xa6So:v\xd4V\x17\x87\xc6$\xbb\x83\xd9E\tJv\x0b\xc2\xd0*\x80Y\xf3$\xc50\xcdN\x9c\x13D\x1e\xe2 \xee%<\xab\xcdF\xa9\xa5\xa2{\xd5\x94\x9a\x02\n?\xd7\x91\xfd/\xcb\xfc\xab\x80\x14z\x11]Q\xc0qB\x818GH-\xa9]@Di\xc4s\x8e\x82\xa0\xd1X\x93\x00\x83\xf5e\xe1\r\xe2\xdb\x9c\xf6\x1f\xb1\xe7\r4md\x18\xda?\x95j\x05\xa5\x0c\x03[=\x80\x0c\xb3\x90?\xc3b\xd4#8\x8c\xa2\x98m#\xbe \t\x18w\x94\xec^\x1b\xd4Q\x0f\xbb8,e\xb0\xc9\xfcS\x06\xd9\xef\x01J\xdf\x9c\xd0\xbfE\xed\xa8\x85nx\x14\x05\xe5O\xb5gt\xd36\'#\xcb\xb4a\xc1\x9a\x08\x07\xadA\xfb7\xd1\x13N\xaei\xb1\xa2-\x90$\x00\xef\x90\x86\xb8\x89/ \xce\n\xaf\xa3D.\xdd\x12\x0c\xce_\xed\n\xaa\x0eD\x8bx\x9br?z\xa2\x1d\xd4%FN\xe1>\xde$\xc8\xc77Q@\xbc\x9d\x1b"\nN\xa2\x98D\x1b\xe5\xb0\x1d\xf5\xeeH\x88\x7f\x12\xbe\xfd\x1a1\xee\xaeQ\xc0\xec\x03\xb8\x13 \xb0G\xb1A\x82@\xb8\x18\xf00QJaR.\xec\xd2\xf2\x11\xd4\xbbO\xa5\x16\xaa]\x07h\x03?\xbe\xdc+\xe7\x9e\x87\x03\x9cH\x03-Xv\xa1\x1cL\x05\xec{\xb4\xd9@\xdc(\xe6\xdd\x869)\xc3w\x11.G)ZN\x92R!;\xf8\x9e4w\x89%\xfe\x00\x0e\xfe\x8e\x12\xb0\x86;\xf0\xa8n\x02\xac\x91 k\x02\x9d-\xe8\x17%\x82\x19\xa2;G\xad\x9b\x8d]P\xb8\x80R}\xfb\xf0\x8a\xf2{\xe4=\x1e\xd2\x15P\xa1\x9eG\xe1}>\xd3\xd6p\xfb\'+\x1c\x7f\x98\xde3\xb4\xc1.Jy\x14\x82\xca<\xd8\xa4{\xa8\x92\xf6\xf33\xf6$d\x9b\x9d\x03yEY#*!\xa5!\xaf\xd7\x17x\x8b2\x12%n\\\x00j\x89\x0fH \xe2yQ\xe2\xdfb\xd8r\xbb=\xf9\xbbP\xb0\xf7\n\x93\xc0k\x94\x06\xc5\x801\x00Jf\xb9\xf2Y\xb4\x06o\xd8\x02\x95^#o\xc0J\xf8\x95W\x90\xe8\x043\xcc\x1b\x9d\xebv\x9bW\x8bC\x17\xa6$_\x1e\xf0\xeb@\x94\xc4\xb7{\xdc\x0f\xc0\x0e\x93[\xfb\xdc\xcbM\x1c2\x0f\xef1\x8e\x08\x05\xda6fO(\xa1\x1a\xc1\xfd\t%0\x08M\xc3\xf9\xcd\xbd\xabC,\x92O9\x04\xfc\x01\xbb\xc1\xc9R\x98\x13/\x91m\xa0\x13\xe2\x10|\xdf\xd5\x05$\x05&D\xcb\xaaY\x1a\xca\xe5\xfc\xab}u#\x94F+w\xd0\x85*\xe9\x97W\xf3n\xea\x06\x02\x94\x93\x11\x0f\x1f\xa6.\x97\x8b\xcf\x90\xb6\xf0$\n\xcfC\xda\xf2\x88w \x17\xb8\x14\xf1P\xf4\x92\xdb4@+\x1c\xb8@\xafh\xc2\xcd\x88\x06\x18B\x18B\x00.\xa1eS(\xae\xee\xb8J\xd9\x8f4\IOU7J\xa2Se\xd3_\x94M\xef\x94M\x7f]6\xbd%[!\xdaH\xd3\x8cZ\xceW\x05\xbeY\x1a\x07\x02\x8f^P&\xd0+^\xd5\xa1C\xaf\x87\x04\xa7\xa9\xb8\x10\xd8\x122\xb4\x85w\xed&\xec\xf5\x99\xcd/\x0ff\xa6\xbf4\xb3\xf9\xe5+3; x\xd3\xcc\xc6\x1d3\xd3\xc1~;\xa0]@s;I\x0b\xcb\xcb\xeb\x03-\x98/h\x01\xe8_\xd6\xc2!\xc1\x9b\xb409m\x1a\xdf\xf0n\x15\x81#+f\xbd0\x83\x92T9\x10\xbd\xc4\x1c\x13\xb9\x9e\xd6\xb7r\x17\xb4AN\n\x11\xbe\x9eU\xa3\xd5\xc3\x1c\x85\xbb\x86\x04\x91\xe3\x8by\xd8/\xd9c\xd1A\x91\xa8Csl\xe3\xff\xa2,\n\xba#\xeb\x81\xbcGA\xfd\x8a\xf2\xff\x85$.\xce\x85r\x98\xe2\x18\xd1l@\xe2$\xd2\x82\x05\xe6\x90\x1c7\xb2\xa9\x06\xd0\xd9B&\xd8f\x91g\x1e~\x8e\x86\xc4\xe8\x10\r\xe6"\xd9\x9f\xb8"\xfa\x89+R\x1c\x81\x1f\x88\x8f\xa3ym[\xe3\x17\xd6$\xa7U\xbcN\xeb\xaaq\xfd\xecK?\xc9\xbe21\xfa-\n\x97\xe4\xbf0\xda\xb7\x0bw\xa2O\r\x116\xf7\xc0"\xa4C\x06)\xb2&V\x04\xf3\xaa\xd9k\xbdd\xa6<Z,\xd3\x18\x8e\xaa\x15\xd5>X\x8c5\x82\xf4\x8c\xfa8\x01\xf9\x1a\xc9d\x1b\xd1\x7f\x19\xae\xe6\x97\xad\xbdQ\xf8\xc4c+\x01\xe4\xc7v\x86\x1cF\x89\xa8\xc2\xb7X)2\x0b%\x94|\x14\xe1\xc6\xc1\x1f\x01\x0eq%N"\xa1B\xa609/\x05\x8eG\x9d\xbd\xbc(\x0ca=\xe4\xf1\\!\xe2\xe8\xb2F\xc7w\x1b\x0b".\x9e\x0e\xa7+\x85\xbb\xf1\xc8E\xca\x96\x05\x15\xcc8\xf6\x88h\x15\xcb=\x82\xa5mC\x80QA|\xa2\x1d\xe9v\xdb\x90\x88\xef\x0e\xc0.H^&\x08\xa2\xa7{\n\xf9\x16O\x88\xc7\xb1?oN\xb2\\\xf9W\xa8^X\xe0\x1b\x94\xa02\x0c\xcd\x97\x9d\xd1\xf8\x85@\x04=^\x8eD\x0fW"\xadUb\xe0R\xae\x96\xe8\xf4AK\xa2[\xda\xbb\xad\xc9\xa8\xbd$\xaf\x84\xcavn\x00\xe7\xa8s\x1f\xf6W\x18ee\xa1\xa0\x05r\x18$\xfc\xd8\x87\xa9\xb84*\x0e\x9d h\x05t\x98\xc7\xc8\x9c\x07\xc9}-\x01\x98H\x07\xf4\xf5\xad;\xf7\x93(\xac\x93F\xe3\xe8b\xce\x17\xea\xe2a\xa1\xf8\t\xc9pG\xbe+D\xe7\xb8\xda\xce\'\x06\xb0\\\n9\xc4\rb\x8co\x93(\xddl\xdf1\x84\xe1g/H\x19\x88^9\xc3\n\xd0\x8eU\x14\xc8\x85\x9b\xcc\xcfk\t\x9fKH\xe3\xe8\xde\x86\xca\r\x98\x17c\x8a\xbdQV~\x0e\xe0\xe5\xe8\xf5X5@0\xe3\xb0\xb2)\x15\xe5f?g#\xda\x15\x8d\x14\xa9m\x8e\xf9\xa1\xe4\xfd\xb2\x1b\x881\x8f\xf5Q\xec\xf8\xae\xfe*B\xa7(MtX\x81n)\xb6m+\x06\xfc~\xbb8\xd9\n\x84\x04_\x02\xc4\x1fpb\xb4\xd7^\xd4\xeb\xdeZ\xc2\xf4\x1fe\xbdO\x1a\x8b\x8f8b\x1c\xce\xc6EI~Q\xb6\xcf\xdc\n5\xd0\xf5)\x88\\6+\x89\xaf\xf3\x8a\xfe\xa5\xef\x9a\x93\x81P\xd1@\xabl\xa7B\xe5\xb5\x9c+\xc8\x8d\xdcX\xd4\r\x19\xc7\xe2\x84_\x01\x1d\x88\xe3\xa4.\xb7\xe5\r\xe7)!\x1c\xdfI\x9b/Q-\x98\xc3!\x80\xdd\x888\'*\x91U9z\x1f*\xab\xe5\x90Xksc\nj\xf2\xd0z\xb0\x9e\xae\xf5\xc1\xc40\xec\xc1\xd4_\xfb\xc86\x8d\xb5\x81\x8d\xb2Z.\xac\x07\x04\x04\xb9\xad\xd5\xc8\x1cO\xec\xb1\xa7\xdb\xfe\xd4\xc2\xba\xe5Y+M7<\xdf\x98"\xcb\x98N\xa5\xa5IZ\x98\xe3\x06\x0c\xfb\xa0Z\xd5\x04\x1e\xcd\x00e\xc4\xe8m\xb6\x1e\x8a\x91G\xf8.\xcf\x8ct\x0b\xac\x0b\x8c\x0b\xfa7\xc1\r\xa2\x8b\x1d\xc7\x904\xd9\xba=\x9dXS}b6I%Rz\xd7\xfaW\nT\x02\x03\x9c\x81A\xd3(\tE\xedT\xb6j\xac\xb0\x07\xb4\xc1\x97\xd7\xe7AY\xe7\x87.$\x84U\x14\x11Y>\xfd\x16\x06\xa2p\x92drM\xd6\xb0\xca\xa6p\n\x1d\xdc\x85i\xed\x1b\xa64\xb8\xda&\xdd\xfb\x82(\x8ew\xc5\xee\x9f\xbc\xb4\xfb%\xe5+a\xe0\xe4\x9d/G\x95\x9d\xdf\xfd\xf8\xf2\xff\xea\xdf\xcd\xf7=\xbd>\x84\xcf\x14\xf3Q]@8\xbe\xc8?0\x7f\x8a\x92G\x05\xf9(\x86,\xb9c\x9d\x17\x0f\xcb'\xc2\xbd\xedL\x19\x9b\x8a\x06\x96\xe0+cM\xb1\x90\xe2y\x8ai\x03d0\x1a\xc1AJ\xd1\xe1OS\xec\xb1\xb2\xf2\x95\xc9T\xf1W'\x9b\xc6gH\xe5\x13\x10\x1c\xef @\x80\xfeV)\xa8\xb4:\xf9&\xbcm_\xf2h\xc3r\xe9\xe4K\xc0\x93\x05\xac\xfb\xe6\xa3m\xc0\t\xc7B\xfbV5\x07\xb6.\xca\xd3\rdN\x9a\x87\xe5\xf1T\xa2rh\xb1\xbe\xb0U\xe7Q\xf4H\xb0\xab\x8f,c26M\xabZ\xfb\x1a'\xfb\xf5\xb5Xi\x88\x7f\xa8\xc1\xfe\xd6\x84|\xfa\x87\xa4\xbd3\x12\xf2}p\x9e,/\xbdCFI6T\xcc\xa2\tu\xe0\x.\xdb\xae\xa6\xcd\xc6\xf0g\xcd\xa6\xfeL\x1b\xcd, m\x9d\'\xf4\x88\xaf\xe9wD\xcb\xe8&Uz\x00nT\xc3\xea\x92\xbd\x17\xa7M\x7f\xfd\x92\x87\xc7\xcf1\xa2\xbe\x18\xeb\xb6\x01\xae2\xd6.\xe4\xbbF\x1fuOV\xf9\x92\xe0\x8f\x94^\xbc\xac\xe8/\xfe\xa1\xbc"\x19\xa4\xden\x89)#\x9cd\x90\x06\x1c\x1b\xa4\x8bR\x8e\xf75?\x9b\xede;](\xb1\xd4\x9d\xc4\x07\xf0\x82R\x9e\xf7:\x89\xdb(\xd0-O\x90\xbc\xe9!\xfd\xb7\xb82\xe3\x0f\x81vx(x\xe1\xd73\x14\xa4\xcd8\xf0\xcc\xfc\x99\xf0\x9ftsV\xcd>\xa7q\xc5\xf24\xc6?\x96\xbf\xcc\x1d\xe6w\x13\x86>f\x8f<\x8a\x87\xa2\x04z~\xec\xc1\xec\xcb\xf9\xf7\xe5\xe7\xbe\xbch\x96\xa0\xb0\xc7\xa0\x87\xa9~\xd1\xb3\x1f\x1b\xf0:\x17\t\xf17X\x1b\xc6\xf2mU\x0f\x9ew\xb7\xf7\xbd\xe7\xc1\xb2\r\xfa\xa0\xa1+\xd9\xcd\x8fg\x90U\xee\xbc\x07\x0f\xe8\x87o#\xf1\x968\xe1o\xe0\xb5Ni\x1e\rY\x0fV\x93\x93\xc7\x1f\x7f\xb4\xb2\xc6\xbf\xa3\xb2\xc6\x1f\xac,\xeb\xa3\x95e\xfd\x8e\xca\xb2>XY\xf6G+\xcb\xfe\x1d\x95e\x7f\x8c\xb2\xb61\xe6\xa7\xb8Z\x99a\xf5\x1b\xbbP\xce\xd7\x9fCq\x1b1\xf5 \xc3\rcH\x00V$\xe8\x17\r\xc5\x1b,\x91\x1e\xf6\xf4\xecy\xe8\x15\xd5Vm\xa6\r\x8bZe\x9c\xc2\t%\xee\xc1+\x12\xd7iz\xce+\xf4\xc8pM\xc4\xa5\xbf\xa1|y\xf3\xce\x8a\xc3\xc5\xd9\n\x16\xa6\x99\x84\xf7\xe0"\xdf\x9d\x1ciO\xe5b\xbf%$\x9e\xc8\xc4\xd0\xdf\x12JNer\xba\xba\xac\xd3\x99\x8c\xde\xe2\xbaNeb\xf6e\x92\xe4\x17\xbf\x86\xc5k9\xb1\xbf^\x1d\xbc\xbcI\xd4s\x1f\xc2\x0e<\xdd\xa6\xc4K\xa0S\x180\xc4~\xfe\xbc\xf4\x18z\xac)\xdaX\xfc\x892\xc3ZA\x13\x05\xfb\x8a\xd6\x9f]\xb4\xae.\xa2\xbds$\x11\x9e\xe4tU\x8dz\x1bm\x16F"b\x0c\xeb[m_.\xc4\xfb\xec>\x11d4\x99XZ\xef8\x92\x85\xe2T=\x94'\x92\xfc\x1d.EAq]\xbc\xd7f\xafo\xf7\xbe\x81a\x82\xff\x93\x92\x04\xfb\xfd\x19NG\xe3\xde\x1b&$\x9b\x04N4C\x11\x8e\xbeG\x9b%G\xbc\x8f\x06iD{\xef\x99\x92\x85\xfc\xcd\xaf\xa9\xf7\xe0p\xcc\x84\xabW$\xf7IP|\x18P\xbf\x9f)\xbf\nH\x01\xa7f\xe1\x9a\xa9Y\x14\xa4!f_^\x8d\x91\xaf\xafW\x03O\x9bh62\xc0\xda\x05Q\xe3\x95K>\x1e{B\xf1M\x80<\x1c\x8a\xbb\x84\x84B\xac"\xe2\xb6d\x0b\xec\xac \xd1\xb9\x8e\xf3|E6\x16\x18\xbcN\xfe\x1a\xb6j8X\x18\xca\xc5\xe5\xf5r\x89y\x1a\xd7\x17"Z\xd0\xbc\xb7\xf8\xe0c\xff\x1e\xeb\x01\xbc\xa6\x94\xe3\x8b\x1a\x8b\xd6\xa0+\xb8\xaa-\xd9\xb2s\xc6p\xc2\xd9\xde\xe0\xfb\xe0\xe2\x13\x8e\xbbD\x96\x00\xf7\x8b\x03\x9dHgM\x92\xdcL\xdd\x15\x89\x98x\xddU4\x9d\x10=_=\xb2yUhd\xae\xa9\x89\xda\xd6>T~\x91 \xaa\xe6\xe2N\xf2\x1e\xd3N\Q\x1ciTs\xe4m\xe6\xbb\xe8\n=\xb7\xab$Gh\x1cB\t'(\xb8\x86\xdd\xb4\xc5\xc8\xaf\x00W\xfb\xbd\xdd\x98\xe8\x96=\x1dY\xe2k\x8d#4e\xef%\xd8G\x13n\x98\x869\xd5G"a9BQ!jI(\x16\x19\xe1\xd7\x87=M\xec\x83\x9d\xec\xe6j\xbe\xbf\xa0\r\x90\x93\xe7\x8a)<~-\xea\x81\xc5E|Y\xe0L[\xb7\xf2)\xce\x84[N\xf7\xae\xea\x1f\x19a)\x0b\xb2r\xf3\xbfBt\x9c@\xca\x91}\t\x10\xdb\xce\x11\x10\xdd\xb6\x0b|G0\xb9?\x10\xe5\xea\xf2\x9b%\xb5\xfa\xdaIm|\x02\xa5\xbe\xf4\xf9\x94\xfb\x8b\xa3\xee}m\xa5\xee\x7fj\xe6\xfe\x0f\x06\xf0\xa4$\xa46\x00\x00 parse error at: line:1, col:0'

Thanks.

Regards

@nitrohuffer2001
Copy link

This is a slick script. any chance you could add functionality that would allow you to clone more than 1 VM at a time? e.g. So if you needed 10 vm's test-vm1 through test-vm10 starting with IP: 10.0.0.10 and ending at 10.0.0.20

command would look something like:

ezmomi clone --template my_template --hostname test-vm -num10 --cpus 2 --mem 4 --ip's 10.0.0.10, 10.0.0.19

Thanks.

@notsure44
Copy link

I'm looking for a way to deploy from template without setting the IP address, the template is set to DHCP from an adapter it already has.

@iahmad-khan
Copy link

@notsure44 hi , i want to deploy a vm from template too, with dhcp , can you share your thoughts. thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment