Home > vSphere API > How to Import and Export OVF Packages

How to Import and Export OVF Packages

This article is based on a similar one at vSphere Java API home page. At that time, one of VMware community members sent me an email for samples of using OvfManager APIs. Then I went to office on a Saturday writing two samples, which have been validated by several folks as “working” samples.

The purpose of the samples are to illustrate the vSphere APIs. Let’s take a look at them one by one.

Time to learn how to "Google" and manage your VMware and clouds in a fast and secure

HTML5 App

First, ExportOvfToLocal.java. This sample shows how to download either a VM or vApp to your local machine. The typical flow is:

  • Find the VM or vApp
  • Call their exportVm() or exportVApp() methods and get HttpNfcLease
  • Set lease time out
  • Wait for HttpNfcLease until it’s ready
  • From the HttpNfcLease.info property, find the all URLs from which you download the vmdk files
  • Call OvfManager.createDescriptor() API to create the content of ovf and save it to a file along with downloaded vmdk files.
  • Release the lease by calling httpNfcLeaseComplete() method
/*================================================================================
Copyright (c) 2008 VMware, Inc. All Rights Reserved.
<pre>Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

 * Neither the name of VMware, Inc. nor the names of its contributors may be used
to endorse or promote products derived from this software without specific prior
written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
================================================================================*/
package com.vmware.vim25.mo.samples.ovf;

import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;

import com.vmware.vim25.HttpNfcLeaseDeviceUrl;
import com.vmware.vim25.HttpNfcLeaseInfo;
import com.vmware.vim25.HttpNfcLeaseState;
import com.vmware.vim25.OvfCreateDescriptorParams;
import com.vmware.vim25.OvfCreateDescriptorResult;
import com.vmware.vim25.OvfFile;
import com.vmware.vim25.mo.HostSystem;
import com.vmware.vim25.mo.HttpNfcLease;
import com.vmware.vim25.mo.InventoryNavigator;
import com.vmware.vim25.mo.ManagedEntity;
import com.vmware.vim25.mo.ServiceInstance;
import com.vmware.vim25.mo.VirtualApp;
import com.vmware.vim25.mo.VirtualMachine;

/**
 * Exports VMDK(s) and OVF Descriptor for a VM or a vApp.
 * http://vijava.sf.net
 * @author Steve Jin (sjin at vmware.com)
 */

public class ExportOvfToLocal
{
   public static LeaseProgressUpdater leaseProgUpdater;

	 public static void main(String[] args) throws Exception
	  {
	    if (args.length != 7)
	    {
	      System.out.println("java ExportOvfToLocal <SdkUrl> <username> <password> <VappOrVmName> <hostip> <VirtualMachine|VirtualApp> <localDir>");
	      System.out.println("java ExportOvfToLocal https://10.20.152.74/sdk root password NewVM1 10.20.152.74 VirtualMachine C:\\Temp\\ovf\\");
	      return;
	    }

	    ServiceInstance si = new ServiceInstance(new URL(args[0]), args[1], args[2], true);

	    String vAppOrVmName = args[3];
	    String hostip = args[4];
	    String entityType = args[5];
	    String targetDir = args[6];

	    HostSystem host = (HostSystem) si.getSearchIndex().findByIp(null, hostip, false);

	    System.out.println("Host Name : " + host.getName());
	    System.out.println("Network : " + host.getNetworks()[0].getName());
	    System.out.println("Datastore : " + host.getDatastores()[0].getName());

	    InventoryNavigator iv = new InventoryNavigator(si.getRootFolder());

	    HttpNfcLease hnLease = null;

	    ManagedEntity me = null;
	    if (entityType.equals("VirtualApp"))
	    {
	      me = iv.searchManagedEntity("VirtualApp", vAppOrVmName);
	      hnLease = ((VirtualApp)me).exportVApp();
	    }
	    else
	    {
	      me = iv.searchManagedEntity("VirtualMachine", vAppOrVmName);
	      hnLease = ((VirtualMachine)me).exportVm();
	    }

	    // Wait until the HttpNfcLeaseState is ready
	    HttpNfcLeaseState hls;
	    for(;;)
	    {
	      hls = hnLease.getState();
	      if(hls == HttpNfcLeaseState.ready)
	      {
	        break;
	      }
	      if(hls == HttpNfcLeaseState.error)
	      {
	        si.getServerConnection().logout();
	        return;
	      }
	    }

	    System.out.println("HttpNfcLeaseState: ready ");
	    HttpNfcLeaseInfo httpNfcLeaseInfo = hnLease.getInfo();
	    httpNfcLeaseInfo.setLeaseTimeout(300*1000*1000);
	    printHttpNfcLeaseInfo(httpNfcLeaseInfo);

	    //Note: the diskCapacityInByte could be many time bigger than
	    //the total size of VMDK files downloaded.
	    //As a result, the progress calculated could be much less than reality.
	    long diskCapacityInByte = (httpNfcLeaseInfo.getTotalDiskCapacityInKB()) * 1024;

	    leaseProgUpdater = new LeaseProgressUpdater(hnLease, 5000);
	    leaseProgUpdater.start();

	    long alredyWrittenBytes = 0;
	    HttpNfcLeaseDeviceUrl[] deviceUrls = httpNfcLeaseInfo.getDeviceUrl();
	    if (deviceUrls != null)
	    {
	      OvfFile[] ovfFiles = new OvfFile[deviceUrls.length];
	      System.out.println("Downloading Files:");
	      for (int i = 0; i < deviceUrls.length; i++)
	      {
	        String deviceId = deviceUrls[i].getKey();
	        String deviceUrlStr = deviceUrls[i].getUrl();
	        String diskFileName = deviceUrlStr.substring(deviceUrlStr.lastIndexOf("/") + 1);
	        String diskUrlStr = deviceUrlStr.replace("*", hostip);
	        String diskLocalPath = targetDir + diskFileName;
	        System.out.println("File Name: " + diskFileName);
	        System.out.println("VMDK URL: " + diskUrlStr);
	        String cookie = si.getServerConnection().getVimService().getWsc().getCookie();
	        long lengthOfDiskFile = writeVMDKFile(diskLocalPath, diskUrlStr, cookie, alredyWrittenBytes, diskCapacityInByte);
	        alredyWrittenBytes += lengthOfDiskFile;
	        OvfFile ovfFile = new OvfFile();
	        ovfFile.setPath(diskFileName);
	        ovfFile.setDeviceId(deviceId);
	        ovfFile.setSize(lengthOfDiskFile);
	        ovfFiles[i] = ovfFile;
	      }

	      OvfCreateDescriptorParams ovfDescParams = new OvfCreateDescriptorParams();
	      ovfDescParams.setOvfFiles(ovfFiles);
	      OvfCreateDescriptorResult ovfCreateDescriptorResult =
	        si.getOvfManager().createDescriptor(me, ovfDescParams);

	      String ovfPath = targetDir + vAppOrVmName + ".ovf";
	      FileWriter out = new FileWriter(ovfPath);
	      out.write(ovfCreateDescriptorResult.getOvfDescriptor());
	      out.close();
	      System.out.println("OVF Desriptor Written to file: " + ovfPath);
	    }

	    System.out.println("Completed Downloading the files");
	    leaseProgUpdater.interrupt();
	    hnLease.httpNfcLeaseProgress(100);
	    hnLease.httpNfcLeaseComplete();

	    si.getServerConnection().logout();
	  }

