/******************************************************************************* * This file is part of OpenNMS(R). * * Copyright (C) 2008-2012 The OpenNMS Group, Inc. * OpenNMS(R) is Copyright (C) 1999-2012 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.tca; import java.io.File; import java.util.ArrayList; import java.util.Date; import java.util.List; import org.opennms.core.utils.ThreadCategory; import org.opennms.netmgt.collectd.CollectionAgent; import org.opennms.netmgt.collectd.CollectionException; import org.opennms.netmgt.collectd.CollectionTimedOut; import org.opennms.netmgt.collectd.CollectionWarning; import org.opennms.netmgt.collectd.ServiceCollector; import org.opennms.netmgt.config.collector.AttributeGroupType; 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.dao.support.ResourceTypeUtils; import org.opennms.netmgt.model.RrdRepository; import org.opennms.netmgt.snmp.SnmpUtils; import org.opennms.netmgt.snmp.SnmpWalker; /** * The Class TcaCollectionSet. * * @author Alejandro Galue <agalue@opennms.org> */ public class TcaCollectionSet implements CollectionSet { /** The Constant LAST_TIMESTAMP. */ public static final String LAST_TIMESTAMP = "__tcaLastTimestamp"; /** The Constant INBOUND_DELAY. */ public static final String INBOUND_DELAY = "inboundDelay"; /** The Constant INBOUND_JITTER. */ public static final String INBOUND_JITTER = "inboundJitter"; /** The Constant OUTBOUND_DELAY. */ public static final String OUTBOUND_DELAY = "outboundDelay"; /** The Constant OUTBOUND_JITTER. */ public static final String OUTBOUND_JITTER = "outboundJitter"; /** The Constant TIMESYNC_STATUS. */ public static final String TIMESYNC_STATUS = "timesyncStatus"; /** The Collection Status. */ private int m_status; /** The list of SNMP collection resources. */ private List<TcaCollectionResource> m_collectionResources; /** The Collection timestamp. */ private Date m_timestamp; /** The Colelction Agent. */ private CollectionAgent m_agent; /** The RRD Repository. */ private RrdRepository m_rrdRepository; /** * Instantiates a new TCA collection set. * * @param agent the agent * @param repository the repository */ public TcaCollectionSet(CollectionAgent agent, RrdRepository repository) { m_status = ServiceCollector.COLLECTION_FAILED; m_collectionResources = new ArrayList<TcaCollectionResource>(); m_agent = agent; m_rrdRepository = repository; } /* (non-Javadoc) * @see org.opennms.netmgt.config.collector.CollectionSet#getStatus() */ @Override public int getStatus() { return m_status; } /* (non-Javadoc) * @see org.opennms.netmgt.config.collector.CollectionSet#visit(org.opennms.netmgt.config.collector.CollectionSetVisitor) */ @Override public void visit(CollectionSetVisitor visitor) { visitor.visitCollectionSet(this); for (CollectionResource resource : m_collectionResources) { resource.visit(visitor); } visitor.completeCollectionSet(this); } /* (non-Javadoc) * @see org.opennms.netmgt.config.collector.CollectionSet#ignorePersist() */ @Override public boolean ignorePersist() { return false; } /* (non-Javadoc) * @see org.opennms.netmgt.config.collector.CollectionSet#getCollectionTimestamp() */ @Override public Date getCollectionTimestamp() { return m_timestamp; } /** * Sets the collection timestamp. * * @param date the new collection timestamp */ public void setCollectionTimestamp(Date date) { m_timestamp = date; } /** * Collect. * * @throws CollectionException the collection exception */ protected void collect() throws CollectionException { try { TcaData tracker = new TcaData(m_agent.getInetAddress()); SnmpWalker walker = SnmpUtils.createWalker(m_agent.getAgentConfig(), "TcaCollector for " + m_agent.getHostAddress(), tracker); walker.start(); log().debug("collect: successfully instantiated " + "TCA Collector for " + m_agent.getHostAddress()); walker.waitFor(); log().info("collect: node TCA query for address " + m_agent.getHostAddress() + " complete."); verifySuccessfulWalk(walker); process(tracker); m_status = ServiceCollector.COLLECTION_SUCCEEDED; } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new CollectionWarning("Collection of node TCA data for interface " + m_agent.getHostAddress() + " interrupted: " + e, e); } catch (Exception e) { throw new CollectionException("Can't collect TCA data because " + e.getMessage(), e); } } /** * Gets the collection resources. * * @return the collection resources */ protected List<TcaCollectionResource> getCollectionResources() { return m_collectionResources; } /** * Process. * * <p>A sample TCA Data looks like the following:</p> * <ul> * <li>OID=.1.3.6.1.4.1.27091.3.1.6.1.1.172.19.37.60.1, Type=OctetString, Value=172.19.37.60 </li> * <li>OID=.1.3.6.1.4.1.27091.3.1.6.1.2.172.19.37.60.1, Type=OctetString, Value= * |25|1327451762,11,0,11,0,1|1327451763,11,0,11,0,1|1327451764,11,0,11,0,1|1327451765,11,0,11,0,1|1327451766,11,0,11,0,1| * 1327451767,11,0,11,0,1|1327451768,11,0,11,0,1|1327451769,11,0,11,0,1|1327451770,11,0,11,0,1|1327451771,11,0,11,0,1| * 1327451772,11,0,11,0,1|1327451773,11,0,11,0,1|1327451774,11,0,11,0,1|1327451775,11,0,11,0,1|1327451776,11,0,11,0,1| * 1327451777,11,0,11,0,1|1327451778,11,0,11,0,1|1327451779,11,0,11,0,1|1327451780,11,0,11,0,1|1327451781,11,0,11,0,1| * 1327451782,11,0,11,0,1|1327451783,11,0,11,0,1|1327451784,11,0,11,0,1|1327451785,11,0,11,0,1|1327451786,11,0,11,0,1|</li> * </ul> * * <ul> * <li>timestamp (epoch)</li> * <li>delay local-remote ~ current inbound-delay</li> * <li>jitter local-remote ~ current inbound-jitter</li> * <li>delay remote-local ~ current outbound-delay</li> * <li>jitter remote-local ~ current outbound-jitter-</li> * <li>timesync status (1 = good, time is synced, 0 = bad, out-of sync)</li> * </ul> * * @param tracker the tracker * @throws Exception the exception */ private void process(TcaData tracker) throws Exception { log().debug("process: processing raw TCA data for " + tracker.size() + " peers."); AttributeGroupType attribGroupType = new AttributeGroupType(TcaCollectionResource.RESOURCE_TYPE_NAME, "all"); // It will be treated like a Multi-Instance Resource long timestamp = 0; for (TcaDataEntry entry : tracker.getEntries()) { long lastTimestamp = getLastTimestamp(new TcaCollectionResource(m_agent, entry.getPeerAddress())); String[] rawData = entry.getRawData().split("\\|"); int samples = Integer.parseInt(rawData[1]); for (int i=0; i<samples; i++) { log().debug("process: processing row " + i + ": " + rawData[2 + i]); String[] rawEntry = rawData[2 + i].split(","); timestamp = Long.parseLong(rawEntry[0]); if (timestamp > lastTimestamp) { TcaCollectionResource resource = new TcaCollectionResource(m_agent, entry.getPeerAddress()); resource.setTimeKeeper(new ConstantTimeKeeper(timestamp)); resource.setAttributeValue(new TcaCollectionAttributeType(attribGroupType, INBOUND_DELAY), rawEntry[1]); resource.setAttributeValue(new TcaCollectionAttributeType(attribGroupType, INBOUND_JITTER), rawEntry[2]); resource.setAttributeValue(new TcaCollectionAttributeType(attribGroupType, OUTBOUND_DELAY), rawEntry[3]); resource.setAttributeValue(new TcaCollectionAttributeType(attribGroupType, OUTBOUND_JITTER), rawEntry[4]); resource.setAttributeValue(new TcaCollectionAttributeType(attribGroupType, TIMESYNC_STATUS), rawEntry[5]); m_collectionResources.add(resource); } else { log().debug("process: skipping row " + i + " " + rawData[2 + i] + " because it was already processed."); } } setLastTimestamp(new TcaCollectionResource(m_agent, entry.getPeerAddress()), timestamp); } } /** * Log error and return COLLECTION_FAILED is there is a failure. * * @param walker the walker * @throws CollectionException the collection exception */ private void verifySuccessfulWalk(SnmpWalker walker) throws CollectionException { if (!walker.failed()) { return; } if (walker.timedOut()) { throw new CollectionTimedOut(walker.getErrorMessage()); } String message = "collection failed for " + m_agent.getHostAddress() + " due to: " + walker.getErrorMessage(); throw new CollectionWarning(message, walker.getErrorThrowable()); } /** * Gets the last timestamp. * * @param resource the TCA resource * @return the last timestamp * @throws Exception the exception */ private long getLastTimestamp(TcaCollectionResource resource) throws Exception { File file = null; long timestamp = 0; try { file = resource.getResourceDir(m_rrdRepository); String ts = ResourceTypeUtils.getStringProperty(resource.getResourceDir(m_rrdRepository), LAST_TIMESTAMP); if (ts != null) timestamp = Long.parseLong(ts); } catch (Exception e) { log().info("getLastFilename: creating a new filename tracker on " + file); } return timestamp; } /** * Sets the last timestamp. * * @param resource the resource * @param timestamp the timestamp * @throws Exception the exception */ private void setLastTimestamp(TcaCollectionResource resource, long timestamp) throws Exception { ResourceTypeUtils.updateStringProperty(resource.getResourceDir(m_rrdRepository), Long.toString(timestamp), LAST_TIMESTAMP); } /** * Log. * * @return the thread category */ private ThreadCategory log() { return ThreadCategory.getInstance(getClass()); } }