免费版的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主机的登陆用户名和密码
- <soap:Envelope xmlns:xsd="" xmlns:xsi="-instance" xmlns:soap="">
-
<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="" xmlns:xsd="" xmlns:xsi="-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
可以有多个,用来一次性获取多台虚拟机的信息
- <soapenv:Envelope xmlns:soapenv="" xmlns:xsd="" xmlns:xsi="-instance">
-
<soapenv:Body>
-
<RetrieveProperties xmlns="urn:vim25">
-
<_this type="PropertyCollector">ha-property-collector</_this>
-
<specSet>
-
<propSet>
-
<type>VirtualMachine</type>
-
<all>0</all>
-
<pathSet>name</pathSet>
-
<pathSet>guest.hostName</pathSet>
-
<pathSet>runtime.powerState</pathSet>
-
<pathSet>guest.ipAddress</pathSet>
-
<pathSet>guest.toolsRunningStatus</pathSet>
-
</propSet>
-
<objectSet>
-
<obj type="VirtualMachine">$VM1ID$</obj>
-
</objectSet>
-
<objectSet>
-
<obj type="VirtualMachine">$VM2ID$</obj>
-
</objectSet>
-
</specSet>
-
</RetrieveProperties>
-
</soapenv:Body>
-
</soapenv:Envelope>
第四步,到这里,我们的准备工作就结束了,可以发送SOAP的控制消息,控制虚拟机的开关机/重起等操作了,这部分SOAP消息esxi-control.pl做得比较深入,值得借鉴。
这里只举一个重起虚拟机的SOAP消息做例子, $VMID$就是要被重起的虚拟机的ID
- <soap:Envelope xmlns:xsd="" xmlns:xsi="-instance" xmlns:soap="">
-
<soap:Body>
-
<ResetVM_Task xmlns="urn:internalvim25">
-
<_this xsi:type="VirtualMachine" type="VirtualMachine" serverGuid="">$VMID$</_this>
-
</ResetVM_Task>
-
</soap:Body>
-
</soap:Envelope>
第五步,断开连接
- <soap:Envelope xmlns:xsd="" xmlns:xsi="-instance" xmlns:soap="">
-
<soap:Body>
-
<Logout xmlns="urn:internalvim25">
-
<_this xsi:type="ManagedObjectReference" type="SessionManager" serverGuid="">ha-sessionmgr</_this>
-
</Logout>
-
</soap:Body>
-
</soap:Envelope>
JAVA实现代码如下
- package java_vc;
-
-
/**
-
*
-
* @author yyz_tj_cn@sina.com.cn
-
*/
-
-
import org.apache.http.Header;
-
import org.apache.http.HttpEntity;
-
import org.apache.http.HttpResponse;
-
import org.apache.http.client.methods.HttpPost;
-
import org.apache.http.impl.client.DefaultHttpClient;
-
import org.apache.http.util.EntityUtils;
-
import javax.net.ssl.SSLContext;
-
import org.apache.http.conn.ssl.SSLSocketFactory;
-
import javax.net.ssl.TrustManager;
-
import javax.net.ssl.X509TrustManager;
-
import java.security.cert.X509Certificate;
-
import java.security.cert.CertificateException;
-
import org.apache.http.conn.scheme.Scheme;
-
import org.apache.http.entity.StringEntity;
-
import org.apache.http.client.params.ClientPNames;
-
import org.apache.http.client.params.CookiePolicy;
-
import org.w3c.dom.Document;
-
import org.w3c.dom.NodeList;
-
import javax.xml.parsers.*;
-
import java.util.*;
-
-
-
public class Vmoperation {
-
-
//This Embeded Class is used to store Virtual Machine information
-
public class Vminfo {
-
private String id = null;
-
private String name = null;
-
private String networkName = null;
-
private String ipv4 = null;
-
private String powerState = null;
-
private String vmToolRunningSattus = null;
-
-
public Vminfo() {
-
-
}
-
public String getID () {
-
return id;
-
}
-
public void setID (String val) {
-
id=val.trim();
-
}
-
-
public String getName() {
-
return name;
-
}
-
public void setName(String val) {
-
name=val.trim();
-
}
-
-
public String getNetworkName() {
-
return networkName;
-
}
-
public void setNetworkName(String val) {
-
networkName=val.trim();
-
}
-
-
public String getIpAddress() {
-
return ipv4;
-
}
-
public void setIpAddress(String val) {
-
ipv4=val.trim();
-
}
-
-
public String getPowerState() {
-
return powerState;
-
}
-
public void setPowerState(String val) {
-
powerState=val.trim();
-
}
-
-
public String getVMToolRunningSattus() {
-
return vmToolRunningSattus;
-
}
-
public void setVMToolRunningSattus(String val) {
-
vmToolRunningSattus=val.trim();
-
}
-
}
-
-
//Vmoperation Class start...
-
private boolean debug = true;
-
private boolean connected = false;
-
private DefaultHttpClient httpclient = null;
-
private TrustManager easyTrustManager = null;
-
private ArrayList vmList = null;
-
private String hostURL = null;
-
private String xml_login = " "+
-
"" +
-
"" +
-
"<_this xsi:type=\"SessionManager\" type=\"SessionManager\" serverGuid=\"\">ha-sessionmgr" +
-
"$USERNAME$" +
-
"$PASSWORD$" +
-
"en_US" +
-
"" +
-
"" +
-
"";
-
private String xml_logout = "" +
-
"" +
-
"" +
-
"<_this xsi:type=\"ManagedObjectReference\" type=\"SessionManager\" serverGuid=\"\">ha-sessionmgr" +
-
"" +
-
"" +
-
"";
-
private String xml_poweroff = "" +
-
"" +
-
"" +
-
"<_this xsi:type=\"VirtualMachine\" type=\"VirtualMachine\" serverGuid=\"\">$VMID$" +
-
"" +
-
"" +
-
"";
-
private String xml_poweron = "" +
-
"" +
-
"" +
-
"<_this xsi:type=\"VirtualMachine\" type=\"VirtualMachine\" serverGuid=\"\">$VMID$" +
-
"" +
-
"" +
-
"";
-
private String xml_reset = "" +
-
"" +
-
"" +
-
"<_this xsi:type=\"VirtualMachine\" type=\"VirtualMachine\" serverGuid=\"\">$VMID$" +
-
"" +
-
"" +
-
"";
-
-
private String xml_getVMIDs = "" +
-
"" +
-
"" +
-
"<_this type=\"PropertyCollector\">ha-property-collector" +
-
"" +
-
"" +
-
"HostSystem" +
-
"0" +
-
"vm" +
-
"" +
-
"" +
-
"ha-host" +
-
"" +
-
"" +
-
"" +
-
"" +
-
"";
-
-
private String xml_getVMInfo = "" +
-
"" +
-
"" +
-
"<_this type=\"PropertyCollector\">ha-property-collector" +
-
"" +
-
"" +
-
"VirtualMachine" +
-
"0" +
-
"name" +
-
"guest.hostName" +
-
"runtime.powerState" +
-
"guest.ipAddress" +
-
"guest.toolsRunningStatus" +
-
"" +
-
"$VMIDLISTOBJ$" +
-
"" +
-
"" +
-
"" +
-
"";
-
-
-
//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
-
/*
-
-
128
-
guest.hostNameaaa.ccc.bbb
-
guest.ipAddressaaa.ccc.bbb
-
guest.toolsRunningStatusguestToolsRunning
-
nameaaa.ccc.bbb
-
runtime.powerStatepoweredOn
-
-
-
-
-
240
-
guest.toolsRunningStatusguestToolsNotRunning
-
namevSphere Management Assistant (vMA)
-
runtime.powerStatepoweredOff
-
-
*
-
*
-
*/
-
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\n"+msg+"\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 += ""+vmIDList[i]+"";
-
}
-
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的定义,导致程序不能正常工作。
阅读(4965) | 评论(0) | 转发(0) |