org.opennms.mock.snmp.MockSnmpAgent.java Source code

Java tutorial

Introduction

Here is the source code for org.opennms.mock.snmp.MockSnmpAgent.java

Source

/*
 * This file is part of the OpenNMS(R) Application.
 *
 * OpenNMS(R) is Copyright (C) 2006 The OpenNMS Group, Inc.  All rights reserved.
 * OpenNMS(R) is a derivative work, containing both original code, included code and modified
 * code that was published under the GNU General Public License. Copyrights for modified
 * and included code are below.
 *
 * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc.
 *
 * Original code base Copyright (C) 1999-2001 Oculan Corp.  All rights reserved.
 *
 * This program 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 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 * For more information contact:
 *      OpenNMS Licensing       <license@opennms.org>
 *      http://www.opennms.org/
 *      http://www.opennms.com/
 */
package org.opennms.mock.snmp;

import java.io.File;
import java.io.IOException;
import java.net.BindException;
import java.util.Iterator;
import java.util.List;

import org.snmp4j.TransportMapping;
import org.snmp4j.agent.BaseAgent;
import org.snmp4j.agent.CommandProcessor;
import org.snmp4j.agent.DuplicateRegistrationException;
import org.snmp4j.agent.ManagedObject;
import org.snmp4j.agent.io.ImportModes;
import org.snmp4j.agent.mo.MOTableRow;
import org.snmp4j.agent.mo.snmp.RowStatus;
import org.snmp4j.agent.mo.snmp.SnmpCommunityMIB;
import org.snmp4j.agent.mo.snmp.SnmpNotificationMIB;
import org.snmp4j.agent.mo.snmp.SnmpTargetMIB;
import org.snmp4j.agent.mo.snmp.StorageType;
import org.snmp4j.agent.mo.snmp.TransportDomains;
import org.snmp4j.agent.mo.snmp.VacmMIB;
import org.snmp4j.log.Log4jLogFactory;
import org.snmp4j.log.LogFactory;
import org.snmp4j.mp.MPv3;
import org.snmp4j.mp.MessageProcessingModel;
import org.snmp4j.security.AuthMD5;
import org.snmp4j.security.AuthSHA;
import org.snmp4j.security.PrivDES;
import org.snmp4j.security.SecurityLevel;
import org.snmp4j.security.SecurityModel;
import org.snmp4j.security.USM;
import org.snmp4j.security.UsmUser;
import org.snmp4j.smi.Counter32;
import org.snmp4j.smi.Counter64;
import org.snmp4j.smi.Integer32;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.UdpAddress;
import org.snmp4j.smi.Variable;
import org.snmp4j.transport.DefaultUdpTransportMapping;
import org.snmp4j.util.ThreadPool;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

/*
 * The <code>MockSnmpAgent</code> class extends the SNMP4J BaseAgent
 * class to provide a mock SNMP agent for SNMP-based OpenNMS tests.
 * Large chunks of code were lifted from the org.snmp4j.agent.test.TestAgent
 * class.
 * 
 * @author Jeff Gehlbach
 * @version 1.0
 */
public class MockSnmpAgent extends BaseAgent implements Runnable {

    // initialize Log4J logging
    static {
        LogFactory.setLogFactory(new Log4jLogFactory());
    }

    protected String m_address;
    private Resource m_moFile;
    private boolean m_running;
    private boolean m_stopped;
    private List<ManagedObject> m_moList;
    private MockSnmpMOLoader m_moLoader;

    /*
     * Creates the mock agent with files to read and store the boot counter,
     * to read and store the agent configuration, and to read the mocked
     * managed objects (MOs), plus a string describing the address and port
     * to bind to.
     * 
     * @param bootFile
     *       a file containing the boot counter in serialized form (as expected by BaseAgent).
     * @param confFile
     *       a configuration file with serialized management information.
     * @param moFile
     *       a MIB dump file describing the managed objects to be mocked.  The current implementation
     *       expects a Java properties file, which can conveniently be generated using the Net-SNMP
     *       utility <code>snmpwalk</code> with the <code>-One</code> option set.
     */
    public MockSnmpAgent(File bootFile, File confFile, Resource moFile, String bindAddress) {
        super(bootFile, confFile, new CommandProcessor(new OctetString(MPv3.createLocalEngineID())));
        m_address = bindAddress;
        m_moFile = moFile;
        agent.setThreadPool(ThreadPool.create("RequestPool", 4));
    }

