免费版的VMWare ESXi 从v3.5 u3开始,禁止了SDK和vCli的“写”调用。
也就是说,从ESXi 3.5u3开始,我们不能用SDK或者vCLI命令行,控制免费版ESXi上运行的虚拟机了,不能对其进行重起,关机等任何“写”操作。
后来无意中在网上发现了一个叫esxi-control.pl的脚本,可以用来控制免费版ESXi上的虚拟机,地址如下

脚本是用Perl写的,通过模拟vSphere Client发出的SOAP消息来控制ESXi.但是这个Perl脚本 仍然需要调用Perl-vCLI去获得虚拟机的id信息。我想既然能够模拟SOAP的控制消息,那也一定能模拟读取虚拟机信息的消息啊,但是平时用Perl很少,所以干脆就用JAVA写了一个实现。

先说说程序的原理,
程序调用Apache的httpclient来完成SOAP消息的发送与接受。

第一步,发送下列SOAP消息来建立连接与身份认证,$USERNAME$和$PASSWORD$为ESXi主机的登陆用户名和密码
  1. <soap:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  2.     <soap:Body>
  3.         <Login xmlns="urn:internalvim25">
  4.             <_this xsi:type="SessionManager" type="SessionManager" serverGuid="">ha-sessionmgr</_this>
  5.             <userName>$USERNAME$</userName>
  6.             <password>$PASSWORD$</password>
  7.             <locale>en_US</locale>
  8.         </Login>
  9.     </soap:Body>
  10. </soap:Envelope>
第二步,获取当前已连接主机上的虚拟机列表,SOAP消息如下
  1. <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  2.         <soapenv:Body>
  3.                 <RetrieveProperties xmlns="urn:vim25">
  4.                         <_this type="PropertyCollector">ha-property-collector</_this>
  5.                         <specSet>
  6.                                 <propSet>
  7.                                         <type>HostSystem</type>
  8.                                         <all>0</all>
  9.                                         <pathSet>vm</pathSet>
  10.                                 </propSet>
  11.                                 <objectSet>
  12.                                         <obj type="HostSystem">ha-host</obj>
  13.                                 </objectSet>
  14.                         </specSet>
  15.                 </RetrieveProperties>
  16.         </soapenv:Body>
  17. </soapenv:Envelope>
