Created
June 27, 2016 20:51
-
-
Save vmwarecode/0ee2cbb83a38254b5167251fcdb1aa4c to your computer and use it in GitHub Desktop.
cim-reader
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * ***************************************************** | |
| * Copyright VMware, Inc. 2010-2012. All Rights Reserved. | |
| * ***************************************************** | |
| * | |
| * DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT | |
| * WARRANTIES OR CONDITIONS # OF ANY KIND, WHETHER ORAL OR WRITTEN, | |
| * EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY # DISCLAIMS ANY IMPLIED | |
| * WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY # QUALITY, | |
| * NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. | |
| */ | |
| package com.vmware.cim; | |
| import com.vmware.cim.helpers.GetCim; | |
| import com.vmware.cim.helpers.GetHost; | |
| import com.vmware.common.annotations.Action; | |
| import com.vmware.common.annotations.Option; | |
| import com.vmware.common.annotations.Sample; | |
| import com.vmware.connection.ConnectedVimServiceBase; | |
| import com.vmware.connection.helpers.ApiValidator; | |
| import com.vmware.vim25.HostServiceTicket; | |
| import javax.cim.CIMClass; | |
| import javax.cim.CIMInstance; | |
| import javax.cim.CIMObjectPath; | |
| import javax.cim.CIMProperty; | |
| import javax.wbem.CloseableIterator; | |
| import javax.wbem.WBEMException; | |
| import javax.wbem.client.WBEMClient; | |
| import java.io.Console; | |
| import java.io.IOException; | |
| import java.net.MalformedURLException; | |
| import java.net.URL; | |
| import java.util.*; | |
| import static java.lang.System.out; | |
| /** | |
| * examples of how to work with CIM and vSphere API together. | |
| * <p/> | |
| * Requires the sblim-cim-client2-2.1.1.jar and the sblim-cim-client2.properties | |
| * files these must <strong>both</strong> be in the classpath. The | |
| * sblim-cim-client2.properties should have the value | |
| * <code>sblim.wbem.httpMPOST=true</code> set so that the CIM client functions | |
| * properly. | |
| * <p/> | |
| * | |
| * <pre> | |
| * cim-reader | |
| * | |
| * allows you to walk the Common Information Model (CIM) | |
| * data associated with an ESX Host You cannot read CIM data | |
| * from a vCenter. | |
| * | |
| * --url <url> [required] full url to vcenter | |
| * --username <username> [required] username on remote system | |
| * --password <password> [required] password on remote system | |
| * --host <host> optional | |
| * host name or IP to gather CIM | |
| * data from (only if not talking | |
| * directly to an ESX Host) | |
| * | |
| * --instance <instance> optional | |
| * the CIM class instance to list | |
| * properties of, if none specified | |
| * then the command will list all | |
| * available instances of the specified | |
| * class | |
| * | |
| * --namespace <namespace> optional | |
| * the namespace to explore, if | |
| * none is specified, then the | |
| * command will list all namespaces | |
| * available at the target. | |
| * | |
| * --port <port> optional | |
| * The port number on our remote | |
| * host that the CIM services are | |
| * running on. Defaults to 5989 | |
| * if not specified. | |
| * | |
| * --class <class> optional | |
| * the CIM class to explore, if | |
| * none specified, then the command | |
| * will list all available class | |
| * names under the namespace. | |
| * | |
| * --descendants <class> optional | |
| * Display the class hierarchy for a given specified class. | |
| *</pre> | |
| */ | |
| @Sample(name = "cim-reader", description = "allows you to walk the Common Information Model (CIM) data associated with an ESX Host " | |
| + "You cannot read CIM data from a vCenter. This sample relies on classes in the javax.cim " | |
| + "and javax.wbem packages. Implementations can be found in the sblim-cim-client2-2.1.1.jar " | |
| + "or equivalent library. This sample allows you to drill down into CIM information by first " | |
| + "connecting to a CIM service then exploring it's namespaces, classes, and class instances. ") | |
| public class CIMReader extends ConnectedVimServiceBase { | |
| private GetCim getCim; | |
| String host = null; | |
| @Option(name = "host", required = false, description = "host's entity name or IP to gather CIM data from (if not talking directly to" | |
| + " the ESX host).") | |
| public void setHost(final String hostNameOrIp) { | |
| this.host = hostNameOrIp; | |
| } | |
| int cimPort = 5989; // note default value | |
| @Option(name = "port", required = false, description = "The port number on our remote host that the CIM services are running on. " | |
| + "Defaults to 5989 if not specified.") | |
| public void setCimPort(final String port) { | |
| this.cimPort = (port != null && !"".equals(port)) ? Integer | |
| .parseInt(port) : 5989; | |
| } | |
| String namespace = null; | |
| @Option(name = "namespace", required = false, description = "the namespace to explore, if none is specified, " | |
| + "then the command will list all namespaces available at the target.") | |
| public void setNamespace(final String namespace) { | |
| this.namespace = namespace; | |
| } | |
| String cimClass = null; | |
| @Option(name = "class", required = false, description = "the CIM class to explore, if none specified, " | |
| + "then the command will list all available class names under the namespace.") | |
| public void setCimClass(final String cimClass) { | |
| this.cimClass = cimClass; | |
| } | |
| String instance = null; | |
| @Option(name = "instance", required = false, description = "the CIM class instance to list properties of, if none specified then" | |
| + " the command will list all available instances of the specified class") | |
| public void setInstance(final String name) { | |
| this.instance = name; | |
| } | |
| Boolean descendants = Boolean.FALSE; | |
| @Option(name = "descendants", required = false, description = "the CIM class inheritance details" | |
| + " the command will list class inheritance hierarchy for the specified class", parameter = false) | |
| public void setdescendants(final Boolean descendants) { | |
| this.descendants = descendants; | |
| } | |
| /** | |
| * builds a base URL to use for CIMObjectPath objects based on the host and | |
| * connection objects already present in this object on initialization | |
| * | |
| * @return a URL to talk to the CIM server on | |
| */ | |
| public URL cimBaseUrl() { | |
| URL url; | |
| try { | |
| String hostname = this.host != null ? host : connection.getHost(); | |
| url = new URL("https", hostname, this.cimPort, "/"); | |
| } catch (MalformedURLException e) { | |
| throw new CIMReaderIllegalArgumentException( | |
| "check your CIM port & host parameters", e); | |
| } | |
| return check(url) ? url : null; | |
| } | |
| /** | |
| * checks a URL to see if we can open a connection to it | |
| * | |
| * @param url | |
| * - to examine | |
| * @return true if we can talk to the host | |
| */ | |
| public boolean check(final URL url) { | |
| boolean valid; | |
| try { | |
| url.openConnection(); | |
| valid = true; | |
| } catch (IOException e) { | |
| throw new CIMReaderUnreachableHost(url, e); | |
| } | |
| return valid; | |
| } | |
| /** | |
| * creates a list of namespaces for a host, this is the same for ALL ESX | |
| * hosts | |
| * | |
| * @see javax.cim.CIMObjectPath | |
| * @return a collection of CIMObjectPath objects representing the namespaces | |
| * on the host | |
| * @throws WBEMException | |
| */ | |
| public Collection<CIMObjectPath> listNamespaces() throws WBEMException { | |
| final List<CIMObjectPath> results = new LinkedList<CIMObjectPath>(); | |
| for (String namespace : GetCim.NAMESPACES) { | |
| CIMObjectPath path = getCim().baseObjectPath(cimBaseUrl(), | |
| namespace); | |
| results.add(path); | |
| } | |
| return results; | |
| } | |
| /** | |
| * creates a set of namespaces... based on a collection of objectPaths | |
| * | |
| * @param objectPaths | |
| * the object paths to examine | |
| * @return a set of unique namespace names (strings) | |
| */ | |
| public Collection<String> listNamespaces( | |
| Collection<CIMObjectPath> objectPaths) { | |
| final Set<String> results = new HashSet<String>(); | |
| for (CIMObjectPath objectPath : objectPaths) { | |
| results.add(objectPath.getNamespace()); | |
| } | |
| return results; | |
| } | |
| /** | |
| * lists all the classes at the client that are available | |
| * | |
| * @param client | |
| * an initialized client at the host | |
| * @param namespace | |
| * the namespace to look at | |
| * @return a collection of CIMClass objects available at the host + | |
| * namespace | |
| * @throws WBEMException | |
| */ | |
| public Collection<CIMClass> listClasses(final WBEMClient client, | |
| final String namespace) throws WBEMException { | |
| CIMObjectPath objectPath = getCim().baseObjectPath(cimBaseUrl(), | |
| namespace); | |
| final List<CIMClass> results = new LinkedList<CIMClass>(); | |
| CloseableIterator<CIMClass> enumeration = client.enumerateClasses( | |
| objectPath, true, true, true, true); | |
| while (enumeration.hasNext()) { | |
| results.add(enumeration.next()); | |
| } | |
| return results; | |
| } | |
| /** | |
| * builds a list of instances of a particular class at the client | |
| * | |
| * @param client | |
| * initialized client to use | |
| * @param namespace | |
| * the namespace to consider | |
| * @param classname | |
| * the class to examine | |
| * @return a collection of CIMInstances that are of the specified class | |
| * @throws WBEMException | |
| */ | |
| public Collection<CIMInstance> listInstances(final WBEMClient client, | |
| final String namespace, final String classname) | |
| throws WBEMException { | |
| CIMObjectPath objectPath = getCim().objectPath(cimBaseUrl(), namespace, | |
| classname); | |
| final List<CIMInstance> results = new LinkedList<CIMInstance>(); | |
| CloseableIterator<CIMInstance> enumeration = client.enumerateInstances( | |
| objectPath, true, true, true, null); | |
| while (enumeration.hasNext()) { | |
| results.add(enumeration.next()); | |
| } | |
| return results; | |
| } | |
| /** | |
| * Displays a list of instances of a particular class at the client | |
| * | |
| * @param client | |
| * initialized client to use | |
| * @param namespace | |
| * the namespace to consider | |
| * @param classname | |
| * the class to be used for the descendants | |
| * @return a collection of CIMInstances that are of the specified class | |
| * @throws WBEMException | |
| */ | |
| public Collection<CIMClass> listdescendants(final WBEMClient client, | |
| final String namespace, String classname) throws WBEMException { | |
| CIMObjectPath objectPath = getCim().baseObjectPath(cimBaseUrl(), | |
| namespace); | |
| final List<CIMClass> results = new LinkedList<CIMClass>(); | |
| CloseableIterator<CIMClass> enumeration = client.enumerateClasses( | |
| objectPath, true, true, true, true); | |
| boolean condition = false; | |
| do { | |
| CIMClass enum_class = enumeration.next(); | |
| if (enum_class.getName().equals(classname)) { | |
| classname = GetParent(enum_class); | |
| if (condition) | |
| results.add(enum_class); | |
| condition = true; | |
| enumeration = client.enumerateClasses(objectPath, true, true, | |
| true, true); | |
| } | |
| } while (enumeration.hasNext()); | |
| return results; | |
| } | |
| public static String GetParent(CIMClass Child) { | |
| return Child.getSuperClassName(); | |
| } | |
| /** | |
| * gets a specific instance of a CIM class. Remember to command line escape | |
| * or otherwise properly encode the string representing the URI to the CIM | |
| * object. The path often contains quotes and other special characters that | |
| * confuse many simple-minded parsers. | |
| * <p/> | |
| * | |
| * @param client | |
| * a configured and initialized client to use | |
| * @param objectPath | |
| * as a URI to a specific instance | |
| * @return the instance specified by the objectPath | |
| * @throws WBEMException | |
| */ | |
| public CIMInstance getInstance(final WBEMClient client, | |
| final String objectPath) throws WBEMException { | |
| CIMObjectPath cimObjectPath = new CIMObjectPath(objectPath); | |
| return getInstance(client, cimObjectPath); | |
| } | |
| /** | |
| * gets a specific CIM instance based on a cimObjectPath instance | |
| * <p/> | |
| * | |
| * @param client | |
| * a configured and initialized client to use | |
| * @param cimObjectPath | |
| * a properly constructed CIMObjectPath representing the | |
| * instance's location | |
| * @return an instance object representing the instance | |
| * @throws WBEMException | |
| */ | |
| public CIMInstance getInstance(final WBEMClient client, | |
| final CIMObjectPath cimObjectPath) throws WBEMException { | |
| return client.getInstance(cimObjectPath, true, true, null); | |
| } | |
| /** | |
| * builds a list of properties as a map based on an instance, instance | |
| * objects hold local copies of the properties associated with the | |
| * server-side instance. This may not be the whole set of properties. | |
| * <p/> | |
| * NOTE: be sure to use "getInstance(path,true,true,null)" if you want to | |
| * see <i>all</i> the | |
| * | |
| * @param instance | |
| * the instance to examine (holds a local subset of properties) | |
| * @return a map of the properties available in the instance | |
| * @throws WBEMException | |
| */ | |
| public Map<String, Object> listProperties(CIMInstance instance) | |
| throws WBEMException { | |
| final Map<String, Object> results = new java.util.LinkedHashMap<String, Object>(); | |
| for (CIMProperty<?> property : instance.getProperties()) { | |
| results.put(property.getName(), property.getValue()); | |
| } | |
| return results; | |
| } | |
| public GetCim getCim() { | |
| if (getCim == null) { | |
| // use the specified host name if it is set | |
| final String hostname; | |
| if (isDirectConnection()) { | |
| hostname = connection.getHost(); | |
| } else { | |
| hostname = host; | |
| } | |
| this.getCim = new GetCim(connection, hostname); | |
| } | |
| return getCim; | |
| } | |
| int detectParams(String[] params) { | |
| int found = -1; | |
| int count = 0; | |
| while (count < params.length) { | |
| if (params[count] != null) { | |
| found = count; | |
| } | |
| count++; | |
| } | |
| return found + 1; | |
| } | |
| /** | |
| * Two ways to build a client, either with a username and password for | |
| * direct login to the ESX host or using a ticket. | |
| * | |
| * @param namespace | |
| * @return | |
| */ | |
| public WBEMClient client(String namespace) { | |
| WBEMClient client; | |
| if (isDirectConnection()) { | |
| // this must mean we have a direct ESX connection, use this formula: | |
| client = getCim().client(connection.getUsername(), | |
| connection.getPassword(), cimBaseUrl(), namespace); | |
| } else { | |
| // we will need to obtain a ticket for our host and connect via | |
| // vCenter | |
| HostServiceTicket ticket = getCim().ticket(); | |
| client = getCim().client(ticket, cimBaseUrl(), namespace); | |
| } | |
| return client; | |
| } | |
| /** | |
| * if no hostname is specified, then look for a direct host connection | |
| * otherwise we should be talking to a vCenter. | |
| */ | |
| boolean checkTypeAndHost() { | |
| final ApiValidator apiValidator = new ApiValidator(connection); | |
| final String type = apiValidator.getApiType(); | |
| boolean good = false; | |
| if (host == null) { | |
| good |= ApiValidator.HOST_API_TYPE.equals(type); | |
| if (ApiValidator.VCENTER_API_TYPE.equals(type)) { | |
| System.out | |
| .println(String | |
| .format( | |
| "when talking to a '%s' you must specify a --host <name> to talk to", | |
| ApiValidator.VCENTER_API_TYPE)); | |
| } | |
| } else { | |
| good |= ApiValidator.VCENTER_API_TYPE.equals(type); | |
| } | |
| return good; | |
| } | |
| public Boolean isDirectConnection() { | |
| return isDirectConnection(getConnectionType()); | |
| } | |
| public String getConnectionType() { | |
| final ApiValidator apiValidator = new ApiValidator(connection); | |
| return apiValidator.getApiType(); | |
| } | |
| public Boolean isDirectConnection(final String type) { | |
| return ApiValidator.HOST_API_TYPE.equals(type); | |
| } | |
| private String alias(final Object item, final boolean prettyprint) { | |
| if (item instanceof CIMClass) { | |
| return alias((CIMClass) item); | |
| } | |
| if (item instanceof CIMInstance) { | |
| CIMInstance inst = (CIMInstance) item; | |
| String path = inst.getObjectPath().toString(); | |
| return String.format("\t'%s'\n", path); | |
| } | |
| if (item instanceof CIMObjectPath) { | |
| CIMObjectPath objectPath = (CIMObjectPath) item; | |
| String path = objectPath.toString(); // alias(objectPath); | |
| return String.format("\"%s\"", path.replaceAll("\"", "\\\"")); | |
| } | |
| if (item instanceof CIMProperty<?>[]) { | |
| return cimProperties((CIMProperty<?>[]) item, | |
| (prettyprint) ? "\t%s=\"%s\"\n" : "%s=\"%s\","); | |
| } | |
| if (item instanceof Object[]) { | |
| return listing((Object[]) item); | |
| } | |
| return (item != null) ? item.toString() : ""; | |
| } | |
| private String listing(final Object... item) { | |
| StringBuilder out = new StringBuilder(); | |
| for (int i = 0; i < item.length; i++) { | |
| out.append(item[i]); | |
| if (i + 1 < item.length) { | |
| out.append(","); | |
| } | |
| } | |
| return out.toString(); | |
| } | |
| /** | |
| * create an "alias" string for an object path, this is intended for display | |
| * purposes and not really for looking up the object path later. If you want | |
| * to provide a canonical representation that can be used to find an | |
| * instance use the CIMObjectPath toString method to produce a URI. The URI | |
| * cannot necessarily specify an instance if the properties are too short. | |
| * | |
| * @param objectPath | |
| * @return a pretty print string representing the object for display | |
| * @see CIMObjectPath review the section on keys | |
| */ | |
| public String alias(CIMObjectPath objectPath) { | |
| String cimClass = objectPath.getObjectName(); | |
| String properties = cimProperties(objectPath.getKeys(), "%s=\"%s\","); | |
| return String.format("%s(%s);", cimClass, properties); | |
| } | |
| /** | |
| * pretty print a CIM class | |
| * | |
| * @param cimClass | |
| * @return the name of the class | |
| */ | |
| public String alias(CIMClass cimClass) { | |
| return cimClass.getName(); | |
| } | |
| /** | |
| * produces a pretty print alias for an instance | |
| * | |
| * @param instance | |
| * to examine | |
| * @return string representation of the CIMInstance | |
| */ | |
| public String alias(CIMInstance instance) { | |
| return alias(instance.getObjectPath()); | |
| } | |
| /** | |
| * pretty print the properties of an instance | |
| * | |
| * @param instance | |
| * examine this | |
| * @return a string pretty print of the instance's properties | |
| */ | |
| public String instanceProperties(CIMInstance instance) { | |
| final CIMProperty<?>[] properties = instance.getProperties(); | |
| return cimProperties(properties, "%s=\"%s\","); | |
| } | |
| /** | |
| * Knows how to read CIMProperty objects and put them in a string format | |
| * | |
| * @param properties | |
| * to list out pretty print | |
| * @param format | |
| * to use in pretty print, like "%s='%s'," | |
| * @return a string representing the properties with the format string | |
| * repeatedly applied | |
| */ | |
| public String cimProperties(final CIMProperty<?>[] properties, | |
| final String format) { | |
| StringBuffer out = new StringBuffer(); | |
| for (CIMProperty<?> property : properties) { | |
| String name = property.getName(); | |
| Object value = property.getValue(); | |
| if (value instanceof Object[]) { | |
| value = listing((Object[]) value); | |
| } | |
| out.append(String | |
| .format(format, name, (value != null) ? value : "")); | |
| } | |
| return out.toString(); | |
| } | |
| private void browseCIMData() throws WBEMException { | |
| out.println(); | |
| // never allow a null list, null lists confuse API consumers and | |
| // frustrate code | |
| Collection results = new LinkedList<Object>(); | |
| if (namespace != null) { | |
| if (cimClass != null) { | |
| if (instance != null) { | |
| out.println("listing properties"); | |
| results.add(getInstance(client(namespace), instance) | |
| .getProperties()); // a URI pointing to a sample | |
| } else if (descendants) { | |
| out.println("listing inheritance hierarchy"); | |
| results = (Collection) listdescendants(client(namespace), | |
| namespace, cimClass); | |
| } else { | |
| out | |
| .println("listing instances look inside an instance using --instance a URL from below "); | |
| results = (Collection) listInstances(client(namespace), | |
| namespace, cimClass); | |
| } | |
| } | |
| else { | |
| out.println("choose a class using --class "); | |
| results = (Collection) listClasses(client(namespace), namespace); | |
| } | |
| } else { | |
| out.println("choose a namespace using --namespace "); | |
| results = (Collection) listNamespaces(listNamespaces()); | |
| } | |
| out.println("--"); | |
| for (Object item : results) { | |
| System.out.println(alias(item, true)); | |
| } | |
| if (results.size() == 0) { | |
| System.out.print(System.getProperty("cim.results.empty", | |
| "\tno results to display")); | |
| } | |
| out.println("--"); | |
| } | |
| /** | |
| * The primary action entry point for this sample, presumes that all the | |
| * property setters have been called and connection and other settings have | |
| * been injected. The sample switches logically on the provided arguments | |
| * set by the setter. | |
| * <p/> | |
| * | |
| * @throws WBEMException | |
| */ | |
| @Action | |
| @SuppressWarnings( { "rawtypes", "unchecked" }) | |
| public void run() throws WBEMException { | |
| if (checkTypeAndHost()) { | |
| browseCIMData(); | |
| } | |
| } | |
| /** | |
| * for general CIMReader related Exceptions. | |
| */ | |
| private class CIMReaderException extends RuntimeException { | |
| private static final long serialVersionUID = 3798539954464044318L; | |
| public CIMReaderException(String message, Throwable cause) { | |
| super(message, cause); | |
| } | |
| } | |
| /** | |
| * When we get a command line argument that makes no sense | |
| */ | |
| private class CIMReaderIllegalArgumentException extends CIMReaderException { | |
| private static final long serialVersionUID = -3208774982004613509L; | |
| public CIMReaderIllegalArgumentException(String message, Throwable cause) { | |
| super(message, cause); | |
| } | |
| } | |
| /** | |
| * thrown when a host is unreachable | |
| */ | |
| private class CIMReaderUnreachableHost extends CIMReaderException { | |
| private static final long serialVersionUID = 1890494682069661937L; | |
| public CIMReaderUnreachableHost(URL url, IOException e) { | |
| super("could not talk to: " + url.toString(), e); | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment