diff options
author | Ethan Lynn <ethanlynnl@vmware.com> | 2019-03-25 16:31:59 +0800 |
---|---|---|
committer | Ethan Lynn <ethanlynnl@vmware.com> | 2019-04-04 18:54:53 +0800 |
commit | 7a02c59adf4fdf4fe79ad34c248679850311a784 (patch) | |
tree | 90f31ee6c261629a2c8ff4dafac6cd579ecf0093 /vio/vio/vsphere/ovf.py | |
parent | 04ad05f0302fa1e059b3c3ab3470759dc333e33e (diff) |
Add more functions to vsphere plugin
Add esxi ability to exec shell command.
Add ovf upload function.
Add vmdk validation function.
Change-Id: I41e658e8d35f9ec2ae8c9238954b705997fa1b3b
Issue-ID: MULTICLOUD-488
Signed-off-by: Ethan Lynn <ethanlynnl@vmware.com>
Diffstat (limited to 'vio/vio/vsphere/ovf.py')
-rw-r--r-- | vio/vio/vsphere/ovf.py | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/vio/vio/vsphere/ovf.py b/vio/vio/vsphere/ovf.py new file mode 100644 index 0000000..d37db24 --- /dev/null +++ b/vio/vio/vsphere/ovf.py @@ -0,0 +1,173 @@ +# Copyright (c) 2019 VMware, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +from os import path +# from sys import exit +from threading import Thread +from time import sleep +# from argparse import ArgumentParser +# from getpass import getpass +import requests + +# from pyVim import connect +from pyVmomi import vim +from pyVmomi.VmomiSupport import long + +from vio.vsphere import utils + + +def get_ovf_descriptor(ovf_path): + """ + Read in the OVF descriptor. + """ + if path.exists(ovf_path): + with open(ovf_path, 'r') as f: + try: + ovfd = f.read() + f.close() + return ovfd + except Exception as ex: + raise Exception("Could not read file %s: %s" % ( + ovf_path, str(ex))) + + +def get_obj_in_list(obj_name, obj_list): + """ + Gets an object out of a list (obj_list) whos name matches obj_name. + """ + for o in obj_list: + if o.name == obj_name: + return o + raise Exception("Unable to find object by the name of %s in list:%s" % + (o.name, map(lambda o: o.name, obj_list))) + + +def get_objects(si, datacenter_name=None, datastore_name=None, + cluster_name=None): + """ + Return a dict containing the necessary objects for deployment. + """ + # Get datacenter object. + datacenter_list = si.content.rootFolder.childEntity + if datacenter_name: + datacenter_obj = get_obj_in_list(datacenter_name, datacenter_list) + else: + datacenter_obj = datacenter_list[0] + + # Get datastore object. + datastore_list = datacenter_obj.datastoreFolder.childEntity + if datastore_name: + datastore_obj = get_obj_in_list(datastore_name, datastore_list) + elif len(datastore_list) > 0: + datastore_obj = datastore_list[0] + else: + print("No datastores found in DC (%s)." % datacenter_obj.name) + + # Get cluster object. + cluster_list = datacenter_obj.hostFolder.childEntity + if cluster_name: + cluster_obj = get_obj_in_list(cluster_name, cluster_list) + elif len(cluster_list) > 0: + cluster_obj = cluster_list[0] + else: + print("No clusters found in DC (%s)." % datacenter_obj.name) + + # Generate resource pool. + resource_pool_obj = cluster_obj.resourcePool + + return {"datacenter": datacenter_obj, + "datastore": datastore_obj, + "resource pool": resource_pool_obj} + + +def keep_lease_alive(lease): + """ + Keeps the lease alive while POSTing the VMDK. + """ + while(True): + sleep(5) + try: + # Choosing arbitrary percentage to keep the lease alive. + lease.HttpNfcLeaseProgress(50) + if (lease.state == vim.HttpNfcLease.State.done): + return + # If the lease is released, we get an exception. + # Returning to kill the thread. + except Exception: + return + + +def deploy_ovf(si, vmdk_path, ovf_path, datacenter, cluster, datastore): + default_ovf = False + if ovf_path is None: + default_ovf = True + cpath = path.dirname(path.realpath(__file__)) + ovf_path = cpath + "/templates/template.ovf" + # import ipdb; ipdb.set_trace() + vmdk_meta = utils.vmdk_metadata(vmdk_path) + # vmdk_size = path.getsize(vmdk_path) + ovfd = get_ovf_descriptor(ovf_path) + objs = get_objects(si, datacenter, datastore, cluster) + manager = si.content.ovfManager + spec_params = vim.OvfManager.CreateImportSpecParams() + print("Creating import ovf spec") + import_spec = manager.CreateImportSpec(ovfd, + objs["resource pool"], + objs["datastore"], + spec_params) + if default_ovf: + import_spec.importSpec.configSpec.deviceChange[ + 1].device.capacityInKB = long(vmdk_meta['size']) + lease = objs["resource pool"].ImportVApp(import_spec.importSpec, + objs["datacenter"].vmFolder) + while(True): + if (lease.state == vim.HttpNfcLease.State.ready): + # Assuming single VMDK. + # url = lease.info.deviceUrl[0].url.replace('*', host) + url = lease.info.deviceUrl[0].url + # Spawn a dawmon thread to keep the lease active while POSTing + # VMDK. + keepalive_thread = Thread(target=keep_lease_alive, args=(lease,)) + keepalive_thread.start() + print("Uploading %s to %s" % (vmdk_path, url)) + # POST the VMDK to the host via curl. Requests library would work + # too. + # curl_cmd = ( + # "curl -Ss -X POST --insecure -T %s -H 'Content-Type: \ + # application/x-vnd.vmware-streamVmdk' %s" % + # (vmdk_path, url)) + # system(curl_cmd) + headers = {'Content-Type': 'application/x-vnd.vmware-streamVmdk'} + client_cookie = si._stub.cookie + cookie_name = client_cookie.split("=", 1)[0] + cookie_value = client_cookie.split("=", 1)[1].split(";", 1)[0] + cookie_path = client_cookie.split("=", 1)[1].split( + ";", 1)[1].split(";", 1)[0].lstrip() + cookie_text = " " + cookie_value + "; $" + cookie_path + # Make a cookie + cookie = dict() + cookie[cookie_name] = cookie_text + with open(vmdk_path, "rb") as f: + resp = requests.post(url, + # params=params, + data=f, + # files={"file": f}, + headers=headers, + cookies=cookie, + verify=False) + print("Upload results %s: %s" % ( + resp.status_code, resp.content)) + lease.HttpNfcLeaseComplete() + keepalive_thread.join() + return + elif (lease.state == vim.HttpNfcLease.State.error): + raise Exception("Lease error: " + lease.error.msg) |