/*******************************************************************************
* 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.capsd;
import java.net.InetAddress;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.opennms.core.utils.ConfigFileConstants;
import org.opennms.core.utils.DBUtils;
import org.opennms.core.utils.InetAddressUtils;
import org.opennms.core.utils.ThreadCategory;
import org.opennms.netmgt.config.CapsdConfig;
import org.opennms.netmgt.config.CollectdConfigFactory;
import org.opennms.netmgt.config.OpennmsServerConfigFactory;
import org.opennms.netmgt.config.PollerConfig;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.ConnectionCallback;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.Assert;
/**
* <p>JdbcCapsdDbSyncer class.</p>
*
* @author ranger
* @version $Id: $
*/
public class JdbcCapsdDbSyncer implements InitializingBean, CapsdDbSyncer {
/**
* <P>
* LightWeightIfEntry is designed to hold specific information about an IP
* interface in the database such as its IP address, its parent node id, and
* its managed status and represents a lighter weight version of the
* DbIpInterfaceEntry class.
* </P>
*/
protected static final class LightWeightIfEntry {
/**
* Represents NULL value for 'ifIndex' field in the ipInterface table
*/
protected final static int NULL_IFINDEX = -1;
protected final static int NULL_IFTYPE = -1;
protected final static int LOOPBACK_IFTYPE = 24;
private int m_nodeId;
private int m_ifIndex;
private int m_ifType;
private String m_address;
private char m_managementState;
private char m_snmpPrimaryState;
private boolean m_primaryStateChanged;
/**
* <P>
* Constructs a new LightWeightIfEntry object.
* </P>
*
* @param nodeId
* Interface's parent node id
* @param ifIndex
* Interface's index
* @param address
* Interface's ip address
* @param managementState
* Interface's management state
* @param snmpPrimaryState
* Interface's primary snmp interface state
* @param ifType
* Interface's type as determined via SNMP
*/
public LightWeightIfEntry(int nodeId, int ifIndex, String address, char managementState, char snmpPrimaryState, int ifType) {
m_nodeId = nodeId;
m_ifIndex = ifIndex;
m_address = address;
m_managementState = managementState;
m_snmpPrimaryState = snmpPrimaryState;
m_ifType = ifType;
m_primaryStateChanged = false;
}
/**
* <P>
* Returns the IP address of the interface.
* </P>
*/
public String getAddress() {
return m_address;
}
/**
* <P>
* Returns the parent node id of the interface.
* </P>
*/
public int getNodeId() {
return m_nodeId;
}
/**
* <P>
* Returns the ifIndex of the interface.
* </P>
*/
public int getIfIndex() {
return m_ifIndex;
}
/**
* <P>
* Returns the ifType of the interface.
* </P>
*/
public int getIfType() {
return m_ifType;
}
/**
*
*/
public char getManagementState() {
return m_managementState;
}
/**
*
*/
public char getSnmpPrimaryState() {
return m_snmpPrimaryState;
}
/**
*
*/
public void setSnmpPrimaryState(char state) {
if (state != m_snmpPrimaryState) {
m_snmpPrimaryState = state;
m_primaryStateChanged = true;
}
}
/**
*
*/
public boolean hasSnmpPrimaryStateChanged() {
return m_primaryStateChanged;
}
}
/**
* The SQL statement used to retrieve all non-deleted/non-forced unamanaged
* IP interfaces from the 'ipInterface' table.
*/
private static final String SQL_DB_RETRIEVE_IP_INTERFACE =
"SELECT ip.nodeid, ip.ipaddr, ip.ismanaged " +
"FROM ipinterface as ip " +
"JOIN node as n ON ip.nodeid = n.nodeid " +
"WHERE ip.ipaddr!='0.0.0.0' " +
"AND ip.isManaged!='D' " +
"AND ip.isManaged!='F' " +
"AND n.foreignSource is null";
/**
* The SQL statement used to retrieve all non-deleted/non-forced unamanaged
* IP interfaces from the 'ipInterface' table with the local OpenNMS server
* restriction.
*/
private static final String SQL_DB_RETRIEVE_IP_INTERFACE_IN_LOCAL_SERVER =
"SELECT ip.nodeid, ip.ipaddr, ip.ismanaged " +
"FROM ipinterface as ip " +
"JOIN node as n ON n.nodeid = ip.nodeid " +
"JOIN servermap as s ON ip.ipaddr = s.ipaddr " +
"WHERE ip.ipaddr!='0.0.0.0' " +
"AND ip.isManaged!='D' " +
"AND ip.isManaged!='F' " +
"AND s.servername = ? " +
"AND n.foreignSource is null";
/**
* SQL statement to retrieve all non-deleted IP addresses from the
* ipInterface table which support SNMP.
*/
private static final String SQL_DB_RETRIEVE_SNMP_IP_INTERFACES =
"SELECT DISTINCT ipinterface.nodeid,ipinterface.ipaddr,ipinterface.ifindex,ipinterface.issnmpprimary,snmpinterface.snmpiftype,snmpinterface.snmpifindex " +
"FROM ipinterface " +
"JOIN node ON node.nodeid = ipinterface.nodeid " +
"JOIN snmpinterface ON ipinterface.snmpinterfaceid = snmpinterface.id " +
"JOIN ifservices ON ifservices.ipinterfaceid = ipinterface.id " +
"JOIN service ON ifservices.serviceid = service.serviceid " +
"WHERE ipinterface.ismanaged!='D' " +
"AND ifservices.status != 'D' " +
"AND service.servicename='SNMP' " +
"AND node.foreignSource is null";
/**
* SQL statement used to update the 'isSnmpPrimary' field of the ipInterface
* table.
*/
private static final String SQL_DB_UPDATE_SNMP_PRIMARY_STATE = "UPDATE ipinterface SET issnmpprimary=? WHERE nodeid=? AND ipaddr=? AND ismanaged!='D'";
/**
* The SQL statement used to retrieve all non-deleted/non-forced unamanaged
* services for a nodeid/ip from the 'ifservices' table.
*/
private static final String SQL_DB_RETRIEVE_IF_SERVICES = "SELECT serviceid, status FROM ifservices WHERE nodeid=? AND ipaddr=? AND status!='D' AND status!='F'";
/**
* The SQL statement which updates the 'isManaged' field in the ipInterface
* table for a specific node/ipAddr pair
*/
private static final String SQL_DB_UPDATE_IP_INTERFACE = "UPDATE ipinterface SET ismanaged=? WHERE nodeid=? AND ipaddr=? AND isManaged!='D' AND isManaged!='F'";
/**
* The SQL statement which updates the 'status' field in the ifServices
* table for a specific node/ipAddr pair
*/
private static final String SQL_DB_UPDATE_ALL_SERVICES_FOR_NIP = "UPDATE ifservices SET status=? WHERE nodeid=? AND ipaddr=? AND status!='D' AND status!='F'";
private static final String SQL_DB_UPDATE_SERVICE_FOR_NIP = "UPDATE ifservices SET status=? WHERE nodeid=? AND ipaddr=? AND serviceid=? AND status!='D' AND status!='F'";
// /**
// * The SQL statement used to determine if an IP address is already in the
// * ipInterface table and there is known.
// */
// private static final String RETRIEVE_IPADDR_SQL =
// "SELECT ip.ipaddr " +
// "FROM ipinterface as ip " +
// "JOIN node as n ON ip.nodeid = n.nodeid " +
// "WHERE ip.ipaddr=? " +
// "AND ip.ismanaged!='D'" +
// "AND n.foreignSource is null";
//
// /**
// * The SQL statement used to determine if an IP address is already in the
// * ipInterface table and if so what its parent nodeid is.
// */
// private static final String RETRIEVE_IPADDR_NODEID_SQL =
// "SELECT ip.nodeid " +
// "FROM ipinterface as ip " +
// "JOIN node as n ON ip.nodeid = n.nodeid " +
// "WHERE ip.ipaddr=? " +
// "AND ip.ismanaged!='D' " +
// "AND n.foreignSource is null";
/**
* The SQL statement used to load the currenly defined service table.
*/
private static final String SVCTBL_LOAD_SQL = "SELECT serviceID, serviceName FROM service";
/**
* The SQL statement used to add a new entry into the service table
*/
private static final String SVCTBL_ADD_SQL = "INSERT INTO service (serviceID, serviceName) VALUES (?,?)";
/**
* The SQL statement used to mark all ifservices table entries which refer
* to the specified serviceId as deleted.
*/
private static final String DELETE_IFSERVICES_SQL =
"update ifservices " +
" set status = 'D' " +
" where serviceid = ?" +
" and id in (" +
" select svc.id" +
" from ifservices as svc" +
" join ipinterface as ip" +
" on (ip.id = svc.ipinterfaceid)" +
" join node as n" +
" on (n.nodeid = ip.nodeid)" +
" where n.foreignsource is null)";
/**
* The SQL statement used to get the next value for a service identifier.
* This is a sequence defined in the database.
*/
private static final String DEFAULT_NEXT_SVC_ID_SQL = "SELECT nextval('serviceNxtId')";
/**
* The SQL statement used to determine if an IP address is already in the
* ipInterface table and if so what its parent nodeid is.
*/
public static final String RETRIEVE_IPADDR_NODEID_SQL =
"SELECT ip.nodeid " +
"FROM ipinterface as ip " +
"JOIN node as n ON ip.nodeid = n.nodeid " +
"WHERE ip.ipaddr=? " +
"AND ip.ismanaged!='D' " +
"AND n.foreignSource is null";
/**
* The SQL statement used to determine if an IP address is already in the
* ipInterface table and there is known.
*/
public static final String RETRIEVE_IPADDR_SQL =
"SELECT ip.ipaddr " +
"FROM ipinterface as ip " +
"JOIN node as n ON ip.nodeid = n.nodeid " +
"WHERE ip.ipaddr=? " +
"AND ip.ismanaged!='D'" +
"AND n.foreignSource is null";
private CapsdConfig m_capsdConfig;
/**
* The map of service identifiers, mapped by the service id to the service
* name.
*/
private Map<Integer, String> m_serviceIdToName = new HashMap<Integer,String>();
/**
* The map of service identifiers, mapped by the service name to the service
* id.
*/
private Map<String, Integer> m_serviceNameToId = new HashMap<String, Integer>();
private OpennmsServerConfigFactory m_opennmsServerConfig;
private CollectdConfigFactory m_collectdConfig;
private PollerConfig m_pollerConfig;
private String m_nextSvcIdSql = DEFAULT_NEXT_SVC_ID_SQL;
private JdbcTemplate m_jdbcTemplate;
/**
* <p>Constructor for JdbcCapsdDbSyncer.</p>
*/
public JdbcCapsdDbSyncer() {
}
/**
* {@inheritDoc}
*
* Returns the service ID from the service table that was loaded
* during class initialization for the specified name.
*/
@Override
public Integer getServiceId(String name) {
Assert.notNull(name, "name argument must not be null");
return m_serviceNameToId.get(name);
}
/**
* {@inheritDoc}
*
* Returns the service name from the service table that was loaded
* during class initialization for the specified ID.
*/
@Override
public String getServiceName(Integer id) {
Assert.notNull(id, "id argument must not be null");
return m_serviceIdToName.get(id);
}
/* (non-Javadoc)
* @see org.opennms.netmgt.capsd.CapsdDbSyncerI#syncServices()
*/
/**
* <p>syncServices</p>
*/
@Override
public void syncServices() {
m_jdbcTemplate.execute(new ConnectionCallback<Object>() {
public Object doInConnection(Connection con) throws SQLException, DataAccessException {
syncServices(con);
return null;
}
});
}
/**
* <p>syncServices</p>
*
* @param conn a {@link java.sql.Connection} object.
* @throws java.sql.SQLException if any.
*/
public void syncServices(Connection conn) throws SQLException {
List<String> serviceNames = syncServicesTable(conn);
PreparedStatement delFromIfServicesStmt = null;
final DBUtils d = new DBUtils(getClass());
try {
List<String> protocols = getCapsdConfig().getConfiguredProtocols();
/*
* now iterate over the services from the 'service' table
* and determine if any no longer exist in the list of
* configured protocols
*/
for(String service : serviceNames) {
if (!protocols.contains(service)) {
if (log().isDebugEnabled()) {
log().debug("syncServices: service " + service + " exists in the database but not in the Capsd config file.");
}
Integer id = m_serviceNameToId.get(service);
// Delete 'ifServices' table entries which refer to the
// service
if (log().isDebugEnabled()) {
log().debug("syncServices: deleting all references to service id " + id + " from the IfServices table.");
}
delFromIfServicesStmt = conn.prepareStatement(DELETE_IFSERVICES_SQL);
d.watch(delFromIfServicesStmt);
delFromIfServicesStmt.setInt(1, id.intValue());
delFromIfServicesStmt.executeUpdate();
log().info("syncServices: deleted service id " + id + " for service '" + service + "' from the IfServices table.");
}
}
} finally {
d.cleanUp();
}
}
private ThreadCategory log() {
return ThreadCategory.getInstance(getClass());
}
/* (non-Javadoc)
* @see org.opennms.netmgt.capsd.CapsdDbSyncerI#syncServicesTable()
*/
/**
* <p>syncServicesTable</p>
*
* @return a {@link java.util.List} object.
*/
@Override
public List<String> syncServicesTable() {
return m_jdbcTemplate.execute(new ConnectionCallback<List<String>>() {
public List<String> doInConnection(Connection con) throws SQLException, DataAccessException {
return syncServicesTable(con);
}
});
}
/**
* <p>syncServicesTable</p>
*
* @param conn a {@link java.sql.Connection} object.
* @return a {@link java.util.List} object.
* @throws java.sql.SQLException if any.
*/
public List<String> syncServicesTable(Connection conn) throws SQLException {
log().debug("syncServicesTable: synchronizing services list with the database");
List<String> serviceNames;
final DBUtils d = new DBUtils(getClass());
try {
PreparedStatement insStmt = conn.prepareStatement(SVCTBL_ADD_SQL);
d.watch(insStmt);
PreparedStatement nxtStmt = conn.prepareStatement(getNextSvcIdSql());
d.watch(nxtStmt);
PreparedStatement loadStmt = conn.prepareStatement(SVCTBL_LOAD_SQL);
d.watch(loadStmt);
// go ahead and load the table first if it can be loaded
serviceNames = new ArrayList<String>();
ResultSet rs = loadStmt.executeQuery();
d.watch(rs);
while (rs.next()) {
Integer id = new Integer(rs.getInt(1));
String name = rs.getString(2);
m_serviceIdToName.put(id, name);
m_serviceNameToId.put(name, id);
serviceNames.add(name);
}
/*
* now iterate over the configured protocols
* and make sure that each is represented in the database.
*/
for (String protocol : getCapsdConfig().getConfiguredProtocols()) {
log().debug("syncServicesTable: checking protocol '" + protocol + "'.");
if (!serviceNames.contains(protocol)) {
log().debug("syncServicesTable: protocol '" + protocol + "' is not in the database... adding.");
// get the next identifier
rs = nxtStmt.executeQuery();
d.watch(rs);
rs.next();
int id = rs.getInt(1);
rs.close();
log().debug("syncServicesTable: using id " + id + " for protocol '" + protocol + "'.");
insStmt.setInt(1, id);
insStmt.setString(2, protocol);
insStmt.executeUpdate();
m_serviceIdToName.put(id, protocol);
m_serviceNameToId.put(protocol, id);
serviceNames.add(protocol);
log().info("syncServicesTable: added service entry to the database for protocol '" + protocol + "' with id of " + id);
}
}
} finally {
d.cleanUp();
}
return serviceNames;
}
/* (non-Javadoc)
* @see org.opennms.netmgt.capsd.CapsdDbSyncerI#syncManagementState()
*/
/**
* <p>syncManagementState</p>
*/
@Override
public void syncManagementState() {
m_jdbcTemplate.execute(new ConnectionCallback<Object>() {
public Object doInConnection(Connection con) throws SQLException, DataAccessException {
syncManagementState(con);
return null;
}
});
}
/**
* <p>syncManagementState</p>
*
* @param conn a {@link java.sql.Connection} object.
* @throws java.sql.SQLException if any.
*/
public void syncManagementState(Connection conn) throws SQLException {
boolean verifyServer = getOpennmsServerConfig().verifyServer();
String localServer = getOpennmsServerConfig().getServerName();
if (log().isDebugEnabled()) {
log().debug("syncManagementState: local server: " + localServer + " verify server: " + verifyServer);
}
if (conn == null) {
log().error("CapsdConfigFactory.syncManagementState: Sync failed...must have valid database connection.");
return;
}
// Get default management state.
//
String managementPolicy = getCapsdConfig().getConfiguration().getManagementPolicy();
boolean managedByDefault = (managementPolicy == null || managementPolicy.equalsIgnoreCase("managed"));
if (log().isDebugEnabled()) {
log().debug("syncManagementState: managed_by_default: " + managedByDefault);
}
//
// Retrieve list of interfaces and their managed status from the
// database
// NOTE: Interfaces with an 'isManaged' field equal to 'D' (Deleted) or
// 'F' (Forced Unmanaged) are
// not eligible to be managed and will not be included in the interfaces
// retrieved from the database. Likewise, interfaces with IP address of
// '0.0.0.0' will also be excluded by the SQL query.
//
// prepare the SQL statement to query the database
PreparedStatement ipRetStmt = null;
final DBUtils d = new DBUtils(getClass());
List<LightWeightIfEntry> ifList = new ArrayList<LightWeightIfEntry>();
try {
if (verifyServer) {
ipRetStmt = conn.prepareStatement(SQL_DB_RETRIEVE_IP_INTERFACE_IN_LOCAL_SERVER);
d.watch(ipRetStmt);
ipRetStmt.setString(1, localServer);
} else {
ipRetStmt = conn.prepareStatement(SQL_DB_RETRIEVE_IP_INTERFACE);
d.watch(ipRetStmt);
}
ResultSet result = null;
// run the statement
result = ipRetStmt.executeQuery();
d.watch(result);
// Build array list of CapsdInterface objects representing each
// of the interfaces retrieved from the database
while (result.next()) {
// Node Id
int nodeId = result.getInt(1);
// IP address
String address = result.getString(2);
if (address == null) {
log().warn("invalid ipInterface table entry, no IP address, skipping...");
continue;
}
// Management State
char managedState = DbIpInterfaceEntry.STATE_UNKNOWN;
String str = result.getString(3);
if (str != null) {
managedState = str.charAt(0);
}
ifList.add(new LightWeightIfEntry(nodeId, LightWeightIfEntry.NULL_IFINDEX, address, managedState, DbIpInterfaceEntry.SNMP_UNKNOWN, LightWeightIfEntry.NULL_IFTYPE));
}
} finally {
d.cleanUp();
}
try {
// For efficiency, prepare the SQL statements in advance
PreparedStatement ifUpdateStmt = conn.prepareStatement(SQL_DB_UPDATE_IP_INTERFACE);
d.watch(ifUpdateStmt);
PreparedStatement allSvcUpdateStmt = conn.prepareStatement(SQL_DB_UPDATE_ALL_SERVICES_FOR_NIP);
d.watch(allSvcUpdateStmt);
PreparedStatement svcRetStmt = conn.prepareStatement(SQL_DB_RETRIEVE_IF_SERVICES);
d.watch(svcRetStmt);
PreparedStatement svcUpdateStmt = conn.prepareStatement(SQL_DB_UPDATE_SERVICE_FOR_NIP);
d.watch(svcUpdateStmt);
/*
* Loop through interface list and determine if there has been a
* change in the managed status of the interface based on the
* newly loaded package configuration data.
*/
for (LightWeightIfEntry ifEntry : ifList) {
String ipaddress = ifEntry.getAddress();
// Convert to InetAddress object
InetAddress ifAddress = null;
ifAddress = InetAddressUtils.addr(ipaddress);
if (ifAddress == null) {
log().warn("Failed converting ip address " + ipaddress + " to InetAddress.");
continue;
}
// Check interface address against Capsd config information to
// determine
// if interface management state should be managed or unmanaged.
boolean address_is_unmanaged = getCapsdConfig().isAddressUnmanaged(ifAddress);
if (log().isDebugEnabled()) {
log().debug("syncManagementState: " + ipaddress + " unmanaged based on capsd config?: " + address_is_unmanaged);
}
if (address_is_unmanaged) {
// Interface not managed, check current
// management state for this interface.
if (ifEntry.getManagementState() != DbIpInterfaceEntry.STATE_UNMANAGED) {
// Update management state to unmanaged for the
// interface as well as for its services.
// Update the 'ipInterface' table
ifUpdateStmt.setString(1, new String(new char[] { DbIpInterfaceEntry.STATE_UNMANAGED }));
ifUpdateStmt.setInt(2, ifEntry.getNodeId());
ifUpdateStmt.setString(3, ipaddress);
ifUpdateStmt.executeUpdate();
// Update the 'ifServices' table
allSvcUpdateStmt.setString(1, new String(new char[] { DbIfServiceEntry.STATUS_UNMANAGED }));
allSvcUpdateStmt.setInt(2, ifEntry.getNodeId());
allSvcUpdateStmt.setString(3, ipaddress);
allSvcUpdateStmt.executeUpdate();
if (log().isDebugEnabled()) {
log().debug("syncManagementState: update completed for node/interface: " + ifEntry.getNodeId() + "/" + ipaddress + " to unmanaged");
}
}
} else {
/*
* Interface should be managed - check the status against
* poller config to see if interface will be polled
*
* NOTE: Try to avoid re-evaluating the ip against filters
* for each service, try to get the first package here and
* for that for service evaluation
*/
final PollerConfig pollerConfig = getPollerConfig();
pollerConfig.getReadLock().lock();
try {
org.opennms.netmgt.config.poller.Package ipPkg = pollerConfig.getFirstPackageMatch(ipaddress);
boolean ipToBePolled = false;
if (ipPkg != null) {
ipToBePolled = true;
}
if (log().isDebugEnabled()) {
log().debug("syncManagementState: " + ipaddress + " to be polled based on poller config?: " + ipToBePolled);
}
if ((ifEntry.getManagementState() == DbIpInterfaceEntry.STATE_MANAGED && ipToBePolled) || (ifEntry.getManagementState() == DbIpInterfaceEntry.STATE_NOT_POLLED && !ipToBePolled)) {
// current status is right
if (log().isDebugEnabled()) {
log().debug("syncManagementState: " + ipaddress + " - no change in status");
}
} else {
if (ipToBePolled) {
ifUpdateStmt.setString(1, new String(new char[] { DbIpInterfaceEntry.STATE_MANAGED }));
} else {
ifUpdateStmt.setString(1, new String(new char[] { DbIpInterfaceEntry.STATE_NOT_POLLED }));
}
ifUpdateStmt.setInt(2, ifEntry.getNodeId());
ifUpdateStmt.setString(3, ipaddress);
ifUpdateStmt.executeUpdate();
if (log().isDebugEnabled()) {
log().debug("syncManagementState: update completed for node/interface: " + ifEntry.getNodeId() + "/" + ipaddress);
}
}
// get services for this nodeid/ip and update
svcRetStmt.setInt(1, ifEntry.getNodeId());
svcRetStmt.setString(2, ipaddress);
ResultSet svcRS = svcRetStmt.executeQuery();
d.watch(svcRS);
while (svcRS.next()) {
int svcId = svcRS.getInt(1);
char svcStatus = DbIfServiceEntry.STATUS_UNKNOWN;
String str = svcRS.getString(2);
if (str != null) {
svcStatus = str.charAt(0);
}
String svcName = getServiceName(svcId);
/*
* try the first package that had the ip first, if
* service is not enabled, try all packages
*/
char oldStatus = svcStatus;
char newStatus = 'U';
boolean svcToBePolledLocally = isServicePolledLocally(ipaddress, svcName, ipPkg);
boolean svcToBePolledRemotely = isServicePolled(ipaddress, svcName, ipPkg);
if (log().isDebugEnabled()) {
log().debug("syncManagementState: " + ipaddress + "/" + svcName + " to be polled based on poller config?: " + svcToBePolledLocally);
}
if ((svcStatus == DbIfServiceEntry.STATUS_ACTIVE && svcToBePolledLocally) || (svcStatus == DbIfServiceEntry.STATUS_NOT_POLLED && !ipToBePolled)) {
// current status is right
if (log().isDebugEnabled()) {
log().debug("syncManagementState: " + ifEntry.getNodeId() + "/" + ipaddress + "/" + svcName + " status = " + svcStatus + " - no change in status");
}
} else {
// Update the 'ifServices' table
if (svcStatus == DbIfServiceEntry.STATUS_SUSPEND && svcToBePolledLocally) {
svcUpdateStmt.setString(1, new String(new char[] { DbIfServiceEntry.STATUS_FORCED }));
newStatus = 'F';
} else if (svcToBePolledLocally) {
svcUpdateStmt.setString(1, new String(new char[] { DbIfServiceEntry.STATUS_ACTIVE }));
newStatus = 'A';
} else if (svcToBePolledRemotely) {
svcUpdateStmt.setString(1, new String(new char[] { DbIfServiceEntry.STATUS_REMOTE }));
newStatus = 'X';
} else {
svcUpdateStmt.setString(1, new String(new char[] { DbIfServiceEntry.STATUS_NOT_POLLED }));
newStatus = 'N';
}
svcUpdateStmt.setInt(2, ifEntry.getNodeId());
svcUpdateStmt.setString(3, ipaddress);
svcUpdateStmt.setInt(4, svcId);
svcUpdateStmt.executeUpdate();
if (log().isDebugEnabled()) {
log().debug("syncManagementState: update completed for node/interface/svc: " + ifEntry.getNodeId() + "/" + ipaddress + "/" + svcName + " status changed from " + oldStatus + " to " + newStatus);
}
}
} // end ifservices result
} finally {
pollerConfig.getReadLock().unlock();
}
} // interface managed
} // end while
} finally {
d.cleanUp();
}
}
private boolean isServicePolled(final String ifAddr, final String svcName, final org.opennms.netmgt.config.poller.Package ipPkg) {
boolean svcToBePolled = false;
if (ipPkg != null) {
final PollerConfig pollerConfig = getPollerConfig();
pollerConfig.getReadLock().lock();
try {
svcToBePolled = pollerConfig.isPolled(svcName, ipPkg);
if (!svcToBePolled) svcToBePolled = pollerConfig.isPolled(ifAddr, svcName);
} finally {
pollerConfig.getReadLock().unlock();
}
}
return svcToBePolled;
}
private boolean isServicePolledLocally(final String ifAddr, final String svcName, final org.opennms.netmgt.config.poller.Package ipPkg) {
boolean svcToBePolled = false;
if (ipPkg != null && !ipPkg.getRemote()) {
final PollerConfig pollerConfig = getPollerConfig();
pollerConfig.getReadLock().lock();
try {
svcToBePolled = pollerConfig.isPolled(svcName, ipPkg);
if (!svcToBePolled) svcToBePolled = pollerConfig.isPolledLocally(ifAddr, svcName);
} finally {
pollerConfig.getReadLock().unlock();
}
}
return svcToBePolled;
}
/* (non-Javadoc)
* @see org.opennms.netmgt.capsd.CapsdDbSyncerI#syncSnmpPrimaryState()
*/
/**
* <p>syncSnmpPrimaryState</p>
*/
@Override
public void syncSnmpPrimaryState() {
m_jdbcTemplate.execute(new ConnectionCallback<Object>() {
public Object doInConnection(Connection con) throws SQLException, DataAccessException {
syncSnmpPrimaryState(con);
return null;
}
});
}
/**
* <p>syncSnmpPrimaryState</p>
*
* @param conn a {@link java.sql.Connection} object.
* @throws java.sql.SQLException if any.
*/
public synchronized void syncSnmpPrimaryState(Connection conn) throws SQLException {
if (conn == null) {
throw new IllegalArgumentException("Sync failed...must have valid database connection.");
}
/*
* Retrieve all non-deleted SNMP-supporting IP interfaces from the
* ipInterface table and build a map of nodes to interface entry list
*/
log().debug("syncSnmpPrimaryState: building map of nodes to interfaces...");
Map<Integer, List<LightWeightIfEntry>> nodes = new HashMap<Integer, List<LightWeightIfEntry>>();
final DBUtils d = new DBUtils(getClass());
try {
// prepare the SQL statement to query the database
PreparedStatement ipRetStmt = conn.prepareStatement(SQL_DB_RETRIEVE_SNMP_IP_INTERFACES);
d.watch(ipRetStmt);
ResultSet result = ipRetStmt.executeQuery();
d.watch(result);
// Iterate over result set and build map of interface
// entries keyed by node id.
List<LightWeightIfEntry> ifList = new ArrayList<LightWeightIfEntry>();
while (result.next()) {
// Node Id
int nodeId = result.getInt(1);
// IP address
String address = result.getString(2);
if (address == null) {
log().warn("invalid ipInterface table entry, no IP address, skipping...");
continue;
}
// ifIndex
int ifIndex = result.getInt(6);
if (result.wasNull()) {
if (log().isDebugEnabled()) {
log().debug("ipInterface table entry for address " + address + " does not have a valid ifIndex ");
}
ifIndex = LightWeightIfEntry.NULL_IFINDEX;
} else if (ifIndex < 1) {
if (ifIndex == CapsdConfig.LAME_SNMP_HOST_IFINDEX) {
if (log().isDebugEnabled()) {
log().debug("Using ifIndex = " + CapsdConfig.LAME_SNMP_HOST_IFINDEX + " for address " + address);
}
} else {
if (log().isDebugEnabled()) {
log().debug("ipInterface table entry for address " + address + " does not have a valid ifIndex ");
}
ifIndex = LightWeightIfEntry.NULL_IFINDEX;
}
}
// Primary SNMP State
char primarySnmpState = DbIpInterfaceEntry.SNMP_UNKNOWN;
String str = result.getString(4);
if (str != null) {
primarySnmpState = str.charAt(0);
}
// ifType
int ifType = result.getInt(5);
if (result.wasNull()) {
if (log().isDebugEnabled()) {
log().debug("snmpInterface table entry for address " + address + " does not have a valid ifType");
}
ifType = LightWeightIfEntry.NULL_IFTYPE;
}
// New node or existing node?
ifList = nodes.get(new Integer(nodeId));
if (ifList == null) {
// Create new interface entry list
ifList = new ArrayList<LightWeightIfEntry>();
ifList.add(new LightWeightIfEntry(nodeId, ifIndex, address, DbIpInterfaceEntry.STATE_UNKNOWN, primarySnmpState, ifType));
// Add interface entry list to the map
nodes.put(nodeId, ifList);
} else {
// Just add the current interface to the
// node's interface list
ifList.add(new LightWeightIfEntry(nodeId, ifIndex, address, DbIpInterfaceEntry.STATE_UNKNOWN, primarySnmpState, ifType));
}
}
} finally {
d.cleanUp();
}
/*
* Iterate over the nodes in the map and determine what the primary
* SNMP interface for each node should be. Keep track of those
* interfaces whose primary SNMP interface state has changed so that
* the database can be updated accordingly.
*/
if (log().isDebugEnabled()) {
log().debug("syncSnmpPrimaryState: iterating over nodes in map and checking primary SNMP interface, node count: " + nodes.size());
}
Iterator<Integer> niter = nodes.keySet().iterator();
while (niter.hasNext()) {
// Get the nodeid (key)
Integer nId = niter.next();
if (log().isDebugEnabled()) {
log().debug("building SNMP address list for node " + nId);
}
// Lookup the interface list (value)
List<LightWeightIfEntry> ifEntries = nodes.get(nId);
/*
* From the interface entries build a list of InetAddress objects
* eligible to be the primary SNMP interface for the node, and a
* list of loopback InetAddress objects eligible to be the primary
* SNMP interface for the node.
*/
List<InetAddress> addressList = new ArrayList<InetAddress>();
List<InetAddress> lbAddressList = new ArrayList<InetAddress>();
for (LightWeightIfEntry lwIf : ifEntries) {
/*
* Skip interfaces which do not have a valid (non-null) ifIndex
* as they are not eligible to be the primary SNMP interface
*/
if (lwIf.getIfIndex() == LightWeightIfEntry.NULL_IFINDEX) {
if (log().isDebugEnabled()) {
log().debug("skipping address " + lwIf.getAddress() + ": does not have a valid ifIndex.");
}
continue;
}
InetAddress addr = InetAddressUtils.addr(lwIf.getAddress());
addressList.add(addr);
if (lwIf.getIfType() == LightWeightIfEntry.LOOPBACK_IFTYPE) {
lbAddressList.add(addr);
}
}
/*
* Determine primary SNMP interface from the lists of possible addresses
* in this order: loopback interfaces in collectd-configuration.xml,
* other interfaces in collectd-configuration.xml, loopback interfaces in
* the database, other interfaces in the database.
*/
boolean strict = true;
InetAddress primarySnmpIf = null;
String psiType = null;
if (lbAddressList != null) {
primarySnmpIf = getCapsdConfig().determinePrimarySnmpInterface(lbAddressList, strict);
psiType = ConfigFileConstants.getFileName(ConfigFileConstants.COLLECTD_CONFIG_FILE_NAME) + " loopback addresses";
}
if (primarySnmpIf == null) {
primarySnmpIf = getCapsdConfig().determinePrimarySnmpInterface(addressList, strict);
psiType = ConfigFileConstants.getFileName(ConfigFileConstants.COLLECTD_CONFIG_FILE_NAME) + " addresses";
}
strict = false;
if ((primarySnmpIf == null) && (lbAddressList != null)){
primarySnmpIf = getCapsdConfig().determinePrimarySnmpInterface(lbAddressList, strict);
psiType = "DB loopback addresses";
}
if (primarySnmpIf == null) {
primarySnmpIf = getCapsdConfig().determinePrimarySnmpInterface(addressList, strict);
psiType = "DB addresses";
}
if (log().isDebugEnabled()) {
if(primarySnmpIf == null) {
log().debug("syncSnmpPrimaryState: No primary SNMP interface found for node " + nId);
} else {
log().debug("syncSnmpPrimaryState: primary SNMP interface for node " + nId + " is: " + primarySnmpIf + ", selected from " + psiType);
}
}
/*
* Iterate back over interface list and update primary SNMP
* iinterface state for this node...if the primary SNMP interface
* state has changed, update the database to reflect the new state.
*/
for (LightWeightIfEntry lwIf : ifEntries) {
if (lwIf.getIfIndex() == LightWeightIfEntry.NULL_IFINDEX) {
lwIf.setSnmpPrimaryState(DbIpInterfaceEntry.SNMP_NOT_ELIGIBLE);
} else if (primarySnmpIf == null || !lwIf.getAddress().equals(InetAddressUtils.str(primarySnmpIf))) {
if (getCollectdConfig().isServiceCollectionEnabled(lwIf.getAddress(), "SNMP")) {
lwIf.setSnmpPrimaryState(DbIpInterfaceEntry.SNMP_SECONDARY);
} else {
lwIf.setSnmpPrimaryState(DbIpInterfaceEntry.SNMP_NOT_ELIGIBLE);
}
} else {
lwIf.setSnmpPrimaryState(DbIpInterfaceEntry.SNMP_PRIMARY);
}
// Has SNMP primary state changed?
if (lwIf.hasSnmpPrimaryStateChanged()) {
if (log().isDebugEnabled()) {
log().debug("syncSnmpPrimaryState: updating " + lwIf.getNodeId() + "/" + lwIf.getAddress() + ", marking with state: " + lwIf.getSnmpPrimaryState());
}
try {
// prepare the SQL statement to query the database
PreparedStatement updateStmt = conn.prepareStatement(SQL_DB_UPDATE_SNMP_PRIMARY_STATE);
d.watch(updateStmt);
updateStmt.setString(1, new String(new char[] { lwIf.getSnmpPrimaryState() }));
updateStmt.setInt(2, lwIf.getNodeId());
updateStmt.setString(3, lwIf.getAddress());
updateStmt.executeUpdate();
} finally {
d.cleanUp();
}
}
}
}
log().debug("syncSnmpPrimaryState: sync completed.");
}
/**
* <p>getCapsdConfig</p>
*
* @return a {@link org.opennms.netmgt.config.CapsdConfig} object.
*/
public CapsdConfig getCapsdConfig() {
return m_capsdConfig;
}
/**
* <p>setCapsdConfig</p>
*
* @param capsdConfig a {@link org.opennms.netmgt.config.CapsdConfig} object.
*/
public void setCapsdConfig(CapsdConfig capsdConfig) {
m_capsdConfig = capsdConfig;
}
/**
* <p>getOpennmsServerConfig</p>
*
* @return a {@link org.opennms.netmgt.config.OpennmsServerConfigFactory} object.
*/
public OpennmsServerConfigFactory getOpennmsServerConfig() {
return m_opennmsServerConfig;
}
/**
* <p>setOpennmsServerConfig</p>
*
* @param serverConfigFactory a {@link org.opennms.netmgt.config.OpennmsServerConfigFactory} object.
*/
public void setOpennmsServerConfig(OpennmsServerConfigFactory serverConfigFactory) {
m_opennmsServerConfig = serverConfigFactory;
}
/**
* <p>getPollerConfig</p>
*
* @return a {@link org.opennms.netmgt.config.PollerConfig} object.
*/
public PollerConfig getPollerConfig() {
return m_pollerConfig;
}
/**
* <p>setPollerConfig</p>
*
* @param pollerConfig a {@link org.opennms.netmgt.config.PollerConfig} object.
*/
public void setPollerConfig(PollerConfig pollerConfig) {
m_pollerConfig = pollerConfig;
}
/**
* <p>getCollectdConfig</p>
*
* @return a {@link org.opennms.netmgt.config.CollectdConfigFactory} object.
*/
public CollectdConfigFactory getCollectdConfig() {
return m_collectdConfig;
}
/**
* <p>setCollectdConfig</p>
*
* @param collectdConfigFactory a {@link org.opennms.netmgt.config.CollectdConfigFactory} object.
*/
public void setCollectdConfig(CollectdConfigFactory collectdConfigFactory) {
m_collectdConfig = collectdConfigFactory;
}
/**
* <p>afterPropertiesSet</p>
*/
@Override
public void afterPropertiesSet() {
Assert.state(m_jdbcTemplate != null, "property jdbcTemplate must be set to a non-null value");
Assert.state(m_opennmsServerConfig != null, "property opennmsServerConfig must be set to a non-null value");
Assert.state(m_pollerConfig != null, "property pollerConfig must be set to a non-null value");
Assert.state(m_collectdConfig != null, "property collectdConfig must be set to a non-null value");
}
/* (non-Javadoc)
* @see org.opennms.netmgt.capsd.CapsdDbSyncerI#getInterfaceDbNodeId(java.sql.Connection, java.net.InetAddress, int)
*/
/**
* <p>getInterfaceDbNodeId</p>
*
* @param dbConn a {@link java.sql.Connection} object.
* @param ifAddress a {@link java.net.InetAddress} object.
* @param ifIndex a int.
* @return a int.
* @throws java.sql.SQLException if any.
*/
public int getInterfaceDbNodeId(Connection dbConn, InetAddress ifAddress, int ifIndex) throws SQLException {
if (log().isDebugEnabled()) {
log().debug("getInterfaceDbNodeId: attempting to lookup interface " + InetAddressUtils.str(ifAddress) + "/ifindex: " + ifIndex + " in the database.");
}
// Set connection as read-only
// dbConn.setReadOnly(true);
StringBuffer qs = new StringBuffer(RETRIEVE_IPADDR_NODEID_SQL);
if (ifIndex != -1) {
qs.append(" AND ifindex=?");
}
int nodeid = -1;
final DBUtils d = new DBUtils(getClass());
try {
PreparedStatement s = dbConn.prepareStatement(qs.toString());
d.watch(s);
s.setString(1, InetAddressUtils.str(ifAddress));
if (ifIndex != -1) {
s.setInt(2, ifIndex);
}
ResultSet rs = s.executeQuery();
d.watch(rs);
if (rs.next()) {
nodeid = rs.getInt(1);
}
} finally {
d.cleanUp();
}
return nodeid;
}
/* (non-Javadoc)
* @see org.opennms.netmgt.capsd.CapsdDbSyncerI#isInterfaceInDB(java.sql.Connection, java.net.InetAddress)
*/
/** {@inheritDoc} */
@Override
public boolean isInterfaceInDB(final InetAddress ifAddress) {
return m_jdbcTemplate.execute(new ConnectionCallback<Boolean>() {
public Boolean doInConnection(Connection con) throws SQLException, DataAccessException {
return isInterfaceInDB(con, ifAddress) ? Boolean.TRUE : Boolean.FALSE;
}
}).booleanValue();
}
/** {@inheritDoc} */
@Override
public boolean isInterfaceInDB(Connection dbConn, InetAddress ifAddress) throws SQLException {
boolean result = false;
if (log().isDebugEnabled()) {
log().debug("isInterfaceInDB: attempting to lookup interface " + InetAddressUtils.str(ifAddress) + " in the database.");
}
// Set connection as read-only
//
// dbConn.setReadOnly(true);
ResultSet rs = null;
final DBUtils d = new DBUtils(getClass());
try {
PreparedStatement s = dbConn.prepareStatement(RETRIEVE_IPADDR_SQL);
d.watch(s);
s.setString(1, InetAddressUtils.str(ifAddress));
rs = s.executeQuery();
d.watch(rs);
result = rs.next();
} finally {
d.cleanUp();
}
return result;
}
/**
* <p>setNextSvcIdSql</p>
*
* @param nextSvcIdSql a {@link java.lang.String} object.
*/
public void setNextSvcIdSql(String nextSvcIdSql) {
m_nextSvcIdSql = nextSvcIdSql;
}
/**
* <p>getNextSvcIdSql</p>
*
* @return a {@link java.lang.String} object.
*/
public String getNextSvcIdSql() {
return m_nextSvcIdSql;
}
/**
* <p>setJdbcTemplate</p>
*
* @param jdbcTemplate a {@link org.springframework.jdbc.core.JdbcTemplate} object.
*/
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
m_jdbcTemplate = jdbcTemplate;
}
}