第三步,第二步返回的消息里面只有虚拟机的ID,但是用户一般是不知道虚拟机的ID是干啥的,所以,我们需要虚拟机的名称等其它信息,所以发送下面的消息用来获取虚拟机其它的信息,包括虚拟机的名称,虚拟机的网络名称,IP地址,开关机状态以及VMWareTool的运行情况。
其中的$VMID$就是要获取具体信息的虚拟机ID
可以有多个" +
  •                                                 "" +
  •                                         "" +
  •                                 "" +
  •                         "";

  •     private String xml_getVMInfo = "";

  •     
  •     //Connect to ESXi Host
  •     public String Connect (String IPAddress, String Username, String Password)throws Exception {

  •         //Clear previous connection, if any.
  •         if (connected) {
  •             Disconnect();
  •             finalCleanup();
  •         }

  •         debugOutput("Connecting to host " + ip2URL(IPAddress));
  •         //Init new connection
  •         hostURL = ip2URL(IPAddress);
  •         httpclient = new DefaultHttpClient();
  •         //Init a customer X509TrustManager to trust any certificates
  •         easyTrustManager = new X509TrustManager() {
  •             @Override
  •             public void checkClientTrusted(
  •                 X509Certificate[] chain,
  •                 String authType) throws CertificateException {
  •                 // Oh, I am easy!
  •             }
  •             @Override
  •             public void checkServerTrusted(
  •                 X509Certificate[] chain,
  •                 String authType) throws CertificateException {
  •                 // Oh, I am easy!
  •             }
  •             @Override
  •             public X509Certificate[] getAcceptedIssuers() {
  •                 return null;
  •             }
  •         };

  •         SSLContext sslcontext = SSLContext.getInstance("TLS");
  •         sslcontext.init(null, new TrustManager[] { easyTrustManager }, null);
  •         //Init SSLSocketFactory to accept any hostname and any certificates
  •         SSLSocketFactory sf = new SSLSocketFactory(sslcontext,SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
  •         Scheme sch = new Scheme("https", 443, sf);
  •         httpclient.getConnectionManager().getSchemeRegistry().register(sch);
  •         httpclient.getParams().setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.BROWSER_COMPATIBILITY);

  •         //Send Hello Message
  •         xml_login = xml_login.replace("$USERNAME$", Username);
  •         xml_login = xml_login.replace("$PASSWORD$", Password);
  •         HttpResponse result;
  •         result = sendXML(hostURL, xml_login);
  •         if (debug) dispalyHttpResponse(result); else EntityUtils.consume(result.getEntity());

  •         //If not HTTP 200 returned, error occured.
  •         if (result.getStatusLine().toString().trim().equals("HTTP/1.1 200 OK")) connected=true;

  •         //Get Virtual Machine List
  •         if (connected) vmList=getVMList();
  •         
  •         //Return connect result
  •         return result.getStatusLine().toString();
  •     }

  •     //disconnect from ESXi Host
  •     public String Disconnect() throws Exception {
  •         String ret = null;
  •         if (debug) System.out.println("Disconnecting from host " + hostURL);
  •         if (connected) {
  •             HttpResponse result = null;
  •             result = sendXML(hostURL, xml_logout);
  •             if (debug) dispalyHttpResponse(result); else EntityUtils.consume(result.getEntity());
  •             //If not HTTP 200 returned, error occured.
  •             if (result.getStatusLine().toString().trim().equals("HTTP/1.1 200 OK")) {
  •                 finalCleanup();
  •             }
  •             ret = result.getStatusLine().toString();
  •         }
  •         //Return connect result
  •         return ret;
  •     }

  •     //Display Virtual Machine List on connected ESXi Host
  •     public void DisplayVMList () {
  •         debugOutput("Displaying Virtual Machine List...");
  •         //init Column Width
  •         int width1=3,width2=12,width3=12,width4=10,width5=12,width6=21;

  •         if (vmList != null) {
  •             //Get Col width
  •             for (int i=0; i<vmList.size(); i++) {
  •                 Vminfo VMNode=null;
  •                 VMNode=(Vminfo)vmList.get(i);
  •                 if (VMNode.getID()!=null) width1 = Math.max(VMNode.getID().length(), width1);
  •                 if (VMNode.getName()!=null) width2 = Math.max(VMNode.getName().length(), width2);
  •                 if (VMNode.getNetworkName()!=null) width3 = Math.max(VMNode.getNetworkName().length(), width3);
  •                 if (VMNode.getIpAddress()!=null) width4 = Math.max(VMNode.getIpAddress().length(), width4);
  •                 if (VMNode.getPowerState()!=null) width5 = Math.max(VMNode.getPowerState().length(), width5);
  •                 if (VMNode.getVMToolRunningSattus()!=null) width6 = Math.max(VMNode.getVMToolRunningSattus().length(), width6);
  •             }
  •             //Output Result
  •             //Title
  •             String title = "";
  •             title += formatData("ID",width1);
  •             title += formatData("Machine Name",width2);
  •             title += formatData("Network Name",width3);
  •             title += formatData("IP Address",width4);
  •             title += formatData("Power Status",width5);
  •             title += formatData("VMTool running Status",width6);
  •             title += "\n";
  •             for (int i=0; i<=width1+width2+width3+width4+width5+width6+6; i++) {
  •                 title += "-";
  •             }
  •             System.out.println(title);
  •             //Data
  •             for (int i=0; i<vmList.size(); i++) {
  •                 Vminfo VMNode=null;
  •                 String output = "";
  •                 VMNode=(Vminfo)vmList.get(i);
  •                 output += formatData(VMNode.getID(),width1);
  •                 output += formatData(VMNode.getName(),width2);
  •                 output += formatData(VMNode.getNetworkName(),width3);
  •                 output += formatData(VMNode.getIpAddress(),width4);
  •                 output += formatData(VMNode.getPowerState(),width5);
  •                 output += formatData(VMNode.getVMToolRunningSattus(),width6);
  •                 System.out.println(output);
  •             }
  •         }
  •     }

  •     //Power-Off virtual machine on connected ESXi host
  •     public String PowerOffVM (String VMName) throws Exception {
  •         String ret = null;
  •         debugOutput("Powering Off "+VMName);
  •         if (connected) {
  •             String xmldata = xml_poweroff.replace("$VMID$", getVMId(VMName));
  •             HttpResponse result;
  •             result = sendXML(hostURL, xmldata);
  •             if (debug) dispalyHttpResponse(result); else EntityUtils.consume(result.getEntity());
  •             ret = result.getStatusLine().toString();
  •         }
  •         //Return result
  •         return ret;
  •     }

  •     //Power-On virtual machine on connected ESXi host
  •     public String PowerOnVM (String VMName) throws Exception {
  •         String ret = null;
  •         debugOutput("Powering On "+VMName);
  •         if (connected) {
  •             String xmldata = xml_poweron.replace("$VMID$", getVMId(VMName));
  •             HttpResponse result;
  •             result = sendXML(hostURL, xmldata);
  •             if (debug) dispalyHttpResponse(result); else EntityUtils.consume(result.getEntity());
  •             ret = result.getStatusLine().toString();
  •         }
  •         //Return result
  •         return ret;
  •     }

  •     //Reset virtual machine on connected ESXi host
  •     public String ResetVM (String VMName) throws Exception {
  •         String ret = null;
  •         debugOutput("Reseting "+VMName);
  •         if (connected) {
  •             String xmldata = xml_reset.replace("$VMID$", getVMId(VMName));
  •             HttpResponse result;
  •             result = sendXML(hostURL, xmldata);
  •             if (debug) dispalyHttpResponse(result); else EntityUtils.consume(result.getEntity());
  •             ret = result.getStatusLine().toString();
  •         }
  •         //Return result
  •         return ret;
  •     }

  •     public boolean getConnected() {
  •         return this.connected;
  •     }

  •     private void finalCleanup() {
  •         if (httpclient!=null) httpclient.getConnectionManager().shutdown();
  •         connected=false;
  •         vmList=null;
  •         httpclient = null;
  •         easyTrustManager = null;
  •         hostURL = null;
  •     }
  •     //Get VMID from given virtual machine name
  •     private String getVMId (String VMName) {
  •         String result = null;
  •         Iterator it = vmList.iterator();
  •         while (it.hasNext()) {
  •             Vminfo VMNode = null;
  •             VMNode = (Vminfo) it.next();
  •             if (VMName.toLowerCase().trim().equals(VMNode.getName().toLowerCase())) {
  •                 result = VMNode.getID();
  •                 break;
  •             }
  •         }
  •         return result;
  •     }
  •     //Get All Virtual Machine Information on connected ESXi host
  •     private ArrayList getVMList() throws Exception {
  •         ArrayList result = new ArrayList();
  •         Vminfo VMNode = null;
  •         HttpResponse rspVMList = sendXML(hostURL,genXML_getVMInfo(getVMIDs ()));
  •         //Parse returned XML and store information in vmList
  •         //NEED MORE SMART!!!

  •         //Returned XML sample
  •         /*
  •         


  •         
  •          *
  •          *
  •          */
  •         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
  •         DocumentBuilder db = dbf.newDocumentBuilder();
  •         Document doc = db.parse(rspVMList.getEntity().getContent());
  •         NodeList nl1 = doc.getElementsByTagName("returnval");
  •         //
  •         for (int i=0; i<nl1.getLength(); i++) {
  •             if (nl1.item(i).hasChildNodes()) {
  •                 VMNode = new Vminfo();
  •                 NodeList nl2 = nl1.item(i).getChildNodes();
  •                 //&
  •                 for(int j=0; j<nl2.getLength(); j++) {
  •                     if (nl2.item(j).getNodeName().trim().equals("obj")) {
  •                         VMNode.setID(nl2.item(j).getTextContent());
  •                     }
  •                     else {
  •                         if (nl2.item(j).hasChildNodes()) {
  •                             NodeList nl3 = nl2.item(j).getChildNodes();
  •                             //
  •                             //There are 2 childnodes in , one is for value name, another is value, it's a pair. so k+=2
  •                             for (int k=0; k< nl3.getLength(); k+=2) {
  •                                 if (nl3.item(k).getTextContent().trim().toLowerCase().equals("name") && nl3.item(k+1).getNodeName().trim().toLowerCase().equals("val")) {
  •                                     VMNode.setName(nl3.item(k+1).getTextContent());
  •                                 } else if (nl3.item(k).getTextContent().trim().toLowerCase().equals("guest.hostname") && nl3.item(k+1).getNodeName().trim().toLowerCase().equals("val")) {
  •                                     VMNode.setNetworkName(nl3.item(k+1).getTextContent());
  •                                 } else if (nl3.item(k).getTextContent().trim().toLowerCase().equals("runtime.powerstate") && nl3.item(k+1).getNodeName().trim().toLowerCase().equals("val")) {
  •                                     VMNode.setPowerState(nl3.item(k+1).getTextContent());
  •                                 } else if (nl3.item(k).getTextContent().trim().toLowerCase().equals("guest.toolsrunningstatus") && nl3.item(k+1).getNodeName().trim().toLowerCase().equals("val")) {
  •                                     VMNode.setVMToolRunningSattus(nl3.item(k+1).getTextContent());
  •                                 } else if (nl3.item(k).getTextContent().trim().toLowerCase().equals("guest.ipaddress") && nl3.item(k+1).getNodeName().trim().toLowerCase().equals("val")) {
  •                                     VMNode.setIpAddress(nl3.item(k+1).getTextContent());
  •                                 }
  •                             }
  •                         }
  •                     }
  •                 }
  •                 result.add(VMNode);
  •                 debugOutput ("1 VM Added. VMID="+VMNode.getID()+" VMName="+VMNode.getName()+" VMNetworkName="+VMNode.getNetworkName()+" VMIP="+VMNode.getIpAddress()+" VMPower="+VMNode.getPowerState()+" ToolStatus="+VMNode.getVMToolRunningSattus());
  •             }
  •         }
  •         return result;
  •     }

  •     private void debugOutput (String msg) {
  •         if (debug) System.out.println("\n");
  •     }
  •     //Get VMID list on a connected ESXi
  •     private String[] getVMIDs () throws Exception{
  •         String[] result = null;
  •         //Sent xml to host to get VM ID list
  •         HttpResponse rspVMIDList = sendXML(hostURL,xml_getVMIDs);
  •         //Parse returned XML
  •         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
  •         DocumentBuilder db = dbf.newDocumentBuilder();
  •         Document doc = db.parse(rspVMIDList.getEntity().getContent());
  •         NodeList nl1 = doc.getElementsByTagName("ManagedObjectReference");
  •         //init the return value array
  •         result = new String[nl1.getLength()];
  •         //set return array
  •         for (int i=0; i<nl1.getLength(); i++) {
  •             //make sure the ID is for Virtual Machine
  •             if (nl1.item(i).hasChildNodes() &&
  •                 nl1.item(i).getAttributes().getNamedItem("type").toString().trim().equals("type=\"VirtualMachine\"")) {
  •                 result[i] = nl1.item(i).getFirstChild().getNodeValue().toString().trim();
  •                 debugOutput("VMID="+result[i]);
  •             }
  •         }
  •         return result;
  •     }
  •     private String genXML_getVMInfo(String[] vmIDList) {
  •         String result;
  •         String tmpxml="";
  •         for (int i=0; i< vmIDList.length; i++) {
  •             tmpxml += "";
  •         }
  •         result = xml_getVMInfo.replace("$VMIDLISTOBJ$", tmpxml);
  •         debugOutput(result);
  •         return result;
  •     }
  •     private void dispalyHttpResponse (HttpResponse rsp) throws Exception {
  •         HttpEntity entity = rsp.getEntity();
  •         System.out.println("****************************************");
  •         System.out.println("----------------------------------------------");
  •         System.out.println(rsp.getStatusLine());
  •         Header[] headers = rsp.getAllHeaders();
  •         for (int i = 0; i < headers.length; i++) {
  •             System.out.println(headers[i]);
  •         }
  •         System.out.println("------------------------------------------------");
  •         if (entity != null) {
  •             System.out.println(EntityUtils.toString(entity));
  •         }
  •         System.out.println("*************************************************");
  •         System.out.println();
  •         System.out.println();
  •     }
  •     private HttpResponse sendXML(String URL, String xml) throws Exception {
  •         HttpPost httppost = new HttpPost(URL);
  •         StringEntity myEntity = new StringEntity(xml);
  •         httppost.addHeader("Content-Type", "text/xml; charset=\"utf-8\"");
  •         httppost.addHeader("User-Agent", "VMware VI Client/4.1.0");
  •         httppost.addHeader("SOAPAction", "\"urn:internalvim25/4.0\"");
  •         httppost.setEntity(myEntity);
  •         if (debug) System.out.println("executing request to " + httppost);
  •         HttpResponse rsp = httpclient.execute(httppost);
  •         return rsp;
  •     }
  •     private String ip2URL (String IPAddress) {
  •         return "HTTPS://"+IPAddress+"/sdk/";
  •     }
  •     private String formatData (String data, int width) {
  •         String result;
  •         
  •         if (data!=null) {
  •             result = data;
  •         } else {
  •             result = "N/A";
  •         }
  •         //Append space
  •         for (int i=result.length(); i<=width; i++) {
  •             result += " ";
  •         }
  •         return result;
  •     }
  •     
  •      public static void main(String[] args) throws Exception{

  •         Vmoperation temp = new Vmoperation();


  •         System.out.println(temp.Connect("","",""));
  •         System.in.read();
  •         System.out.println(temp.PowerOffVM("New Virtual Machine"));
  •         System.in.read();
  •         temp.DisplayVMList();
  •         System.in.read();
  •         System.out.println(temp.PowerOnVM("New Virtual Machine"));
  •         System.in.read();
  •         System.out.println(temp.ResetVM("New Virtual Machine"));
  •         System.in.read();
  •         System.out.println(temp.Disconnect());

  •      }
  • }

  • 注:以上仅用于学术研究,禁止用于实际生产环境。否则将导致违反VMWare License Agreement. VMWare可能随时改变XML的定义,导致程序不能正常工作。


    09-18 17:18