    public static MockSnmpAgent createAgentAndRun(Resource moFile, String bindAddress) throws InterruptedException {
        try {
            if (moFile.getInputStream() == null) {
                throw new IllegalArgumentException(
                        "could not get InputStream mock object resource; does it exist?  Resource: " + moFile);
            }
        } catch (IOException e) {
            throw new RuntimeException("Got IOException while checking for existence of mock object file: " + e, e);
        }

        MockSnmpAgent agent = new MockSnmpAgent(new File("/dev/null"), new File("/dev/null"), moFile, bindAddress);
        Thread thread = new Thread(agent);
        thread.start();

        try {
            while (!agent.isRunning() && thread.isAlive()) {
                Thread.sleep(10);
            }
        } catch (InterruptedException e) {
            agent.shutDownAndWait();
            throw e;
        }

        if (!thread.isAlive()) {
            agent.m_running = false;
            agent.m_stopped = true;
            throw new IllegalStateException("agent failed to start--check logs");
        }

        return agent;
    }

    public static void main(String[] args) {
        if (args.length < 2) {
            System.err.println(
                    "Usage: MockSnmpAgent props-file listen-addr\n\nWhere props-file is relative to CLASSPATH\nand listen-addr is of the form 10.11.12.13/1161 to listen on port 1161");
            System.exit(1);
        }
        ClassPathResource moFile = new ClassPathResource(args[0]);
        String bindAddress = args[1];

        try {
            MockSnmpAgent agt = MockSnmpAgent.createAgentAndRun(moFile, bindAddress);
        } catch (InterruptedException e) {
            System.exit(0);
        }
    }

    public void shutDownAndWait() throws InterruptedException {
        if (!isRunning()) {
            return;
        }

        shutDown();

        while (!isStopped()) {
            Thread.sleep(10);
        }
    }

    /*
     * Starts the <code>MockSnmpAgent</code> running.  Meant to be called from the
     * <code>start</code> method of class <code>Thread</code>, but could also be
     * used to bring up a standalone mock agent.
     * @see org.snmp4j.agent.BaseAgent#run()
     * 
     * @author Jeff Gehlbach
     * @version 1.0
     */
    // XXX fix catch blocks
    public void run() {
        try {
            init();
            loadConfig(ImportModes.UPDATE_CREATE);
            addShutdownHook();
            finishInit();
            super.run();
            m_running = true;
        } catch (BindException be) {
            be.printStackTrace();
            System.err.println(
                    "You probably specified an invalid address or a port < 1024 and are not running as root");
        } catch (IOException ie) {
            ie.printStackTrace();
        }

        while (m_running) {
            try {
                Thread.sleep(10); // fast, Fast, FAST, *FAST*!!!
            } catch (InterruptedException e) {
                break;
            }
        }

        try {
            for (TransportMapping transportMapping : transportMappings) {
                transportMapping.close();
            }
        } catch (Throwable t) {
            t.printStackTrace();
        }

        m_stopped = true;
    }

    /*
     * 
     */
    public void shutDown() {
        m_running = false;
        m_stopped = false;
    }

    public boolean isRunning() {
        return m_running;
    }

    public boolean isStopped() {
        return m_stopped;
    }

    @Override
    protected void addCommunities(SnmpCommunityMIB communityMIB) {
        Variable[] com2sec = new Variable[] { new OctetString("public"), // community name
                new OctetString("public"), // security name
                getAgent().getContextEngineID(), // local engine ID
                new OctetString(), // default context name
                new OctetString(), // transport tag
                new Integer32(StorageType.nonVolatile), // storage type
                new Integer32(RowStatus.active) // row status
        };
        MOTableRow row = communityMIB.getSnmpCommunityEntry()
                .createRow(new OctetString("public2public").toSubIndex(true), com2sec);
        communityMIB.getSnmpCommunityEntry().addRow(row);
    }

