/** * Abiquo community edition * cloud management application for hybrid clouds * Copyright (C) 2008-2010 - Abiquo Holdings S.L. * * This application is free software; you can redistribute it and/or * modify it under the terms of the GNU LESSER GENERAL PUBLIC * LICENSE as published by the Free Software Foundation under * version 3 of the License * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * LESSER GENERAL PUBLIC LICENSE v.3 for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ package com.abiquo.vsm.monitor.esxi.util; import static com.vmware.vim25.mo.util.PropertyCollectorUtil.creatObjectSpec; import static com.vmware.vim25.mo.util.PropertyCollectorUtil.createPropertySpec; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import com.vmware.vim25.DynamicProperty; import com.vmware.vim25.LocalizedMethodFault; import com.vmware.vim25.ManagedObjectReference; import com.vmware.vim25.ObjectContent; import com.vmware.vim25.ObjectSpec; import com.vmware.vim25.ObjectUpdate; import com.vmware.vim25.ObjectUpdateKind; import com.vmware.vim25.PropertyChange; import com.vmware.vim25.PropertyChangeOp; import com.vmware.vim25.PropertyFilterSpec; import com.vmware.vim25.PropertyFilterUpdate; import com.vmware.vim25.PropertySpec; import com.vmware.vim25.SelectionSpec; import com.vmware.vim25.TaskInfo; import com.vmware.vim25.TaskInfoState; import com.vmware.vim25.UpdateSet; import com.vmware.vim25.VimPortType; import com.vmware.vim25.mo.util.PropertyCollectorUtil; /** * Utility wrapper methods for the vimService methods */ public class ServiceUtil { private AppUtil appUtil; public ServiceUtil() { } public static ServiceUtil CreateServiceUtil() { return new ServiceUtil(); } public void init(AppUtil cb) { appUtil = cb; } static String[] meTree = {"ManagedEntity", "ComputeResource", "ClusterComputeResource", "Datacenter", "Folder", "HostSystem", "ResourcePool", "VirtualMachine"}; static String[] crTree = {"ComputeResource", "ClusterComputeResource"}; static String[] hcTree = {"HistoryCollector", "EventHistoryCollector", "TaskHistoryCollector"}; boolean typeIsA(String searchType, String foundType) { if (searchType.equals(foundType)) { return true; } else if (searchType.equals("ManagedEntity")) { for (int i = 0; i < meTree.length; ++i) { if (meTree[i].equals(foundType)) { return true; } } } else if (searchType.equals("ComputeResource")) { for (int i = 0; i < crTree.length; ++i) { if (crTree[i].equals(foundType)) { return true; } } } else if (searchType.equals("HistoryCollector")) { for (int i = 0; i < hcTree.length; ++i) { if (hcTree[i].equals(foundType)) { return true; } } } return false; } /** * Get the ManagedObjectReference for an item under the specified root folder that has the type * and name specified. * * @param root a root folder if available, or null for default * @param type type of the managed object * @param name name to match * @return First ManagedObjectReference of the type / name pair found */ public ManagedObjectReference getDecendentMoRef(ManagedObjectReference root, String type, String name) throws Exception { if (name == null || name.length() == 0) { return null; } String[][] typeinfo = new String[][] {new String[] {type, "name",},}; ObjectContent[] ocary = getContentsRecursively(null, root, typeinfo, true); if (ocary == null || ocary.length == 0) { return null; } ObjectContent oc = null; ManagedObjectReference mor = null; DynamicProperty[] propary = null; String propval = null; boolean found = false; for (int oci = 0; oci < ocary.length && !found; oci++) { oc = ocary[oci]; mor = oc.getObj(); propary = oc.getPropSet(); propval = null; if (type == null || typeIsA(type, mor.getType())) { if (propary.length > 0) { propval = (String) propary[0].getVal(); } found = propval != null && name.equals(propval); } } if (!found) { mor = null; } return mor; } /** * Get the first ManagedObjectReference from a root of the specified type * * @param root a root folder if available, or null for default * @param type the type of the entity - e.g. VirtualMachine * @return managed object reference available */ public ManagedObjectReference getFirstDecendentMoRef(ManagedObjectReference root, String type) throws Exception { ArrayList morlist = getDecendentMoRefs(root, type); ManagedObjectReference mor = null; if (morlist.size() > 0) { mor = (ManagedObjectReference) morlist.get(0); } return mor; } /** * Retrieve all the ManagedObjectReferences of the type specified. * * @param root a root folder if available, or null for default * @param type type of container refs to retrieve * @return List of MORefs */ public ArrayList getDecendentMoRefs(ManagedObjectReference root, String type) throws Exception { ArrayList mors = getDecendentMoRefs(root, type, null); return mors; } public ArrayList getDecendentMoRefs(ManagedObjectReference root, String type, String[][] filter) throws Exception { String[][] typeinfo = new String[][] {new String[] {type, "name"},}; ObjectContent[] ocary = getContentsRecursively(null, root, typeinfo, true); ArrayList refs = new ArrayList(); if (ocary == null || ocary.length == 0) { return refs; } for (int oci = 0; oci < ocary.length; oci++) { refs.add(ocary[oci].getObj()); } if (filter != null) { ArrayList filtermors = filterMOR(refs, filter); return filtermors; } else { return refs; } } private ArrayList filterMOR(ArrayList mors, String[][] filter) throws Exception { ArrayList filteredmors = new ArrayList(); for (int i = 0; i < mors.size(); i++) { boolean flag = true; String guest = null; for (int k = 0; k < filter.length; k++) { String prop = filter[k][0]; String reqVal = filter[k][1]; String value = getProp(((ManagedObjectReference) mors.get(i)), prop); if (reqVal == null) { continue; } if (value == null && reqVal == null) { continue; } if (value == null && reqVal != null) { flag = false; k = filter.length + 1; } else if (value.equalsIgnoreCase(reqVal)) { } else { flag = false; k = filter.length + 1; } } if (flag) { filteredmors.add(mors.get(i)); } } return filteredmors; } private String getProp(ManagedObjectReference obj, String prop) { String propVal = null; try { propVal = (String) getDynamicProperty(obj, prop); } catch (Exception e) { } return propVal; } /** * Retrieve Container contents for all containers recursively from root * * @return retrieved object contents */ public ObjectContent[] getAllContainerContents() throws Exception { ObjectContent[] ocary = getContentsRecursively(null, true); return ocary; } /** * Retrieve container contents from specified root recursively if requested. * * @param root a root folder if available, or null for default * @param recurse retrieve contents recursively from the root down * @return retrieved object contents */ public ObjectContent[] getContentsRecursively(ManagedObjectReference root, boolean recurse) throws Exception { String[][] typeinfo = new String[][] {new String[] {"ManagedEntity",},}; ObjectContent[] ocary = getContentsRecursively(null, root, typeinfo, recurse); return ocary; } /** * Retrieve content recursively with multiple properties. the typeinfo array contains typename + * properties to retrieve. * * @param collector a property collector if available or null for default * @param root a root folder if available, or null for default * @param typeinfo 2D array of properties for each typename * @param recurse retrieve contents recursively from the root down * @return retrieved object contents */ public ObjectContent[] getContentsRecursively(ManagedObjectReference collector, ManagedObjectReference root, String[][] typeinfo, boolean recurse) throws Exception { if (typeinfo == null || typeinfo.length == 0) { return null; } ManagedObjectReference usecoll = collector; if (usecoll == null) { usecoll = getPropertyCollector(); } ManagedObjectReference useroot = root; if (useroot == null) { useroot = appUtil.getServiceInstance().getServiceContent().getRootFolder(); } SelectionSpec[] selectionSpecs = null; if (recurse) { selectionSpecs = PropertyCollectorUtil.buildFullTraversal(); } PropertySpec[] propspecary = buildPropertySpecArray(typeinfo); PropertyFilterSpec filterSpec = new PropertyFilterSpec(); filterSpec.setPropSet(propspecary); filterSpec.setObjectSet(new ObjectSpec[] {PropertyCollectorUtil.creatObjectSpec(useroot, false, selectionSpecs)}); ObjectContent[] retoc = getVimService().retrieveProperties(usecoll, new PropertyFilterSpec[] {filterSpec}); return retoc; } /** * Get a MORef from the property returned. * * @param objMor Object to get a reference property from * @param propName name of the property that is the MORef * @return ManagedObjectReference. */ public ManagedObjectReference getMoRefProp(ManagedObjectReference objMor, String propName) throws Exception { Object props = getDynamicProperty(objMor, propName); ManagedObjectReference propmor = null; if (!props.getClass().isArray()) { propmor = (ManagedObjectReference) props; } return propmor; } /** * Retrieve contents for a single object based on the property collector registered with the * service. * * @param collector Property collector registered with service * @param mobj Managed Object Reference to get contents for * @param properties names of properties of object to retrieve * @return retrieved object contents */ public ObjectContent[] getObjectProperties(ManagedObjectReference collector, ManagedObjectReference mobj, String[] properties) throws Exception { if (mobj == null) { return null; } ManagedObjectReference usecoll = collector; if (usecoll == null) { usecoll = getPropertyCollector(); } PropertySpec propertySpec = createPropertySpec(mobj.getType(), new Boolean(properties == null || properties.length == 0), properties); PropertyFilterSpec spec = new PropertyFilterSpec(); spec.setPropSet(new PropertySpec[] {propertySpec}); ObjectSpec objectSpec = creatObjectSpec(mobj, false, new SelectionSpec[] {}); spec.setObjectSet(new ObjectSpec[] {objectSpec}); return getVimService().retrieveProperties(usecoll, new PropertyFilterSpec[] {spec}); } /** * Retrieve a single object * * @param mor Managed Object Reference to get contents for * @param propertyName of the object to retrieve * @return retrieved object */ public Object getDynamicProperty(ManagedObjectReference mor, String propertyName) throws Exception { ObjectContent[] objContent = getObjectProperties(null, mor, new String[] {propertyName}); Object propertyValue = null; if (objContent != null) { DynamicProperty[] dynamicProperty = objContent[0].getPropSet(); if (dynamicProperty != null) { /* * Check the dynamic propery for ArrayOfXXX object */ Object dynamicPropertyVal = dynamicProperty[0].getVal(); String dynamicPropertyName = dynamicPropertyVal.getClass().getName(); if (dynamicPropertyName.indexOf("ArrayOf") != -1) { String methodName = dynamicPropertyName.substring(dynamicPropertyName.indexOf("ArrayOf") + "ArrayOf".length(), dynamicPropertyName.length()); /* * If object is ArrayOfXXX object, then get the XXX[] by invoking getXXX() on * the object. For Ex: ArrayOfManagedObjectReference.getManagedObjectReference() * returns ManagedObjectReference[] array. */ if (methodExists(dynamicPropertyVal, "get" + methodName, null)) { methodName = "get" + methodName; } else { /* * Construct methodName for ArrayOf primitive types Ex: For ArrayOfInt, * methodName is get_int */ methodName = "get_" + methodName.toLowerCase(); } Method getMorMethod = dynamicPropertyVal.getClass().getDeclaredMethod(methodName, (Class[]) null); propertyValue = getMorMethod.invoke(dynamicPropertyVal, (Object[]) null); } else if (dynamicPropertyVal.getClass().isArray()) { /* * Handle the case of an unwrapped array being deserialized. */ propertyValue = dynamicPropertyVal; } else { propertyValue = dynamicPropertyVal; } } } return propertyValue; } public String waitForTask(ManagedObjectReference taskmor) throws Exception { Object[] result = waitForValues(taskmor, new String[] {"info.state", "info.error"}, new String[] {"state"}, new Object[][] {new Object[] {TaskInfoState.success, TaskInfoState.error}}); if (result[0].equals(TaskInfoState.success)) { return "success"; } else { TaskInfo tinfo = (TaskInfo) getDynamicProperty(taskmor, "info"); LocalizedMethodFault fault = tinfo.getError(); String error = "Error Occured"; if (fault != null) { error = fault.getFault().getFaultCause().getLocalizedMessage(); System.out.println("Fault " + fault.getFault().getFaultCause().getLocalizedMessage()); } return error; } } /** * Handle Updates for a single object. waits till expected values of properties to check are * reached Destroys the ObjectFilter when done. * * @param objmor MOR of the Object to wait for</param> * @param filterProps Properties list to filter * @param endWaitProps Properties list to check for expected values these be properties of a * property in the filter properties list * @param expectedVals values for properties to end the wait * @return true indicating expected values were met, and false otherwise */ public Object[] waitForValues(ManagedObjectReference objmor, String[] filterProps, String[] endWaitProps, Object[][] expectedVals) throws Exception { // version string is initially null String version = ""; Object[] endVals = new Object[endWaitProps.length]; Object[] filterVals = new Object[filterProps.length]; PropertyFilterSpec spec = new PropertyFilterSpec(); spec .setObjectSet(new ObjectSpec[] {creatObjectSpec(objmor, false, new SelectionSpec[] {})}); spec .setPropSet(new PropertySpec[] {createPropertySpec(objmor.getType(), false, filterProps)}); ManagedObjectReference filterSpecRef = getVimService().createFilter(getPropertyCollector(), spec, true); boolean reached = false; UpdateSet updateset = null; PropertyFilterUpdate[] filtupary = null; PropertyFilterUpdate filtup = null; ObjectUpdate[] objupary = null; ObjectUpdate objup = null; PropertyChange[] propchgary = null; PropertyChange propchg = null; while (!reached) { boolean retry = true; while (retry) { try { updateset = getVimService().waitForUpdates(getPropertyCollector(), version); retry = false; } catch (Exception e) { if (e.getCause().getMessage().indexOf("java.net.SocketTimeoutException") != -1) { System.out.println("Retrying2........"); retry = true; } else { throw e; } } } version = updateset.getVersion(); if (updateset == null || updateset.getFilterSet() == null) { continue; } // Make this code more general purpose when PropCol changes later. filtupary = updateset.getFilterSet(); filtup = null; for (int fi = 0; fi < filtupary.length; fi++) { filtup = filtupary[fi]; objupary = filtup.getObjectSet(); objup = null; propchgary = null; for (int oi = 0; oi < objupary.length; oi++) { objup = objupary[oi]; // TODO: Handle all "kind"s of updates. if (objup.getKind() == ObjectUpdateKind.modify || objup.getKind() == ObjectUpdateKind.enter || objup.getKind() == ObjectUpdateKind.leave) { propchgary = objup.getChangeSet(); for (int ci = 0; ci < propchgary.length; ci++) { propchg = propchgary[ci]; updateValues(endWaitProps, endVals, propchg); updateValues(filterProps, filterVals, propchg); } } } } Object expctdval = null; // Check if the expected values have been reached and exit the loop if done. // Also exit the WaitForUpdates loop if this is the case. for (int chgi = 0; chgi < endVals.length && !reached; chgi++) { for (int vali = 0; vali < expectedVals[chgi].length && !reached; vali++) { expctdval = expectedVals[chgi][vali]; reached = expctdval.equals(endVals[chgi]) || reached; } } } // Destroy the filter when we are done. getVimService().destroyPropertyFilter(filterSpecRef); return filterVals; } protected void updateValues(String[] props, Object[] vals, PropertyChange propchg) { for (int findi = 0; findi < props.length; findi++) { if (propchg.getName().lastIndexOf(props[findi]) >= 0) { if (propchg.getOp() == PropertyChangeOp.remove) { vals[findi] = ""; } else { vals[findi] = propchg.getVal(); // System.out.println("Changed value : " + propchg.getVal()); } } } } /** * This code takes an array of [typename, property, property, ...] and converts it into a * PropertySpec[]. handles case where multiple references to the same typename are specified. * * @param typeinfo 2D array of type and properties to retrieve * @return Array of container filter specs */ public PropertySpec[] buildPropertySpecArray(String[][] typeinfo) { // Eliminate duplicates HashMap tInfo = new HashMap(); for (int ti = 0; ti < typeinfo.length; ++ti) { Set props = (Set) tInfo.get(typeinfo[ti][0]); if (props == null) { props = new HashSet(); tInfo.put(typeinfo[ti][0], props); } boolean typeSkipped = false; for (int pi = 0; pi < typeinfo[ti].length; ++pi) { String prop = typeinfo[ti][pi]; if (typeSkipped) { props.add(prop); } else { typeSkipped = true; } } } // Create PropertySpecs ArrayList pSpecs = new ArrayList(); for (Iterator ki = tInfo.keySet().iterator(); ki.hasNext();) { String type = (String) ki.next(); PropertySpec pSpec = new PropertySpec(); Set<String> props = (Set<String>) tInfo.get(type); pSpec.setType(type); pSpec.setAll(props.isEmpty() ? Boolean.TRUE : Boolean.FALSE); pSpec.setPathSet(props.toArray(new String[props.size()])); pSpecs.add(pSpec); } return (PropertySpec[]) pSpecs.toArray(new PropertySpec[0]); } /** * Determines of a method 'methodName' exists for the Object 'obj' * * @param obj The Object to check * @param methodName The method name * @param parameterTypes Array of Class objects for the parameter types * @return true if the method exists, false otherwise */ boolean methodExists(Object obj, String methodName, Class[] parameterTypes) { boolean exists = false; try { Method method = obj.getClass().getMethod(methodName, parameterTypes); if (method != null) { exists = true; } } catch (Exception e) { } return exists; } private ManagedObjectReference getPropertyCollector() { return appUtil.getServiceInstance().getPropertyCollector().getMOR(); } public VimPortType getVimService() { return appUtil.getServiceInstance().getServerConnection().getVimService(); } }