/*******************************************************************************
* 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.threshd;
import java.io.File;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import junit.framework.Assert;
import org.apache.log4j.Level;
import org.easymock.EasyMock;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.opennms.core.resource.Vault;
import org.opennms.core.test.MockLogAppender;
import org.opennms.netmgt.collectd.CollectionAgent;
import org.opennms.netmgt.collectd.IfInfo;
import org.opennms.netmgt.collectd.IfResourceType;
import org.opennms.netmgt.collectd.NodeInfo;
import org.opennms.netmgt.collectd.NodeResourceType;
import org.opennms.netmgt.collectd.NumericAttributeType;
import org.opennms.netmgt.collectd.OnmsSnmpCollection;
import org.opennms.netmgt.collectd.SnmpAttribute;
import org.opennms.netmgt.collectd.SnmpAttributeType;
import org.opennms.netmgt.collectd.SnmpCollectionResource;
import org.opennms.netmgt.collectd.SnmpIfData;
import org.opennms.netmgt.config.DataSourceFactory;
import org.opennms.netmgt.config.MibObject;
import org.opennms.netmgt.config.collector.AttributeGroupType;
import org.opennms.netmgt.config.collector.CollectionAttribute;
import org.opennms.netmgt.config.collector.ServiceParameters;
import org.opennms.netmgt.mock.MockDataCollectionConfig;
import org.opennms.netmgt.mock.MockDatabase;
import org.opennms.netmgt.mock.MockNetwork;
import org.opennms.netmgt.model.OnmsNode;
import org.opennms.netmgt.model.OnmsSnmpInterface;
import org.opennms.netmgt.model.RrdRepository;
import org.opennms.netmgt.snmp.SnmpUtils;
import org.opennms.netmgt.snmp.SnmpValue;
/**
* @author <a href="mailto:agalue@opennms.org">Alejandro Galue</a>
*
*/
public class CollectionResourceWrapperTest {
Level m_logLevelToCheck;
@Before
public void setUp() throws Exception {
CollectionResourceWrapper.s_cache.clear();
m_logLevelToCheck = Level.WARN;
MockLogAppender.setupLogging();
}
@After
public void tearDown() throws Exception {
MockLogAppender.assertNotGreaterOrEqual(m_logLevelToCheck);
}
@Test
public void testGetGaugeValue() throws Exception {
// Create Resource
CollectionAgent agent = createCollectionAgent();
SnmpCollectionResource resource = createNodeResource(agent);
// Add Gauge Attribute
Map<String, CollectionAttribute> attributes = new HashMap<String, CollectionAttribute>();
SnmpAttribute attribute = addAttributeToCollectionResource(resource, "myGauge", "gauge", "0", 100);
attributes.put(attribute.getName(), attribute);
// Create Wrapper
CollectionResourceWrapper wrapper = createWrapper(resource, attributes);
// Get gauge value 3 times
Assert.assertEquals(100.0, wrapper.getAttributeValue("myGauge"));
Assert.assertEquals(100.0, wrapper.getAttributeValue("myGauge"));
Assert.assertEquals(100.0, wrapper.getAttributeValue("myGauge"));
EasyMock.verify(agent);
}
@Test
public void testGetCounterValue() throws Exception {
// Create Resource
CollectionAgent agent = createCollectionAgent();
SnmpCollectionResource resource = createNodeResource(agent);
// Add Counter Attribute
String attributeName = "myCounter";
String attributeId = "node[1]." + attributeName;
Map<String, CollectionAttribute> attributes = new HashMap<String, CollectionAttribute>();
SnmpAttribute attribute = addAttributeToCollectionResource(resource, attributeName, "counter", "0", 1000);
attributes.put(attribute.getName(), attribute);
//We manipulate the Date objects passed to the CollectionResourceWrapper to simulate various collection intervals
Date baseDate = new Date();
// Get counter value - first time
CollectionResourceWrapper wrapper = createWrapper(resource, attributes, baseDate);
Assert.assertFalse(CollectionResourceWrapper.s_cache.containsKey(attributeId));
Assert.assertEquals(Double.NaN, wrapper.getAttributeValue(attributeName)); // Last value is null
Assert.assertEquals(Double.NaN, wrapper.getAttributeValue(attributeName)); // Last value is null
Assert.assertEquals(1000.0, CollectionResourceWrapper.s_cache.get(attributeId).value);
// Increase counter
attribute = addAttributeToCollectionResource(resource, attributeName, "counter", "0", 2500);
attributes.put(attribute.getName(), attribute);
//Next wrapper is told the data was collected 5 minutes in the future (300 seconds)
wrapper = createWrapper(resource, attributes, new Date(baseDate.getTime()+300000));
// Get counter value - second time
// Last value is 1000.0, so 2500-1000/300 = 1500/300 = 5.
Assert.assertEquals(1000.0, CollectionResourceWrapper.s_cache.get(attributeId).value);
Assert.assertEquals(5.0, wrapper.getAttributeValue(attributeName));
//Validate that the cached counter value has been updated
Assert.assertEquals(2500.0, CollectionResourceWrapper.s_cache.get(attributeId).value);
//but that calling getAttributeValue doesn't re-calculate the rate inappropriately
Assert.assertEquals(5.0, wrapper.getAttributeValue(attributeName));
Assert.assertEquals(2500.0, CollectionResourceWrapper.s_cache.get(attributeId).value);
Assert.assertEquals(5.0, wrapper.getAttributeValue(attributeName));
Assert.assertEquals(2500.0, CollectionResourceWrapper.s_cache.get(attributeId).value);
// Increase counter
attribute = addAttributeToCollectionResource(resource, attributeName, "counter", "0", 5500);
attributes.put(attribute.getName(), attribute);
//Next wrapper is told the data was collected 10 minutes in the future (600 seconds), or after the first collection
wrapper = createWrapper(resource, attributes, new Date(baseDate.getTime()+600000));
// Get counter value - third time
// Last value is 2500.0, so 5500-2500/300 = 3000/300 = 10;
Assert.assertEquals(2500.0, CollectionResourceWrapper.s_cache.get(attributeId).value);
Assert.assertEquals(10.0, wrapper.getAttributeValue(attributeName));
Assert.assertEquals(5500.0, CollectionResourceWrapper.s_cache.get(attributeId).value);
Assert.assertEquals(10.0, wrapper.getAttributeValue(attributeName));
Assert.assertEquals(5500.0, CollectionResourceWrapper.s_cache.get(attributeId).value);
Assert.assertEquals(10.0, wrapper.getAttributeValue(attributeName));
Assert.assertEquals(5500.0, CollectionResourceWrapper.s_cache.get(attributeId).value);
}
/**
* Per bug report NMS-4244, multiple calls to the getCounter functionality on CollectionResourceWrapper used to pay
* no mind of the actual time when samples were collected, instead assuming that it was the collection interval ago.
* When a collection cycle fails (entirely or partly) and thresholded values weren't available, the counter value
* was incorrectly calculated on the next succeeding cycle (taking the difference from the last successful
* collection and dividing by just a single collection interval.
*/
@Test
public void testGetCounterValueWithGap() throws Exception {
m_logLevelToCheck = Level.ERROR; // We're expecting a WARN; an ERROR or
// worse would be unexpected
CollectionAgent agent = createCollectionAgent();
SnmpCollectionResource resource = createNodeResource(agent);
// Add Counter Attribute
String attributeName = "myCounter";
String attributeId = "node[1]." + attributeName;
Map<String, CollectionAttribute> attributes = new HashMap<String, CollectionAttribute>();
SnmpAttribute attribute = addAttributeToCollectionResource(resource,
attributeName, "counter", "0", 1000);
attributes.put(attribute.getName(), attribute);
// We manipulate the Date objects passed to the
// CollectionResourceWrapper to simulate various collection intervals
Date baseDate = new Date();
// Get counter value - first time
CollectionResourceWrapper wrapper = createWrapper(resource, attributes,
baseDate);
Assert.assertFalse(CollectionResourceWrapper.s_cache
.containsKey(attributeId));
Assert.assertEquals(Double.NaN,
wrapper.getAttributeValue(attributeName)); // Last value is null
Assert.assertEquals(Double.NaN,
wrapper.getAttributeValue(attributeName)); // Last value is null
Assert.assertEquals(1000.0,
CollectionResourceWrapper.s_cache.get(attributeId).value);
// Increase counter
attribute = addAttributeToCollectionResource(resource, attributeName, "counter", "0", 2500);
attributes.put(attribute.getName(), attribute);
//Next wrapper is told the data was collected 5 minutes in the future (300 seconds)
wrapper = createWrapper(resource, attributes, new Date(baseDate.getTime()+300000));
// Get counter value - second time
// Last value is 1000.0, so 2500-1000/300 = 1500/300 = 5.
Assert.assertEquals(1000.0, CollectionResourceWrapper.s_cache.get(attributeId).value);
Assert.assertEquals(5.0, wrapper.getAttributeValue(attributeName));
//Validate that the cached counter value has been updated
Assert.assertEquals(2500.0, CollectionResourceWrapper.s_cache.get(attributeId).value);
//but that calling getAttributeValue doesn't re-calculate the rate inappropriately or update the static cache
Assert.assertEquals(5.0, wrapper.getAttributeValue(attributeName));
Assert.assertEquals(2500.0, CollectionResourceWrapper.s_cache.get(attributeId).value);
// Now create a collection that is missing the counter value; we're
// expecting null result and no cache updates
attributes = new HashMap<String, CollectionAttribute>();
attribute = addAttributeToCollectionResource(resource, "notMyCounter",
"counter", "0", 1000); // We want a value, just not one called "myCounter"
attributes.put(attribute.getName(), attribute);
// Next collection is 10 minutes (600 seconds) after the first.
wrapper = createWrapper(resource, attributes,
new Date(baseDate.getTime() + 600000));
// No change, so we expect the cache to have (and continue to) remain
// the same, and to get no attribute value out
Assert.assertEquals(2500.0,
CollectionResourceWrapper.s_cache.get(attributeId).value);
Assert.assertNull(wrapper.getAttributeValue(attributeName));
Assert.assertEquals(2500.0,
CollectionResourceWrapper.s_cache.get(attributeId).value);
// Now if we collect successfully again, we expect the counter to be the
// change divided by two collection cycles
attributes = new HashMap<String, CollectionAttribute>();
attribute = addAttributeToCollectionResource(resource, attributeName,
"counter", "0", 7300);
attributes.put(attribute.getName(), attribute);
// Next collection is 15 minutes (900 seconds) after the first.
wrapper = createWrapper(resource, attributes,
new Date(baseDate.getTime() + 900000));
// Get counter value - fourth time
// Last value is 5500, but we've had two collection cycles, so
// 7300-2500/600 = 4800/600 = 8
Assert.assertEquals(2500.0,
CollectionResourceWrapper.s_cache.get(attributeId).value);
Assert.assertEquals(8.0, wrapper.getAttributeValue(attributeName));
Assert.assertEquals(7300.0,
CollectionResourceWrapper.s_cache.get(attributeId).value);
Assert.assertEquals(8.0, wrapper.getAttributeValue(attributeName));
Assert.assertEquals(7300.0,
CollectionResourceWrapper.s_cache.get(attributeId).value);
Assert.assertEquals(8.0, wrapper.getAttributeValue(attributeName));
Assert.assertEquals(7300.0,
CollectionResourceWrapper.s_cache.get(attributeId).value);
EasyMock.verify(agent);
}
@Test
public void testGetCounterValueWithWrap() throws Exception {
// Create Resource
CollectionAgent agent = createCollectionAgent();
SnmpCollectionResource resource = createNodeResource(agent);
// We manipulate the Date objects passed to the
// CollectionResourceWrapper to simulate various collection intervals
Date baseDate = new Date();
// Add Counter Attribute
String attributeName = "myCounter";
String attributeId = "node[1]." + attributeName;
Map<String, CollectionAttribute> attributes = new HashMap<String, CollectionAttribute>();
BigInteger initialValue = new BigDecimal(Math.pow(2, 32) - 20000).toBigInteger();
SnmpAttribute attribute = addAttributeToCollectionResource(resource, attributeName, "counter", "0", initialValue);
attributes.put(attribute.getName(), attribute);
// Get counter value - first time
CollectionResourceWrapper wrapper = createWrapper(resource, attributes, baseDate);
Assert.assertFalse(CollectionResourceWrapper.s_cache.containsKey(attributeId));
Assert.assertEquals(Double.NaN, wrapper.getAttributeValue(attributeName)); // Last value is null
Assert.assertEquals(Double.NaN, wrapper.getAttributeValue(attributeName)); // Last value is null
Assert.assertEquals(initialValue.doubleValue(), CollectionResourceWrapper.s_cache.get(attributeId).value);
// Increase counter
attribute = addAttributeToCollectionResource(resource, attributeName, "counter", "0", new BigInteger("40000"));
attributes.put(attribute.getName(), attribute);
wrapper = createWrapper(resource, attributes, new Date(baseDate.getTime() + 300000));
// Get counter value - second time (wrap)
// last = MAX - 20000, new = 40000; then last - new = 60000, rate: 60000/300 = 200
Assert.assertEquals(initialValue.doubleValue(), CollectionResourceWrapper.s_cache.get(attributeId).value);
Assert.assertEquals(200.0, wrapper.getAttributeValue(attributeName));
Assert.assertEquals(40000.0, CollectionResourceWrapper.s_cache.get(attributeId).value);
Assert.assertEquals(200.0, wrapper.getAttributeValue(attributeName));
Assert.assertEquals(40000.0, CollectionResourceWrapper.s_cache.get(attributeId).value);
Assert.assertEquals(200.0, wrapper.getAttributeValue(attributeName));
Assert.assertEquals(40000.0, CollectionResourceWrapper.s_cache.get(attributeId).value);
EasyMock.verify(agent);
}
@Test
public void testInterfaceResource() throws Exception {
// Set Defaults
String ipAddress = "10.0.0.1";
String ifName = "eth0";
int ifIndex = 2;
// Initialize Database
MockNetwork network = new MockNetwork();
network.setCriticalService("ICMP");
network.addNode(1, "testNode");
network.addInterface(ipAddress);
network.setIfAlias(ifName);
network.addService("ICMP");
network.addService("SNMP");
network.addService("HTTP");
MockDatabase db = new MockDatabase();
db.populate(network);
db.update("update snmpinterface set snmpifindex=?, snmpifname=?, snmpifdescr=? where id=?", ifIndex, ifName, ifName, 1);
DataSourceFactory.setInstance(db);
Vault.setDataSource(db);
// Create SnmpIfData
OnmsNode node = new OnmsNode();
node.setId(1);
node.setLabel("testNode");
OnmsSnmpInterface snmpIface = new OnmsSnmpInterface(node, ifIndex);
snmpIface.setIfDescr(ifName);
snmpIface.setIfName(ifName);
snmpIface.setIfAlias(ifName);
snmpIface.setIfSpeed(10000000l);
SnmpIfData ifData = new SnmpIfData(snmpIface);
// Creating IfResourceType
CollectionAgent agent = createCollectionAgent();
MockDataCollectionConfig dataCollectionConfig = new MockDataCollectionConfig();
OnmsSnmpCollection collection = new OnmsSnmpCollection(agent, new ServiceParameters(new HashMap<String, Object>()), dataCollectionConfig);
IfResourceType resourceType = new IfResourceType(agent, collection);
// Creating Resource
SnmpCollectionResource resource = new IfInfo(resourceType, agent, ifData);
SnmpAttribute attribute = addAttributeToCollectionResource(resource, "ifInOctets", "counter", "ifIndex", 5000);
Map<String, CollectionAttribute> attributes = new HashMap<String, CollectionAttribute>();
attributes.put(attribute.getName(), attribute);
// Create Wrapper
CollectionResourceWrapper wrapper = createWrapper(resource, attributes);
// Validations
Assert.assertEquals(node.getId().intValue(), wrapper.getNodeId());
Assert.assertEquals("127.0.0.1", wrapper.getHostAddress()); // Should be the address of the SNMP Agent (Bug 3808)
Assert.assertEquals("eth0", wrapper.getIfLabel());
Assert.assertEquals("if", wrapper.getResourceTypeName());
Assert.assertEquals("SNMP", wrapper.getServiceName());
Assert.assertEquals(true, wrapper.isAnInterfaceResource());
Assert.assertEquals(Integer.toString(ifIndex), wrapper.getInstance());
Assert.assertEquals(Integer.toString(ifIndex), wrapper.getIfIndex());
Assert.assertEquals(Integer.toString(ifIndex), wrapper.getIfIndex()); // IfLabel is called only once
Assert.assertEquals(Integer.toString(ifIndex), wrapper.getIfIndex()); // IfLabel is called only once
Assert.assertEquals("eth0", wrapper.getIfInfoValue("snmpifname")); // IfLabel is called only once
}
private SnmpCollectionResource createNodeResource(CollectionAgent agent) {
MockDataCollectionConfig dataCollectionConfig = new MockDataCollectionConfig();
OnmsSnmpCollection collection = new OnmsSnmpCollection(agent, new ServiceParameters(new HashMap<String, Object>()), dataCollectionConfig);
NodeResourceType resourceType = new NodeResourceType(agent, collection);
return new NodeInfo(resourceType, agent);
}
// Wrapper interval value for counter rates calculation should be expressed in seconds.
private CollectionResourceWrapper createWrapper(SnmpCollectionResource resource, Map<String, CollectionAttribute> attributes, Date timestamp) {
CollectionResourceWrapper wrapper = new CollectionResourceWrapper(timestamp, 1, "127.0.0.1", "SNMP", getRepository(), resource, attributes);
return wrapper;
}
private CollectionResourceWrapper createWrapper(SnmpCollectionResource resource, Map<String, CollectionAttribute> attributes) {
return this.createWrapper(resource, attributes, new Date());
}
private CollectionAgent createCollectionAgent() {
CollectionAgent agent = EasyMock.createMock(CollectionAgent.class);
EasyMock.expect(agent.getNodeId()).andReturn(1).anyTimes();
EasyMock.expect(agent.getHostAddress()).andReturn("127.0.0.1").anyTimes();
EasyMock.expect(agent.getSnmpInterfaceInfo((IfResourceType)EasyMock.anyObject())).andReturn(new HashSet<IfInfo>()).anyTimes();
EasyMock.replay(agent);
return agent;
}
private SnmpAttribute addAttributeToCollectionResource(SnmpCollectionResource resource, String attributeName, String attributeType, String attributeInstance, long value) {
MibObject object = createMibObject(attributeType, attributeName, attributeInstance);
SnmpAttributeType objectType = new NumericAttributeType(resource.getResourceType(), "default", object, new AttributeGroupType("mibGroup", "ignore"));
SnmpValue snmpValue = attributeType.equals("counter") ? SnmpUtils.getValueFactory().getCounter32(value) : SnmpUtils.getValueFactory().getGauge32(value);
resource.setAttributeValue(objectType, snmpValue);
return new SnmpAttribute(resource, objectType, snmpValue);
}
private SnmpAttribute addAttributeToCollectionResource(SnmpCollectionResource resource, String attributeName, String attributeType, String attributeInstance, BigInteger value) {
MibObject object = createMibObject(attributeType, attributeName, attributeInstance);
SnmpAttributeType objectType = new NumericAttributeType(resource.getResourceType(), "default", object, new AttributeGroupType("mibGroup", "ignore"));
SnmpValue snmpValue = SnmpUtils.getValueFactory().getCounter64(value);
resource.setAttributeValue(objectType, snmpValue);
return new SnmpAttribute(resource, objectType, snmpValue);
}
private MibObject createMibObject(String type, String alias, String instance) {
MibObject mibObject = new MibObject();
mibObject.setOid(".1.1.1.1");
mibObject.setAlias(alias);
mibObject.setType(type);
mibObject.setInstance(instance);
mibObject.setMaxval(null);
mibObject.setMinval(null);
return mibObject;
}
private RrdRepository getRepository() {
RrdRepository repo = new RrdRepository();
repo.setRrdBaseDir(new File("/tmp"));
return repo;
}
}