    @Override
    protected void addViews(VacmMIB vacm) {
        vacm.addGroup(SecurityModel.SECURITY_MODEL_SNMPv1, new OctetString("public"), new OctetString("v1v2group"),
                StorageType.nonVolatile);
        vacm.addGroup(SecurityModel.SECURITY_MODEL_SNMPv2c, new OctetString("public"), new OctetString("v1v2group"),
                StorageType.nonVolatile);
        vacm.addGroup(SecurityModel.SECURITY_MODEL_USM, new OctetString("SHADES"), new OctetString("v3group"),
                StorageType.nonVolatile);
        vacm.addGroup(SecurityModel.SECURITY_MODEL_USM, new OctetString("TEST"), new OctetString("v3test"),
                StorageType.nonVolatile);
        vacm.addGroup(SecurityModel.SECURITY_MODEL_USM, new OctetString("opennmsUser"), new OctetString("v3group"),
                StorageType.nonVolatile);
        vacm.addGroup(SecurityModel.SECURITY_MODEL_USM, new OctetString("SHA"), new OctetString("v3restricted"),
                StorageType.nonVolatile);

        vacm.addAccess(new OctetString("v1v2group"), new OctetString(), SecurityModel.SECURITY_MODEL_ANY,
                SecurityLevel.NOAUTH_NOPRIV, VacmMIB.vacmExactMatch, new OctetString("fullReadView"),
                new OctetString("fullWriteView"), new OctetString("fullNotifyView"), StorageType.nonVolatile);
        vacm.addAccess(new OctetString("v3group"), new OctetString(), SecurityModel.SECURITY_MODEL_USM,
                SecurityLevel.AUTH_PRIV, VacmMIB.vacmExactMatch, new OctetString("fullReadView"),
                new OctetString("fullWriteView"), new OctetString("fullNotifyView"), StorageType.nonVolatile);
        vacm.addAccess(new OctetString("v3restricted"), new OctetString(), SecurityModel.SECURITY_MODEL_USM,
                SecurityLevel.AUTH_NOPRIV, VacmMIB.vacmExactMatch, new OctetString("restrictedReadView"),
                new OctetString("restrictedWriteView"), new OctetString("restrictedNotifyView"),
                StorageType.nonVolatile);
        vacm.addAccess(new OctetString("v3test"), new OctetString(), SecurityModel.SECURITY_MODEL_USM,
                SecurityLevel.AUTH_PRIV, VacmMIB.vacmExactMatch, new OctetString("testReadView"),
                new OctetString("testWriteView"), new OctetString("testNotifyView"), StorageType.nonVolatile);

        vacm.addViewTreeFamily(new OctetString("fullReadView"), new OID("1.3"), new OctetString(),
                VacmMIB.vacmViewIncluded, StorageType.nonVolatile);
        vacm.addViewTreeFamily(new OctetString("fullWriteView"), new OID("1.3"), new OctetString(),
                VacmMIB.vacmViewIncluded, StorageType.nonVolatile);
        vacm.addViewTreeFamily(new OctetString("fullNotifyView"), new OID("1.3"), new OctetString(),
                VacmMIB.vacmViewIncluded, StorageType.nonVolatile);

        vacm.addViewTreeFamily(new OctetString("restrictedReadView"), new OID("1.3.6.1.2"), new OctetString(),
                VacmMIB.vacmViewIncluded, StorageType.nonVolatile);
        vacm.addViewTreeFamily(new OctetString("restrictedWriteView"), new OID("1.3.6.1.2.1"), new OctetString(),
                VacmMIB.vacmViewIncluded, StorageType.nonVolatile);
        vacm.addViewTreeFamily(new OctetString("restrictedNotifyView"), new OID("1.3.6.1.2"), new OctetString(),
                VacmMIB.vacmViewIncluded, StorageType.nonVolatile);

        vacm.addViewTreeFamily(new OctetString("testReadView"), new OID("1.3.6.1.2"), new OctetString(),
                VacmMIB.vacmViewIncluded, StorageType.nonVolatile);
        vacm.addViewTreeFamily(new OctetString("testReadView"), new OID("1.3.6.1.2.1.1"), new OctetString(),
                VacmMIB.vacmViewExcluded, StorageType.nonVolatile);
        vacm.addViewTreeFamily(new OctetString("testWriteView"), new OID("1.3.6.1.2.1"), new OctetString(),
                VacmMIB.vacmViewIncluded, StorageType.nonVolatile);
        vacm.addViewTreeFamily(new OctetString("testNotifyView"), new OID("1.3.6.1.2"), new OctetString(),
                VacmMIB.vacmViewIncluded, StorageType.nonVolatile);

    }

