/******************************************************************************* * This file is part of OpenNMS(R). * * Copyright (C) 2009-2011 The OpenNMS Group, Inc. * OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc. * * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc. * * OpenNMS(R) is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * OpenNMS(R) 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenNMS(R). If not, see: * http://www.gnu.org/licenses/ * * For more information contact: * OpenNMS(R) Licensing <license@opennms.org> * http://www.opennms.org/ * http://www.opennms.com/ *******************************************************************************/ package org.opennms.netmgt.collectd; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.lang.reflect.UndeclaredThrowableException; import java.util.Date; import java.util.HashMap; import java.util.Map; import org.exolab.castor.xml.MarshalException; import org.exolab.castor.xml.ValidationException; import org.opennms.core.utils.LogUtils; import org.opennms.core.utils.ParameterMap; import org.opennms.netmgt.collectd.wmi.WmiAgentState; import org.opennms.netmgt.collectd.wmi.WmiCollectionAttributeType; import org.opennms.netmgt.collectd.wmi.WmiCollectionResource; import org.opennms.netmgt.collectd.wmi.WmiCollectionSet; import org.opennms.netmgt.collectd.wmi.WmiMultiInstanceCollectionResource; import org.opennms.netmgt.collectd.wmi.WmiSingleInstanceCollectionResource; import org.opennms.netmgt.config.DataCollectionConfigFactory; import org.opennms.netmgt.config.DataSourceFactory; import org.opennms.netmgt.config.WmiDataCollectionConfigFactory; import org.opennms.netmgt.config.WmiPeerFactory; import org.opennms.netmgt.config.collector.AttributeGroupType; import org.opennms.netmgt.config.collector.CollectionSet; import org.opennms.netmgt.config.wmi.Attrib; import org.opennms.netmgt.config.wmi.WmiCollection; import org.opennms.netmgt.config.wmi.Wpm; import org.opennms.netmgt.model.RrdRepository; import org.opennms.netmgt.model.events.EventProxy; import org.opennms.protocols.wmi.WmiClient; import org.opennms.protocols.wmi.WmiException; import org.opennms.protocols.wmi.WmiManager; import org.opennms.protocols.wmi.WmiParams; import org.opennms.protocols.wmi.WmiResult; import org.opennms.protocols.wmi.wbem.OnmsWbemObject; import org.opennms.protocols.wmi.wbem.OnmsWbemObjectSet; import org.opennms.protocols.wmi.wbem.OnmsWbemProperty; /** * <P> * This class is designed to be used by the performance collection daemon to * collect various WMI performance metrics from a remote server. * </P> * * @author <a href="mailto:matt.raykowski@gmail.com">Matt Raykowski</a> * @author <a href="http://www.opennms.org">OpenNMS</a> */ public class WmiCollector implements ServiceCollector { // Don't make this static because each service will have its own // copy and the key won't require the service name as part of the key. private final HashMap<Integer, WmiAgentState> m_scheduledNodes = new HashMap<Integer, WmiAgentState>(); private HashMap<String, AttributeGroupType> m_groupTypeList = new HashMap<String, AttributeGroupType>(); private HashMap<String, WmiCollectionAttributeType> m_attribTypeList = new HashMap<String, WmiCollectionAttributeType>(); /** {@inheritDoc} */ public CollectionSet collect(final CollectionAgent agent, final EventProxy eproxy, final Map<String, Object> parameters) { String collectionName = ParameterMap.getKeyedString(parameters, "collection", ParameterMap.getKeyedString(parameters, "wmi-collection", null)); // Find attributes to collect - check groups in configuration. For each, // check scheduled nodes to see if that group should be collected final WmiCollection collection = WmiDataCollectionConfigFactory.getInstance().getWmiCollection(collectionName); final WmiAgentState agentState = m_scheduledNodes.get(agent.getNodeId()); // Load the attribute group types. loadAttributeGroupList(collection); // Load the attribute types. loadAttributeTypeList(collection); // Create a new collection set. final WmiCollectionSet collectionSet = new WmiCollectionSet(agent); collectionSet.setCollectionTimestamp(new Date()); // Iterate through the WMI collection groups. for (final Wpm wpm : collection.getWpms().getWpm()) { // A wpm consists of a list of attributes, identified by name if (agentState.shouldCheckAvailability(wpm.getName(), wpm.getRecheckInterval())) { if (!isGroupAvailable(agentState, wpm)) { continue; } } if (agentState.groupIsAvailable(wpm.getName())) { WmiClient client = null; // Collect the data try { // Tell the agent to connect agentState.connect(); // And retrieve the client object for working. client = (WmiClient) agentState.getWmiClient(); // Retrieve the WbemObjectSet from the class defined on the group. final OnmsWbemObjectSet wOS = client.performInstanceOf(wpm.getWmiClass()); // If we received a WbemObjectSet result, lets go through it and collect it. if (wOS != null) { // Go through each object (class instance) in the object set. for (int i = 0; i < wOS.count(); i++) { // Create a new collection resource. WmiCollectionResource resource = null; // Fetch our WBEM Object final OnmsWbemObject obj = wOS.get(i); // If this is multi-instance, fetch the instance name and store it. if(wOS.count()>1) { // Fetch the value of the key value. e.g. Name. final OnmsWbemProperty prop = obj.getWmiProperties().getByName(wpm.getKeyvalue()); final Object propVal = prop.getWmiValue(); String instance = null; if(propVal instanceof String) { instance = (String)propVal; } else { instance = propVal.toString(); } resource = new WmiMultiInstanceCollectionResource(agent,instance,wpm.getResourceType()); } else { resource = new WmiSingleInstanceCollectionResource(agent); } for (final Attrib attrib : wpm.getAttrib()) { final OnmsWbemProperty prop = obj.getWmiProperties().getByName(attrib.getWmiObject()); final WmiCollectionAttributeType attribType = m_attribTypeList.get(attrib.getName()); resource.setAttributeValue(attribType, prop.getWmiValue().toString()); } collectionSet.getResources().add(resource); } } } catch (final WmiException e) { LogUtils.infof(this, e, "unable to collect params for wpm '%s'", wpm.getName()); } finally { if (client != null) { try { client.disconnect(); } catch (final WmiException e) { LogUtils.warnf(this, e, "An error occurred disconnecting while collecting from WMI."); } } } } } collectionSet.setStatus(ServiceCollector.COLLECTION_SUCCEEDED); return collectionSet; } private void loadAttributeGroupList(final WmiCollection collection) { for (final Wpm wpm : collection.getWpms().getWpm()) { final AttributeGroupType attribGroupType1 = new AttributeGroupType(wpm.getName(), wpm.getIfType()); m_groupTypeList.put(wpm.getName(), attribGroupType1); } } private void loadAttributeTypeList(final WmiCollection collection) { for (final Wpm wpm : collection.getWpms().getWpm()) { for (final Attrib attrib : wpm.getAttrib()) { final AttributeGroupType attribGroupType = m_groupTypeList.get(wpm.getName()); final WmiCollectionAttributeType attribType = new WmiCollectionAttributeType(attrib, attribGroupType); m_attribTypeList.put(attrib.getName(), attribType); } } } private boolean isGroupAvailable(final WmiAgentState agentState, final Wpm wpm) { LogUtils.debugf(this, "Checking availability of group %s", wpm.getName()); WmiManager manager = null; /* * We provide a bogus comparison value and use an operator of "NOOP" * to ensure that, regardless of results, we receive a result and perform * no logic. We're only validating that the agent is reachable and gathering * the result objects. */ try { // Get and initialize the WmiManager manager = agentState.getManager(); manager.init(); final WmiParams params = new WmiParams(WmiParams.WMI_OPERATION_INSTANCEOF, "not-applicable", "NOOP", wpm.getWmiClass(), wpm.getKeyvalue()); final WmiResult result = manager.performOp(params); final boolean isAvailable = (result.getResultCode() == WmiResult.RES_STATE_OK); agentState.setGroupIsAvailable(wpm.getName(), isAvailable); LogUtils.debugf(this, "Group %s is %s%s.", wpm.getName(), (isAvailable ? "" : "not "), "available"); } catch (final WmiException e) { // Log a warning signifying that this group is unavailable. LogUtils.warnf(this, e, "Error checking group (%s) availability.", wpm.getName()); // Set the group as unavailable. agentState.setGroupIsAvailable(wpm.getName(), false); // And then continue on to check the next wpm entry. return false; } finally { if (manager != null) { try { manager.close(); } catch (WmiException e) { LogUtils.warnf(this, e, "An error occurred closing the WMI Manager"); } } } return true; } /** {@inheritDoc} */ public void initialize(final Map<String, String> parameters) { LogUtils.debugf(this, "initialize: Initializing WmiCollector."); m_scheduledNodes.clear(); initWMIPeerFactory(); initWMICollectionConfig(); initDatabaseConnectionFactory(); initializeRrdRepository(); } private void initWMIPeerFactory() { LogUtils.debugf(this, "initialize: Initializing WmiPeerFactory"); try { WmiPeerFactory.init(); } catch (final MarshalException e) { LogUtils.errorf(this, e, "initialize: Error marshalling configuration."); throw new UndeclaredThrowableException(e); } catch (final ValidationException e) { LogUtils.errorf(this, e, "initialize: Error validating configuration."); throw new UndeclaredThrowableException(e); } catch (final IOException e) { LogUtils.errorf(this, e, "initialize: Error reading configuration."); throw new UndeclaredThrowableException(e); } } private void initWMICollectionConfig() { LogUtils.debugf(this, "initialize: Initializing collector: %s", getClass()); try { WmiDataCollectionConfigFactory.init(); } catch (final MarshalException e) { LogUtils.errorf(this, e, "initialize: Error marshalling configuration."); throw new UndeclaredThrowableException(e); } catch (ValidationException e) { LogUtils.errorf(this, e, "initialize: Error validating configuration."); throw new UndeclaredThrowableException(e); } catch (FileNotFoundException e) { LogUtils.errorf(this, e, "initialize: Error locating configuration."); throw new UndeclaredThrowableException(e); } catch (IOException e) { LogUtils.errorf(this, e, "initialize: Error reading configuration."); throw new UndeclaredThrowableException(e); } } private void initializeRrdRepository() { LogUtils.debugf(this, "initializeRrdRepository: Initializing RRD repo from WmiCollector..."); initializeRrdDirs(); } private void initializeRrdDirs() { /* * If the RRD file repository directory does NOT already exist, create * it. */ final File f = new File(WmiDataCollectionConfigFactory.getInstance().getRrdPath()); if (!f.isDirectory()) { if (!f.mkdirs()) { throw new RuntimeException("Unable to create RRD file repository. Path doesn't already exist and could not make directory: " + DataCollectionConfigFactory.getInstance().getRrdPath()); } } } private void initDatabaseConnectionFactory() { try { DataSourceFactory.init(); } catch (final Exception e) { LogUtils.errorf(this, e, "initDatabaseConnectionFactory: Error initializing DataSourceFactory."); throw new UndeclaredThrowableException(e); } } /** {@inheritDoc} */ public void initialize(final CollectionAgent agent, final Map<String, Object> parameters) { LogUtils.debugf(this, "initialize: Initializing WMI collection for agent: %s", agent); final Integer scheduledNodeKey = new Integer(agent.getNodeId()); WmiAgentState nodeState = m_scheduledNodes.get(scheduledNodeKey); if (nodeState != null) { LogUtils.infof(this, "initialize: Not scheduling interface for WMI collection: %s", nodeState.getAddress()); final StringBuffer sb = new StringBuffer(); sb.append("initialize service: "); sb.append(" for address: "); sb.append(nodeState.getAddress()); sb.append(" already scheduled for collection on node: "); sb.append(agent); LogUtils.debugf(this, sb.toString()); throw new IllegalStateException(sb.toString()); } else { nodeState = new WmiAgentState(agent.getInetAddress(), parameters); LogUtils.infof(this, "initialize: Scheduling interface for collection: %s", nodeState.getAddress()); m_scheduledNodes.put(scheduledNodeKey, nodeState); } } /** * <p>release</p> */ public void release() { m_scheduledNodes.clear(); } /** {@inheritDoc} */ public void release(final CollectionAgent agent) { final WmiAgentState nodeState = m_scheduledNodes.get((Integer) agent.getNodeId()); if (nodeState != null) { m_scheduledNodes.remove((Integer) agent.getNodeId()); } } /** {@inheritDoc} */ public RrdRepository getRrdRepository(final String collectionName) { return WmiDataCollectionConfigFactory.getInstance().getRrdRepository(collectionName); } }