How to Upload File to Guest Operating System on VMware

My last post explained how to download file from a guest operating system. Naturally this post is about how to upload file. After a quick sample code, I will discuss how to extend the capability of existing APIs that run program inside guest operating system. My next post will wrap up this series of guest related APIs in vSphere API.

Let’s take a look at a sample code: (To run it, first check out the simple prerequisites in a previous post)

Bothered by SLOW Web UI to manage vSphere? Want to manage ALL your VMware vCenters, AWS, Azure, Openstack, container behind a SINGLE pane of glass? Want to search, analyze, report, visualize VMs, hosts, networks, datastores, events as easily as Google the Web? Find out more about vSearch 3.0: the search engine for all your private and public clouds.

/*=============================================================================
Copyright (c) 2012 Steve Jin, All Rights Reserved.
http://www.doublecloud.org
=============================================================================*/

package org.doublecloud.vi.vmware.guest.samples;

import java.net.URL;

import org.doublecloud.vi.vmware.guest.GuestProcessDirector;

import com.vmware.vim25.mo.Folder;
import com.vmware.vim25.mo.InventoryNavigator;
import com.vmware.vim25.mo.ManagedEntity;
import com.vmware.vim25.mo.ServiceInstance;
import com.vmware.vim25.mo.VirtualMachine;

public class GuestDownloadFile
{
  public static void main(String[] args) throws Exception
  {
    ServiceInstance si = new ServiceInstance(new URL("https://8.8.8.8/sdk"), "Administrator", "doublecloud.org", true);
    Folder rootFolder = si.getRootFolder();

    ManagedEntity[] mes = new InventoryNavigator(rootFolder).searchManagedEntities("VirtualMachine");
    if (mes == null || mes.length == 0)
    {
      return;
    }

    VirtualMachine vm = (VirtualMachine) mes[0];

    System.out.println("guest tool status:" + vm.getGuest().toolsRunningStatus);
    if (!"guestToolsRunning".equals(vm.getGuest().toolsRunningStatus))
    {
      System.out.println("The VMware Tools is not running in the Guest OS on VM: " + vm.getName());
      System.out.println("Exiting...");
      return;
    }

    GuestFileDirector fd = new GuestFileDirector(vm, "Administrator", "vijava");
    fd.uploadFile("C:\\temp\\guest\\steveproxy.jar", "c:\\temp\\steveproxy.jar");
    fd.uploadFile("C:\\temp1\\guest\\", "c:\\temp\\");

    si.getServerConnection().logout();
  }
}

As you can see, the sample uploads a local file (vSphere Java code generator) to the guest operating system. Similar to the downloading directory feature, I implemented a new feature in the Guest Operating System Management API (GuestFileDirector class) that allows you to upload a whole directory recursively to the guest operating system. Again, if you archive a directory and upload the archive, you likely get much better performance than uploading individual files one by one.

Discussion

So far, you’ve seen several samples illustrating the individual APIs in the Guest Operating System Management APIs. Combining them together, you can achieve much more. For example, limited by the vSphere API, the run() method returns only the process ID (PID) of a newly started program. What if you want to get the output of a script you run in the guest operating system? There is no direct way to do it. The workaround is that you pipeline the stand out to a file, then download the file (remember to delete the file afterwards). While implementing this, you may need to handle cases like long run scripts whose output file is continuously changing therefore require continuous downloading.

Less common case is that you want to send a property file, or data input file to a program before it gets run in the guest operating system? You cannot do it without the feature introduced in this post.

This entry was posted in Software Development, vSphere API and tagged , , , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

