使用VMware VSphere WebService SDK进行开发 (一)——基本信息阐述

               
欢迎支持笔者新作:《深入理解Kafka:核心设计与实践原理》和《RabbitMQ实战指南》,同时欢迎关注笔者的微信公众号:朱小厮的博客。

使用VMware VSphere WebService SDK进行开发 (一)——基本信息阐述

 

网上对于VSphere WebService SDK的介绍比较少(至少我能查到的资料比较少),官方提供的也是英文版的api,而且没有注明使用方法。最近接触到关于VSphere WebService SDK的开发,刚开始也是烦躁,比如要获取一个cpu使用情况的信息,按照惯例,API应该提供类似:long getCpuUsage() 之类的接口,但是绝逼没有那么easy,不过很快掌握了规律。我觉得有必要分享一下我所了解到的知识点,希望能够给各位读者有那么一点抛砖引玉的作用。

我准备通过几篇文章来主要讲述如何使用VSphere WebService SDK 进行对资源信息的监控和告警的采集。对资源监视的监控主要包括:对虚拟机(Virtual Machine)信息的监控(cpu使用情况、磁盘的写入以及读取速度、内存的滞后时间、网络的丢弃的传输和接收的数据报数等待)、对主机(HostSystem)的监控、对集群(Cluster, Compute Resource)信息的监控. 告警也是对这几个主要的对象进行告警采集。

关于软件的安装,譬如vSphere的配置以及vSphere Client的安装就此略过。我这里使用的版本是VMware-vSphere-SDK-5.0.0-429209。

本篇文章主要先阐述一些基本知识。

VMware vSphere支持健壮的、容错的虚拟化应用、网络和存储。vSphere提供许多可选的组件和模块,例如VMware High Availability(HA) 和VMware VMotion。VMware vSphere Web Services SDK提供给Web Services开发者通过编程的方式访问vSphere组件。

vSphere API以无关语言的Web Serivce的形式实现,客户端应用通过远程调用来访问ESX/ESXi, VCenter vSphere systems上的服务和组件。

VMware vSphere客户端程序基于一个异步通讯的分布式架构模型,架构的基础基于server-side managed object, client-side managed object references和data objects.

Managed Object: 在vSphere server(ESX/ESXi 或 vCenter Server system)上,代表着vSphere的服务和组件。服务包括 PropertyCollector, SearchIndex, PerformanceManager和ViewManager。组件包括inventory objects例如VirtualMachine,Datastore和Folder.

Managed Object refereneces:是客户端应用服务器端managed objects.你的客户端应用程序通过使用ManagedObjectReference objects来向服务器发送请求操作。在object的生命周期内ManagedObjectReferences是唯一和持久有效地。当一个存在与清单中由于过期sessions或服务器重启而删除的object的应用会依然存在。假如你删除一个object,例如一个虚拟机,然后又找回它,对它的引用将改变。

Data objects:包含着关于managed objects的信息,你的客户端程序发送data objects和接收data objects与一个vSphere server, 不同的标准和功能object例如VirtualMachineConfigSp和HostCapability.

下图清楚的说明了这三种数据对象及 vSphere Sever 与 client 的关系。

使用VMware VSphere WebService SDK进行开发 (一)——基本信息阐述

在这三种数据对象中,MO 代表了服务器端的服务或组件,他们都直接或间接继承自 ManagedEntity 抽象类。下面的类图展示了目前 vSphere Infrastructure 中的 7 种最重要的 MO 类型和它们的继承关系,它们代表了 vSphere Infrastructure 中的 7 种组件或者实体。

使用VMware VSphere WebService SDK进行开发 (一)——基本信息阐述

使用 SDK 开发自己的 vSphere 客户端程序,首要的问题就是如何访问和遍历在 vSphere Inventory 中的对象。下面我们将介绍这方面的内容。

 

vSphere Inventory 介绍

 

 

vSphere inventory 其实就是 vSphere datacenter 及其管理的对象。在 vSphere inventory 中包含了以下三种类型的对象:

在 datacenter 中被管理的系统,比如 Host、VirtualMachine、VirtualApp 等。

具有一定功能的组件,比如 ComputeResource、DataStore,、Network 等。

负责组织归类的组件,它们负责把 datacenter 中的对象按照层级关系组织起来形成了一个树状结构,比如 Folder 和 DataCenter。

ESX/ESXi server 和 vCenter 的 inventory 结构是类似的,只是在 ESX server 中,有些对象的数量有限制,比如在一个 ESX server 的 inventory 中只能有一个 Host 实体。下面两张图分别给出了 vCenter 这 ESX server 的 inventory 的结构。

 

vCenter Inventory 结构

使用VMware VSphere WebService SDK进行开发 (一)——基本信息阐述

 

 

 

