/*******************************************************************************
* This file is part of OpenNMS(R).
*
* Copyright (C) 2006-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.translator;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import org.exolab.castor.xml.MarshalException;
import org.exolab.castor.xml.ValidationException;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.opennms.core.test.MockLogAppender;
import org.opennms.netmgt.EventConstants;
import org.opennms.netmgt.config.DataSourceFactory;
import org.opennms.netmgt.config.EventTranslatorConfigFactory;
import org.opennms.netmgt.mock.EventAnticipator;
import org.opennms.netmgt.mock.MockDatabase;
import org.opennms.netmgt.mock.MockEventIpcManager;
import org.opennms.netmgt.mock.MockEventUtil;
import org.opennms.netmgt.mock.MockNetwork;
import org.opennms.netmgt.mock.OutageAnticipator;
import org.opennms.netmgt.model.events.EventBuilder;
import org.opennms.netmgt.model.events.EventUtils;
import org.opennms.netmgt.xml.event.Event;
import org.opennms.netmgt.xml.event.Logmsg;
import org.opennms.netmgt.xml.event.Parm;
import org.opennms.netmgt.xml.event.Value;
public class EventTranslatorTest {
/* TODO for PassiveSTatusKeeper
add reason mapper for status reason
be able to create an event with translated values
- determine new event values based on config
- assign computed values to new event
- copy over (or not) untranslated attributes
make sure we can translate uei if desired
modify passive status config to handle specific event with specific parms
*/
private EventTranslator m_translator;
private String m_passiveStatusConfiguration = getStandardConfig();
private MockEventIpcManager m_eventMgr;
private MockDatabase m_db;
private MockNetwork m_network;
private EventAnticipator m_anticipator;
private OutageAnticipator m_outageAnticipator;
private EventTranslatorConfigFactory m_config;
@Before
public void setUp() throws Exception {
// MockUtil.println("------------ Begin Test "+getName()+" --------------------------");
MockLogAppender.setupLogging();
createMockNetwork();
createMockDb();
createAnticipators();
m_eventMgr = new MockEventIpcManager();
m_eventMgr.setEventWriter(m_db);
m_eventMgr.setEventAnticipator(m_anticipator);
m_eventMgr.addEventListener(m_outageAnticipator);
m_eventMgr.setSynchronous(true);
InputStream rdr = new ByteArrayInputStream(m_passiveStatusConfiguration.getBytes("UTF-8"));
m_config = new EventTranslatorConfigFactory(rdr, m_db);
EventTranslatorConfigFactory.setInstance(m_config);
m_translator = EventTranslator.getInstance();
m_translator.setEventManager(m_eventMgr);
m_translator.setConfig(EventTranslatorConfigFactory.getInstance());
m_translator.setDataSource(m_db);
m_translator.init();
m_translator.start();
}
@After
public void tearDown() throws Exception {
m_eventMgr.finishProcessingEvents();
m_translator.stop();
sleep(200);
MockLogAppender.assertNoWarningsOrGreater();
m_db.drop();
// MockUtil.println("------------ End Test "+getName()+" --------------------------");
// super.tearDown();
}
private void createAnticipators() {
m_anticipator = new EventAnticipator();
m_outageAnticipator = new OutageAnticipator(m_db);
}
private void createMockDb() throws Exception {
m_db = new MockDatabase();
m_db.populate(m_network);
DataSourceFactory.setInstance(m_db);
}
private void createMockNetwork() {
m_network = new MockNetwork();
m_network.setCriticalService("ICMP");
m_network.addNode(1, "Router");
m_network.addInterface("192.168.1.1");
m_network.addService("ICMP");
m_network.addService("SMTP");
m_network.addInterface("192.168.1.2");
m_network.addService("ICMP");
m_network.addService("SMTP");
m_network.addNode(2, "Server");
m_network.addInterface("192.168.1.3");
m_network.addService("ICMP");
m_network.addService("HTTP");
m_network.addNode(3, "Firewall");
m_network.addInterface("192.168.1.4");
m_network.addService("SMTP");
m_network.addService("HTTP");
m_network.addInterface("192.168.1.5");
m_network.addService("SMTP");
m_network.addService("HTTP");
m_network.addNode(100, "localhost");
m_network.addInterface("127.0.0.1");
m_network.addService("PSV");
m_network.addService("PSV2");
}
private void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
}
}
@Test
public void testSubElementString() throws Exception {
m_passiveStatusConfiguration = getSqlSubValueString();
tearDown();
setUp();
testTranslateEvent();
}
@Test
public void testSubElementLong() throws Exception {
m_passiveStatusConfiguration = getSqlSubValueLong();
tearDown();
setUp();
testTranslateEvent();
}
@Test
public void testIsTranslationEvent() throws Exception {
// test non matching uei match fails
Event pse = createTestEvent("someOtherUei", "Router", "192.168.1.1", "ICMP", "Down");
assertFalse(m_config.isTranslationEvent(pse));
// test matchin uei succeeds
Event te = createTestEvent("translationTest", "Router", "192.168.1.1", "ICMP", "Down");
assertTrue(m_config.isTranslationEvent(te));
// test null parms fails
Event teWithNullParms = createTestEvent("translationTest", "Router", "192.168.1.1", "ICMP", "Down");
teWithNullParms.setParmCollection(null);
assertFalse(m_config.isTranslationEvent(teWithNullParms));
// test empty parm list fails
Event teWithNoParms = createTestEvent("translationTest", "Router", "192.168.1.1", "ICMP", "Down");
teWithNoParms.setParmCollection(new ArrayList<Parm>());
assertFalse(m_config.isTranslationEvent(teWithNoParms));
// test missing a parm fails
Event teWithWrongParms = createTestEvent("translationTest", "Router", "192.168.1.1", "ICMP", "Down");
List<Parm> p = teWithWrongParms.getParmCollection();
p.get(2).setParmName("unmatching"); // change the name for the third parm so it fails to match
assertFalse(m_config.isTranslationEvent(teWithWrongParms));
// that a matching parm value succeeds
Event te2 = createTestEvent("translationTest", "Router", "xxx192.168.1.1xxx", "ICMP", "Down");
assertTrue(m_config.isTranslationEvent(te2));
// that a matching parm value succeeds
Event te3 = createTestEvent("translationTest", "Router", "xxx192.168.1.2", "ICMP", "Down");
assertFalse(m_config.isTranslationEvent(te3));
}
@Test
public void testTranslateEvent() throws MarshalException, ValidationException {
// test non matching uei match fails
Event pse = createTestEvent("someOtherUei", "Router", "192.168.1.1", "ICMP", "Down");
assertTrue(m_config.translateEvent(pse).isEmpty());
// test matchin uei succeeds
Event te = createTestEvent("translationTest", "Router", "192.168.1.1", "ICMP", "This node is way Down!");
List<Event> translatedEvents = m_config.translateEvent(te);
assertNotNull(translatedEvents);
assertEquals(1, translatedEvents.size());
validateTranslatedEvent((Event)translatedEvents.get(0));
// test null parms fails
Event teWithNullParms = createTestEvent("translationTest", "Router", "192.168.1.1", "ICMP", "Down");
teWithNullParms.setParmCollection(null);
assertTrue(m_config.translateEvent(teWithNullParms).isEmpty());
// test empty parm list fails
Event teWithNoParms = createTestEvent("translationTest", "Router", "192.168.1.1", "ICMP", "Down");
teWithNoParms.setParmCollection(new ArrayList<Parm>());
assertTrue(m_config.translateEvent(teWithNoParms).isEmpty());
// test missing a parm fails
Event teWithWrongParms = createTestEvent("translationTest", "Router", "192.168.1.1", "ICMP", "Down");
List<Parm> p = teWithWrongParms.getParmCollection();
p.get(2).setParmName("unmatching"); // change the name for the third parm so it fails to match
assertTrue(m_config.translateEvent(teWithWrongParms).isEmpty());
// that a matching parm value succeeds
Event te2 = createTestEvent("translationTest", "Router", "xxx192.168.1.1xxx", "ICMP", "Down");
assertNotNull(m_config.translateEvent(te2));
assertEquals(1, translatedEvents.size());
validateTranslatedEvent((Event)translatedEvents.get(0));
// that a matching parm value succeeds
Event te3 = createTestEvent("translationTest", "Router", "xxx192.168.1.2", "ICMP", "Down");
assertTrue(m_config.translateEvent(te3).isEmpty());
}
@Test
public void testTranslateLinkDown() throws MarshalException, ValidationException, SQLException, UnsupportedEncodingException {
InputStream rdr = new ByteArrayInputStream(getLinkDownTranslation().getBytes("UTF-8"));
m_config = new EventTranslatorConfigFactory(rdr, m_db);
EventTranslatorConfigFactory.setInstance(m_config);
m_translator = EventTranslator.getInstance();
m_translator.setEventManager(m_eventMgr);
m_translator.setConfig(EventTranslatorConfigFactory.getInstance());
//m_translator.setDataSource(m_db);
Connection c = m_db.getConnection();
Statement stmt = c.createStatement();
stmt.executeUpdate("update snmpinterface set snmpifname = 'david', snmpifalias = 'p-brane' WHERE nodeid = 1 and snmpifindex = 2");
stmt.close();
c.close();
List<Event> translatedEvents = m_config.translateEvent(createLinkDownEvent());
assertNotNull(translatedEvents);
assertEquals(1, translatedEvents.size());
assertEquals(3, translatedEvents.get(0).getParmCollection().size());
assertEquals(".1.3.6.1.2.1.2.2.1.1.2", translatedEvents.get(0).getParmCollection().get(0).getParmName());
assertEquals("ifName", translatedEvents.get(0).getParmCollection().get(1).getParmName());
assertEquals("ifAlias", translatedEvents.get(0).getParmCollection().get(2).getParmName());
assertEquals("david", translatedEvents.get(0).getParmCollection().get(1).getValue().getContent());
assertEquals("p-brane", translatedEvents.get(0).getParmCollection().get(2).getValue().getContent());
}
private String getLinkDownTranslation() {
String linkDownConfig = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<event-translator-configuration xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
" xsi:schemaLocation=\"http://xmlns.opennms.org/xsd/translator-configuration http://www.opennms.org/xsd/config/translator-configuration.xsd \">\n" +
" <translation>\n" +
" <!-- This translation is predifined for integration with Hyperic-HQ server and the OpenNMS integrations found in\n" +
" the $OPENNMS_HOME/contrib/hyperic-integration directory -->\n" +
" <event-translation-spec uei=\"uei.opennms.org/generic/traps/SNMP_Link_Down\">\n" +
" <mappings>\n" +
" <mapping>\n" +
" <assignment name=\"ifName\" type=\"parameter\">\n" +
" <value type=\"sql\" result=\"SELECT snmp.snmpIfName FROM snmpInterface snmp WHERE snmp.nodeid = ?::integer AND snmp.snmpifindex = ?::integer\" >\n" +
" <value type=\"field\" name=\"nodeid\" matches=\".*\" result=\"${0}\" />\n" +
" <value type=\"parameter\" name=\"~^\\.1\\.3\\.6\\.1\\.2\\.1\\.2\\.2\\.1\\.1\\.([0-9]*)$\" matches=\".*\" result=\"${0}\" />\n" +
" </value>\n" +
" </assignment>\n" +
" <assignment name=\"ifAlias\" type=\"parameter\">\n" +
" <value type=\"sql\" result=\"SELECT snmp.snmpIfAlias FROM snmpInterface snmp WHERE snmp.nodeid = ?::integer AND snmp.snmpifindex = ?::integer\" >\n" +
" <value type=\"field\" name=\"nodeid\" matches=\".*\" result=\"${0}\" />\n" +
" <value type=\"parameter\" name=\"~^\\.1\\.3\\.6\\.1\\.2\\.1\\.2\\.2\\.1\\.1\\.([0-9]*)$\" matches=\".*\" result=\"${0}\" />\n" +
" </value>\n" +
" </assignment>\n" +
" </mapping>\n" +
" </mappings>\n" +
" </event-translation-spec>\n" +
" </translation>\n" +
"</event-translator-configuration>";
return linkDownConfig;
}
private void validateTranslatedEvent(Event event) {
assertEquals(m_translator.getName(), event.getSource());
assertEquals(Long.valueOf(3), event.getNodeid());
assertEquals("www.opennms.org", event.getHost());
assertEquals("a generated event", event.getDescr());
assertEquals("192.168.1.1", event.getInterface());
assertEquals("Switch", EventUtils.getParm(event, "nodeLabel"));
assertEquals("PSV", event.getService());
assertEquals("Down", EventUtils.getParm(event, "passiveStatus"));
}
@Test
public void testUEIList() {
List<String> ueis = m_config.getUEIList();
assertEquals(1, ueis.size());
assertTrue(ueis.contains("uei.opennms.org/services/translationTest"));
}
private Event createLinkDownEvent() {
EventBuilder builder = new EventBuilder("uei.opennms.org/generic/traps/SNMP_Link_Down", "Trapd");
builder.setField("nodeid", "1");
builder.addParam(".1.3.6.1.2.1.2.2.1.1.2", "2");
return builder.getEvent();
}
private Event createTestEvent(String type, String nodeLabel, String ipAddr, String serviceName, String status) {
final List<Parm> parms = new ArrayList<Parm>();
if(nodeLabel != null) parms.add(buildParm(EventConstants.PARM_PASSIVE_NODE_LABEL, nodeLabel));
if(ipAddr != null) parms.add(buildParm(EventConstants.PARM_PASSIVE_IPADDR, ipAddr));
if(serviceName != null) parms.add(buildParm(EventConstants.PARM_PASSIVE_SERVICE_NAME, serviceName));
if(status != null) parms.add(buildParm(EventConstants.PARM_PASSIVE_SERVICE_STATUS, status));
return createEventWithParms("uei.opennms.org/services/"+type, parms);
}
private Event createEventWithParms(String uei, List<Parm> parms) {
Event e = MockEventUtil.createEventBuilder("Automation", uei).getEvent();
e.setHost("localhost");
e.setParmCollection(parms);
Logmsg logmsg = new Logmsg();
logmsg.setContent("Testing Passive Status Keeper with down status");
e.setLogmsg(logmsg);
return e;
}
private Parm buildParm(String parmName, String parmValue) {
Value v = new Value();
v.setContent(parmValue);
Parm p = new Parm();
p.setParmName(parmName);
p.setValue(v);
return p;
}
private String getSqlSubValueLong() {
return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<event-translator-configuration \n" +
"xmlns=\"http://xmlns.opennms.org/xsd/translator-configuration\" \n" +
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" >\n" +
" <translation>\n" +
" <event-translation-spec uei=\"uei.opennms.org/services/translationTest\">\n" +
" <mappings>\n" +
" <mapping>\n" +
" <assignment type=\"field\" name=\"nodeid\">\n" +
" <value type=\"sql\" result=\"select node.nodeid from node, ipInterface where node.nodeLabel=? and ipinterface.ipaddr=? and node.nodeId=ipinterface.nodeid and ipInterface.isManaged != 'D' and node.nodeType != 'D' and to_number(?, '999999') = 9999 \" >\n" +
" <value type=\"parameter\" name=\"passiveNodeLabel\" matches=\"Router\" result=\"Firewall\" />\n" +
" <value type=\"constant\" result=\"192.168.1.4\" />\n" +
" <value type=\"field\" name=\"nodeid\" result=\"9999\" />\n" +
" </value>\n" +
" </assignment>\n" +
" <assignment type=\"parameter\" name=\"nodeLabel\">\n" +
" <value type=\"field\" name=\"host\" result=\"Switch\" />\n" +
" </assignment>\n" +
" <assignment type=\"field\" name=\"interface\">\n" +
" <value type=\"parameter\" name=\"passiveIpAddr\" matches=\".*(192\\.168\\.1\\.1).*\" result=\"192.168.1.1\" />\n" +
" </assignment>\n" +
" <assignment type=\"field\" name=\"host\">\n" +
" <value type=\"field\" name=\"host\" result=\"www.opennms.org\" />\n" +
" </assignment>\n" +
" <assignment type=\"field\" name=\"descr\">\n" +
" <value type=\"constant\" result=\"a generated event\" />\n" +
" </assignment>\n" +
" <assignment type=\"field\" name=\"service\">\n" +
" <value type=\"parameter\" name=\"passiveServiceName\" result=\"PSV\" />\n" +
" </assignment>\n" +
" <assignment type=\"parameter\" name=\"passiveStatus\">\n" +
" <value type=\"parameter\" name=\"passiveStatus\" matches=\".*(Up|Down).*\" result=\"${1}\" />\n" +
" </assignment>\n" +
" </mapping>\n" +
" </mappings>\n" +
" </event-translation-spec>\n" +
" </translation>\n" +
"</event-translator-configuration>\n" +
"";
}
private String getSqlSubValueString() {
return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<event-translator-configuration \n" +
"xmlns=\"http://xmlns.opennms.org/xsd/translator-configuration\" \n" +
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" >\n" +
" <translation>\n" +
" <event-translation-spec uei=\"uei.opennms.org/services/translationTest\">\n" +
" <mappings>\n" +
" <mapping>\n" +
" <assignment type=\"field\" name=\"nodeid\">\n" +
" <value type=\"sql\" result=\"select node.nodeid from node, ipInterface where node.nodeLabel=? and ipinterface.ipaddr=? and node.nodeId=ipinterface.nodeid and ipInterface.isManaged != 'D' and node.nodeType != 'D' and ? = 'test' \" >\n" +
" <value type=\"parameter\" name=\"passiveNodeLabel\" matches=\"Router\" result=\"Firewall\" />\n" +
" <value type=\"constant\" result=\"192.168.1.4\" />\n" +
" <value type=\"field\" name=\"host\" result=\"test\" />\n" +
" </value>\n" +
" </assignment>\n" +
" <assignment type=\"parameter\" name=\"nodeLabel\">\n" +
" <value type=\"field\" name=\"host\" result=\"Switch\" />\n" +
" </assignment>\n" +
" <assignment type=\"field\" name=\"interface\">\n" +
" <value type=\"parameter\" name=\"passiveIpAddr\" matches=\".*(192\\.168\\.1\\.1).*\" result=\"192.168.1.1\" />\n" +
" </assignment>\n" +
" <assignment type=\"field\" name=\"host\">\n" +
" <value type=\"field\" name=\"host\" result=\"www.opennms.org\" />\n" +
" </assignment>\n" +
" <assignment type=\"field\" name=\"descr\">\n" +
" <value type=\"constant\" result=\"a generated event\" />\n" +
" </assignment>\n" +
" <assignment type=\"field\" name=\"service\">\n" +
" <value type=\"parameter\" name=\"passiveServiceName\" result=\"PSV\" />\n" +
" </assignment>\n" +
" <assignment type=\"parameter\" name=\"passiveStatus\">\n" +
" <value type=\"parameter\" name=\"passiveStatus\" matches=\".*(Up|Down).*\" result=\"${1}\" />\n" +
" </assignment>\n" +
" </mapping>\n" +
" </mappings>\n" +
" </event-translation-spec>\n" +
" </translation>\n" +
"</event-translator-configuration>\n" +
"";
}
private String getStandardConfig() {
return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<event-translator-configuration \n" +
"xmlns=\"http://xmlns.opennms.org/xsd/translator-configuration\" \n" +
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" >\n" +
" <translation>\n" +
" <event-translation-spec uei=\"uei.opennms.org/services/translationTest\">\n" +
" <mappings>\n" +
" <mapping>\n" +
" <assignment type=\"field\" name=\"nodeid\">\n" +
" <value type=\"sql\" result=\"select node.nodeid from node, ipInterface where node.nodeLabel=? and ipinterface.ipaddr=? and node.nodeId=ipinterface.nodeid and ipInterface.isManaged != 'D' and node.nodeType != 'D'\" >\n" +
" <value type=\"parameter\" name=\"passiveNodeLabel\" matches=\"Router\" result=\"Firewall\" />\n" +
" <value type=\"constant\" result=\"192.168.1.4\" />\n" +
" </value>\n" +
" </assignment>\n" +
" <assignment type=\"parameter\" name=\"nodeLabel\">\n" +
" <value type=\"field\" name=\"host\" result=\"Switch\" />\n" +
" </assignment>\n" +
" <assignment type=\"field\" name=\"interface\">\n" +
" <value type=\"parameter\" name=\"passiveIpAddr\" matches=\".*(192\\.168\\.1\\.1).*\" result=\"192.168.1.1\" />\n" +
" </assignment>\n" +
" <assignment type=\"field\" name=\"host\">\n" +
" <value type=\"field\" name=\"host\" result=\"www.opennms.org\" />\n" +
" </assignment>\n" +
" <assignment type=\"field\" name=\"descr\">\n" +
" <value type=\"constant\" result=\"a generated event\" />\n" +
" </assignment>\n" +
" <assignment type=\"field\" name=\"service\">\n" +
" <value type=\"parameter\" name=\"passiveServiceName\" result=\"PSV\" />\n" +
" </assignment>\n" +
" <assignment type=\"parameter\" name=\"passiveStatus\">\n" +
" <value type=\"parameter\" name=\"passiveStatus\" matches=\".*(Up|Down).*\" result=\"${1}\" />\n" +
" </assignment>\n" +
" </mapping>\n" +
" </mappings>\n" +
" </event-translation-spec>\n" +
" </translation>\n" +
"</event-translator-configuration>\n" +
"";
}
}