    @Override
    protected void addNotificationTargets(SnmpTargetMIB targetMIB, SnmpNotificationMIB notificationMIB) {
        targetMIB.addDefaultTDomains();

        targetMIB.addTargetAddress(new OctetString("notification"), TransportDomains.transportDomainUdpIpv4,
                new OctetString(new UdpAddress("127.0.0.1/162").getValue()), 200, 1, new OctetString("notify"),
                new OctetString("v2c"), StorageType.permanent);
        targetMIB.addTargetParams(new OctetString("v2c"), MessageProcessingModel.MPv2c,
                SecurityModel.SECURITY_MODEL_SNMPv2c, new OctetString("public"), SecurityLevel.NOAUTH_NOPRIV,
                StorageType.permanent);
        notificationMIB.addNotifyEntry(new OctetString("default"), new OctetString("notify"),
                SnmpNotificationMIB.SnmpNotifyTypeEnum.trap, StorageType.permanent);
    }

    @Override
    protected void addUsmUser(USM usm) {
        UsmUser user = new UsmUser(new OctetString("SHADES"), AuthSHA.ID, new OctetString("SHADESAuthPassword"),
                PrivDES.ID, new OctetString("SHADESPrivPassword"));
        usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
        user = new UsmUser(new OctetString("TEST"), AuthSHA.ID, new OctetString("maplesyrup"), PrivDES.ID,
                new OctetString("maplesyrup"));
        usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
        user = new UsmUser(new OctetString("opennmsUser"), AuthMD5.ID, new OctetString("0p3nNMSv3"), PrivDES.ID,
                new OctetString("0p3nNMSv3"));
        usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
        user = new UsmUser(new OctetString("SHA"), AuthSHA.ID, new OctetString("SHAAuthPassword"), null, null);
        usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
    }

    protected void initTransportMappings() throws IOException {
        transportMappings = new TransportMapping[1];
        transportMappings[0] = new DefaultUdpTransportMapping(new UdpAddress(m_address));
    }

    // override the agent defaults since we are providing all the agent data
    @Override
    protected void registerSnmpMIBs() {
        registerManagedObjects();
    }

    @Override
    protected void unregisterSnmpMIBs() {
    }

    @Override
    protected void registerManagedObjects() {
        m_moList = createMockMOs();
        Iterator<ManagedObject> moListIter = m_moList.iterator();
        while (moListIter.hasNext()) {
            try {
                server.register(moListIter.next(), null);
            } catch (DuplicateRegistrationException ex) {
                ex.printStackTrace();
            }
        }
    }

    @Override
    protected void unregisterManagedObjects() {
        // here we should unregister those objects previously registered...
    }

    protected List<ManagedObject> createMockMOs() {
        //        m_moLoader = new PropsMockSnmpMOLoaderImpl(m_moFile);
        m_moLoader = new PropertiesBackedManagedObject(m_moFile);
        return m_moLoader.loadMOs();
    }

    private ManagedObject findMOForOid(OID oid) {
        for (ManagedObject mo : m_moList) {
            if (mo.getScope().covers(oid)) {
                return mo;
            }
        }
        return null;
    }

    public void updateValue(OID oid, Variable value) {
        ManagedObject mo = findMOForOid(oid);
        assertNotNull("Unable to find oid in mib for mockAgent: " + oid, mo);
        if (mo instanceof Updatable) {
            ((Updatable) mo).updateValue(oid, value);
        }
    }

    private void assertNotNull(String string, Object o) {
        if (o == null) {
            throw new IllegalStateException(string);
        }
    }

    public void updateValue(String oid, Variable value) {
        updateValue(new OID(oid), value);
    }

    public void updateIntValue(String oid, int val) {
        updateValue(oid, new Integer32(val));
    }

    public void updateStringValue(String oid, String val) {
        updateValue(oid, new OctetString(val));
    }

    public void updateCounter32Value(String oid, int val) {
        updateValue(oid, new Counter32(val));
    }

    public void updateCounter64Value(String oid, long val) {
        updateValue(oid, new Counter64(val));
    }

}