	private static void printHttpNfcLeaseInfo(HttpNfcLeaseInfo info)
	{
		System.out.println("########################  HttpNfcLeaseInfo  ###########################");
		System.out.println("Lease Timeout: " + info.getLeaseTimeout());
		System.out.println("Total Disk capacity: "	+ info.getTotalDiskCapacityInKB());
		HttpNfcLeaseDeviceUrl[] deviceUrlArr = info.getDeviceUrl();
		if (deviceUrlArr != null)
		{
			int deviceUrlCount = 1;
			for (HttpNfcLeaseDeviceUrl durl : deviceUrlArr)
			{
				System.out.println("HttpNfcLeaseDeviceUrl : "
						+ deviceUrlCount++);
				System.out.println("	Device URL Import Key: "
						+ durl.getImportKey());
				System.out.println("	Device URL Key: " + durl.getKey());
				System.out.println("	Device URL : " + durl.getUrl());
				System.out.println("	SSL Thumbprint : "	+ durl.getSslThumbprint());
			}
		}
		else
		{
			System.out.println("No Device URLS Found");
		}
	}

	private static long writeVMDKFile(String localFilePath, String diskUrl, String cookie,
			long bytesAlreadyWritten, long totalBytes) throws IOException
	{
		HttpsURLConnection conn = getHTTPConnection(diskUrl, cookie);
		InputStream in = conn.getInputStream();
		OutputStream out = new FileOutputStream(new File(localFilePath));
		byte[] buf = new byte[102400];
		int len = 0;
		long bytesWritten = 0;
		while ((len = in.read(buf)) > 0)
		{
			out.write(buf, 0, len);
			bytesWritten += len;
			int percent = (int)(((bytesAlreadyWritten + bytesWritten) * 100) / totalBytes);
			leaseProgUpdater.setPercent(percent);
			System.out.println("written: " + bytesWritten);
		}
		in.close();
		out.close();
		return bytesWritten;
	}

	private static HttpsURLConnection getHTTPConnection(String urlStr, String cookieStr) throws IOException
	{
		HostnameVerifier hv = new HostnameVerifier()
		{
			public boolean verify(String urlHostName, SSLSession session)
			{
				return true;
			}
		};
		HttpsURLConnection.setDefaultHostnameVerifier(hv);
		URL url = new URL(urlStr);
		HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();

		conn.setDoInput(true);
		conn.setDoOutput(true);
		conn.setAllowUserInteraction(true);
		conn.setRequestProperty("Cookie",	cookieStr);
		conn.connect();
		return conn;
	}

}