31 Comments

  1. Atul Khandelwal
    Posted March 21, 2012 at 5:56 pm | Permalink

    Hi Steve,
    On trying to upload a file to guest, I am getting the following exceptions:
    java.net.UnknownHostException: *
    at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:177)
    at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366)
    at java.net.Socket.connect(Socket.java:529)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:559)
    at com.sun.net.ssl.internal.ssl.BaseSSLSocketImpl.connect(BaseSSLSocketImpl.java:141)
    at sun.net.NetworkClient.doConnect(NetworkClient.java:163)
    at sun.net.www.http.HttpClient.openServer(HttpClient.java:394)
    at sun.net.www.http.HttpClient.openServer(HttpClient.java:529)
    at sun.net.www.protocol.https.HttpsClient.(HttpsClient.java:272)
    at sun.net.www.protocol.https.HttpsClient.New(HttpsClient.java:329)
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.getNewHttpClient(AbstractDelegateHttpsURLConnection.java:172)
    at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:916)
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:158)
    at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1019)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:230)
    at org.doublecloud.vi.vmware.guest.GuestFileDirector.uploadData(GuestFileDirector.java:231)
    at org.doublecloud.vi.vmware.guest.GuestFileDirector.uploadFromStream(GuestFileDirector.java:218)
    at org.doublecloud.vi.vmware.guest.GuestFileDirector.uploadFile(GuestFileDirector.java:189)

    Not sure what is the reason.

    Code is exactly same as shown in your example. I am have the same issue with download as well.
    Also, I was able to run a script in the guest.

    Any idea?
    Thanks
    Atul

  2. Posted March 22, 2012 at 8:39 pm | Permalink

    Are you connecting to ESXi directly? There is a chance for the URL to use * as placeholder for host.
    Steve

  3. Atul Khandelwal
    Posted March 23, 2012 at 11:32 am | Permalink

    Yes, I am connecting to ESXi directly. Also, I am able to get the Virtual Machine and guest tool status is “guestToolRunning”.
    I tried to run the above mentioned sample and get the same exception.

  4. Atul Khandelwal
    Posted March 27, 2012 at 11:50 am | Permalink

    Any ideas?

  5. sanquanfeng
    Posted March 28, 2012 at 1:38 am | Permalink

    Hi, I ran into the same exception as Atul did..
    Exception in thread “main” java.net.UnknownHostException: *
    at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:177)
    at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366)
    at java.net.Socket.connect(Socket.java:519)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:550)
    at com.sun.net.ssl.internal.ssl.BaseSSLSocketImpl.connect(BaseSSLSocketImpl.java:141)
    at sun.net.NetworkClient.doConnect(NetworkClient.java:163)
    at sun.net.www.http.HttpClient.openServer(HttpClient.java:394)
    at sun.net.www.http.HttpClient.openServer(HttpClient.java:529)
    at sun.net.www.protocol.https.HttpsClient.(HttpsClient.java:271)
    at sun.net.www.protocol.https.HttpsClient.New(HttpsClient.java:328)
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.getNewHttpClient(AbstractDelegateHttpsURLConnection.java:172)
    at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:731)
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:158)
    at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:834)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:230)
    at org.doublecloud.vi.vmware.guest.GuestFileDirector.uploadData(GuestFileDirector.java:231)
    at org.doublecloud.vi.vmware.guest.GuestFileDirector.uploadFromStream(GuestFileDirector.java:218)
    at org.doublecloud.vi.vmware.guest.GuestFileDirector.uploadFile(GuestFileDirector.java:189)
    at org.doublecloud.vi.vmware.guest.GuestFileDirector.uploadDirectory(GuestFileDirector.java:172)
    at com.vmware.vim25.mo.samples.HelloVM.main(HelloVM.java:123)
    ==========================================================
    However, it works when i just upload a directory to guest with: fd.uploadDirectory(“c:\\temp1”, “c:\\temp1”);
    very appreicated if there are any pointers…

  6. Atul Khandelwal
    Posted March 28, 2012 at 10:43 am | Permalink

    Hi,
    I tried uploadDirectory and it gives me the same exception as mentioned earlier. Though it creates the directory in the guest.
    Any help is highly appreciated…

  7. Atul Khandelwal
    Posted March 28, 2012 at 3:57 pm | Permalink

    Problem seems to be in “InitiateFileTransferToGuest” . It returns xsd::string and the description of the same is as under:
    “A URL to which the user has to send a PUT request. The host part of the URL is returned as ‘*’ if the hostname to be used is the name of the server to which the call was made. For example, if the call is made to esx-svr-1.domain1.com, and the file can be uploaded to http://esx-svr-1.domain1.com/guestFile?id=1&token=1234, the URL returned may be http://*/guestFile?id=1&token=1234. The client replaces the asterisk with the server name on which it invoked the call.”

  8. Posted March 28, 2012 at 4:14 pm | Permalink

    I think you are right on this. Do you want to give it a try via vCenter to see the problem is there as well? Thanks!

    Steve

  9. Atul Khandelwal
    Posted March 28, 2012 at 6:52 pm | Permalink

    Hey Steve,
    I am not sure how to give it a try with vCenter. If you can guide me, I can give it a try.
    Thanks!
    Atul

  10. Posted March 30, 2012 at 12:19 am | Permalink

    Instead of connecting to ESXi directly, connect to vCenter. Thanks!
    Steve

  11. Posted March 30, 2012 at 12:32 am | Permalink

    It’s interesting uploadDirectory works but not the uploadFile because the former calls the latter. I think it may be same cause with * in the returned URL. Are you connecting to ESXi directly?

    Steve

  12. Atul Khandelwal
    Posted April 2, 2012 at 10:11 am | Permalink

    Yes, I am connecting to ESXi directly. We don’t have vCenter currently.
    Thanks
    Atul

  13. luke zeng
    Posted April 3, 2012 at 3:49 am | Permalink

    Hi steve,

    how can i change a guest file’s permisson after success upload?

    for now it always 0644 after upload…

    i can use below script on SDK 5.0 nut not sure how to resolve in vijava.
    posixFileAttributes.setPermissions((long) 0755);

    thanks
    luke

  14. Posted April 3, 2012 at 9:45 am | Permalink

    It is intentionally hidden in guest API, and I change it.
    Steve

  15. luke zeng
    Posted April 3, 2012 at 11:01 pm | Permalink

    Thanks steve,

    So what can I do for now?
    I want to upload a script and then run the script, this is critical for my project…

    Thanks
    Luke

  16. Terry lei
    Posted April 5, 2012 at 9:50 am | Permalink

    Hi Steve,

    Any update about this issue? I agree with that it causes by the URL is replaced by “*”, when I run the example, I also get the same error as posted by sanquanfeng.

    In the internal of GuestFileDirector.uploadFile it will call GuestFileManager.initiateFileTransferToGuest to initialize the urlStr, I expected to see a urlStr like:

    https://x.x.x.x:443/guestFile?id=2&token=5223b47d-921a-e7ae-03b1-19b7e19b86172

    But actually, it is something like:
    https://*:443/guestFile?id=2&token=5223b47d-921a-e7ae-03b1-19b7e19b86172.

    Is there a workaround about the upload/download file?

    As you suggest to using vCenter, does that mean you tested this example with vCenter?

    Thanks,
    Terry

  17. Posted April 6, 2012 at 10:31 am | Permalink

    Yes, I tested the code with vCenter which seems to have full IP address, not just place holder. To workaround this, the * has to be replaced with real IP address.

    Steve

  18. Posted April 6, 2012 at 10:34 am | Permalink

    Hi Luke,

    Sorry that I haven’t got time to look into the issue. You can code against GuestFileManager directly. Optionally, you can break your script into multiple commands and run them one by one. I know it may not be an option if you have complex logics in your script.

    Steve

  19. Posted April 6, 2012 at 10:35 am | Permalink

    Good point there. I think the API should add one parameter for permission setting. Will include a new method later.

    Steve

  20. Posted April 6, 2012 at 10:36 am | Permalink

    No worry Atul,
    Will fix the issue later. Thanks!
    Steve

  21. Atul Khandelwal
    Posted April 6, 2012 at 1:01 pm | Permalink

    Hi Steve,
    Do you have an ETA for the fix?
    Thanks
    Atul

  22. Posted April 8, 2012 at 9:27 am | Permalink

    Hi Atul,
    I don’t have an ETA for this, but will try depending on my time. Thanks!
    Steve

  23. Terry Lei
    Posted May 10, 2012 at 10:17 pm | Permalink

    Hi Steve,

    Do those APIs (GuestFileDirector) support empty password?

    When I test with a user with password configured like “Administrator/vijava”, everything works fine, the file could be uploaded to the guest OS.

    Then I remove the password in the guest OS, and using:

    GuestFileDirector fd = new GuestFileDirector(vm, “Administrator”, “”);
    fd.uploadFile(“C:\\temp\\guest\\steveproxy.jar”, “c:\\temp\\steveproxy.jar”);

    to test again, this time, I get exception like:
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:525)
    at java.lang.Class.newInstance0(Class.java:372)
    at java.lang.Class.newInstance(Class.java:325)
    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:133)
    at com.vmware.vim25.ws.VimStub.initiateFileTransferToGuest(VimStub.java:4199)
    at com.vmware.vim25.mo.GuestFileManager.initiateFileTransferToGuest(GuestFileManager.java:99)

    From the exception, it looks like the soap request is not formed correctly. Does this API support a empty password? Or, is there a work around for such user case?

    Thanks,
    Terry

  24. Posted May 14, 2012 at 6:31 pm | Permalink

    Interesting. What exact exception did it throw? I haven’t tried an empty password, but what is the use case for that? Just curious.

    Steve

  25. Steve Cocks
    Posted May 16, 2012 at 7:10 am | Permalink

    Hi Steve

    Love your API but I am getting the same as everyone else when using the GuestFileDirector using an * instead of the IP.

    I have tried using GuestFileManger and my code seems to work (no exceptions thrown) but nothing arrives at the other end.

    Any idea when you will have a fix for GuestFileDirector or why this code should fail?

    GuestOperationsManager gom = si.getGuestOperationsManager();
    NamePasswordAuthentication npa = new NamePasswordAuthentication();
    npa.username = user;
    npa.password = password;
    GuestFileManager fm = gom.getFileManager(vm);
    String fi = fm.initiateFileTransferToGuest(npa, guestFileLocation, new GuestFileAttributes(), localFileLocation.length(), true);
    URL url = new URL(fi.replace(“*”, getVmwHostIp()));
    HttpsURLConnection httpCon = (HttpsURLConnection ) url.openConnection();
    httpCon.setDoOutput(true);
    httpCon.setRequestMethod(“PUT”);
    OutputStreamWriter outStream = new OutputStreamWriter (httpCon.getOutputStream()); FileInputStream fos = new FileInputStream(localFileLocation); int oneChar, count=0;
    while ((oneChar=fos.read()) != -1) { outStream.write(oneChar); }
    outStream.close();
    fos.close();
    httpCon.disconnect();

  26. Steve Cocks
    Posted May 16, 2012 at 9:40 am | Permalink

    Ok cracked it!! For all those having problems with Uploading and Downloading files here is some working code.

    Common to both

    GuestOperationsManager gom = si.getGuestOperationsManager();
    NamePasswordAuthentication npa = new NamePasswordAuthentication();
    npa.username = user;
    npa.password = password;

    Get a file

    FileTransferInformation fi = fm.initiateFileTransferFromGuest(npa, guestFileLocation);
    URL url = new URL(fi.getUrl().replace(“*”, getVmwHostIp()));
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    conn.setDoInput(true);
    conn.setDoOutput(true);
    conn.setRequestProperty(“Content-Type”, “application/octet-stream”);
    conn.setRequestMethod(“GET”);
    InputStream in = conn.getInputStream();
    OutputStream out = new FileOutputStream(localFileLocation);
    byte[] buf = new byte[102400];
    int len = 0;
    while ((len = in.read(buf)) > 0) { out.write(buf, 0, len); }
    in.close();
    out.close();
    int returnErrorCode = conn.getResponseCode();
    conn.disconnect();

    Put a file

    String fi = fm.initiateFileTransferToGuest(npa, guestFileLocation, new GuestFileAttributes(), localFileLocation.length(), true);
    URL url = new URL(fi.replace(“*”, getVmwHostIp()));
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    conn.setDoInput(true);
    conn.setDoOutput(true);
    conn.setRequestProperty(“Content-Type”, “application/octet-stream”);
    conn.setRequestMethod(“PUT”);
    conn.setRequestProperty(“Content-Length”, Long.toString(localFileLocation.length()));
    OutputStream out = conn.getOutputStream();
    InputStream in = new FileInputStream(localFileLocation);
    byte[] buf = new byte[102400];
    int len = 0;
    while ((len = in.read(buf)) > 0) { out.write(buf, 0, len); }
    in.close();
    out.close();
    conn.disconnect();

  27. Posted May 16, 2012 at 7:32 pm | Permalink

    Thanks for sharing the code!

    Steve

  28. Posted May 16, 2012 at 7:40 pm | Permalink

    You are right about that. I just haven’t got time to fix it yet. Saw your contributed code and thanks for that!

    Steve

  29. Alexander
    Posted November 2, 2012 at 3:02 pm | Permalink

    As of 5.1 I’m having trouble with the GuestFileDirector I get the following problem.
    Exception in thread “main” java.lang.NullPointerException
    at org.doublecloud.vi.vmware.guest.GuestFileDirector.(GuestFileDirector.java:44)

  30. Alexander
    Posted November 2, 2012 at 4:23 pm | Permalink

    @Alexander
    Apologies, the 5.0 jar was still being loaded.

  31. Cody
    Posted June 15, 2015 at 9:54 am | Permalink

    How to upload a file to Linux Guest OS. I tried uploading using initiateFileTransferToGuest but was unable to write the file. I even checked the permissions of the file.It has both read and wrire permissiosns.

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

  • NEED HELP?


    My company has created products like vSearch ("Super vCenter"), vijavaNG APIs, EAM APIs, ICE tool. We also help clients with virtualization and cloud computing on customized development, training. Should you, or someone you know, need these products and services, please feel free to contact me: steve __AT__ doublecloud.org.

    Me: Steve Jin, VMware vExpert who authored the VMware VI and vSphere SDK by Prentice Hall, and created the de factor open source vSphere Java API while working at VMware engineering. Companies like Cisco, EMC, NetApp, HP, Dell, VMware, are among the users of the API and other tools I developed for their products, internal IT orchestration, and test automation.