也就是说,从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主机的登陆用户名和密码
- <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/">
- <soap:Body>
- <Login xmlns="urn:internalvim25">
- <_this xsi:type="SessionManager" type="SessionManager" serverGuid="">ha-sessionmgr</_this>
- <userName>$USERNAME$</userName>
- <password>$PASSWORD$</password>
- <locale>en_US</locale>
- </Login>
- </soap:Body>
- </soap:Envelope>
第二步,获取当前已连接主机上的虚拟机列表,SOAP消息如下
- <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">
- <soapenv:Body>
- <RetrieveProperties xmlns="urn:vim25">
- <_this type="PropertyCollector">ha-property-collector</_this>
- <specSet>
- <propSet>
- <type>HostSystem</type>
- <all>0</all>
- <pathSet>vm</pathSet>
- </propSet>
- <objectSet>
- <obj type="HostSystem">ha-host</obj>
- </objectSet>
- </specSet>
- </RetrieveProperties>
- </soapenv:Body>
- </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());
}
}