Second, ImportLocalOvfVApp.java. This sample shows how to upload a VM or vApp. The flow is:

  • Read in the *.ovf file and call OvfManager().createImportSpec() method
  • From a ResoucePool, call its importVApp() method() and get HttpNfcLease object
  • Wait until the lease is ready
  • Upload the vmdk files using the URL provided by the lease object
  • Release the lease by calling httpNfcLeaseComplete() method

Note: with VI Java API 5.0 GA, remove the line “ovfDescriptor = escapeSpecialChars(ovfDescriptor);” becuase escaping is added to underlying engine.

/*================================================================================
Copyright (c) 2008 VMware, Inc. All Rights Reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

 * Neither the name of VMware, Inc. nor the names of its contributors may be used
to endorse or promote products derived from this software without specific prior
written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
================================================================================*/
package com.vmware.vim25.mo.samples.ovf;

import java.io.*;
import java.net.*;
import javax.net.ssl.*;
import com.vmware.vim25.*;
import com.vmware.vim25.mo.ComputeResource;
import com.vmware.vim25.mo.Folder;
import com.vmware.vim25.mo.HostSystem;
import com.vmware.vim25.mo.HttpNfcLease;
import com.vmware.vim25.mo.ResourcePool;
import com.vmware.vim25.mo.ServiceInstance;

/**
 * Deploy VM or vApp from local disk to an ESX(i) server
 * http://vijava.sf.net
 * @author Steve Jin (sjin at vmware.com)
 */

public class ImportLocalOvfVApp
{
	private static final int CHUCK_LEN = 64 * 1024;

	public static LeaseProgressUpdater leaseUpdater;

	public static void main(String[] args) throws Exception
	{
		if (args.length < 6)
		{
			System.out.println(
			"java ImportLocalOvfVApp <targetURL> <username> <password> <hostip> <OVFFile LocalPath> <NewVMName>");
			System.out.println(
			"java ImportLocalOvfVApp https://10.20.140.47/sdk Administrator password 10.17.204.115 E:/Downloads/Nostalgia.ovf NewVM");
			return;
		}

		ServiceInstance si = new ServiceInstance(new URL(args[0]), args[1], args[2], true);

		String ovfLocal = args[4];
		String hostip = args[3];
		String newVmName = args[5];

		HostSystem host = (HostSystem) si.getSearchIndex().findByIp(null, hostip, false);

		System.out.println("Host Name : " + host.getName());
		System.out.println("Network : " + host.getNetworks()[0].getName());
		System.out.println("Datastore : " + host.getDatastores()[0].getName());

		Folder vmFolder = (Folder) host.getVms()[0].getParent();

		OvfCreateImportSpecParams importSpecParams = new OvfCreateImportSpecParams();
		importSpecParams.setHostSystem(host.getMOR());
		importSpecParams.setLocale("US");
		importSpecParams.setEntityName(newVmName);
		importSpecParams.setDeploymentOption("");
		OvfNetworkMapping networkMapping = new OvfNetworkMapping();
		networkMapping.setName("Network 1");
		networkMapping.setNetwork(host.getNetworks()[0].getMOR()); // network);
		importSpecParams.setNetworkMapping(new OvfNetworkMapping[] { networkMapping });
		importSpecParams.setPropertyMapping(null);

		String ovfDescriptor = readOvfContent(ovfLocal);
		if (ovfDescriptor == null)
		{
			si.getServerConnection().logout();
			return;
		}

		ovfDescriptor = escapeSpecialChars(ovfDescriptor);
		System.out.println("ovfDesc:" + ovfDescriptor);

		ResourcePool rp = ((ComputeResource)host.getParent()).getResourcePool();

		OvfCreateImportSpecResult ovfImportResult = si.getOvfManager().createImportSpec(
				ovfDescriptor, rp, host.getDatastores()[0], importSpecParams);

		if(ovfImportResult==null)
		{
			si.getServerConnection().logout();
			return;
		}

		long totalBytes = addTotalBytes(ovfImportResult);
		System.out.println("Total bytes: " + totalBytes);

		HttpNfcLease httpNfcLease = null;

		httpNfcLease = rp.importVApp(ovfImportResult.getImportSpec(), vmFolder, host);

		// Wait until the HttpNfcLeaseState is ready
		HttpNfcLeaseState hls;
		for(;;)
		{
			hls = httpNfcLease.getState();
			if(hls == HttpNfcLeaseState.ready || hls == HttpNfcLeaseState.error)
			{
				break;
			}
		}

		if (hls.equals(HttpNfcLeaseState.ready))
		{
			System.out.println("HttpNfcLeaseState: ready ");
			HttpNfcLeaseInfo httpNfcLeaseInfo = (HttpNfcLeaseInfo) httpNfcLease.getInfo();
			printHttpNfcLeaseInfo(httpNfcLeaseInfo);

			leaseUpdater = new LeaseProgressUpdater(httpNfcLease, 5000);
			leaseUpdater.start();

			HttpNfcLeaseDeviceUrl[] deviceUrls = httpNfcLeaseInfo.getDeviceUrl();

			long bytesAlreadyWritten = 0;
			for (HttpNfcLeaseDeviceUrl deviceUrl : deviceUrls)
			{
				String deviceKey = deviceUrl.getImportKey();
				for (OvfFileItem ovfFileItem : ovfImportResult.getFileItem())
				{
					if (deviceKey.equals(ovfFileItem.getDeviceId()))
					{
						System.out.println("Import key==OvfFileItem device id: " + deviceKey);
						String absoluteFile = new File(ovfLocal).getParent() + File.separator + ovfFileItem.getPath();
						String urlToPost = deviceUrl.getUrl().replace("*", hostip);
						uploadVmdkFile(ovfFileItem.isCreate(), absoluteFile, urlToPost, bytesAlreadyWritten, totalBytes);
						bytesAlreadyWritten += ovfFileItem.getSize();
						System.out.println("Completed uploading the VMDK file:" + absoluteFile);
					}
				}
			}

			leaseUpdater.interrupt();
			httpNfcLease.httpNfcLeaseProgress(100);
			httpNfcLease.httpNfcLeaseComplete();
		}
		si.getServerConnection().logout();
	}

	public static long addTotalBytes(OvfCreateImportSpecResult ovfImportResult)
	{
		OvfFileItem[] fileItemArr = ovfImportResult.getFileItem();

		long totalBytes = 0;
		if (fileItemArr != null)
		{
			for (OvfFileItem fi : fileItemArr)
			{
				printOvfFileItem(fi);
				totalBytes += fi.getSize();
			}
		}
		return totalBytes;
	}

	private static void uploadVmdkFile(boolean put, String diskFilePath, String urlStr,
			long bytesAlreadyWritten, long totalBytes) throws IOException
	{
		HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier()
		{
			public boolean verify(String urlHostName, SSLSession session)
			{
				return true;
			}
		});

		HttpsURLConnection conn = (HttpsURLConnection) new URL(urlStr).openConnection();
		conn.setDoOutput(true);
		conn.setUseCaches(false);
		conn.setChunkedStreamingMode(CHUCK_LEN);
		conn.setRequestMethod(put? "PUT" : "POST"); // Use a post method to write the file.
		conn.setRequestProperty("Connection", "Keep-Alive");
		conn.setRequestProperty("Content-Type",	"application/x-vnd.vmware-streamVmdk");
		conn.setRequestProperty("Content-Length", Long.toString(new File(diskFilePath).length()));

		BufferedOutputStream bos = new BufferedOutputStream(conn.getOutputStream());

		BufferedInputStream diskis = new BufferedInputStream(new FileInputStream(diskFilePath));
		int bytesAvailable = diskis.available();
		int bufferSize = Math.min(bytesAvailable, CHUCK_LEN);
		byte[] buffer = new byte[bufferSize];

		long totalBytesWritten = 0;
		while (true)
		{
			int bytesRead = diskis.read(buffer, 0, bufferSize);
			if (bytesRead == -1)
			{
				System.out.println("Total bytes written: " + totalBytesWritten);
				break;
			}

			totalBytesWritten += bytesRead;
			bos.write(buffer, 0, bufferSize);
			bos.flush();
			System.out.println("Total bytes written: " + totalBytesWritten);
			int progressPercent = (int) (((bytesAlreadyWritten + totalBytesWritten) * 100) / totalBytes);
			leaseUpdater.setPercent(progressPercent);
		}

		diskis.close();
		bos.flush();
		bos.close();
		conn.disconnect();
	}

	public static String readOvfContent(String ovfFilePath)	throws IOException
	{
		StringBuffer strContent = new StringBuffer();
		BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(ovfFilePath)));
		String lineStr;
		while ((lineStr = in.readLine()) != null)
		{
			strContent.append(lineStr);
		}
		in.close();
		return strContent.toString();
	}

	private static void printHttpNfcLeaseInfo(HttpNfcLeaseInfo info)
	{
		System.out.println("================ HttpNfcLeaseInfo ================");
		HttpNfcLeaseDeviceUrl[] deviceUrlArr = info.getDeviceUrl();
		for (HttpNfcLeaseDeviceUrl durl : deviceUrlArr)
		{
			System.out.println("Device URL Import Key: " + durl.getImportKey());
			System.out.println("Device URL Key: " + durl.getKey());
			System.out.println("Device URL : " + durl.getUrl());
			System.out.println("Updated device URL: " + durl.getUrl());
		}
		System.out.println("Lease Timeout: " + info.getLeaseTimeout());
		System.out.println("Total Disk capacity: " + info.getTotalDiskCapacityInKB());
		System.out.println("==================================================");
	}

	private static void printOvfFileItem(OvfFileItem fi)
	{
		System.out.println("================ OvfFileItem ================");
		System.out.println("chunkSize: " + fi.getChunkSize());
		System.out.println("create: " + fi.isCreate());
		System.out.println("deviceId: " + fi.getDeviceId());
		System.out.println("path: " + fi.getPath());
		System.out.println("size: " + fi.getSize());
		System.out.println("==============================================");
	}

	public static String escapeSpecialChars(String str)
	{
		str = str.replaceAll("<", "&lt;");
		return str.replaceAll(">", "&gt;"); // do not escape "&" -> "&amp;", "\"" -> "&quot;"
	}
}

While you are downloading or uploading the files, you would also like to update the progress with the httpNfcLease.httpNfcLeaseProgress() API. This is done periodically in a separate thread with both samples. Note that the size calculation is not accurate, so you may find mismatch there.

/*================================================================================
Copyright (c) 2008 VMware, Inc. All Rights Reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

 * Neither the name of VMware, Inc. nor the names of its contributors may be used
to endorse or promote products derived from this software without specific prior
written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
================================================================================*/
package com.vmware.vim25.mo.samples.ovf;

import com.vmware.vim25.mo.HttpNfcLease;

/**
 * http://vijava.sf.net
 * @author Steve Jin (sjin at vmware.com)
 */

public class LeaseProgressUpdater extends Thread
{
	private HttpNfcLease httpNfcLease = null;
	private int progressPercent = 0;
	private int updateInterval;

	public LeaseProgressUpdater(HttpNfcLease httpNfcLease, int updateInterval)
	{
		this.httpNfcLease = httpNfcLease;
		this.updateInterval = updateInterval;
	}

	public void run()
	{
		while (true)
		{
			try
			{
				httpNfcLease.httpNfcLeaseProgress(progressPercent);
				Thread.sleep(updateInterval);
			}
			catch(InterruptedException ie)
			{
				break;
			}
			catch(Exception e)
			{
				throw new RuntimeException(e);
			}
		}
	}

	public void setPercent(int percent)
	{
		this.progressPercent = percent;
	}
}

You can import an OVF package from a URL using vSphere Client. How to implement it using the API? Easy. Instead of reading from a local file, you read from the URL. I leave it to you to try out.

For more details, check out the code repository. I have tested both samples in a round trip: export a VM to a local disk, and then import it back. The imported VM works well.

Marcus Ludvigson from Lawson sent me an email with a fix for unfinished upload disk file issue that happens occasionally. You need to add the following two sections of code into uploadVmdkFile() method.

conn.setDoInput(true);
try
{
  DataInputStream dis = new DataInputStream(conn.getInputStream());
  dis.close();
} catch (Exception e) {}

