Last active
September 17, 2015 08:47
-
-
Save rgerganov/caeed4a28d8d621b7086 to your computer and use it in GitHub Desktop.
Import VM into vSphere
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import argparse | |
import getpass | |
import os | |
import logging.config | |
import struct | |
import sys | |
import urlparse | |
logging.config.fileConfig('logging.conf') | |
logging.captureWarnings(True) | |
from oslo_vmware import api | |
from oslo_vmware import rw_handles | |
from oslo_vmware import vim_util | |
def err(msg): | |
sys.stderr.write(msg + '\n') | |
sys.exit(1) | |
def parse(url): | |
p = urlparse.urlparse(url) | |
if p.scheme != 'vi': | |
err('Invalid URL: only vi scheme is supported') | |
if not p.username: | |
err('Invalid URL: missing username') | |
if not p.hostname: | |
err('Invalid URL: missing hostname') | |
if not p.query: | |
err('Invalid URL: missing query') | |
if p.query.startswith('moref=vim.ClusterComputeResource'): | |
moref = vim_util.get_moref(p.query[33:], 'ClusterComputeResource') | |
elif p.query.startswith('moref=vim.ComputeResource'): | |
moref = vim_util.get_moref(p.query[26:], 'ComputeResource') | |
else: | |
err('Only references to compute resources are supported') | |
port = p.port if p.port else 443 | |
pwd = p.password | |
if not pwd: | |
pwd = getpass.getpass() | |
return p.username, pwd, p.hostname, port, moref | |
def get_vm_config_spec(session, name, image_size, ds_name, num_cpu, mem_mb): | |
cf = session.vim.client.factory | |
controller_device = cf.create('ns0:VirtualLsiLogicController') | |
controller_device.key = -100 | |
controller_device.busNumber = 0 | |
controller_device.sharedBus = 'noSharing' | |
controller_spec = cf.create('ns0:VirtualDeviceConfigSpec') | |
controller_spec.operation = 'add' | |
controller_spec.device = controller_device | |
disk_device = cf.create('ns0:VirtualDisk') | |
disk_device.capacityInKB = int(image_size) / 1024 | |
disk_device.key = -101 | |
disk_device.unitNumber = 0 | |
disk_device.controllerKey = -100 | |
disk_device_bkng = cf.create('ns0:VirtualDiskFlatVer2BackingInfo') | |
disk_device_bkng.thinProvisioned = True | |
disk_device_bkng.fileName = '[%s]' % ds_name | |
disk_device_bkng.diskMode = 'persistent' | |
disk_device.backing = disk_device_bkng | |
disk_spec = cf.create('ns0:VirtualDeviceConfigSpec') | |
disk_spec.operation = 'add' | |
disk_spec.fileOperation = 'create' | |
disk_spec.device = disk_device | |
vm_file_info = cf.create('ns0:VirtualMachineFileInfo') | |
vm_file_info.vmPathName = '[%s]' % ds_name | |
create_spec = cf.create('ns0:VirtualMachineConfigSpec') | |
create_spec.name = name | |
create_spec.guestId = 'otherGuest' | |
create_spec.numCPUs = num_cpu | |
create_spec.memoryMB = mem_mb | |
create_spec.deviceChange = [controller_spec, disk_spec] | |
create_spec.files = vm_file_info | |
return create_spec | |
def get_image_size(image): | |
with open(image, 'rb') as f: | |
data = f.read(512) | |
header = struct.unpack('<IIIQQQQIQQQ?ccccH433s', data) | |
if header[0] != 0x564d444b: | |
err('This image is not VMDK') | |
if not (header[2] & (1 << 16)): | |
err('This image is not streamOptimized') | |
return header[3] * 512 | |
def main(): | |
parser = argparse.ArgumentParser() | |
parser.add_argument("-ds", help="Datastore name", required=True) | |
parser.add_argument("-name", help="VM name", required=True) | |
parser.add_argument("-mem", help="Memory (in MB)", type=int, default=512) | |
parser.add_argument("-cpu", help="Number of vCPUs", type=int, default=1) | |
parser.add_argument("-image", help="VMDK image", required=True) | |
parser.add_argument("url", help="URL to ComputeCluster (e.g. " | |
"'vi://user:pass@vchost?moref=vim.ClusterComputeResource:domain-c7')") | |
args = parser.parse_args() | |
user, pwd, host, port, moref = parse(args.url) | |
image_size = get_image_size(args.image) | |
session = api.VMwareAPISession(host, user, pwd, 10, 0.5, insecure=True) | |
rp_ref = vim_util.get_object_property(session.vim, moref, 'resourcePool') | |
folder_ref = vim_util.get_object_property(session.vim, moref, 'parent') | |
dc_ref = vim_util.get_object_property(session.vim, folder_ref, 'parent') | |
datastores = vim_util.get_object_property(session.vim, dc_ref, 'datastore').ManagedObjectReference | |
ds_ref = None | |
for ref in datastores: | |
ds_name = vim_util.get_object_property(session.vim, ref, 'name') | |
if ds_name == args.ds: | |
ds_ref = ref | |
break | |
if not ds_ref: | |
err("Datastore '{0}' is not accessible from this compute resource".format(args.ds)) | |
vm_folder_ref = vim_util.get_object_property(session.vim, dc_ref, 'vmFolder') | |
file_size = os.path.getsize(args.image) | |
vm_config_spec = get_vm_config_spec(session, args.name, image_size, args.ds, args.cpu, args.mem) | |
client_factory = session.vim.client.factory | |
vm_import_spec = client_factory.create('ns0:VirtualMachineImportSpec') | |
vm_import_spec.configSpec = vm_config_spec | |
write_handle = rw_handles.VmdkWriteHandle(session, | |
session._host, | |
session._port, | |
rp_ref, | |
vm_folder_ref, | |
vm_import_spec, | |
file_size, | |
http_method='POST') | |
f = open(args.image, 'rb') | |
last_progress = 0 | |
bytes_written = 0 | |
try: | |
while True: | |
data = f.read(64 * 1024) | |
if not data: | |
break | |
write_handle.write(data) | |
write_handle.update_progress() | |
bytes_written += len(data) | |
progress = (bytes_written * 100 // file_size) | |
if progress != last_progress: | |
sys.stdout.write('\rProgress: {0}% '.format(progress)) | |
sys.stdout.flush() | |
last_progress = progress | |
finally: | |
f.close() | |
write_handle.close() | |
sys.stdout.write('\rDone \n') | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment