/******************************************************************************* * 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.config; import static org.opennms.core.utils.InetAddressUtils.addr; import static org.opennms.core.utils.InetAddressUtils.isInetAddressInRange; import static org.opennms.core.utils.InetAddressUtils.toIpAddrBytes; import java.io.IOException; import java.io.InputStream; import java.io.StringWriter; import java.net.InetAddress; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import org.exolab.castor.xml.MarshalException; import org.exolab.castor.xml.Marshaller; import org.exolab.castor.xml.ValidationException; import org.opennms.core.utils.ByteArrayComparator; import org.opennms.core.utils.IpListFromUrl; import org.opennms.core.utils.LogUtils; import org.opennms.core.utils.ThreadCategory; import org.opennms.core.xml.CastorUtils; import org.opennms.netmgt.config.threshd.ExcludeRange; import org.opennms.netmgt.config.threshd.IncludeRange; import org.opennms.netmgt.config.threshd.Package; import org.opennms.netmgt.config.threshd.Service; import org.opennms.netmgt.config.threshd.ThreshdConfiguration; import org.opennms.netmgt.filter.FilterDaoFactory; /** * <p>Abstract ThreshdConfigManager class.</p> * * @author mhuot * @version $Id: $ */ public abstract class ThreshdConfigManager { /** * The config class loaded from the config file */ protected ThreshdConfiguration m_config; /** * A mapping of the configured URLs to a list of the specific IPs configured * in each - so as to avoid file reads */ private Map<String, List<String>> m_urlIPMap; /** * A mapping of the configured package to a list of IPs selected via filter * rules, so as to avoid repetitive database access. */ private Map<Package, List<InetAddress>> m_pkgIpMap; /** * A boolean flag to indicate If a filter rule against the local OpenNMS * server has to be used. */ protected boolean m_verifyServer; /** * The name of the local OpenNMS server */ protected String m_localServer; /** * <p>Constructor for ThreshdConfigManager.</p> * * @param stream a {@link java.io.InputStream} object. * @param localServer a {@link java.lang.String} object. * @param verifyServer a boolean. * @throws org.exolab.castor.xml.MarshalException if any. * @throws org.exolab.castor.xml.ValidationException if any. */ public ThreshdConfigManager(InputStream stream, String localServer, boolean verifyServer) throws MarshalException, ValidationException { m_config = CastorUtils.unmarshal(ThreshdConfiguration.class, stream); createUrlIpMap(); m_verifyServer = verifyServer; m_localServer = localServer; createPackageIpListMap(); } /** * Go through the configuration and build a mapping of each configured URL * to a list of IPs configured in that URL - done at init() time so that * repeated file reads can be avoided */ protected void createUrlIpMap() { m_urlIPMap = new HashMap<String, List<String>>(); for (Package pkg : m_config.getPackageCollection()) { for (String urlname : pkg.getIncludeUrlCollection()) { java.util.List<String> iplist = IpListFromUrl.parse(urlname); if (iplist.size() > 0) { m_urlIPMap.put(urlname, iplist); } } } } /** * This method is used to establish package against an iplist iplist mapping, * with which, the iplist is selected per package via the configured filter * rules from the database. */ protected void createPackageIpListMap() { ThreadCategory log = ThreadCategory.getInstance(this.getClass()); m_pkgIpMap = new HashMap<Package, List<InetAddress>>(); Enumeration<org.opennms.netmgt.config.threshd.Package> pkgEnum = m_config.enumeratePackage(); while (pkgEnum.hasMoreElements()) { org.opennms.netmgt.config.threshd.Package pkg = pkgEnum.nextElement(); // // Get a list of ipaddress per package agaist the filter rules from // database and populate the package, IP list map. // StringBuffer filterRules = new StringBuffer(pkg.getFilter().getContent()); try { if (m_verifyServer) { filterRules.append(" & (serverName == "); filterRules.append('\"'); filterRules.append(m_localServer); filterRules.append('\"'); filterRules.append(")"); } if (log.isDebugEnabled()) log.debug("createPackageIpMap: package is " + pkg.getName() + ". filer rules are " + filterRules.toString()); List<InetAddress> ipList = FilterDaoFactory.getInstance().getActiveIPAddressList(filterRules.toString()); if (ipList.size() > 0) { m_pkgIpMap.put(pkg, ipList); } } catch (Throwable t) { LogUtils.errorf(this, t, "createPackageIpMap: failed to map package: %s to an IP List with filter \"%s\"", pkg.getName(), pkg.getFilter().getContent()); } } } /** * This nethod is used to rebuild the package agaist iplist mapping when * needed. When a node gained service event occurs, threshd has to determine * which package the ip/service combination is in, but if the interface is a * newly added one, the package iplist should be rebuilt so that threshd * could know which package this ip/service pair is in. */ public synchronized void rebuildPackageIpListMap() { createPackageIpListMap(); } /** * Saves the current in-memory configuration to disk and reloads * * @throws org.exolab.castor.xml.MarshalException if any. * @throws java.io.IOException if any. * @throws org.exolab.castor.xml.ValidationException if any. */ public synchronized void saveCurrent() throws MarshalException, IOException, ValidationException { //marshall to a string first, then write the string to the file. This way the original config //isn't lost if the xml from the marshall is hosed. StringWriter stringWriter = new StringWriter(); Marshaller.marshal(m_config, stringWriter); String xmlString = stringWriter.toString(); if (xmlString!=null) { saveXML(xmlString); } reloadXML(); } /** * <p>reloadXML</p> * * @throws java.io.IOException if any. * @throws org.exolab.castor.xml.MarshalException if any. * @throws org.exolab.castor.xml.ValidationException if any. */ public abstract void reloadXML() throws IOException, MarshalException, ValidationException; /** * <p>saveXML</p> * * @param xmlString a {@link java.lang.String} object. * @throws java.io.IOException if any. */ protected abstract void saveXML(String xmlString) throws IOException; /** * Return the threshd configuration object. * * @return a {@link org.opennms.netmgt.config.threshd.ThreshdConfiguration} object. */ public synchronized ThreshdConfiguration getConfiguration() { return m_config; } /** * <p>getPackage</p> * * @param name a {@link java.lang.String} object. * @return a org$opennms$netmgt$config$threshd$Package object. */ public synchronized org.opennms.netmgt.config.threshd.Package getPackage(String name) { for (org.opennms.netmgt.config.threshd.Package thisPackage : m_config.getPackageCollection()) { if(thisPackage.getName().equals(name)) { return thisPackage; } } return null; } /** * This method is used to determine if the named interface is included in * the passed package's url includes. If the interface is found in any of * the URL files, then a value of true is returned, else a false value is * returned. * * <pre> * The file URL is read and each entry in this file checked. Each line * in the URL file can be one of - * <IP><space>#<comments> * or * <IP> * or * #<comments> * * Lines starting with a '#' are ignored and so are characters after * a '<space>#' in a line. * </pre> * * @param addr * The interface to test against the package's URL * @param url * The url file to read * * @return True if the interface is included in the url, false otherwise. */ private boolean interfaceInUrl(String addr, String url) { boolean bRet = false; // get list of IPs in this URL java.util.List<String> iplist = m_urlIPMap.get(url); if (iplist != null && iplist.size() > 0) { bRet = iplist.contains(addr); } return bRet; } /** * This method is used to determine if the named interface is included in * the passed package definition. If the interface belongs to the package * then a value of true is returned. If the interface does not belong to the * package a false value is returned. * * <strong>Note: </strong>Evaluation of the interface against a package * filter will only work if the IP is already in the database. * * @param iface * The interface to test against the package. * @param pkg * The package to check for the inclusion of the interface. * @return True if the interface is included in the package, false * otherwise. */ public synchronized boolean interfaceInPackage(String iface, org.opennms.netmgt.config.threshd.Package pkg) { ThreadCategory log = ThreadCategory.getInstance(this.getClass()); final InetAddress ifaceAddr = addr(iface); boolean filterPassed = false; // get list of IPs in this package java.util.List<InetAddress> ipList = m_pkgIpMap.get(pkg); if (ipList != null && ipList.size() > 0) { filterPassed = ipList.contains(ifaceAddr); } if (log.isDebugEnabled()) log.debug("interfaceInPackage: Interface " + iface + " passed filter for package " + pkg.getName() + "?: " + filterPassed); if (!filterPassed) return false; // // Ensure that the interface is in the specific list or // that it is in the include range and is not excluded // boolean has_specific = false; boolean has_range_include = false; boolean has_range_exclude = false; has_range_include = pkg.getIncludeRangeCount() == 0 && pkg.getSpecificCount() == 0; for (IncludeRange rng : pkg.getIncludeRangeCollection()) { if (isInetAddressInRange(iface, rng.getBegin(), rng.getEnd())) { has_range_include = true; break; } } byte[] addr = toIpAddrBytes(iface); for (String spec : pkg.getSpecificCollection()) { byte[] speca = toIpAddrBytes(spec); if (new ByteArrayComparator().compare(speca, addr) == 0) { has_specific = true; break; } } Enumeration<String> eurl = pkg.enumerateIncludeUrl(); while (!has_specific && eurl.hasMoreElements()) { has_specific = interfaceInUrl(iface, eurl.nextElement()); } for (ExcludeRange rng : pkg.getExcludeRangeCollection()) { if (isInetAddressInRange(iface, rng.getBegin(), rng.getEnd())) { has_range_exclude = true; break; } } return has_specific || (has_range_include && !has_range_exclude); } /** * Returns true if the service is part of the package and the status of the * service is set to "on". Returns false if the service is not in the * package or it is but the status of the service is set to "off". * * @param svcName * The service name to lookup. * @param pkg * The package to lookup up service. * @return a boolean. */ public synchronized boolean serviceInPackageAndEnabled(String svcName, org.opennms.netmgt.config.threshd.Package pkg) { boolean result = false; for (Service tsvc : pkg.getServiceCollection()) { if (tsvc.getName().equalsIgnoreCase(svcName)) { // Ok its in the package. Now check the // status of the service String status = tsvc.getStatus(); if (status.equals("on")) { result = true; break; } } } return result; } }