Categories: vSphere API Tags: ,
  1. xmzhu
    July 13th, 2010 at 19:01 | #1

    Great Sample. Is there any C# code for the same functionality?
    thank you

  2. July 13th, 2010 at 21:06 | #2

    Thanks xmzhu! Sorry that I don’t have C# code, but you can port it easily. I know a company ported the samples to C#.

    -Steve

  3. Gaurav Agarwal
    February 22nd, 2011 at 03:49 | #3

    I am using Perl SDK for some functionalities. Is there a similar code out there for Perl to deploy an OVF.

  4. February 22nd, 2011 at 11:26 | #4

    Functionality wise, VI Perl is very similar to VI Java. Therefore you can port the Java code to Perl. I don’t have Perl sample. You want to check with the VI Perl King @lamw (William Lam) if his vGhetto script library has such a sample.

    -Steve

  5. March 31st, 2011 at 10:55 | #5

    This is awesome. I bought the book. Anyway, for this particular code sample, will it work on a legacy 3.5 ESX host? Frank Yang says hi.

  6. March 31st, 2011 at 11:39 | #6

    Chris,

    Thanks a lot for your support on my book! Glad to know you work with Frank.

    The code sample does not work on a legacy 3.5 because it relies on new APIs in vSphere 4.

    Steve

  7. March 31st, 2011 at 11:44 | #7

    Are you aware of a sample script that would export a VM in OVF 0.9 format off of a 3.5 ESX host?

  8. Chris
    April 21st, 2011 at 14:00 | #8

    How long is the typical wait time for the httpnfclease to change to the ready state?

  9. May 5th, 2011 at 17:44 | #9

    I tried to implement the above in C and gSOAP, using VIM 2.5, but the available WSDL (in SDK 4.1.0-257238) does not seem to be useable at all. In particular the definition of VirtualMachineImportSpec is simply absent. As a result, gSOAP aborts verifying the response of CreateImportSpec() method. Man, Java programmers are so sneaky.

  10. May 5th, 2011 at 17:46 | #10

    @Chris
    Depends on the load, but should be nearly instantaneous. In most cases my poll loop returns after 1 RPC with “ready”.

  11. Christian Dickmann
    August 2nd, 2011 at 23:05 | #11

    Thanks! This was quite useful. You can expect support for downloading OVFs in rbvmomi and RVC (Ruby vSphere Console) in the not so distant future thanks to the examples on this page.

  12. amu
    August 19th, 2011 at 02:29 | #12

    I’m new to VI java. when i tried to use ImportLocalOvfVApp.java, got the following error whle Creating the Import Spec. Am i missing any reference? Currently using vijava2120100824src.jar and dom4j-1.6.1.jar for reference. Could anyone help me in this?

    Exception in thread “main” java.rmi.RemoteException: VI SDK invoke exception:org.dom4j.DocumentException: null Nested exception: null
    at com.vmware.vim25.ws.WSClient.invoke(WSClient.java:181)
    at com.vmware.vim25.ws.WSClient.invoke(WSClient.java:123)
    at com.vmware.vim25.ws.VimStub.createImportSpec(VimStub.java:1193)
    at com.vmware.vim25.mo.OvfManager.createImportSpec(OvfManager.java:69)
    at com.vmware.vim25.mo.samples.ovf.ImportLocalOvfVApp.main(ImportLocalOvfVApp.java:75)

  13. August 21st, 2011 at 15:25 | #13

    I don’t think you missed any reference as long as you had the two jar files. What is your target server version? Thanks!

    Steve

  14. Wendy
    September 7th, 2011 at 07:14 | #14

    I just got these error messages, too:
    java.rmi.RemoteException: VI SDK invoke exception:org.dom4j.DocumentException: null Nested exception: null
    at com.vmware.vim25.ws.WSClient.invoke(WSClient.java:181)
    at com.vmware.vim25.ws.WSClient.invoke(WSClient.java:123)
    at com.vmware.vim25.ws.VimStub.createImportSpec(VimStub.java:1193)
    at com.vmware.vim25.mo.OvfManager.createImportSpec(OvfManager.java:69)

    We have run this function many times, this is the first time I got this error message.
    The server is ESXi 4.1.0, 348481

  15. September 7th, 2011 at 12:48 | #15

    Hi Wendy,

    What is different this time?

    Steve

  16. Wendy
    September 7th, 2011 at 22:29 | #16

    Hi, Steve
    I don’t think there is any difference this time.
    This is our production environment and we did not change the java code.
    I used the same ovf file deploy a VM to the same server successfully a few hours age.
    That’s why I am confused and have no idea about where to start to find the root cause.
    Can you give me some hints? Is it possible that I accidentally changed some configuration of the server and make this error?
    Thank you so much! :)

  17. Wendy
    September 8th, 2011 at 03:39 | #17

    I just found the root cause.
    There is an “&” in one of the parameters!!

  18. amu
    October 10th, 2011 at 04:48 | #18

    the issue was in the ovf file used. There were some unsupported chars in the ovf file in license tag. After removing that it works fine. thanks :)
    @amu

  19. October 10th, 2011 at 10:34 | #19

    Hi Amu, You are very welcome. Glad it works for you now. -Steve

  20. heilong
    October 17th, 2011 at 03:23 | #20

    I have test this project. But when I upload vmdk , it always shows
    Exception in thread “main” java.io.IOException: Error writing request body to server
    at sun.net.www.protocol.http.HttpURLConnection$StreamingOutputStream.checkError(Unknown Source)
    at sun.net.www.protocol.http.HttpURLConnection$StreamingOutputStream.write(Unknown Source)
    at java.io.BufferedOutputStream.write(Unknown Source)
    at ImportLocalOvfVapp.uploadVmdkFile(ImportLocalOvfVapp.java:220)
    at ImportLocalOvfVapp.main(ImportLocalOvfVapp.java:150)

    Is there someone meeting the same error?

  21. October 20th, 2011 at 01:48 | #21

    What version of JRE did you run? There is a Java bug in previous versions of JRE. Please check it out here:
    http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6631048

    Steve

  22. heilong
    October 20th, 2011 at 04:12 | #22

    Thanks for your answer.
    I want to know if my ovf directory contains .iso files. And .ovf file contains the information of iso file too.
    How do I upload this ovf template using this program?
    Cause when I use this program to upload.It just write once and throw error. It always shows:
    C:\Atmos\Atmos-file1.isoBuffersize65536
    Total bytes written: 65536
    Exception in thread “main” java.io.IOException: Error writing request body to server
    at sun.net.www.protocol.http.HttpURLConnection$StreamingOutputStream.checkError(Unknown Source)
    at sun.net.www.protocol.http.HttpURLConnection$StreamingOutputStream.write(Unknown Source)
    at java.io.BufferedOutputStream.write(Unknown Source)
    at ImportLocalOvfVApp.uploadVmdkFile(ImportLocalOvfVApp.java:249)
    at ImportLocalOvfVApp.main(ImportLocalOvfVApp.java:166)

  23. heilong
    October 20th, 2011 at 04:13 | #23

    Should I modify the conn.setChunkedStreamingMode(CHUCK_LEN) or conn.setRequestProperty(“Content-Type”, “application/x-vnd.vmware-streamVmdk”) ?
    Thanks

  24. October 20th, 2011 at 10:46 | #24

    I think you can give it a try. Please let me know how it goes.
    Steve

  25. Amol Powar
    November 3rd, 2011 at 16:29 | #25

    How to deal with the OVA file which already has OVF and VMDK bundeled in single file.
    If i try to deploy OVA it throws “Exception in thread “main” java.lang.OutOfMemoryError: Java heap space” which is expected as it cannot read a huge 500mb file.

    Is there any other alternative for reading OVA file?

  26. November 3rd, 2011 at 20:27 | #26

    Hi Amol,

    According to this wiki page, the OVA is just a TAR that includes OVF and disk files. You can extract it before uploading. For the OutOfMemoryError, it’s another issue. Did you allocate a huge byte array? Thanks!

    Steve

  27. Amol Powar
    November 4th, 2011 at 02:59 | #27

    Hi Steve.

    Thanks for the quick reply.
    The problem was with “readOvfContent(ovfLocal)”, as per the code we read the content into “StringBuffer” which indeed throwed OutOfMemory error because of the OVA (OVF + VMDK) file , I used “jtar” api to extract the OVA file into temp directory and then processed the OVF file which worked for me. @Steve Jin

  28. November 4th, 2011 at 03:06 | #28

    Thanks for letting me know. Glad it works for you. OVF is just a few KB, therefore the sample reads all. :-)
    Steve

  29. January 10th, 2012 at 15:47 | #29

    A quick question:

    I am beginning to hit following error almost everytime I do export:
    java.lang.NullPointerException
    at com.vmware.vim25.mo.OvfManager.createDescriptor(OvfManager.java:64)
    at com.bmc.bco.build.vm.automation.vmware.VMInterface.createOvfDescriptor(VMInterface.java:286)
    at com.bmc.bco.build.vm.automation.vmware.VMInterface.createOvfImage(VMInterface.java:275)
    at com.bmc.bco.build.vm.automation.vmware.VMInterface.exportVM(VMInterface.java:207)
    at com.bmc.bco.build.vm.automation.vmware.VMInterfaceThread.runMultiple(VMInterfaceThread.java:58)
    at com.bmc.bco.build.vm.automation.vmware.VMInterfaceThread.run(VMInterfaceThread.java:39)
    at com.bmc.bco.build.vm.automation.App.executeCommand(App.java:205)
    at com.bmc.bco.build.vm.automation.App.processCommands(App.java:161)
    at com.bmc.bco.build.vm.automation.App.doVMPrep(App.java:140)
    at com.bmc.bco.build.vm.automation.App.main(App.java:72)

    Exception in thread “Thread-1” java.lang.RuntimeException: java.lang.NullPointerException
    at com.bmc.bco.build.vm.automation.vmware.LeaseProgressUpdater.run(LeaseProgressUpdater.java:65)
    Caused by: java.lang.NullPointerException
    at com.vmware.vim25.mo.HttpNfcLease.httpNfcLeaseProgress(HttpNfcLease.java:92)
    at com.bmc.bco.build.vm.automation.vmware.LeaseProgressUpdater.run(LeaseProgressUpdater.java:56)

    I am pretty much clueless about the cause.

    Also why is native export so fast compared to the sample code? How can one achieve the same speed?

    Thanks!

  30. January 10th, 2012 at 22:08 | #30

    What version of vijava are you using? You can debug into this since you can download API source code and watch the NullPointerException.
    Good luck.
    Steve

  31. January 11th, 2012 at 04:14 | #31

    ok steve, I will do that. The version that I am using is the latest 5.0 version 520110926.

    However I am still intrigued by the speed of the operation. A native export is very fast, the percentage completion quickly jumps 10% but via the API its really slow. Any clues/advice?

    Thanks

  32. January 11th, 2012 at 08:12 | #32

    Thanks for the information. Have you compared the total time? The GUI jumping 10% quickly is not really an objective comparison.

    Steve

  33. Kseniya
    February 24th, 2012 at 04:09 | #33

    Usefull article, thank you. But could you please explain in detailes fix of unfinished disk upload, mentioned at the end? I’m implementing OVF export on C# and have encountered with such error. It would be easear to choose .Net analogue when proposed solution is understood.

  34. February 26th, 2012 at 16:15 | #34

    I think it’s closely related to the Java API implementation. You may want to look into the C# API for a workaround.
    Steve

  35. Acecat
    March 5th, 2012 at 16:36 | #35

    Hi,
    Anyone tried reading OVF template from ftp url? I am having issues updating the progress.

    – acecat

  36. Ant1
    March 7th, 2012 at 11:57 | #36

    Hey there,
    I am successfully exporting into an ovf but I have an exception when importing it back:
    com.vmware.vim25.InvalidType
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
    at java.lang.Class.newInstance0(Class.java:355)
    at java.lang.Class.newInstance(Class.java:308)
    at com.vmware.vim25.ws.XmlGen.fromXml(XmlGen.java:201)
    at com.vmware.vim25.ws.XmlGen.parseSoapFault(XmlGen.java:80)
    at com.vmware.vim25.ws.WSClient.invoke(WSClient.java:132)
    at com.vmware.vim25.ws.VimStub.createImportSpec(VimStub.java:1193)
    at com.vmware.vim25.mo.OvfManager.createImportSpec(OvfManager.java:69)

    We are using vijava2120100824.
    I’ve been trying to dig into vi code but I can’t find what type can be invalid …
    Any help greatly appreciated! :)

  37. Ant1
    March 8th, 2012 at 04:32 | #37

    Hey,
    I’m following up my previous post.
    I was working with an invalid HostSystem id. :s
    It works now!
    Thank you for the code!

  38. March 8th, 2012 at 11:56 | #38

    Glad it worked for you. Steve

  39. Acecat
    March 13th, 2012 at 15:39 | #39

    @Acecat
    Figured out the issue. Thanks.

  40. March 17th, 2012 at 10:59 | #40

    Steve,

    VI Java interface is great. I have import and export both working. However, how do I programmatically reconfigure/change new VM parameters like number of CPU, memory, disk size, etc before importing. I was thinking about programmatically modify ovf file before importing. But are there a complete set of API’s like OvfCreateImportSpecParams.setEntityName( ) to set those other system parameters? That would make my life much easier. Directly modifying OVF file is really messy.

    Thanks,

    Min

  41. March 17th, 2012 at 12:09 | #41

    Thanks Min,
    Glad you had a good experience with vijava API. I see what you wanted, but I am not aware of such API to manipulate OVF file directly. In my opinion, the DMTF should offer such a tool.
    Steve

  42. Terry Lei
    May 10th, 2012 at 00:27 | #42

    Hi Steve,

    Thanks for your fantastic posting, this example works very well in my local environment. I just wonder if there are some APIs I can use to “tar” the exported OVF files into OVA? Or I have to call the OVF converter tool to compress the OVF file after it is exported?

    Thanks,
    Terry

  43. May 10th, 2012 at 00:38 | #43

    Hi Terry,
    Glad it works well for you. Once you have the exported OVF files locally, I think you can use CLI to “tar” them and then change the suffix.
    Steve

  44. Terry lei
    May 10th, 2012 at 03:18 | #44

    @Steve Jin

    Thanks a lot for your quick response and confirming. I will try the CLI approach.

    -Terry

  45. Alan Vella
    May 11th, 2012 at 05:11 | #45

    Hi,

    Thanks for your very informative article. With reference to this line of code:

    //Note: the diskCapacityInByte could be many time bigger than
    //the total size of VMDK files downloaded.
    //As a result, the progress calculated could be much less than reality.
    long diskCapacityInByte = (httpNfcLeaseInfo.getTotalDiskCapacityInKB()

    Is there any way I can get the actual size of the VMDK files before I download them. This is very important for me.

    Cheers,

    Alan.

  46. May 14th, 2012 at 18:27 | #46

    You can get it from the layoutEx property of the VirtualMachine to be downloaded.

    Steve

  47. Alan Vella
    May 15th, 2012 at 05:52 | #47

    Hi Steve,

    Thank you for your reply. There is VirtualMachineFileLayoutExFileInfo[] in the layoutEx property that you mention but this gives me the list of flat VMDKs. What you actually export when downloading a VM is a list of sparse VMDKs which are usually smaller in size (how much smaller depends on how much of each disk is being used).

    Alan.

  48. May 15th, 2012 at 23:29 | #48

    Thanks for the info. This is highly possible with thin disks. How smaller in size did you see?
    I checked one of my VMs – in the VirtualMachineFileLayoutFileInfo its size is
    7,204,356,096; and in the Web based datastore browser, 17,179,869,184. The latter is close to what is shown in the vSphere Client as provisioned. I assume the downloading size will be equal or smaller than the first one.
    Steve

  49. Alan Vella
    May 16th, 2012 at 04:25 | #49

    @Steve Jin

    Hi Steve,

    In my case, the difference between the value shown in VirtualMachineFileLayoutFileInfo and the actual size of the downloaded VMDK is quite big as the VM is only using around 10% of the available disk space. And, as you said, the value shown in the datastore browser is of no help either in this case.

    I also tried looking at the contentLength of the URL before downloading the VMDK, however this info is not always available (sometimes URL.getContentLength() returns -1).

    It seems like there is no reliable way of getting the size of the VMDKs that are leased out before they are actually downloaded. You’d think vmware’s api would make this valuable info available. Oh well …

    Alan

  50. May 16th, 2012 at 19:39 | #50

    Hi Alan,

    I don’t think VMware is going to change this anytime soon because the size is mainly used for estimating time which people don’t noramlly take too seriously. That being said, you may have a different reason for getting the exact size info, and things could be thus different.

    Steve

Comment pages
1 2 3 767
  1. No trackbacks yet.