/******************************************************************************* * This file is part of OpenNMS(R). * * Copyright (C) 2007-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.protocols.nsclient.collector; import java.beans.PropertyVetoException; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.lang.reflect.UndeclaredThrowableException; import java.net.InetAddress; import java.sql.SQLException; 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.InetAddressUtils; import org.opennms.core.utils.ThreadCategory; import org.opennms.netmgt.collectd.AbstractCollectionAttribute; import org.opennms.netmgt.collectd.AbstractCollectionResource; import org.opennms.netmgt.collectd.CollectionAgent; import org.opennms.netmgt.collectd.ServiceCollector; import org.opennms.netmgt.config.DataCollectionConfigFactory; import org.opennms.netmgt.config.DataSourceFactory; import org.opennms.netmgt.config.collector.AttributeGroupType; import org.opennms.netmgt.config.collector.CollectionAttribute; import org.opennms.netmgt.config.collector.CollectionAttributeType; import org.opennms.netmgt.config.collector.CollectionResource; import org.opennms.netmgt.config.collector.CollectionSet; import org.opennms.netmgt.config.collector.CollectionSetVisitor; import org.opennms.netmgt.config.collector.Persister; import org.opennms.netmgt.config.collector.ServiceParameters; import org.opennms.netmgt.config.nsclient.Attrib; import org.opennms.netmgt.config.nsclient.NsclientCollection; import org.opennms.netmgt.config.nsclient.Wpm; import org.opennms.netmgt.model.RrdRepository; import org.opennms.netmgt.model.events.EventProxy; import org.opennms.protocols.nsclient.NSClientAgentConfig; import org.opennms.protocols.nsclient.NsclientCheckParams; import org.opennms.protocols.nsclient.NsclientException; import org.opennms.protocols.nsclient.NsclientManager; import org.opennms.protocols.nsclient.NsclientPacket; import org.opennms.protocols.nsclient.config.NSClientDataCollectionConfigFactory; import org.opennms.protocols.nsclient.config.NSClientPeerFactory; /** * <p>NSClientCollector class.</p> * * @author ranger * @version $Id: $ */ public class NSClientCollector 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, NSClientAgentState> m_scheduledNodes = new HashMap<Integer, NSClientAgentState>(); private ThreadCategory log() { return ThreadCategory.getInstance(getClass()); } class NSClientCollectionAttributeType implements CollectionAttributeType { Attrib m_attribute; AttributeGroupType m_groupType; protected NSClientCollectionAttributeType(Attrib attribute, AttributeGroupType groupType) { m_groupType=groupType; m_attribute=attribute; } public AttributeGroupType getGroupType() { return m_groupType; } public void storeAttribute(CollectionAttribute attribute, Persister persister) { //Only numeric data comes back from NSClient in data collection persister.persistNumericAttribute(attribute); } public String getName() { return m_attribute.getAlias(); } public String getType() { return m_attribute.getType(); } } class NSClientCollectionAttribute extends AbstractCollectionAttribute implements CollectionAttribute { String m_alias; String m_value; NSClientCollectionResource m_resource; CollectionAttributeType m_attribType; NSClientCollectionAttribute(NSClientCollectionResource resource, CollectionAttributeType attribType, String alias, String value) { super(); m_resource=resource; m_attribType=attribType; m_alias = alias; m_value = value; } public CollectionAttributeType getAttributeType() { return m_attribType; } public String getName() { return m_alias; } public String getNumericValue() { return m_value; } public CollectionResource getResource() { return m_resource; } public String getStringValue() { return m_value; //Should this be null instead? } public boolean shouldPersist(ServiceParameters params) { return true; } public String getType() { return m_attribType.getType(); } public String toString() { return "NSClientCollectionAttribute " + m_alias+"=" + m_value; } } class NSClientCollectionResource extends AbstractCollectionResource { NSClientCollectionResource(CollectionAgent agent) { super(agent); } public int getType() { return -1; //Is this right? } //A rescan is never needed for the NSClientCollector, at least on resources public boolean rescanNeeded() { return false; } public boolean shouldPersist(ServiceParameters params) { return true; } public void setAttributeValue(CollectionAttributeType type, String value) { NSClientCollectionAttribute attr = new NSClientCollectionAttribute(this, type, type.getName(), value); addAttribute(attr); } public String getResourceTypeName() { return "node"; //All node resources for NSClient; nothing of interface or "indexed resource" type } public String getInstance() { return null; //For node type resources, use the default instance } public String getParent() { return Integer.toString(m_agent.getNodeId()); } } class NSClientCollectionSet implements CollectionSet { private int m_status; private Date m_timestamp; private NSClientCollectionResource m_collectionResource; NSClientCollectionSet(CollectionAgent agent, Date timestamp) { m_status = ServiceCollector.COLLECTION_FAILED; m_collectionResource = new NSClientCollectionResource(agent); } public int getStatus() { return m_status; } void setStatus(int status) { m_status = status; } public void visit(CollectionSetVisitor visitor) { visitor.visitCollectionSet(this); m_collectionResource.visit(visitor); visitor.completeCollectionSet(this); } public NSClientCollectionResource getResource() { return m_collectionResource; } public boolean ignorePersist() { return false; } @Override public Date getCollectionTimestamp() { return m_timestamp; } } /** {@inheritDoc} */ public CollectionSet collect(CollectionAgent agent, EventProxy eproxy, Map<String, Object> parameters) { int status = ServiceCollector.COLLECTION_FAILED; final ServiceParameters serviceParams = new ServiceParameters(parameters); String collectionName = serviceParams.getCollectionName(); // Find attributes to collect - check groups in configuration. For each, // check scheduled nodes to see if that group should be collected NsclientCollection collection = NSClientDataCollectionConfigFactory.getInstance().getNSClientCollection(collectionName); NSClientAgentState agentState = m_scheduledNodes.get(agent.getNodeId()); NSClientCollectionSet collectionSet=new NSClientCollectionSet(agent, new Date()); NSClientCollectionResource collectionResource=collectionSet.getResource(); for (Wpm wpm : collection.getWpms().getWpm()) { //All NSClient Perfmon counters are per node AttributeGroupType attribGroupType=new AttributeGroupType(wpm.getName(),"all"); // A wpm consists of a list of attributes, identified by name if (agentState.shouldCheckAvailability(wpm.getName(), wpm.getRecheckInterval())) { log().debug("Checking availability of group " + wpm.getName()); NsclientManager manager = null; try { manager = agentState.getManager(); manager.init(); NsclientCheckParams params = new NsclientCheckParams(wpm.getKeyvalue()); NsclientPacket result = manager.processCheckCommand(NsclientManager.CHECK_COUNTER, params); manager.close(); boolean isAvailable = (result.getResultCode() == NsclientPacket.RES_STATE_OK); agentState.setGroupIsAvailable(wpm.getName(), isAvailable); log().debug("Group "+wpm.getName()+" is "+(isAvailable?"":"not")+"available "); } catch (NsclientException e) { log().error("Error checking group (" + wpm.getName() + ") availability", e); agentState.setGroupIsAvailable(wpm.getName(), false); } finally { if (manager != null) { manager.close(); } } } if (agentState.groupIsAvailable(wpm.getName())) { // Collect the data try { NsclientManager manager = agentState.getManager(); manager.init(); // Open the connection, then do each // attribute for (Attrib attrib : wpm.getAttrib()) { NsclientPacket result = null; try { NsclientCheckParams params = new NsclientCheckParams(attrib.getName()); result = manager.processCheckCommand(NsclientManager.CHECK_COUNTER, params); } catch (NsclientException e) { log().info("unable to collect params for attribute '" + attrib.getName() + "'", e); } if (result != null) { if (result.getResultCode() != NsclientPacket.RES_STATE_OK) { log().info("not writing parameters for attribute '" + attrib.getName() + "', state is not 'OK'"); } else { NSClientCollectionAttributeType attribType=new NSClientCollectionAttributeType(attrib, attribGroupType); collectionResource.setAttributeValue(attribType, result.getResponse()); status = ServiceCollector.COLLECTION_SUCCEEDED; } } } manager.close(); // Only close once all the attribs have // been done (optimizing as much as // possible with NSClient) } catch (NsclientException e) { log().error("Error collecting data", e); } } } collectionSet.setStatus(status); return collectionSet; } /** {@inheritDoc} */ public void initialize(Map<String, String> parameters) { log().debug("initialize: Initializing NSClientCollector."); m_scheduledNodes.clear(); initNSClientPeerFactory(); initNSClientCollectionConfig(); initDatabaseConnectionFactory(); initializeRrdRepository(); } private void initNSClientPeerFactory() { log().debug("initialize: Initializing NSClientPeerFactory"); try { NSClientPeerFactory.init(); } catch (MarshalException e) { log().fatal("initialize: Error marshalling configuration.", e); throw new UndeclaredThrowableException(e); } catch (ValidationException e) { log().fatal("initialize: Error validating configuration.", e); throw new UndeclaredThrowableException(e); } catch (IOException e) { log().fatal("initialize: Error reading configuration", e); throw new UndeclaredThrowableException(e); } } private void initNSClientCollectionConfig() { log().debug("initialize: Initializing collector: " + getClass()); try { NSClientDataCollectionConfigFactory.init(); } catch (MarshalException e) { log().fatal("initialize: Error marshalling configuration.", e); throw new UndeclaredThrowableException(e); } catch (ValidationException e) { log().fatal("initialize: Error validating configuration.", e); throw new UndeclaredThrowableException(e); } catch (FileNotFoundException e) { log().fatal("initialize: Error locating configuration.", e); throw new UndeclaredThrowableException(e); } catch (IOException e) { log().fatal("initialize: Error reading configuration", e); throw new UndeclaredThrowableException(e); } } private void initializeRrdRepository() { log().debug("initializeRrdRepository: Initializing RRD repo from NSClientCollector..."); initializeRrdDirs(); } private void initializeRrdDirs() { /* * If the RRD file repository directory does NOT already exist, create * it. */ File f = new File(NSClientDataCollectionConfigFactory.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 (IOException e) { log().fatal("initDatabaseConnectionFactory: IOException getting database connection", e); throw new UndeclaredThrowableException(e); } catch (MarshalException e) { log().fatal("initDatabaseConnectionFactory: Marshall Exception getting database connection", e); throw new UndeclaredThrowableException(e); } catch (ValidationException e) { log().fatal("initDatabaseConnectionFactory: Validation Exception getting database connection", e); throw new UndeclaredThrowableException(e); } catch (SQLException e) { log().fatal("initDatabaseConnectionFactory: Failed getting connection to the database.", e); throw new UndeclaredThrowableException(e); } catch (PropertyVetoException e) { log().fatal("initDatabaseConnectionFactory: Failed getting connection to the database.", e); throw new UndeclaredThrowableException(e); } catch (ClassNotFoundException e) { log().fatal("initDatabaseConnectionFactory: Failed loading database driver.", e); throw new UndeclaredThrowableException(e); } } /** {@inheritDoc} */ public void initialize(CollectionAgent agent, Map<String, Object> parameters) { log().debug("initialize: Initializing NSClient collection for agent: " + agent); Integer scheduledNodeKey = agent.getNodeId(); NSClientAgentState nodeState = m_scheduledNodes.get(scheduledNodeKey); if (nodeState != null) { log().info("initialize: Not scheduling interface for NSClient collection: " + 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); log().debug(sb.toString()); throw new IllegalStateException(sb.toString()); } else { nodeState = new NSClientAgentState(agent.getInetAddress(), parameters); log().info("initialize: Scheduling interface for collection: " + nodeState.getAddress()); m_scheduledNodes.put(scheduledNodeKey, nodeState); } } /** * <p>release</p> */ public void release() { m_scheduledNodes.clear(); } /** {@inheritDoc} */ public void release(final CollectionAgent agent) { final Integer scheduledNodeKey = agent.getNodeId(); NSClientAgentState nodeState = m_scheduledNodes.get(scheduledNodeKey); if (nodeState != null) { m_scheduledNodes.remove(scheduledNodeKey); } } private class NSClientAgentState { private NsclientManager m_manager; private NSClientAgentConfig m_agentConfig; // Do we need to keep this? private String m_address; private HashMap<String, NSClientGroupState> m_groupStates = new HashMap<String, NSClientGroupState>(); public NSClientAgentState(InetAddress address, Map<String, Object> parameters) { m_address = InetAddressUtils.str(address); m_agentConfig = NSClientPeerFactory.getInstance().getAgentConfig(address); m_manager = new NsclientManager(m_address); m_manager.setPassword(m_agentConfig.getPassword()); m_manager.setTimeout(m_agentConfig.getTimeout()); m_manager.setPortNumber(m_agentConfig.getPort()); } public String getAddress() { return m_address; } public NsclientManager getManager() { return m_manager; } public boolean groupIsAvailable(String groupName) { NSClientGroupState groupState = m_groupStates.get(groupName); if (groupState == null) { return false; // If the group availability hasn't been set // yet, it's not available. } return groupState.isAvailable(); } public void setGroupIsAvailable(String groupName, boolean available) { NSClientGroupState groupState = m_groupStates.get(groupName); if (groupState == null) { groupState = new NSClientGroupState(available); } groupState.setAvailable(available); m_groupStates.put(groupName, groupState); } public boolean shouldCheckAvailability(String groupName, int recheckInterval) { NSClientGroupState groupState = m_groupStates.get(groupName); if (groupState == null) { // If the group hasn't got a status yet, then it should be // checked regardless (and setGroupIsAvailable will // be called soon to create the status object) return true; } Date lastchecked = groupState.getLastChecked(); Date now = new Date(); return (now.getTime() - lastchecked.getTime() > recheckInterval); } @SuppressWarnings("unused") public void didCheckGroupAvailability(String groupName) { NSClientGroupState groupState = m_groupStates.get(groupName); if (groupState == null) { // Probably an error - log it as a warning, and give up log().warn("didCheckGroupAvailability called on a group without state - this is odd"); return; } groupState.setLastChecked(new Date()); } } private class NSClientGroupState { private boolean available = false; private Date lastChecked; public NSClientGroupState(boolean isAvailable) { this(isAvailable, new Date()); } public NSClientGroupState(boolean isAvailable, Date lastChecked) { this.available = isAvailable; this.lastChecked = lastChecked; } public boolean isAvailable() { return available; } public void setAvailable(boolean available) { this.available = available; } public Date getLastChecked() { return lastChecked; } public void setLastChecked(Date lastChecked) { this.lastChecked = lastChecked; } } /** {@inheritDoc} */ public RrdRepository getRrdRepository(String collectionName) { return NSClientDataCollectionConfigFactory.getInstance().getRrdRepository(collectionName); } }