上面这个关系图很关键,对于系统中关键信息的检索,首先要根据这张图搜寻相关的ManagedObjectReference对象,然后根据此对象的属性树进行遍历。比如搜寻DataCenter对象的相关信息:

 

 private static TraversalSpec getDatacenterTraversalSpec() {  SelectionSpec sSpec = new SelectionSpec();  sSpec.setName("VisitFolders");  TraversalSpec traversalSpec = new TraversalSpec();  traversalSpec.setName("VisitFolders");  traversalSpec.setType("Folder");  traversalSpec.setPath("childEntity");  traversalSpec.setSkip(false);  traversalSpec.getSelectSet().add(sSpec);  return traversalSpec; }

 

 private static ManagedObjectReference getDatacenterByName(String datacenterName) {  ManagedObjectReference retVal = null;  ManagedObjectReference rootFolder = serviceContent.getRootFolder();  try  {   TraversalSpec tSpec = getDatacenterTraversalSpec();   PropertySpec propertySpec = new PropertySpec();   propertySpec.setAll(Boolean.FALSE);   propertySpec.getPathSet().add("name");   propertySpec.setType("Datacenter");   ObjectSpec objectSpec = new ObjectSpec();   objectSpec.setObj(rootFolder);   objectSpec.setSkip(Boolean.TRUE);   objectSpec.getSelectSet().add(tSpec);   PropertyFilterSpec propertyFilterSpec = new PropertyFilterSpec();   propertyFilterSpec.getPropSet().add(propertySpec);   propertyFilterSpec.getObjectSet().add(objectSpec);   List<PropertyFilterSpec> listfps = new ArrayList<PropertyFilterSpec>(1);   listfps.add(propertyFilterSpec);   List<ObjectContent> listobcont = retrievePropertiesAllObjects(listfps);   if (listobcont != null)   {    for (ObjectContent oc : listobcont)    {     ManagedObjectReference mr = oc.getObj();     String dcnm = null;     List<DynamicProperty> dps = oc.getPropSet();     if (dps != null)     {      for (DynamicProperty dp : dps)      {       dcnm = (String) dp.getVal();      }     }     if (dcnm != null && dcnm.equals(datacenterName))     {      retVal = mr;      break;     }    }   }  }  catch (SOAPFaultException sfe)  {   printSoapFaultException(sfe);  }  catch (Exception e)  {   e.printStackTrace();  }  return retVal; }

上面的方法getDatacenterTraversalSpec()就是Datacenter的遍历路径代码,然后方法getDatacenterByName(String datacenterName)才能根据获得的遍历路径进行遍历,获取相应的Datacenter的对象。

对于Datacenter的遍历路径代码,比较简单,而对于VirtualMachine或者集群(ComputeResource)之类的遍历路径代码相对复杂,之后再一一罗列。

 

 

ESX Server Inventory 结构

 

使用VMware VSphere WebService SDK进行开发 (一)——基本信息阐述

想要访问 vCenter 或者 ESX server 中的某个对象或者调用其方法,就必须首先根据这个对象在 inventory 中的位置找个这个对象。从上图可知,ServiceInstance 对象在 inventory 的结构树中处于根位置,因此遍历整个 inventory 或者要查找 inventory 中的某个对象,必须先从 ServiceInstance 开始。ServiceInstance 类中最重要的一个属性(property,可以理解为类的成员变量)是 content,它指向数据类型(Data Object)ServiceContent 的一个实例。ServiceContent 类含有很多该 vSphere 服务实例的重要属性和服务的引用,比如整个 inventory 的 root folder,session manager,property collector(用于查找和遍历对象),以及 EventManager, TaskManager 等。下面的类图展示了 ServiceInstance 和 ServiceContent 的部分属性。

 

ServiceInstance 和 ServiceContent

使用VMware VSphere WebService SDK进行开发 (一)——基本信息阐述

 

以上资料在网上或者vSphere sdk自带的API或者自带的用例demo中可以找到相关的信息。本人只是挑一些重要概念陈述,接下去才主要讲解如何通过编码实现实时监控私有云的状态,譬如虚拟机cpu使用情况等性能指标。

 

下面罗列一些主要的关键代码(可以在vSphere sdk自带的demo中找到相关代码),包括认证、连接、断开之类的操作。

 

