/******************************************************************************* * 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.netmgt.correlation.ncs; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.opennms.core.utils.InetAddressUtils.addr; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.xml.bind.JAXBException; import org.drools.FactHandle; import org.junit.Before; import org.junit.Test; import org.opennms.netmgt.correlation.drools.DroolsCorrelationEngine; import org.opennms.netmgt.dao.DistPollerDao; import org.opennms.netmgt.dao.NodeDao; import org.opennms.netmgt.model.NetworkBuilder; import org.opennms.netmgt.model.OnmsDistPoller; import org.opennms.netmgt.model.events.EventBuilder; import org.opennms.netmgt.model.ncs.NCSBuilder; import org.opennms.netmgt.model.ncs.NCSComponent; import org.opennms.netmgt.model.ncs.NCSComponent.DependencyRequirements; import org.opennms.netmgt.model.ncs.NCSComponentRepository; import org.opennms.netmgt.xml.event.Event; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.annotation.DirtiesContext; public class ImpactProgagationRulesTest extends CorrelationRulesTestCase { @Autowired private NCSComponentRepository m_repository; @Autowired private DistPollerDao m_distPollerDao; @Autowired private NodeDao m_nodeDao; private int m_pe1NodeId; private int m_pe2NodeId; private long m_pwCompId; private DroolsCorrelationEngine m_engine; private List<Object> m_anticipatedWorkingMemory = new ArrayList<Object>(); @Before public void setUp() throws JAXBException, UnsupportedEncodingException { OnmsDistPoller distPoller = new OnmsDistPoller("localhost", "127.0.0.1"); m_distPollerDao.save(distPoller); NetworkBuilder bldr = new NetworkBuilder(distPoller); bldr.addNode("PE1").setForeignSource("space").setForeignId("1111-PE1"); m_nodeDao.save(bldr.getCurrentNode()); m_pe1NodeId = bldr.getCurrentNode().getId(); bldr.addNode("PE2").setForeignSource("space").setForeignId("2222-PE2"); m_nodeDao.save(bldr.getCurrentNode()); m_pe2NodeId = bldr.getCurrentNode().getId(); NCSComponent svc = new NCSBuilder("Service", "NA-Service", "123") .setName("CokeP2P") .pushComponent("ServiceElement", "NA-ServiceElement", "8765") .setName("PE1,SE1") .setNodeIdentity("space", "1111-PE1") .pushComponent("ServiceElementComponent", "NA-SvcElemComp", "8765,jnxVpnIf") .setName("jnxVpnIf") .setNodeIdentity("space", "1111-PE1") .setUpEventUei("uei.opennms.org/vendor/Juniper/traps/jnxVpnIfUp") .setDownEventUei("uei.opennms.org/vendor/Juniper/traps/jnxVpnIfDown") .setAttribute("jnxVpnIfVpnType", "5") .setAttribute("jnxVpnIfVpnName", "ge-1/0/2.50") .pushComponent("ServiceElementComponent", "NA-SvcElemComp", "8765,link") .setName("link") .setNodeIdentity("space", "1111-PE1") .setUpEventUei("uei.opennms.org/vendor/Juniper/traps/linkUp") .setDownEventUei("uei.opennms.org/vendor/Juniper/traps/linkDown") .setAttribute("linkName", "ge-1/0/2") .popComponent() .popComponent() .pushComponent("ServiceElementComponent", "NA-SvcElemComp", "8765,jnxVpnPw-vcid(50)") .setName("jnxVpnPw-vcid(50)") .setNodeIdentity("space", "1111-PE1") .setUpEventUei("uei.opennms.org/vendor/Juniper/traps/jnxVpnPwUp") .setDownEventUei("uei.opennms.org/vendor/Juniper/traps/jnxVpnPwDown") .setAttribute("jnxVpnPwVpnType", "5") .setAttribute("jnxVpnPwVpnName", "ge-1/0/2.50") .setDependenciesRequired(DependencyRequirements.ANY) .pushComponent("ServiceElementComponent", "NA-SvcElemComp", "8765,lspA-PE1-PE2") .setName("lspA-PE1-PE2") .setNodeIdentity("space", "1111-PE1") .setUpEventUei("uei.opennms.org/vendor/Juniper/traps/mplsLspPathUp") .setDownEventUei("uei.opennms.org/vendor/Juniper/traps/mplsLspPathDown") .setAttribute("mplsLspName", "lspA-PE1-PE2") .popComponent() .pushComponent("ServiceElementComponent", "NA-SvcElemComp", "8765,lspB-PE1-PE2") .setName("lspB-PE1-PE2") .setNodeIdentity("space", "1111-PE1") .setUpEventUei("uei.opennms.org/vendor/Juniper/traps/mplsLspPathUp") .setDownEventUei("uei.opennms.org/vendor/Juniper/traps/mplsLspPathDown") .setAttribute("mplsLspName", "lspB-PE1-PE2") .popComponent() .popComponent() .popComponent() .pushComponent("ServiceElement", "NA-ServiceElement", "9876") .setName("PE2,SE1") .setNodeIdentity("space", "2222-PE2") .pushComponent("ServiceElementComponent", "NA-SvcElemComp", "9876,jnxVpnIf") .setName("jnxVpnIf") .setNodeIdentity("space", "2222-PE2") .setUpEventUei("uei.opennms.org/vendor/Juniper/traps/jnxVpnIfUp") .setDownEventUei("uei.opennms.org/vendor/Juniper/traps/jnxVpnIfDown") .setAttribute("jnxVpnIfVpnType", "5") .setAttribute("jnxVpnIfVpnName", "ge-3/1/4.50") .pushComponent("ServiceElementComponent", "NA-SvcElemComp", "9876,link") .setName("link") .setNodeIdentity("space", "2222-PE2") .setUpEventUei("uei.opennms.org/vendor/Juniper/traps/linkUp") .setDownEventUei("uei.opennms.org/vendor/Juniper/traps/linkDown") .setAttribute("linkName", "ge-3/1/4") .popComponent() .popComponent() .pushComponent("ServiceElementComponent", "NA-SvcElemComp", "9876,jnxVpnPw-vcid(50)") .setName("jnxVpnPw-vcid(50)") .setNodeIdentity("space", "2222-PE2") .setUpEventUei("uei.opennms.org/vendor/Juniper/traps/jnxVpnPwUp") .setDownEventUei("uei.opennms.org/vendor/Juniper/traps/jnxVpnPwDown") .setAttribute("jnxVpnPwVpnType", "5") .setAttribute("jnxVpnPwVpnName", "ge-3/1/4.50") .setDependenciesRequired(DependencyRequirements.ANY) .pushComponent("ServiceElementComponent", "NA-SvcElemComp", "9876,lspA-PE2-PE1") .setName("lspA-PE2-PE1") .setNodeIdentity("space", "2222-PE2") .setUpEventUei("uei.opennms.org/vendor/Juniper/traps/mplsLspPathUp") .setDownEventUei("uei.opennms.org/vendor/Juniper/traps/mplsLspPathDown") .setAttribute("mplsLspName", "lspA-PE2-PE1") .popComponent() .pushComponent("ServiceElementComponent", "NA-SvcElemComp", "9876,lspB-PE2-PE1") .setName("lspB-PE2-PE1") .setNodeIdentity("space", "2222-PE2") .setUpEventUei("uei.opennms.org/vendor/Juniper/traps/mplsLspPathUp") .setDownEventUei("uei.opennms.org/vendor/Juniper/traps/mplsLspPathDown") .setAttribute("mplsLspName", "lspB-PE2-PE1") .popComponent() .popComponent() .popComponent() .get(); m_repository.save(svc); m_pwCompId = svc.getSubcomponent("NA-ServiceElement", "9876") .getSubcomponent("NA-SvcElemComp", "9876,jnxVpnPw-vcid(50)") .getId(); // Get engine m_engine = findEngineByName("impactPropagationRules"); // // Create a Marshaller // JAXBContext context = JAXBContext.newInstance(NCSComponent.class); // Marshaller marshaller = context.createMarshaller(); // marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); // // // save the output in a byte array // ByteArrayOutputStream out = new ByteArrayOutputStream(); // // // marshall the output // marshaller.marshal(svc, out); // // // verify its matches the expected results // byte[] utf8 = out.toByteArray(); // // String result = new String(utf8, "UTF-8"); // // System.err.println(result); } @Test @DirtiesContext public void testSimpleDownUpCase() throws Exception { // 1. Assert empty workspace resetFacts(); verifyFacts(); // 2. verify Impact on ComponentDownEvent resetFacts(); resetEvents(); // component to request dependencies for Component c = createComponent("ServiceElementComponent", "NA-SvcElemComp", "9876,jnxVpnPw-vcid(50)"); Event downEvent = createVpnPwDownEvent(17, m_pe2NodeId, "10.1.1.1", "5", "ge-3/1/4.50"); ComponentDownEvent cde = new ComponentDownEvent(c, downEvent); anticipateFacts(cde, new ComponentImpacted(c, cde), new DependenciesNeeded(c, cde), new ImpactEventSent(c, cde)); anticipateEvent(createComponentImpactedEvent("ServiceElementComponent", "jnxVpnPw-vcid(50)", "NA-SvcElemComp", "9876,jnxVpnPw-vcid(50)", 17)); // pretend to be a using rule that inserts the DependenciesNeeded fact insertFactAndFireRules(cde); verifyFacts(); verifyEvents(); // 3. Verify resolution and memory clean up on ComponentUpEvent resetFacts(); resetEvents(); anticipateEvent(createComponentResolvedEvent("ServiceElementComponent", "jnxVpnPw-vcid(50)", "NA-SvcElemComp", "9876,jnxVpnPw-vcid(50)", 17)); // expect all facts to be resolved anticipateFacts(); Event upEvent = createVpnPwUpEvent(17, m_pe2NodeId, "10.1.1.1", "5", "ge-3/1/4.50"); ComponentUpEvent cue = new ComponentUpEvent(c, upEvent); insertFactAndFireRules(cue); verifyFacts(); verifyEvents(); } @Test @DirtiesContext public void testSimpleALLRulesPropagation() throws Exception { // 1. Assert empty workspace resetFacts(); verifyFacts(); // 2. verify Impact on ComponentDownEvent resetFacts(); resetEvents(); // component to request dependencies for Component c = createComponent("ServiceElementComponent", "NA-SvcElemComp", "9876,jnxVpnPw-vcid(50)"); Event downEvent = createVpnPwDownEvent(17, m_pe2NodeId, "10.1.1.1", "5", "ge-3/1/4.50"); ComponentDownEvent cde = new ComponentDownEvent(c, downEvent); // this component depends on c Component parent = createComponent("ServiceElement", "NA-ServiceElement", "9876"); DependsOn dep = new DependsOn( parent, c ); ComponentImpacted componentImpacted = new ComponentImpacted(c, cde); ImpactEventSent eventSent = new ImpactEventSent( c, cde); anticipateFacts( dep, componentImpacted, eventSent, new ComponentImpacted( parent, cde ), new DependenciesNeeded(parent, cde), new ImpactEventSent(parent, cde)); anticipateEvent(createComponentImpactedEvent("ServiceElement", "PE2,SE1", "NA-SvcElement", "9876", 17)); // Insert facts and fire rules FactHandle impactHandle = m_engine.getWorkingMemory().insert( componentImpacted ); FactHandle depHandle = m_engine.getWorkingMemory().insert( dep ); FactHandle eventSentHandle = m_engine.getWorkingMemory().insert( eventSent ); m_engine.getWorkingMemory().fireAllRules(); // pretend to be a using rule that inserts the DependenciesNeeded fact verifyFacts(); verifyEvents(); // 3. Verify resolution and memory clean up on ComponentUpEvent resetFacts(); resetEvents(); //anticipateEvent(createComponentResolvedEvent("ServiceElementComponent", "jnxVpnPw-vcid(50)", "NA-SvcElemComp", "9876,jnxVpnPw-vcid(50)", 17)); anticipateEvent(createComponentResolvedEvent("ServiceElement", "PE2,SE1", "NA-SvcElement", "9876", 17)); // expect all facts to be resolved anticipateFacts(); Event upEvent = createVpnPwUpEvent(18, m_pe2NodeId, "10.1.1.1", "5", "ge-3/1/4.50"); ComponentUpEvent cue = new ComponentUpEvent(c, upEvent); m_engine.getWorkingMemory().retract(impactHandle); m_engine.getWorkingMemory().retract(depHandle); m_engine.getWorkingMemory().retract(eventSentHandle); m_engine.getWorkingMemory().insert(new ComponentEventResolved(cde, cue) ); m_engine.getWorkingMemory().fireAllRules(); // insertFactAndFireRules(cue); verifyFacts(); verifyEvents(); } // add test for two different outages on the same component private Component createComponent(String type, String foreignSource, String foreignId) { NCSComponent ncsComp = m_repository.findByTypeAndForeignIdentity(type, foreignSource, foreignId); return new Component(ncsComp); } private Event createComponentImpactedEvent( String type, String name, String foreignSource, String foreignId, int cause ) { return new EventBuilder("uei.opennms.org/internal/ncs/componentImpacted", "Component Correlator") .addParam("componentType", type ) .addParam("componentName", name ) .addParam("componentForeignSource", foreignSource ) .addParam("componentForeignId", foreignId ) .addParam("cause", cause ) .getEvent(); } private Event createComponentResolvedEvent(String type, String name, String foreignSource, String foreignId, int cause) { return new EventBuilder("uei.opennms.org/internal/ncs/componentResolved", "Component Correlator") .addParam("componentType", type ) .addParam("componentName", name) .addParam("componentForeignSource", foreignSource ) .addParam("componentForeignId", foreignId ) .addParam("cause", cause ) .getEvent(); } @SuppressWarnings("unused") private Event createMplsLspPathDownEvent( int dbId, int nodeid, String ipaddr, String lspname ) { Event event = new EventBuilder("uei.opennms.org/vendor/Juniper/traps/mplsLspPathDown", "Test") .setNodeid(nodeid) .setInterface( addr( ipaddr ) ) .addParam("mplsLspName", lspname ) .getEvent(); event.setDbid(dbId); return event; } @SuppressWarnings("unused") private Event createMplsLspPathUpEvent( int dbId, int nodeid, String ipaddr, String lspname ) { Event event = new EventBuilder("uei.opennms.org/vendor/Juniper/traps/mplsLspPathUp", "Drools") .setNodeid(nodeid) .setInterface( addr( ipaddr ) ) .addParam("mplsLspName", lspname ) .getEvent(); event.setDbid(dbId); return event; } private Event createVpnPwDownEvent( int dbId, int nodeid, String ipaddr, String pwtype, String pwname ) { Event event = new EventBuilder("uei.opennms.org/vendor/Juniper/traps/jnxVpnPwDown", "Test") .setNodeid(nodeid) .setInterface( addr( ipaddr ) ) .addParam("jnxVpnPwVpnType", pwtype ) .addParam("jnxVpnPwVpnName", pwname ) .getEvent(); event.setDbid(dbId); return event; } private Event createVpnPwUpEvent( int dbId, int nodeid, String ipaddr, String pwtype, String pwname ) { Event event = new EventBuilder("uei.opennms.org/vendor/Juniper/traps/jnxVpnPwUp", "Test") .setNodeid(nodeid) .setInterface( addr( ipaddr ) ) .addParam("jnxVpnPwVpnType", pwtype ) .addParam("jnxVpnPwVpnName", pwname ) .getEvent(); event.setDbid(dbId); return event; } private void resetFacts() { m_anticipatedWorkingMemory.clear(); } private void anticipateFacts(Object... facts) { m_anticipatedWorkingMemory.addAll(Arrays.asList(facts)); } private FactHandle insertFactAndFireRules(Object fact) { FactHandle handle = m_engine.getWorkingMemory().insert( fact ); m_engine.getWorkingMemory().fireAllRules(); return handle; } private void retractFactAndFireRules(FactHandle fact) { m_engine.getWorkingMemory().retract( fact ); m_engine.getWorkingMemory().fireAllRules(); } private void verifyFacts() { List<Object> memObjects = m_engine.getMemoryObjects(); String memContents = memObjects.toString(); for(Object anticipated : m_anticipatedWorkingMemory) { assertTrue("Expected "+anticipated+" in memory but memory was "+memContents, memObjects.contains(anticipated)); memObjects.remove(anticipated); } assertEquals("Unexpected objects in working memory " + memObjects, 0, memObjects.size()); } private void resetEvents() { getAnticipator().reset(); } private void anticipateEvent(Event... events) { for(Event event : events) { getAnticipator().anticipateEvent(event); } } private void verifyEvents() { getAnticipator().verifyAnticipated(); } }