public class MoniterWsInterfaceprivate static String url; private static String userName; private static String password; private static final ManagedObjectReference SVC_INST_REF = new ManagedObjectReference(); private static VimService vimService; private static VimPortType vimPort; private static ServiceContent serviceContent; private static final String SVC_INST_NAME = "ServiceInstance"private static Boolean isConnected = falseprivate static ManagedObjectReference perfManager; private static ManagedObjectReference propCollectorRef; public MoniterWsInterface(String puserName, String ppassWord, String purl) {  url = purl;  userName = puserName;  password = ppassWord; } private static class TrustAllTrustManager implements javax.net.ssl.TrustManager, javax.net.ssl.X509TrustManager {  public java.security.cert.X509Certificate[] getAcceptedIssuers()  {   return null;  }  public boolean isServerTrusted(java.security.cert.X509Certificate[] certs)  {   return true;  }  public boolean isClientTrusted(java.security.cert.X509Certificate[] certs)  {   return true;  }  public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) throws java.security.cert.CertificateException  {   return;  }  public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) throws java.security.cert.CertificateException  {   return;  } } private static void trustAllHttpsCertificates() throws Exception {  javax.net.ssl.TrustManager[] trustAllCerts = new javax.net.ssl.TrustManager[1];  javax.net.ssl.TrustManager tm = new TrustAllTrustManager();  trustAllCerts[0] = tm;  javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext.getInstance("SSL");  javax.net.ssl.SSLSessionContext sslsc = sc.getServerSessionContext();  sslsc.setSessionTimeout(0);  sc.init(null, trustAllCerts, null);  javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); } public static void connect() throws Exception {  HostnameVerifier hv = new HostnameVerifier()  {   public boolean verify(String urlHostName, SSLSession session)   {    return true;   }  };  trustAllHttpsCertificates();  HttpsURLConnection.setDefaultHostnameVerifier(hv);  SVC_INST_REF.setType(SVC_INST_NAME);  SVC_INST_REF.setValue(SVC_INST_NAME);  vimService = new VimService();  vimPort = vimService.getVimPort();  Map<String, Object> ctxt = ((BindingProvider) vimPort).getRequestContext();  ctxt.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, url);  ctxt.put(BindingProvider.SESSION_MAINTAIN_PROPERTY, true);  serviceContent = vimPort.retrieveServiceContent(SVC_INST_REF);  vimPort.login(serviceContent.getSessionManager(), userName, password, null);  isConnected = true;  perfManager = serviceContent.getPerfManager();  propCollectorRef = serviceContent.getPropertyCollector(); } public static void disconnect() throws Exception {  if (isConnected)  {   vimPort.logout(serviceContent.getSessionManager());  }  isConnected = false; } private static void printSoapFaultException(SOAPFaultException sfe) {  System.out.println("Soap fault: ");  if (sfe.getFault().hasDetail())  {   System.out.println(sfe.getFault().getDetail().getFirstChild().getLocalName());  }  if (sfe.getFault().getFaultString() != null)  {   System.out.println("Message: " + sfe.getFault().getFaultString());  } } public static void main(String[] args) {  new MoniterWsInterface("xxx", "xxx", "xxx");  try  {   connect();  }  catch (SOAPFaultException sfe)  {   printSoapFaultException(sfe);  }  catch (Exception e)  {   e.printStackTrace();  }  finally  {   try   {    disconnect();   }   catch (SOAPFaultException sfe)   {    printSoapFaultException(sfe);   }   catch (Exception e)   {    e.printStackTrace();   }  } }}

这样就可以通过相关连接信息(username,password,url)进行相关连接。

 

由于篇幅原因,接下来的内容在之后的文章中一一呈现。

补充:retrievePropertiesAllObjects的代码:

 

 private static List<ObjectContent> retrievePropertiesAllObjects(List<PropertyFilterSpec> listpfs) throws Exception {  RetrieveOptions propObjectRetrieveOpts = new RetrieveOptions();  List<ObjectContent> listobjcontent = new ArrayList<ObjectContent>();  try  {   RetrieveResult rslts = vimPort.retrievePropertiesEx(propCollectorRef, listpfs, propObjectRetrieveOpts);   if (rslts != null && rslts.getObjects() != null && !rslts.getObjects().isEmpty())   {    listobjcontent.addAll(rslts.getObjects());   }   String token = null;   if (rslts != null && rslts.getToken() != null)   {    token = rslts.getToken();   }   while (token != null && !token.isEmpty())   {    rslts = vimPort.continueRetrievePropertiesEx(propCollectorRef, token);    token = null;    if (rslts != null)    {     token = rslts.getToken();     if (rslts.getObjects() != null && !rslts.getObjects().isEmpty())     {      listobjcontent.addAll(rslts.getObjects());     }    }   }  }  catch (SOAPFaultException sfe)  {   printSoapFaultException(sfe);  }  catch (Exception e)  {   e.printStackTrace();  }  return listobjcontent; }
欢迎支持笔者新作:《深入理解Kafka:核心设计与实践原理》和《RabbitMQ实战指南》,同时欢迎关注笔者的微信公众号:朱小厮的博客。

使用VMware VSphere WebService SDK进行开发 (一)——基本信息阐述